From 1ec0e750a3296eadb28bb0e57a4a5e3bab439a94 Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sat, 18 May 2024 22:14:22 -0400 Subject: [PATCH 001/211] Added fix for ESP32 --- src/detect/ScanI2C.cpp | 30 +++++++++++++++++++++++++++++- src/detect/ScanI2C.h | 1 + src/main.cpp | 3 +++ src/main.h | 3 ++- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 149bb95f05..941fdf3e89 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,4 +1,6 @@ #include "ScanI2C.h" +#include "main.h" +#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -27,7 +29,33 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } - +bool performScanForCardKB() { + // Example I2C scan code for CardKB (adjust as needed) + Wire.beginTransmission(CARDKB_I2C_ADDRESS); + if (Wire.endTransmission() == 0) { + return true; // CardKB detected + } + return false; // CardKB not detected +} +void scanForCardKB() { + const int maxRetries = 10; // Maximum number of retries + const int retryDelay = 100; // Delay between retries in milliseconds + + for (int i = 0; i < maxRetries; ++i) { + // Perform the scan (example scan code, adjust as needed) + cardKBDetected = performScanForCardKB(); + + if (cardKBDetected) { + Serial.println("CardKB Keyboard detected."); + break; + } + + delay(retryDelay); // Wait before the next retry + } + if (!cardKBDetected) { + Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); + } +} ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 6c01b91000..15668aecb2 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,6 +2,7 @@ #include #include +bool performScanForCardKB(); class ScanI2C { diff --git a/src/main.cpp b/src/main.cpp index 4a9fef5d08..a3e9258baa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,8 @@ #include // #include +bool cardKBDetected = false; +void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -374,6 +376,7 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif +scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index db05a47347..737d424a73 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif - +extern bool cardKBDetected; #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,6 +39,7 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; +#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From a5fdb663e25055292bef3042110e9b8b77d9bf01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 19 May 2024 19:32:08 +0200 Subject: [PATCH 002/211] change the main scan class so they scan only for wanted bits - UNTESTED --- src/detect/ScanI2C.cpp | 31 ++--------------------------- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 13 ++++++++++-- src/detect/ScanI2CTwoWire.h | 4 +++- src/input/kbI2cBase.cpp | 37 +++++++++++++++++++++++++++++++++-- src/main.cpp | 3 --- src/main.h | 3 +-- 7 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 941fdf3e89..7d0a836531 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,6 +1,4 @@ #include "ScanI2C.h" -#include "main.h" -#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -8,6 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, int *address) {} void ScanI2C::setSuppressScreen() { @@ -29,33 +28,7 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } -bool performScanForCardKB() { - // Example I2C scan code for CardKB (adjust as needed) - Wire.beginTransmission(CARDKB_I2C_ADDRESS); - if (Wire.endTransmission() == 0) { - return true; // CardKB detected - } - return false; // CardKB not detected -} -void scanForCardKB() { - const int maxRetries = 10; // Maximum number of retries - const int retryDelay = 100; // Delay between retries in milliseconds - - for (int i = 0; i < maxRetries; ++i) { - // Perform the scan (example scan code, adjust as needed) - cardKBDetected = performScanForCardKB(); - - if (cardKBDetected) { - Serial.println("CardKB Keyboard detected."); - break; - } - - delay(retryDelay); // Wait before the next retry - } - if (!cardKBDetected) { - Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); - } -} + ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 15668aecb2..4aa4549cc8 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,7 +2,6 @@ #include #include -bool performScanForCardKB(); class ScanI2C { @@ -82,6 +81,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); + virtual void scanPort(ScanI2C::I2CPort, int *); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 7828dfb586..f7068ee025 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -135,7 +135,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port) +void ScanI2CTwoWire::scanPort(I2CPort port, int *address) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,6 +163,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port) #endif for (addr.address = 1; addr.address < 127; addr.address++) { + // Skip the address if it is not requested oon a partial scan + if (sizeof(address) > 0 && addr.address != *address) { + continue; + } i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -353,6 +357,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port) } } +void ScanI2CTwoWire::scanPort(I2CPort port) +{ + scanPort(port, nullptr); +} + TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const { if (address.port == ScanI2C::I2CPort::WIRE) { @@ -369,4 +378,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const size_t ScanI2CTwoWire::countDevices() const { return foundDevices.size(); -} +} \ No newline at end of file diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 9acd736d2e..a7c19c7791 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,6 +16,8 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; + void scanPort(ScanI2C::I2CPort, int *) override; + ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const; @@ -53,4 +55,4 @@ class ScanI2CTwoWire : public ScanI2C uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const; DeviceType probeOLED(ScanI2C::DeviceAddress) const; -}; +}; \ No newline at end of file diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index af7c96b206..55f435fda7 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -1,6 +1,7 @@ #include "kbI2cBase.h" #include "configuration.h" #include "detect/ScanI2C.h" +#include "detect/ScanI2CTwoWire.h" extern ScanI2C::DeviceAddress cardkb_found; extern uint8_t kb_model; @@ -30,8 +31,40 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len int32_t KbI2cBase::runOnce() { if (cardkb_found.address == 0x00) { - // Input device is not detected. - return INT32_MAX; + // Input device is not detected. Rescan now. + auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); + int i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; +#if defined(I2C_SDA1) + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); +#endif + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan); + auto kb_info = i2cScanner->firstKeyboard(); + + if (kb_info.type != ScanI2C::DeviceType::NONE) { + cardkb_found = kb_info.address; + switch (kb_info.type) { + case ScanI2C::DeviceType::RAK14004: + kb_model = 0x02; + break; + case ScanI2C::DeviceType::CARDKB: + kb_model = 0x00; + break; + case ScanI2C::DeviceType::TDECKKB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x10; + break; + case ScanI2C::DeviceType::BBQ10KB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x11; + break; + default: + // use this as default since it's also just zero + LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type); + kb_model = 0x00; + } + } + if (cardkb_found.address == 0x00) + return INT32_MAX; } if (!i2cBus) { diff --git a/src/main.cpp b/src/main.cpp index a3e9258baa..4a9fef5d08 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,8 +35,6 @@ #include // #include -bool cardKBDetected = false; -void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -376,7 +374,6 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif -scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index 737d424a73..db05a47347 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif -extern bool cardKBDetected; + #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,7 +39,6 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; -#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From 3a628047ef40f34060e8c8f7e5132d24be45bcad Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sat, 18 May 2024 22:14:22 -0400 Subject: [PATCH 003/211] Added fix for ESP32 --- src/detect/ScanI2C.cpp | 30 +++++++++++++++++++++++++++++- src/detect/ScanI2C.h | 1 + src/main.cpp | 3 +++ src/main.h | 3 ++- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 149bb95f05..941fdf3e89 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,4 +1,6 @@ #include "ScanI2C.h" +#include "main.h" +#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -27,7 +29,33 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } - +bool performScanForCardKB() { + // Example I2C scan code for CardKB (adjust as needed) + Wire.beginTransmission(CARDKB_I2C_ADDRESS); + if (Wire.endTransmission() == 0) { + return true; // CardKB detected + } + return false; // CardKB not detected +} +void scanForCardKB() { + const int maxRetries = 10; // Maximum number of retries + const int retryDelay = 100; // Delay between retries in milliseconds + + for (int i = 0; i < maxRetries; ++i) { + // Perform the scan (example scan code, adjust as needed) + cardKBDetected = performScanForCardKB(); + + if (cardKBDetected) { + Serial.println("CardKB Keyboard detected."); + break; + } + + delay(retryDelay); // Wait before the next retry + } + if (!cardKBDetected) { + Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); + } +} ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 6c01b91000..15668aecb2 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,6 +2,7 @@ #include #include +bool performScanForCardKB(); class ScanI2C { diff --git a/src/main.cpp b/src/main.cpp index 4a9fef5d08..a3e9258baa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,8 @@ #include // #include +bool cardKBDetected = false; +void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -374,6 +376,7 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif +scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index db05a47347..737d424a73 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif - +extern bool cardKBDetected; #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,6 +39,7 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; +#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From a37f309c0379dfa161f2dae41f319acdc0b3d0b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 19 May 2024 19:32:08 +0200 Subject: [PATCH 004/211] change the main scan class so they scan only for wanted bits - UNTESTED --- src/detect/ScanI2C.cpp | 31 ++--------------------------- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 13 ++++++++++-- src/detect/ScanI2CTwoWire.h | 4 +++- src/input/kbI2cBase.cpp | 37 +++++++++++++++++++++++++++++++++-- src/main.cpp | 3 --- src/main.h | 3 +-- 7 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 941fdf3e89..7d0a836531 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,6 +1,4 @@ #include "ScanI2C.h" -#include "main.h" -#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -8,6 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, int *address) {} void ScanI2C::setSuppressScreen() { @@ -29,33 +28,7 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } -bool performScanForCardKB() { - // Example I2C scan code for CardKB (adjust as needed) - Wire.beginTransmission(CARDKB_I2C_ADDRESS); - if (Wire.endTransmission() == 0) { - return true; // CardKB detected - } - return false; // CardKB not detected -} -void scanForCardKB() { - const int maxRetries = 10; // Maximum number of retries - const int retryDelay = 100; // Delay between retries in milliseconds - - for (int i = 0; i < maxRetries; ++i) { - // Perform the scan (example scan code, adjust as needed) - cardKBDetected = performScanForCardKB(); - - if (cardKBDetected) { - Serial.println("CardKB Keyboard detected."); - break; - } - - delay(retryDelay); // Wait before the next retry - } - if (!cardKBDetected) { - Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); - } -} + ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 15668aecb2..4aa4549cc8 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,7 +2,6 @@ #include #include -bool performScanForCardKB(); class ScanI2C { @@ -82,6 +81,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); + virtual void scanPort(ScanI2C::I2CPort, int *); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 7828dfb586..f7068ee025 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -135,7 +135,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port) +void ScanI2CTwoWire::scanPort(I2CPort port, int *address) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,6 +163,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port) #endif for (addr.address = 1; addr.address < 127; addr.address++) { + // Skip the address if it is not requested oon a partial scan + if (sizeof(address) > 0 && addr.address != *address) { + continue; + } i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -353,6 +357,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port) } } +void ScanI2CTwoWire::scanPort(I2CPort port) +{ + scanPort(port, nullptr); +} + TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const { if (address.port == ScanI2C::I2CPort::WIRE) { @@ -369,4 +378,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const size_t ScanI2CTwoWire::countDevices() const { return foundDevices.size(); -} +} \ No newline at end of file diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 9acd736d2e..a7c19c7791 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,6 +16,8 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; + void scanPort(ScanI2C::I2CPort, int *) override; + ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const; @@ -53,4 +55,4 @@ class ScanI2CTwoWire : public ScanI2C uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const; DeviceType probeOLED(ScanI2C::DeviceAddress) const; -}; +}; \ No newline at end of file diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index af7c96b206..55f435fda7 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -1,6 +1,7 @@ #include "kbI2cBase.h" #include "configuration.h" #include "detect/ScanI2C.h" +#include "detect/ScanI2CTwoWire.h" extern ScanI2C::DeviceAddress cardkb_found; extern uint8_t kb_model; @@ -30,8 +31,40 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len int32_t KbI2cBase::runOnce() { if (cardkb_found.address == 0x00) { - // Input device is not detected. - return INT32_MAX; + // Input device is not detected. Rescan now. + auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); + int i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; +#if defined(I2C_SDA1) + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); +#endif + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan); + auto kb_info = i2cScanner->firstKeyboard(); + + if (kb_info.type != ScanI2C::DeviceType::NONE) { + cardkb_found = kb_info.address; + switch (kb_info.type) { + case ScanI2C::DeviceType::RAK14004: + kb_model = 0x02; + break; + case ScanI2C::DeviceType::CARDKB: + kb_model = 0x00; + break; + case ScanI2C::DeviceType::TDECKKB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x10; + break; + case ScanI2C::DeviceType::BBQ10KB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x11; + break; + default: + // use this as default since it's also just zero + LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type); + kb_model = 0x00; + } + } + if (cardkb_found.address == 0x00) + return INT32_MAX; } if (!i2cBus) { diff --git a/src/main.cpp b/src/main.cpp index a3e9258baa..4a9fef5d08 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,8 +35,6 @@ #include // #include -bool cardKBDetected = false; -void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -376,7 +374,6 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif -scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index 737d424a73..db05a47347 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif -extern bool cardKBDetected; + #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,7 +39,6 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; -#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From dca8615eaade72d847866058ce75795a17b1b38a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 24 May 2024 22:59:31 +0200 Subject: [PATCH 005/211] change type to 8 bit uint --- src/detect/ScanI2C.cpp | 2 +- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 6 +++--- src/detect/ScanI2CTwoWire.h | 2 +- src/input/kbI2cBase.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 7d0a836531..f3057c81a2 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -6,7 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} -void ScanI2C::scanPort(ScanI2C::I2CPort port, int *address) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address) {} void ScanI2C::setSuppressScreen() { diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 4aa4549cc8..64c9ddbc28 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -81,7 +81,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); - virtual void scanPort(ScanI2C::I2CPort, int *); + virtual void scanPort(ScanI2C::I2CPort, uint8_t *); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index f7068ee025..06b94d6af9 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -135,7 +135,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port, int *address) +void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,8 +163,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port, int *address) #endif for (addr.address = 1; addr.address < 127; addr.address++) { - // Skip the address if it is not requested oon a partial scan - if (sizeof(address) > 0 && addr.address != *address) { + // Skip the address if it is not requested on a partial scan + if (address != nullptr && *address != addr.address) { continue; } i2cBus->beginTransmission(addr.address); diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index a7c19c7791..332afbf64e 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,7 +16,7 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; - void scanPort(ScanI2C::I2CPort, int *) override; + void scanPort(ScanI2C::I2CPort, uint8_t *) override; ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index 55f435fda7..135de17166 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -33,7 +33,7 @@ int32_t KbI2cBase::runOnce() if (cardkb_found.address == 0x00) { // Input device is not detected. Rescan now. auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); - int i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; + uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; #if defined(I2C_SDA1) i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); #endif From c46c3427f0c6ae8809e0aec3a731792f724dcd85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 25 May 2024 12:37:55 +0200 Subject: [PATCH 006/211] Iterate through uint array --- src/detect/ScanI2C.cpp | 2 +- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 21 +++++++++++++++------ src/detect/ScanI2CTwoWire.h | 2 +- src/input/kbI2cBase.cpp | 5 +++-- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index f3057c81a2..525780af66 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -6,7 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} -void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address, uint8_t asize) {} void ScanI2C::setSuppressScreen() { diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 64c9ddbc28..4084c44797 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -81,7 +81,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); - virtual void scanPort(ScanI2C::I2CPort, uint8_t *); + virtual void scanPort(ScanI2C::I2CPort, uint8_t *, uint8_t); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 06b94d6af9..3376d23beb 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -14,6 +14,15 @@ #define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 #endif +bool in_array(uint8_t *array, int size, uint8_t lookfor) +{ + int i; + for (i = 0; i < size; i++) + if (lookfor == array[i]) + return true; + return false; +} + ScanI2C::FoundDevice ScanI2CTwoWire::find(ScanI2C::DeviceType type) const { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -135,7 +144,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) +void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,10 +172,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) #endif for (addr.address = 1; addr.address < 127; addr.address++) { - // Skip the address if it is not requested on a partial scan - if (address != nullptr && *address != addr.address) { - continue; - } + if (asize != 0) + if (in_array(address, asize, addr.address)) + continue; + i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -359,7 +368,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) void ScanI2CTwoWire::scanPort(I2CPort port) { - scanPort(port, nullptr); + scanPort(port, nullptr, 0); } TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 332afbf64e..82b48f6b47 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,7 +16,7 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; - void scanPort(ScanI2C::I2CPort, uint8_t *) override; + void scanPort(ScanI2C::I2CPort, uint8_t *, uint8_t) override; ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index 135de17166..ce22edb93d 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -34,10 +34,11 @@ int32_t KbI2cBase::runOnce() // Input device is not detected. Rescan now. auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; + uint8_t i2caddr_asize = 3; #if defined(I2C_SDA1) - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize); #endif - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan); + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize); auto kb_info = i2cScanner->firstKeyboard(); if (kb_info.type != ScanI2C::DeviceType::NONE) { From 5554cc46a72acb56bee55613a39bd1e44095ecba Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Wed, 8 May 2024 20:15:06 +0800 Subject: [PATCH 007/211] Add REGULATORY_ prefix to LORA_REGIONCODE Add REGULATORY_ prefix to LORA_REGIONCODE to prepare for more regulatory configuration options, and update comment block accordingly too. Signed-off-by: Andrew Yong --- src/configuration.h | 6 +++--- src/mesh/RadioInterface.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index 462210cf2b..6dcca72dcc 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -75,11 +75,11 @@ along with this program. If not, see . #endif // ----------------------------------------------------------------------------- -// Regulatory overrides for producing regional builds +// Regulatory overrides // ----------------------------------------------------------------------------- -// Define if region should override user saved region -// #define LORA_REGIONCODE meshtastic_Config_LoRaConfig_RegionCode_SG_923 +// Override user saved region, for producing region-locked builds +// #define REGULATORY_LORA_REGIONCODE meshtastic_Config_LoRaConfig_RegionCode_SG_923 // ----------------------------------------------------------------------------- // Feature toggles diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index cc6ccca079..7a1fcfb940 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -154,8 +154,8 @@ static uint8_t bytes[MAX_RHPACKETLEN]; void initRegion() { const RegionInfo *r = regions; -#ifdef LORA_REGIONCODE - for (; r->code != meshtastic_Config_LoRaConfig_RegionCode_UNSET && r->code != LORA_REGIONCODE; r++) +#ifdef REGULATORY_LORA_REGIONCODE + for (; r->code != meshtastic_Config_LoRaConfig_RegionCode_UNSET && r->code != REGULATORY_LORA_REGIONCODE; r++) ; LOG_INFO("Wanted region %d, regulatory override to %s\n", config.lora.region, r->name); #else From 3cda5986732593f23ba2c293c2b0d68ba87fe1ef Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Thu, 9 May 2024 02:27:08 +0800 Subject: [PATCH 008/211] Add REGULATORY_GAIN configuration to remain within regulatory ERP limit REGULATORY_GAIN is the total system gain in dBm to subtract from the configured Tx power, to remain within regulatory ERP limit for non-licensed operators. This value should be set in variant.h and is PA gain + antenna gain (if system ships with an antenna). This is similar to antenna_gain/NL80211_ATTR_WIPHY_ANTENNA_GAIN/NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN setting in Linux Regulatory/OpenWrt/mac80211/nl80211/iw. Signed-off-by: Andrew Yong --- src/configuration.h | 6 ++++++ src/mesh/RadioInterface.cpp | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index 6dcca72dcc..eab2d01204 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -81,6 +81,12 @@ along with this program. If not, see . // Override user saved region, for producing region-locked builds // #define REGULATORY_LORA_REGIONCODE meshtastic_Config_LoRaConfig_RegionCode_SG_923 +// Total system gain in dBm to subtract from Tx power to remain within regulatory ERP limit for non-licensed operators +// This value should be set in variant.h and is PA gain + antenna gain (if system ships with an antenna) +#ifndef REGULATORY_GAIN +#define REGULATORY_GAIN 0 +#endif + // ----------------------------------------------------------------------------- // Feature toggles // ----------------------------------------------------------------------------- diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 7a1fcfb940..8e77beee4e 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -478,8 +478,8 @@ void RadioInterface::applyModemConfig() power = loraConfig.tx_power; - if ((power == 0) || ((power > myRegion->powerLimit) && !devicestate.owner.is_licensed)) - power = myRegion->powerLimit; + if ((power == 0) || ((power + REGULATORY_GAIN > myRegion->powerLimit) && !devicestate.owner.is_licensed)) + power = myRegion->powerLimit - REGULATORY_GAIN; if (power == 0) power = 17; // Default to this power level if we don't have a valid regional power limit (powerLimit of myRegion defaults From d1d49efc6e4f5fd5294a4a3f120b739c25f522e5 Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Thu, 9 May 2024 02:27:29 +0800 Subject: [PATCH 009/211] Implement REGULATORY_GAIN and SX126X_MAX_POWER in XIAO BLE EBYTE E22 Specify REGULATORY_GAIN and SX126X_MAX_POWER to prevent exceeding regulatory and hardware limits (i.e. overloading the PA input) respectively. Also update the build flag to define EBYTE_E22_900M30S instead of just EBYTE_E22, since all the builds on the Discourse topic [New 1W DIY variant: Xiao nRF52840 + Ebyte E22-900M30S](https://meshtastic.discourse.group/t/new-1w-diy-variant-xiao-nrf52840-ebyte-e22-900m30s/7904) are using this module. That should make it clearer as well that the variant header file should be tweaked if DIY builds are using stronger (E22-900M33S, not commonly available at this time) or weaker (E22-900M22S, not popular for DIY builds due to lack of differentiation from ordinary SX1262 modules). Retain EBYTE_E22 flag alongside EBYTE_E22_900M30S build flag to prevent possible regressions in code paths generally intended for EBYTE E22 modules. Signed-off-by: Andrew Yong --- variants/xiao_ble/platformio.ini | 2 +- variants/xiao_ble/variant.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/variants/xiao_ble/platformio.ini b/variants/xiao_ble/platformio.ini index 8e9a663a98..165536cce1 100644 --- a/variants/xiao_ble/platformio.ini +++ b/variants/xiao_ble/platformio.ini @@ -3,7 +3,7 @@ extends = nrf52840_base board = xiao_ble_sense board_level = extra -build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Dxiao_ble -D EBYTE_E22 +build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Dxiao_ble -DEBYTE_E22 -DEBYTE_E22_900M30S -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" build_src_filter = ${nrf52_base.build_src_filter} +<../variants/xiao_ble> lib_deps = diff --git a/variants/xiao_ble/variant.h b/variants/xiao_ble/variant.h index 77af08278c..1869e4eee2 100644 --- a/variants/xiao_ble/variant.h +++ b/variants/xiao_ble/variant.h @@ -142,6 +142,11 @@ static const uint8_t SCK = PIN_SPI_SCK; // (which is the default for the sx1262interface code) #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 +#ifdef EBYTE_E22_900M30S +// 10dB PA gain and 30dB rated output; based on PA output table from Ebyte Robin +#define REGULATORY_GAIN 10 +#define SX126X_MAX_POWER 20 +#endif #endif /* From 537814df588f1c42b2a7bd4b768f743ad4d046f9 Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Wed, 22 May 2024 03:16:27 +0800 Subject: [PATCH 010/211] xiao_ble: Add EBYTE E22-900M33S PA gain and limits Signed-off-by: Andrew Yong --- variants/xiao_ble/variant.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/variants/xiao_ble/variant.h b/variants/xiao_ble/variant.h index 1869e4eee2..4ca38f928a 100644 --- a/variants/xiao_ble/variant.h +++ b/variants/xiao_ble/variant.h @@ -147,6 +147,11 @@ static const uint8_t SCK = PIN_SPI_SCK; #define REGULATORY_GAIN 10 #define SX126X_MAX_POWER 20 #endif +#ifdef EBYTE_E22_900M33S +// 25dB PA gain and 33dB rated output; based on TX Power Curve from E22-900M33S_UserManual_EN_v1.0.pdf +#define REGULATORY_GAIN 25 +#define SX126X_MAX_POWER 8 +#endif #endif /* From 08e1c2f68122e21030879cc3cfe34a5edef54444 Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Thu, 23 May 2024 23:28:07 +0800 Subject: [PATCH 011/211] Rename REGULATORY_GAIN to REGULATORY_GAIN_LORA to allow for other RF gain controls For example, Wi-Fi or BLE gain control (#3962) Signed-off-by: Andrew Yong --- src/configuration.h | 4 ++-- src/mesh/RadioInterface.cpp | 4 ++-- variants/xiao_ble/variant.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index eab2d01204..a8b059d2cf 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -83,8 +83,8 @@ along with this program. If not, see . // Total system gain in dBm to subtract from Tx power to remain within regulatory ERP limit for non-licensed operators // This value should be set in variant.h and is PA gain + antenna gain (if system ships with an antenna) -#ifndef REGULATORY_GAIN -#define REGULATORY_GAIN 0 +#ifndef REGULATORY_GAIN_LORA +#define REGULATORY_GAIN_LORA 0 #endif // ----------------------------------------------------------------------------- diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 8e77beee4e..ae05ed004e 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -478,8 +478,8 @@ void RadioInterface::applyModemConfig() power = loraConfig.tx_power; - if ((power == 0) || ((power + REGULATORY_GAIN > myRegion->powerLimit) && !devicestate.owner.is_licensed)) - power = myRegion->powerLimit - REGULATORY_GAIN; + if ((power == 0) || ((power + REGULATORY_GAIN_LORA > myRegion->powerLimit) && !devicestate.owner.is_licensed)) + power = myRegion->powerLimit - REGULATORY_GAIN_LORA; if (power == 0) power = 17; // Default to this power level if we don't have a valid regional power limit (powerLimit of myRegion defaults diff --git a/variants/xiao_ble/variant.h b/variants/xiao_ble/variant.h index 4ca38f928a..a86ddfde26 100644 --- a/variants/xiao_ble/variant.h +++ b/variants/xiao_ble/variant.h @@ -144,12 +144,12 @@ static const uint8_t SCK = PIN_SPI_SCK; #define SX126X_DIO3_TCXO_VOLTAGE 1.8 #ifdef EBYTE_E22_900M30S // 10dB PA gain and 30dB rated output; based on PA output table from Ebyte Robin -#define REGULATORY_GAIN 10 +#define REGULATORY_GAIN_LORA 10 #define SX126X_MAX_POWER 20 #endif #ifdef EBYTE_E22_900M33S // 25dB PA gain and 33dB rated output; based on TX Power Curve from E22-900M33S_UserManual_EN_v1.0.pdf -#define REGULATORY_GAIN 25 +#define REGULATORY_GAIN_LORA 25 #define SX126X_MAX_POWER 8 #endif #endif From d60d1d74477a5ad3f5d6785b8157f255bb0bbfd4 Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Wed, 12 Jun 2024 23:34:00 +1200 Subject: [PATCH 012/211] Workaround to disable bluetooth on NRF52 (#4055) * Workaround to allow bluetooth disable on NRF52 * Use miminum tx power for bluetooth * Reorganize * Instantiate nrf52Bluetooth correctly.. * Change log message --- src/platform/nrf52/NRF52Bluetooth.cpp | 12 +++++++ src/platform/nrf52/NRF52Bluetooth.h | 1 + src/platform/nrf52/main-nrf52.cpp | 51 ++++++++++++++++++--------- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 39898ab259..4c25f38ea3 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -215,6 +215,18 @@ void NRF52Bluetooth::shutdown() Bluefruit.Advertising.stop(); } +void NRF52Bluetooth::startDisabled() +{ + // Setup Bluetooth + nrf52Bluetooth->setup(); + + // Shutdown bluetooth for minimum power draw + Bluefruit.Advertising.stop(); + Bluefruit.setTxPower(-40); // Minimum power + + LOG_INFO("Disabling NRF52 Bluetooth. (Workaround: tx power min, advertising stopped)\n"); +} + bool NRF52Bluetooth::isConnected() { return Bluefruit.connected(connectionHandle); diff --git a/src/platform/nrf52/NRF52Bluetooth.h b/src/platform/nrf52/NRF52Bluetooth.h index 11e18c1272..450af47f91 100644 --- a/src/platform/nrf52/NRF52Bluetooth.h +++ b/src/platform/nrf52/NRF52Bluetooth.h @@ -8,6 +8,7 @@ class NRF52Bluetooth : BluetoothApi public: void setup(); void shutdown(); + void startDisabled(); void resumeAdvertising(); void clearBonds(); bool isConnected(); diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 9cc52a7de8..1f2c6867d5 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -68,28 +68,47 @@ static const bool useSoftDevice = true; // Set to false for easier debugging #if !MESHTASTIC_EXCLUDE_BLUETOOTH void setBluetoothEnable(bool enable) { - if (enable && config.bluetooth.enabled) { - if (!useSoftDevice) { + // For debugging use: don't use bluetooth + if (!useSoftDevice) { + if (enable) LOG_INFO("DISABLING NRF52 BLUETOOTH WHILE DEBUGGING\n"); - } else { - if (!nrf52Bluetooth) { - LOG_DEBUG("Initializing NRF52 Bluetooth\n"); - nrf52Bluetooth = new NRF52Bluetooth(); - nrf52Bluetooth->setup(); - - // We delay brownout init until after BLE because BLE starts soft device - initBrownout(); - } else { - nrf52Bluetooth->resumeAdvertising(); - } + return; + } + + // If user disabled bluetooth: init then disable advertising & reduce power + // Workaround. Avoid issue where device hangs several days after boot.. + // Allegedly, no significant increase in power consumption + if (!config.bluetooth.enabled) { + static bool initialized = false; + if (!initialized) { + nrf52Bluetooth = new NRF52Bluetooth(); + nrf52Bluetooth->startDisabled(); + initBrownout(); + initialized = true; } - } else { - if (nrf52Bluetooth) { - nrf52Bluetooth->shutdown(); + return; + } + + if (enable) { + // If not yet set-up + if (!nrf52Bluetooth) { + LOG_DEBUG("Initializing NRF52 Bluetooth\n"); + nrf52Bluetooth = new NRF52Bluetooth(); + nrf52Bluetooth->setup(); + + // We delay brownout init until after BLE because BLE starts soft device + initBrownout(); } + // Already setup, apparently + else + nrf52Bluetooth->resumeAdvertising(); } + // Disable (if previously set-up) + else if (nrf52Bluetooth) + nrf52Bluetooth->shutdown(); } #else +#warning NRF52 "Bluetooth disable" workaround does not apply to builds with MESHTASTIC_EXCLUDE_BLUETOOTH void setBluetoothEnable(bool enable) {} #endif /** From 992d1c42e6d73f46e818fb8178d8e067d48bdec0 Mon Sep 17 00:00:00 2001 From: Jan Veeh <33117982+craft4tnt@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:43:50 +0200 Subject: [PATCH 013/211] changed CFG-PM config message to use external signal (#4062) --- src/gps/ubx.h | 61 ++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/src/gps/ubx.h b/src/gps/ubx.h index 0a382a8a3d..df03c16345 100644 --- a/src/gps/ubx.h +++ b/src/gps/ubx.h @@ -319,6 +319,7 @@ const uint8_t GPS::_message_SAVE[] = { // As the M10 has no flash, the best we can do to preserve the config is to set it in RAM and BBR. // BBR will survive a restart, and power off for a while, but modules with small backup // batteries or super caps will not retain the config for a long power off time. +// for all configurations using sleep / low power modes, V_BCKP needs to be hooked to permanent power for fast aquisition after sleep // VALSET Commands for M10 // Please refer to the M10 Protocol Specification: @@ -327,40 +328,44 @@ const uint8_t GPS::_message_SAVE[] = { // and: // https://content.u-blox.com/sites/default/files/u-blox-M10-ROM-5.10_ReleaseNotes_UBX-22001426.pdf // for interesting insights. +// +// Integration manual: +// https://content.u-blox.com/sites/default/files/documents/SAM-M10Q_IntegrationManual_UBX-22020019.pdf +// has details on low-power modes + /* CFG-PM2 has been replaced by many CFG-PM commands -OPERATEMODE E1 2 (0 | 1 | 2) -POSUPDATEPERIOD U4 1000ms for M10 must be >= 5s try 5 -ACQPERIOD U4 10 seems ok for M10 def ok -GRIDOFFSET U4 0 seems ok for M10 def ok -ONTIME U2 1 will try 1 -MINACQTIME U1 0 will try 0 def ok -MAXACQTIME U1 stick with default of 0 def ok -DONOTENTEROFF L 1 stay at 1 -WAITTIMEFIX L 1 stay with 1 -UPDATEEPH L 1 changed to 1 for gps rework default is 1 -EXTINTWAKE L 0 no ext ints -EXTINTBACKUP L 0 no ext ints -EXTINTINACTIVE L 0 no ext ints -EXTINTACTIVITY U4 0 no ext ints -LIMITPEAKCURRENT L 1 stay with 1 -*/ -// CFG-PMS has been removed +CFG-PMS has been removed + +CFG-PM-OPERATEMODE E1 (0 | 1 | 2) -> 1 (PSMOO), because sporadic position updates are required instead of continous tracking <10s (PSMCT) +CFG-PM-POSUPDATEPERIOD U4 -> 0ms, no self-timed wakup because receiver power mode is controlled via "software standby mode" by legacy UBX-RXM-PMREQ request +CFG-PM-ACQPERIOD U4 -> 0ms, because receiver power mode is controlled via "software standby mode" by legacy UBX-RXM-PMREQ request +CFG-PM-ONTIME U4 -> 0ms, optional I guess +CFG-PM-EXTINTBACKUP L -> 1, force receiver into BACKUP mode when EXTINT (should be connected to GPS_EN_PIN) pin is "low" + +This is required because the receiver never enters low power mode if microcontroller is in deep-sleep. +Maybe the changing UART_RX levels trigger a wakeup but even with UBX-RXM-PMREQ[12] = 0x00 (all external wakeup sources disabled) the receivcer remains +in aquisition state -> potentially a bug + +Workaround: Control the EXTINT pin by the GPS_EN_PIN signal + +As mentioned in the M10 operational issues down below, power save won't allow the use of BDS B1C. +CFG-SIGNAL-BDS_B1C_ENA L -> 0 // Ram layer config message: -// b5 62 06 8a 26 00 00 01 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0 -// 10 01 8b de +// 01 01 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01 // BBR layer config message: -// b5 62 06 8a 26 00 00 02 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0 -// 10 01 8c 03 - -const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, - 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; -const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, - 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; +// 01 02 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01 +*/ +const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x01, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, + 0x01, 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, + 0x10, 0x01}; +const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x01, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, + 0x01, 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, + 0x10, 0x01}; /* CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM and one for BBR From b09cee118c5f17c9d9e38473896b041776a3faea Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 12 Jun 2024 06:57:11 -0500 Subject: [PATCH 014/211] Trunk --- src/gps/ubx.h | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/gps/ubx.h b/src/gps/ubx.h index df03c16345..0852c331d0 100644 --- a/src/gps/ubx.h +++ b/src/gps/ubx.h @@ -319,7 +319,8 @@ const uint8_t GPS::_message_SAVE[] = { // As the M10 has no flash, the best we can do to preserve the config is to set it in RAM and BBR. // BBR will survive a restart, and power off for a while, but modules with small backup // batteries or super caps will not retain the config for a long power off time. -// for all configurations using sleep / low power modes, V_BCKP needs to be hooked to permanent power for fast aquisition after sleep +// for all configurations using sleep / low power modes, V_BCKP needs to be hooked to permanent power for fast aquisition after +// sleep // VALSET Commands for M10 // Please refer to the M10 Protocol Specification: @@ -337,15 +338,15 @@ const uint8_t GPS::_message_SAVE[] = { CFG-PM2 has been replaced by many CFG-PM commands CFG-PMS has been removed -CFG-PM-OPERATEMODE E1 (0 | 1 | 2) -> 1 (PSMOO), because sporadic position updates are required instead of continous tracking <10s (PSMCT) -CFG-PM-POSUPDATEPERIOD U4 -> 0ms, no self-timed wakup because receiver power mode is controlled via "software standby mode" by legacy UBX-RXM-PMREQ request -CFG-PM-ACQPERIOD U4 -> 0ms, because receiver power mode is controlled via "software standby mode" by legacy UBX-RXM-PMREQ request -CFG-PM-ONTIME U4 -> 0ms, optional I guess -CFG-PM-EXTINTBACKUP L -> 1, force receiver into BACKUP mode when EXTINT (should be connected to GPS_EN_PIN) pin is "low" +CFG-PM-OPERATEMODE E1 (0 | 1 | 2) -> 1 (PSMOO), because sporadic position updates are required instead of continous tracking <10s +(PSMCT) CFG-PM-POSUPDATEPERIOD U4 -> 0ms, no self-timed wakup because receiver power mode is controlled via "software standby +mode" by legacy UBX-RXM-PMREQ request CFG-PM-ACQPERIOD U4 -> 0ms, because receiver power mode is controlled via "software standby +mode" by legacy UBX-RXM-PMREQ request CFG-PM-ONTIME U4 -> 0ms, optional I guess CFG-PM-EXTINTBACKUP L -> 1, force receiver into +BACKUP mode when EXTINT (should be connected to GPS_EN_PIN) pin is "low" This is required because the receiver never enters low power mode if microcontroller is in deep-sleep. -Maybe the changing UART_RX levels trigger a wakeup but even with UBX-RXM-PMREQ[12] = 0x00 (all external wakeup sources disabled) the receivcer remains -in aquisition state -> potentially a bug +Maybe the changing UART_RX levels trigger a wakeup but even with UBX-RXM-PMREQ[12] = 0x00 (all external wakeup sources disabled) +the receivcer remains in aquisition state -> potentially a bug Workaround: Control the EXTINT pin by the GPS_EN_PIN signal @@ -358,14 +359,12 @@ CFG-SIGNAL-BDS_B1C_ENA L -> 0 // BBR layer config message: // 01 02 00 00 01 00 D0 20 01 02 00 D0 40 00 00 00 00 03 00 D0 40 00 00 00 00 05 00 D0 30 00 00 0D 00 D0 10 01 */ -const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x01, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, - 0x01, 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, - 0x10, 0x01}; -const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x01, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, - 0x01, 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, - 0x10, 0x01}; +const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x01, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, 0x01, + 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, 0x10, 0x01}; +const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x01, 0x02, 0x00, 0x00, 0x0F, 0x00, 0x31, 0x10, 0x00, 0x01, 0x00, 0xD0, 0x20, 0x01, + 0x02, 0x00, 0xD0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xD0, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x00, 0xD0, 0x30, 0x00, 0x00, 0x0D, 0x00, 0xD0, 0x10, 0x01}; /* CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM and one for BBR From 5b1d3ed173fc1eddd8dc8e494095e4353223ccfe Mon Sep 17 00:00:00 2001 From: Heltec-Aaron-Lee Date: Wed, 12 Jun 2024 20:21:26 +0800 Subject: [PATCH 015/211] Add Heltec Capsule Sensor V3 to source code --- platformio.ini | 1 + src/ButtonThread.cpp | 4 ++ src/Power.cpp | 25 +++++++---- src/platform/esp32/architecture.h | 2 + .../heltec_capsule_sensor_v3/platformio.ini | 11 +++++ variants/heltec_capsule_sensor_v3/variant.h | 42 +++++++++++++++++++ 6 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 variants/heltec_capsule_sensor_v3/platformio.ini create mode 100644 variants/heltec_capsule_sensor_v3/variant.h diff --git a/platformio.ini b/platformio.ini index 7ed794a6ed..9c29d2d677 100644 --- a/platformio.ini +++ b/platformio.ini @@ -33,6 +33,7 @@ default_envs = tbeam ;default_envs = wio-e5 ;default_envs = radiomaster_900_bandit_nano ;default_envs = radiomaster_900_bandit_micro +;default_envs = heltec_capsule_sensor_v3 extra_configs = arch/*/*.ini diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index 7e678d69d7..4b3bb3fbc5 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -41,7 +41,11 @@ ButtonThread::ButtonThread() : OSThread("Button") } #elif defined(BUTTON_PIN) int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin +#if defined(HELTEC_CAPSULE_SENSOR_V3) + this->userButton = OneButton(pin, false, false); +#else this->userButton = OneButton(pin, true, true); +#endif LOG_DEBUG("Using GPIO%02d for button\n", pin); #endif diff --git a/src/Power.cpp b/src/Power.cpp index b80d8a0d57..d80bfd55cd 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -335,13 +335,20 @@ class AnalogBatteryLevel : public HasBatteryLevel virtual bool isVbusIn() override { #ifdef EXT_PWR_DETECT - // if external powered that pin will be pulled up - if (digitalRead(EXT_PWR_DETECT) == HIGH) { - return true; - } - // if it's not HIGH - check the battery + #ifdef HELTEC_CAPSULE_SENSOR_V3 + // if external powered that pin will be pulled down + if (digitalRead(EXT_PWR_DETECT) == LOW) { + return true; + } + // if it's not LOW - check the battery + #else + // if external powered that pin will be pulled up + if (digitalRead(EXT_PWR_DETECT) == HIGH) { + return true; + } + // if it's not HIGH - check the battery + #endif #endif - return getBattVoltage() > chargingVolt; } @@ -421,7 +428,11 @@ Power::Power() : OSThread("Power") bool Power::analogInit() { #ifdef EXT_PWR_DETECT - pinMode(EXT_PWR_DETECT, INPUT); + #ifdef HELTEC_CAPSULE_SENSOR_V3 + pinMode(EXT_PWR_DETECT, INPUT_PULLUP); + #else + pinMode(EXT_PWR_DETECT, INPUT); + #endif #endif #ifdef EXT_CHRG_DETECT pinMode(EXT_CHRG_DETECT, ext_chrg_detect_mode); diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index 824c11bdd3..c979d016cb 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -147,6 +147,8 @@ #define HW_VENDOR meshtastic_HardwareModel_WIPHONE #elif defined(RADIOMASTER_900_BANDIT_NANO) #define HW_VENDOR meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO +#elif defined(HELTEC_CAPSULE_SENSOR_V3) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3 #endif // ----------------------------------------------------------------------------- diff --git a/variants/heltec_capsule_sensor_v3/platformio.ini b/variants/heltec_capsule_sensor_v3/platformio.ini new file mode 100644 index 0000000000..f1aef925dc --- /dev/null +++ b/variants/heltec_capsule_sensor_v3/platformio.ini @@ -0,0 +1,11 @@ +[env:heltec_capsule_sensor_v3] +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +board_check = true + +build_flags = + ${esp32s3_base.build_flags} -I variants/heltec_capsule_sensor_v3 + -D HELTEC_CAPSULE_SENSOR_V3 + -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. + ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output + diff --git a/variants/heltec_capsule_sensor_v3/variant.h b/variants/heltec_capsule_sensor_v3/variant.h new file mode 100644 index 0000000000..0d5ab73cfb --- /dev/null +++ b/variants/heltec_capsule_sensor_v3/variant.h @@ -0,0 +1,42 @@ +#define LED_PIN 33 +#define LED_PIN2 34 +#define EXT_PWR_DETECT 35 + +#define BUTTON_PIN 18 + +#define BATTERY_PIN 7 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +#define ADC_CHANNEL ADC1_GPIO7_CHANNEL +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider +#define ADC_MULTIPLIER (4.9 * 1.045) +#define ADC_CTRL 36 // active HIGH, powers the voltage divider. Only on 1.1 +#define ADC_CTRL_ENABLED HIGH + +#undef GPS_RX_PIN +#undef GPS_TX_PIN +#define GPS_RX_PIN 5 +#define GPS_TX_PIN 4 +#define PIN_GPS_RESET 3 +#define GPS_RESET_MODE LOW +#define PIN_GPS_PPS 1 +#define PIN_GPS_EN 21 +#define GPS_EN_ACTIVE HIGH + +#define USE_SX1262 +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define LORA_SCK 9 +#define LORA_MISO 11 +#define LORA_MOSI 10 +#define LORA_CS 8 + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET + +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 From c7769274dd417017bf06a01e5215e61054567cfd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 12 Jun 2024 07:23:54 -0500 Subject: [PATCH 016/211] [create-pull-request] automated change (#4085) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 8c8048798c..8f4faf76e5 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 8c8048798c1b1773b9d8f2c32eb3f4c9e72f8218 +Subproject commit 8f4faf76e52c2ef63c582c26642d312d9781b7c0 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index ad97cb80f8..0e9e6a28d7 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -161,6 +161,8 @@ typedef enum _meshtastic_HardwareModel { /* RadioMaster 900 Bandit Nano, https://www.radiomasterrc.com/products/bandit-nano-expresslrs-rf-module ESP32-D0WDQ6 With SX1276/SKY66122, SSD1306 OLED and No GPS */ meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO = 64, + /* Heltec Capsule Sensor V3 with ESP32-S3 CPU, Portable LoRa device that can replace GNSS modules or sensors */ + meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3 = 65, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ From 871f6854b5751b88fbb3b3905970125f6ffb4285 Mon Sep 17 00:00:00 2001 From: John Gorkos - AB0OO Date: Wed, 12 Jun 2024 08:22:01 -0700 Subject: [PATCH 017/211] feature-mqtt: add hop_start and hop_limit to MQTT uplink --- src/mqtt/MQTT.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 566eb352db..905c2b7d34 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -902,7 +902,9 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) jsonObj["snr"] = new JSONValue((float)mp->rx_snr); if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit)); - + jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); + jsonObj["hop_limit"] = new JSONValue((unsigned int)(mp->hop_limit)); + // serialize and write it to the stream JSONValue *value = new JSONValue(jsonObj); std::string jsonStr = value->Stringify(); From d80bcd7d67df2876b9536cd1418bec64171269e9 Mon Sep 17 00:00:00 2001 From: John Gorkos - AB0OO Date: Wed, 12 Jun 2024 12:59:52 -0700 Subject: [PATCH 018/211] adding only hop_start, per @GUVWAF --- src/mqtt/MQTT.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 905c2b7d34..4f685cd7a6 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -903,7 +903,6 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit)); jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); - jsonObj["hop_limit"] = new JSONValue((unsigned int)(mp->hop_limit)); // serialize and write it to the stream JSONValue *value = new JSONValue(jsonObj); From b42185c722c27e17523bf2474079915f8eca7f04 Mon Sep 17 00:00:00 2001 From: John Gorkos - AB0OO Date: Wed, 12 Jun 2024 13:02:01 -0700 Subject: [PATCH 019/211] included hop_start in conditional for hop_away --- src/mqtt/MQTT.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 4f685cd7a6..d93166ce94 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -900,9 +900,10 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi); if (mp->rx_snr != 0) jsonObj["snr"] = new JSONValue((float)mp->rx_snr); - if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) + if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) { jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit)); - jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); + jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); + } // serialize and write it to the stream JSONValue *value = new JSONValue(jsonObj); From f7433eb4ee772477493545800da88eafc1455e96 Mon Sep 17 00:00:00 2001 From: John Gorkos - AB0OO Date: Wed, 12 Jun 2024 14:36:38 -0700 Subject: [PATCH 020/211] trunk formatting --- src/mqtt/MQTT.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index d93166ce94..9f9ac5c243 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -904,7 +904,7 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit)); jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); } - + // serialize and write it to the stream JSONValue *value = new JSONValue(jsonObj); std::string jsonStr = value->Stringify(); From 26d4d06e2a2359d35f349eaf15b6a703058bacff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 13 Jun 2024 08:39:38 -0500 Subject: [PATCH 021/211] [create-pull-request] automated change (#4093) Co-authored-by: caveman99 <25002+caveman99@users.noreply.github.com> --- protobufs | 2 +- .../generated/meshtastic/telemetry.pb.cpp | 3 ++ src/mesh/generated/meshtastic/telemetry.pb.h | 30 +++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/protobufs b/protobufs index 8f4faf76e5..260d24318d 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 8f4faf76e52c2ef63c582c26642d312d9781b7c0 +Subproject commit 260d24318d811518171ed2916c94c0cfd94eb9d4 diff --git a/src/mesh/generated/meshtastic/telemetry.pb.cpp b/src/mesh/generated/meshtastic/telemetry.pb.cpp index 6388e37a0a..c93483a152 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.cpp +++ b/src/mesh/generated/meshtastic/telemetry.pb.cpp @@ -21,5 +21,8 @@ PB_BIND(meshtastic_AirQualityMetrics, meshtastic_AirQualityMetrics, AUTO) PB_BIND(meshtastic_Telemetry, meshtastic_Telemetry, AUTO) +PB_BIND(meshtastic_Nau7802Config, meshtastic_Nau7802Config, AUTO) + + diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 02b0bdd6dd..47961cd7dc 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -61,7 +61,9 @@ typedef enum _meshtastic_TelemetrySensorType { /* AHT10 Integrated temperature and humidity sensor */ meshtastic_TelemetrySensorType_AHT10 = 23, /* DFRobot Lark Weather station (temperature, humidity, pressure, wind speed and direction) */ - meshtastic_TelemetrySensorType_DFROBOT_LARK = 24 + meshtastic_TelemetrySensorType_DFROBOT_LARK = 24, + /* NAU7802 Scale Chip or compatible */ + meshtastic_TelemetrySensorType_NAU7802 = 25 } meshtastic_TelemetrySensorType; /* Struct definitions */ @@ -174,6 +176,14 @@ typedef struct _meshtastic_Telemetry { } variant; } meshtastic_Telemetry; +/* NAU7802 Telemetry configuration, for saving to flash */ +typedef struct _meshtastic_Nau7802Config { + /* The offset setting for the NAU7802 */ + int32_t zeroOffset; + /* The calibration factor for the NAU7802 */ + float calibrationFactor; +} meshtastic_Nau7802Config; + #ifdef __cplusplus extern "C" { @@ -181,8 +191,9 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET -#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_DFROBOT_LARK -#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_DFROBOT_LARK+1)) +#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_NAU7802 +#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_NAU7802+1)) + @@ -196,11 +207,13 @@ extern "C" { #define meshtastic_PowerMetrics_init_default {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}} +#define meshtastic_Nau7802Config_init_default {0, 0} #define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0, 0} #define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_zero {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}} +#define meshtastic_Nau7802Config_init_zero {0, 0} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_DeviceMetrics_battery_level_tag 1 @@ -245,6 +258,8 @@ extern "C" { #define meshtastic_Telemetry_environment_metrics_tag 3 #define meshtastic_Telemetry_air_quality_metrics_tag 4 #define meshtastic_Telemetry_power_metrics_tag 5 +#define meshtastic_Nau7802Config_zeroOffset_tag 1 +#define meshtastic_Nau7802Config_calibrationFactor_tag 2 /* Struct field encoding specification for nanopb */ #define meshtastic_DeviceMetrics_FIELDLIST(X, a) \ @@ -313,11 +328,18 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,power_metrics,variant.power_metrics) #define meshtastic_Telemetry_variant_air_quality_metrics_MSGTYPE meshtastic_AirQualityMetrics #define meshtastic_Telemetry_variant_power_metrics_MSGTYPE meshtastic_PowerMetrics +#define meshtastic_Nau7802Config_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, INT32, zeroOffset, 1) \ +X(a, STATIC, SINGULAR, FLOAT, calibrationFactor, 2) +#define meshtastic_Nau7802Config_CALLBACK NULL +#define meshtastic_Nau7802Config_DEFAULT NULL + extern const pb_msgdesc_t meshtastic_DeviceMetrics_msg; extern const pb_msgdesc_t meshtastic_EnvironmentMetrics_msg; extern const pb_msgdesc_t meshtastic_PowerMetrics_msg; extern const pb_msgdesc_t meshtastic_AirQualityMetrics_msg; extern const pb_msgdesc_t meshtastic_Telemetry_msg; +extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_DeviceMetrics_fields &meshtastic_DeviceMetrics_msg @@ -325,12 +347,14 @@ extern const pb_msgdesc_t meshtastic_Telemetry_msg; #define meshtastic_PowerMetrics_fields &meshtastic_PowerMetrics_msg #define meshtastic_AirQualityMetrics_fields &meshtastic_AirQualityMetrics_msg #define meshtastic_Telemetry_fields &meshtastic_Telemetry_msg +#define meshtastic_Nau7802Config_fields &meshtastic_Nau7802Config_msg /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size #define meshtastic_AirQualityMetrics_size 72 #define meshtastic_DeviceMetrics_size 27 #define meshtastic_EnvironmentMetrics_size 68 +#define meshtastic_Nau7802Config_size 16 #define meshtastic_PowerMetrics_size 30 #define meshtastic_Telemetry_size 79 From 75d5cd2c356eaa2ff76b1b360325091a92b44d89 Mon Sep 17 00:00:00 2001 From: caveman99 <25002+caveman99@users.noreply.github.com> Date: Thu, 13 Jun 2024 14:50:21 +0000 Subject: [PATCH 022/211] [create-pull-request] automated change --- protobufs | 2 +- src/mesh/generated/meshtastic/telemetry.pb.h | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/protobufs b/protobufs index 260d24318d..ab576a4a12 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 260d24318d811518171ed2916c94c0cfd94eb9d4 +Subproject commit ab576a4a122c1a1d0a3c2235b0a0cf3bd4a83c65 diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 47961cd7dc..28d3687548 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -113,6 +113,8 @@ typedef struct _meshtastic_EnvironmentMetrics { uint16_t wind_direction; /* Wind speed in m/s */ float wind_speed; + /* Weight in KG */ + float weight; } meshtastic_EnvironmentMetrics; /* Power Metrics (voltage / current / etc) */ @@ -203,13 +205,13 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_DeviceMetrics_init_default {0, 0, 0, 0, 0} -#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_default {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}} #define meshtastic_Nau7802Config_init_default {0, 0} #define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0, 0} -#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_zero {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}} @@ -235,6 +237,7 @@ extern "C" { #define meshtastic_EnvironmentMetrics_uv_lux_tag 12 #define meshtastic_EnvironmentMetrics_wind_direction_tag 13 #define meshtastic_EnvironmentMetrics_wind_speed_tag 14 +#define meshtastic_EnvironmentMetrics_weight_tag 15 #define meshtastic_PowerMetrics_ch1_voltage_tag 1 #define meshtastic_PowerMetrics_ch1_current_tag 2 #define meshtastic_PowerMetrics_ch2_voltage_tag 3 @@ -285,7 +288,8 @@ X(a, STATIC, SINGULAR, FLOAT, white_lux, 10) \ X(a, STATIC, SINGULAR, FLOAT, ir_lux, 11) \ X(a, STATIC, SINGULAR, FLOAT, uv_lux, 12) \ X(a, STATIC, SINGULAR, UINT32, wind_direction, 13) \ -X(a, STATIC, SINGULAR, FLOAT, wind_speed, 14) +X(a, STATIC, SINGULAR, FLOAT, wind_speed, 14) \ +X(a, STATIC, SINGULAR, FLOAT, weight, 15) #define meshtastic_EnvironmentMetrics_CALLBACK NULL #define meshtastic_EnvironmentMetrics_DEFAULT NULL @@ -353,10 +357,10 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; #define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size #define meshtastic_AirQualityMetrics_size 72 #define meshtastic_DeviceMetrics_size 27 -#define meshtastic_EnvironmentMetrics_size 68 +#define meshtastic_EnvironmentMetrics_size 73 #define meshtastic_Nau7802Config_size 16 #define meshtastic_PowerMetrics_size 30 -#define meshtastic_Telemetry_size 79 +#define meshtastic_Telemetry_size 80 #ifdef __cplusplus } /* extern "C" */ From 85bca8a32a09d75d786a16d8908c0582389a1d7d Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 13 Jun 2024 11:13:18 -0500 Subject: [PATCH 023/211] Update lark to ref to clear C++ warning --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 9c29d2d677..2064bac483 100644 --- a/platformio.ini +++ b/platformio.ini @@ -143,4 +143,4 @@ lib_deps = ClosedCube OPT3001@^1.1.2 emotibit/EmotiBit MLX90632@^1.0.8 dfrobot/DFRobot_RTU@^1.0.3 - https://github.com/meshtastic/DFRobot_LarkWeatherStation#0e884fc86b7a0b602c7ff3d26b893b997f15c6ac \ No newline at end of file + https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee \ No newline at end of file From 16b41b51af7ea2ae3b0c9ad4e3b0afb4e0051797 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 13 Jun 2024 12:05:14 -0500 Subject: [PATCH 024/211] Update OLED ref --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 2064bac483..34471fc54e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -78,7 +78,7 @@ monitor_speed = 115200 lib_deps = jgromes/RadioLib@~6.6.0 - https://github.com/meshtastic/esp8266-oled-ssd1306.git#ee628ee6c9588d4c56c9e3da35f0fc9448ad54a8 ; ESP8266_SSD1306 + https://github.com/meshtastic/esp8266-oled-ssd1306.git#69ba98fa30e67b12d4577b121f210f3eb7049d6b ; ESP8266_SSD1306 mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4 From 39c9f92c6e7ee1639051a967d761ed5d642f4fcd Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Sat, 15 Jun 2024 01:28:01 +1200 Subject: [PATCH 025/211] GPS: short update intervals, lock-time prediction (#4070) * Refactor GPSPowerState enum Identifies a case where the GPS hardware is awake, but an update is not yet desired * Change terminology * Clear old lock-time prediction on triple press * Use exponential smoothing to predict lock time * Rename averageLockTime to predictedLockTime * Attempt: Send PMREQ with duration 0 on MCU deep-sleep * Attempt 2: Send PMREQ with duration 0 on MCU deep-sleep * Revert "Attempt 2: Send PMREQ with duration 0 on MCU deep-sleep" This reverts commit 8b697cd2a445355dcfab5b33e0ce7a3128cab151. * Revert "Attempt: Send PMREQ with duration 0 on MCU deep-sleep" This reverts commit 9d29ec7603a88056b9115796b29b5023165a93bb. --- src/gps/GPS.cpp | 97 +++++++++++++++++++++++++++++++++---------------- src/gps/GPS.h | 11 +++--- 2 files changed, 71 insertions(+), 37 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 17088910ae..8d46742baa 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -28,6 +28,12 @@ #define GPS_STANDBY_THRESHOLD_MINUTES 15 #endif +// How many seconds of sleep make it worthwhile for the GPS to use powered-on standby +// Shorter than this, and we'll just wait instead +#ifndef GPS_IDLE_THRESHOLD_SECONDS +#define GPS_IDLE_THRESHOLD_SECONDS 10 +#endif + #if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) HardwareSerial *GPS::_serial_gps = &Serial1; #else @@ -776,14 +782,22 @@ void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) { // Record the current powerState if (on) - powerState = GPS_AWAKE; - else if (!on && standbyOnly) + powerState = GPS_ACTIVE; + else if (!enabled) // User has disabled with triple press + powerState = GPS_OFF; + else if (sleepTime <= GPS_IDLE_THRESHOLD_SECONDS * 1000UL) + powerState = GPS_IDLE; + else if (standbyOnly) powerState = GPS_STANDBY; else powerState = GPS_OFF; LOG_DEBUG("GPS::powerState=%d\n", powerState); + // If the next update is due *really soon*, don't actually power off or enter standby. Just wait it out. + if (!on && powerState == GPS_IDLE) + return; + if (on) { clearBuffer(); // drop any old data waiting in the buffer before re-enabling if (en_gpio) @@ -880,54 +894,69 @@ void GPS::setConnected() void GPS::setAwake(bool wantAwake) { - // If user has disabled GPS, make sure it is off, not just in standby + // If user has disabled GPS, make sure it is off, not just in standby or idle if (!wantAwake && !enabled && powerState != GPS_OFF) { setGPSPower(false, false, 0); return; } // If GPS power state needs to change - if ((wantAwake && powerState != GPS_AWAKE) || (!wantAwake && powerState == GPS_AWAKE)) { + if ((wantAwake && powerState != GPS_ACTIVE) || (!wantAwake && powerState == GPS_ACTIVE)) { LOG_DEBUG("WANT GPS=%d\n", wantAwake); // Calculate how long it takes to get a GPS lock if (wantAwake) { + // Record the time we start looking for a lock lastWakeStartMsec = millis(); } else { + // Record by how much we missed our ideal target postion.gps_update_interval (for logging only) + // Need to calculate this before we update lastSleepStartMsec, to make the new prediction + int32_t lateByMsec = (int32_t)(millis() - lastSleepStartMsec) - (int32_t)getSleepTime(); + + // Record the time we finish looking for a lock lastSleepStartMsec = millis(); - if (GPSCycles == 1) { // Skipping initial lock time, as it will likely be much longer than average - averageLockTime = lastSleepStartMsec - lastWakeStartMsec; - } else if (GPSCycles > 1) { - averageLockTime += ((int32_t)(lastSleepStartMsec - lastWakeStartMsec) - averageLockTime) / (int32_t)GPSCycles; + + // How long did it take to get GPS lock this time? + uint32_t lockTime = lastSleepStartMsec - lastWakeStartMsec; + + // Update the lock-time prediction + // Used pre-emptively, attempting to hit target of gps.position_update_interval + switch (GPSCycles) { + case 0: + LOG_DEBUG("Initial GPS lock took %ds\n", lockTime / 1000); + break; + case 1: + predictedLockTime = lockTime; // Avoid slow ramp-up - start with a real value + LOG_DEBUG("GPS Lock took %ds\n", lockTime / 1000); + break; + default: + // Predict lock-time using exponential smoothing: respond slowly to changes + predictedLockTime = (lockTime * 0.2) + (predictedLockTime * 0.8); // Latest lock time has 20% weight on prediction + LOG_INFO("GPS Lock took %ds. %s by %ds. Next lock predicted to take %ds.\n", lockTime / 1000, + (lateByMsec > 0) ? "Late" : "Early", abs(lateByMsec) / 1000, predictedLockTime / 1000); } GPSCycles++; - LOG_DEBUG("GPS Lock took %d, average %d\n", (lastSleepStartMsec - lastWakeStartMsec) / 1000, averageLockTime / 1000); } + // How long to wait before attempting next GPS update + // Aims to hit position.gps_update_interval by using the lock-time prediction + uint32_t compensatedSleepTime = (getSleepTime() > predictedLockTime) ? (getSleepTime() - predictedLockTime) : 0; + // If long interval between updates: power off between updates - if ((int32_t)getSleepTime() - averageLockTime > GPS_STANDBY_THRESHOLD_MINUTES * MS_IN_MINUTE) { - setGPSPower(wantAwake, false, getSleepTime() - averageLockTime); - return; + if (compensatedSleepTime > GPS_STANDBY_THRESHOLD_MINUTES * MS_IN_MINUTE) { + setGPSPower(wantAwake, false, getSleepTime() - predictedLockTime); } - // If waking frequently: standby only. Would use more power trying to reacquire lock each time - else if ((int32_t)getSleepTime() - averageLockTime > 10000) { // 10 seconds is enough for standby + // If waking relatively frequently: don't power off. Would use more energy trying to reacquire lock each time + // We'll either use a "powered-on" standby, or just wait it out, depending on how soon the next update is due + // Will decide which inside setGPSPower method + else { #ifdef GPS_UC6580 - setGPSPower(wantAwake, false, getSleepTime() - averageLockTime); + setGPSPower(wantAwake, false, compensatedSleepTime); #else - setGPSPower(wantAwake, true, getSleepTime() - averageLockTime); + setGPSPower(wantAwake, true, compensatedSleepTime); #endif - return; } - - // Gradually recover from an abnormally long "time to get lock" - if (averageLockTime > 20000) { - averageLockTime -= 1000; // eventually want to sleep again. - } - - // Make sure we don't have a fallthrough where GPS is stuck off - if (wantAwake) - setGPSPower(true, true, 0); } } @@ -1033,14 +1062,14 @@ int32_t GPS::runOnce() uint32_t timeAsleep = now - lastSleepStartMsec; auto sleepTime = getSleepTime(); - if (powerState != GPS_AWAKE && (sleepTime != UINT32_MAX) && - ((timeAsleep > sleepTime) || (isInPowersave && timeAsleep > (sleepTime - averageLockTime)))) { + if (powerState != GPS_ACTIVE && (sleepTime != UINT32_MAX) && + ((timeAsleep > sleepTime) || (isInPowersave && timeAsleep > (sleepTime - predictedLockTime)))) { // We now want to be awake - so wake up the GPS setAwake(true); } // While we are awake - if (powerState == GPS_AWAKE) { + if (powerState == GPS_ACTIVE) { // LOG_DEBUG("looking for location\n"); // If we've already set time from the GPS, no need to ask the GPS bool gotTime = (getRTCQuality() >= RTCQualityGPS); @@ -1086,7 +1115,7 @@ int32_t GPS::runOnce() // 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms // if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake. - return (powerState == GPS_AWAKE) ? GPS_THREAD_INTERVAL : 5000; + return (powerState == GPS_ACTIVE) ? GPS_THREAD_INTERVAL : 5000; } // clear the GPS rx buffer as quickly as possible @@ -1617,9 +1646,9 @@ bool GPS::whileIdle() { unsigned int charsInBuf = 0; bool isValid = false; - if (powerState != GPS_AWAKE) { + if (powerState != GPS_ACTIVE) { clearBuffer(); - return (powerState == GPS_AWAKE); + return (powerState == GPS_ACTIVE); } #ifdef SERIAL_BUFFER_SIZE if (_serial_gps->available() >= SERIAL_BUFFER_SIZE - 1) { @@ -1650,6 +1679,10 @@ bool GPS::whileIdle() } void GPS::enable() { + // Clear the old lock-time prediction + GPSCycles = 0; + predictedLockTime = 0; + enabled = true; setInterval(GPS_THREAD_INTERVAL); setAwake(true); diff --git a/src/gps/GPS.h b/src/gps/GPS.h index e9ec111a75..34e1844c35 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -39,9 +39,10 @@ typedef enum { } GPS_RESPONSE; enum GPSPowerState : uint8_t { - GPS_OFF = 0, - GPS_AWAKE = 1, - GPS_STANDBY = 2, + GPS_OFF = 0, // Physically powered off + GPS_ACTIVE = 1, // Awake and want a position + GPS_STANDBY = 2, // Physically powered on, but soft-sleeping + GPS_IDLE = 3, // Awake, but not wanting another position yet }; // Generate a string representation of DOP @@ -72,7 +73,7 @@ class GPS : private concurrency::OSThread uint32_t rx_gpio = 0; uint32_t tx_gpio = 0; uint32_t en_gpio = 0; - int32_t averageLockTime = 0; + int32_t predictedLockTime = 0; uint32_t GPSCycles = 0; int speedSelect = 0; @@ -93,7 +94,7 @@ class GPS : private concurrency::OSThread bool GPSInitFinished = false; // Init thread finished? bool GPSInitStarted = false; // Init thread finished? - GPSPowerState powerState = GPS_OFF; // GPS_AWAKE if we want a location right now + GPSPowerState powerState = GPS_OFF; // GPS_ACTIVE if we want a location right now uint8_t numSatellites = 0; From 1a5227c8266ee0eaac5f6b4388f62706648db72a Mon Sep 17 00:00:00 2001 From: Wolfgang Nagele Date: Fri, 14 Jun 2024 17:45:16 +0200 Subject: [PATCH 026/211] Ensure data directory ownership is with mesh user (#4097) --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index fee6c62d4b..08cb3925d2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,6 +48,7 @@ USER mesh WORKDIR /home/mesh COPY --from=builder /tmp/firmware/release/meshtasticd /home/mesh/ +RUN mkdir data VOLUME /home/mesh/data CMD [ "sh", "-cx", "./meshtasticd -d /home/mesh/data --hwid=${HWID:-$RANDOM}" ] From 8b8e056b7bcce9f4ee3e4256c6c94a724e1d190f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 14 Jun 2024 16:27:49 -0500 Subject: [PATCH 027/211] Added (excluded) Dropzone Module for more comprehensive module example (#4098) * DropzoneModule hello world * Buttoning things up * Exclude by default * Upstream refs * Cleanup * Add modules folder to path * Case and path matters * Exclude from header * Guard --- platformio.ini | 1 + src/modules/DropzoneModule.cpp | 95 +++++++++++++++++++ src/modules/DropzoneModule.h | 37 ++++++++ src/modules/Modules.cpp | 9 ++ .../Telemetry/Sensor/DFRobotLarkSensor.h | 5 + src/modules/Telemetry/UnitConversions.cpp | 21 ++++ src/modules/Telemetry/UnitConversions.h | 10 ++ 7 files changed, 178 insertions(+) create mode 100644 src/modules/DropzoneModule.cpp create mode 100644 src/modules/DropzoneModule.h create mode 100644 src/modules/Telemetry/UnitConversions.cpp create mode 100644 src/modules/Telemetry/UnitConversions.h diff --git a/platformio.ini b/platformio.ini index 34471fc54e..0de3e25c92 100644 --- a/platformio.ini +++ b/platformio.ini @@ -73,6 +73,7 @@ build_flags = -Wno-missing-field-initializers -DRADIOLIB_EXCLUDE_FSK4 -DRADIOLIB_EXCLUDE_APRS -DRADIOLIB_EXCLUDE_LORAWAN + -DMESHTASTIC_EXCLUDE_DROPZONE=1 monitor_speed = 115200 diff --git a/src/modules/DropzoneModule.cpp b/src/modules/DropzoneModule.cpp new file mode 100644 index 0000000000..8c5b5dcdd8 --- /dev/null +++ b/src/modules/DropzoneModule.cpp @@ -0,0 +1,95 @@ +#if !MESHTASTIC_EXCLUDE_DROPZONE + +#include "DropzoneModule.h" +#include "MeshService.h" +#include "configuration.h" +#include "gps/GeoCoord.h" +#include "gps/RTC.h" +#include "main.h" + +#include + +#include "modules/Telemetry/Sensor/DFRobotLarkSensor.h" +#include "modules/Telemetry/UnitConversions.h" + +#include + +DropzoneModule *dropzoneModule; + +int32_t DropzoneModule::runOnce() +{ + // Send on a 5 second delay from receiving the matching request + if (startSendConditions != 0 && (startSendConditions + 5000U) < millis()) { + service.sendToMesh(sendConditions(), RX_SRC_LOCAL); + startSendConditions = 0; + } + // Run every second to check if we need to send conditions + return 1000; +} + +ProcessMessage DropzoneModule::handleReceived(const meshtastic_MeshPacket &mp) +{ + auto &p = mp.decoded; + char matchCompare[54]; + auto incomingMessage = reinterpret_cast(p.payload.bytes); + sprintf(matchCompare, "%s conditions", owner.short_name); + if (strncasecmp(incomingMessage, matchCompare, strlen(matchCompare)) == 0) { + LOG_DEBUG("Received dropzone conditions request\n"); + startSendConditions = millis(); + } + + sprintf(matchCompare, "%s conditions", owner.long_name); + if (strncasecmp(incomingMessage, matchCompare, strlen(matchCompare)) == 0) { + LOG_DEBUG("Received dropzone conditions request\n"); + startSendConditions = millis(); + } + return ProcessMessage::CONTINUE; +} + +meshtastic_MeshPacket *DropzoneModule::sendConditions() +{ + char replyStr[200]; + /* + CLOSED @ {HH:MM:SS}z + Wind 2 kts @ 125° + 29.25 inHg 72°C + */ + uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); + int hour = 0, min = 0, sec = 0; + if (rtc_sec > 0) { + long hms = rtc_sec % SEC_PER_DAY; + hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; + + hour = hms / SEC_PER_HOUR; + min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; + sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; + } + + // Check if the dropzone is open or closed by reading the analog pin + // If pin is connected to GND (below 100 should be lower than floating voltage), + // the dropzone is open + auto dropzoneStatus = analogRead(A1) < 100 ? "OPEN" : "CLOSED"; + auto reply = allocDataPacket(); + + auto node = nodeDB->getMeshNode(nodeDB->getNodeNum()); + if (sensor.hasSensor()) { + meshtastic_Telemetry telemetry = meshtastic_Telemetry_init_zero; + sensor.getMetrics(&telemetry); + auto windSpeed = UnitConversions::MetersPerSecondToKnots(telemetry.variant.environment_metrics.wind_speed); + auto windDirection = telemetry.variant.environment_metrics.wind_direction; + auto temp = telemetry.variant.environment_metrics.temperature; + auto baro = UnitConversions::HectoPascalToInchesOfMercury(telemetry.variant.environment_metrics.barometric_pressure); + sprintf(replyStr, "%s @ %02d:%02d:%02dz\nWind %.2f kts @ %d°\nBaro %.2f inHg %.2f°C", dropzoneStatus, hour, min, sec, + windSpeed, windDirection, baro, temp); + } else { + LOG_ERROR("No sensor found\n"); + sprintf(replyStr, "%s @ %02d:%02d:%02d\nNo sensor found", dropzoneStatus, hour, min, sec); + } + LOG_DEBUG("Conditions reply: %s\n", replyStr); + reply->decoded.payload.size = strlen(replyStr); // You must specify how many bytes are in the reply + memcpy(reply->decoded.payload.bytes, replyStr, reply->decoded.payload.size); + + return reply; +} + +#endif \ No newline at end of file diff --git a/src/modules/DropzoneModule.h b/src/modules/DropzoneModule.h new file mode 100644 index 0000000000..28f54ee0f2 --- /dev/null +++ b/src/modules/DropzoneModule.h @@ -0,0 +1,37 @@ +#pragma once +#if !MESHTASTIC_EXCLUDE_DROPZONE +#include "SinglePortModule.h" +#include "modules/Telemetry/Sensor/DFRobotLarkSensor.h" + +/** + * An example module that replies to a message with the current conditions + * and status at the dropzone when it receives a text message mentioning it's name followed by "conditions" + */ +class DropzoneModule : public SinglePortModule, private concurrency::OSThread +{ + DFRobotLarkSensor sensor; + + public: + /** Constructor + * name is for debugging output + */ + DropzoneModule() : SinglePortModule("dropzone", meshtastic_PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("DropzoneModule") + { + // Set up the analog pin for reading the dropzone status + pinMode(PIN_A1, INPUT); + } + + virtual int32_t runOnce() override; + + protected: + /** Called to handle a particular incoming message + */ + virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override; + + private: + meshtastic_MeshPacket *sendConditions(); + uint32_t startSendConditions = 0; +}; + +extern DropzoneModule *dropzoneModule; +#endif \ No newline at end of file diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index e6c44fae64..1b4bbc3b4a 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -70,6 +70,11 @@ #include "modules/SerialModule.h" #endif #endif + +#if !MESHTASTIC_EXCLUDE_DROPZONE +#include "modules/DropzoneModule.h" +#endif + /** * Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else) */ @@ -100,6 +105,10 @@ void setupModules() #if !MESHTASTIC_EXCLUDE_ATAK atakPluginModule = new AtakPluginModule(); #endif + +#if !MESHTASTIC_EXCLUDE_DROPZONE + dropzoneModule = new DropzoneModule(); +#endif // Note: if the rest of meshtastic doesn't need to explicitly use your module, you do not need to assign the instance // to a global variable. diff --git a/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h index b26d690b15..7a988e84a5 100644 --- a/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h +++ b/src/modules/Telemetry/Sensor/DFRobotLarkSensor.h @@ -1,3 +1,7 @@ +#pragma once + +#ifndef _MT_DFROBOTLARKSENSOR_H +#define _MT_DFROBOTLARKSENSOR_H #include "configuration.h" #if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR @@ -21,4 +25,5 @@ class DFRobotLarkSensor : public TelemetrySensor virtual bool getMetrics(meshtastic_Telemetry *measurement) override; }; +#endif #endif \ No newline at end of file diff --git a/src/modules/Telemetry/UnitConversions.cpp b/src/modules/Telemetry/UnitConversions.cpp new file mode 100644 index 0000000000..9f40de40fc --- /dev/null +++ b/src/modules/Telemetry/UnitConversions.cpp @@ -0,0 +1,21 @@ +#include "UnitConversions.h" + +float UnitConversions::CelsiusToFahrenheit(float celcius) +{ + return (celcius * 9) / 5 + 32; +} + +float UnitConversions::MetersPerSecondToKnots(float metersPerSecond) +{ + return metersPerSecond * 1.94384; +} + +float UnitConversions::MetersPerSecondToMilesPerHour(float metersPerSecond) +{ + return metersPerSecond * 2.23694; +} + +float UnitConversions::HectoPascalToInchesOfMercury(float hectoPascal) +{ + return hectoPascal * 0.029529983071445; +} diff --git a/src/modules/Telemetry/UnitConversions.h b/src/modules/Telemetry/UnitConversions.h new file mode 100644 index 0000000000..60f9b664ae --- /dev/null +++ b/src/modules/Telemetry/UnitConversions.h @@ -0,0 +1,10 @@ +#pragma once + +class UnitConversions +{ + public: + static float CelsiusToFahrenheit(float celcius); + static float MetersPerSecondToKnots(float metersPerSecond); + static float MetersPerSecondToMilesPerHour(float metersPerSecond); + static float HectoPascalToInchesOfMercury(float hectoPascal); +}; From e55604b8e5e233548c9e160ed008be9d16b647bc Mon Sep 17 00:00:00 2001 From: "Daniel.Cao" <144674500+DanielCao0@users.noreply.github.com> Date: Sat, 15 Jun 2024 08:36:20 +0800 Subject: [PATCH 028/211] rak10701: support touchscreen (#4104) * Add the touch screen driver RAK10701 platform, lib_deps https://github.com/RAKWireless/RAK14014-FT6336U * Added RAK10701 touch screen virtual keyboard, supporting cannedMessageModule free text --- src/graphics/TFTDisplay.cpp | 25 +++++++++++++++++++++++++ src/modules/CannedMessageModule.cpp | 28 ++++++++++++++-------------- src/modules/CannedMessageModule.h | 4 ++-- variants/rak10701/platformio.ini | 2 ++ variants/rak10701/variant.h | 8 ++++---- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index b19e402b82..39099bd737 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -118,7 +118,15 @@ static LGFX *tft = nullptr; #elif defined(RAK14014) #include +#include TFT_eSPI *tft = nullptr; +FT6336U ft6336u; + +static uint8_t _rak14014_touch_int = false; // TP interrupt generation flag. +static void rak14014_tpIntHandle(void) +{ + _rak14014_touch_int = true; +} #elif defined(ST7789_CS) #include // Graphics and font library for ST7735 driver chip @@ -642,8 +650,12 @@ void TFTDisplay::sendCommand(uint8_t com) void TFTDisplay::setDisplayBrightness(uint8_t _brightness) { +#ifdef RAK14014 + //todo +#else tft->setBrightness(_brightness); LOG_DEBUG("Brightness is set to value: %i \n", _brightness); +#endif } void TFTDisplay::flipScreenVertically() @@ -657,6 +669,7 @@ void TFTDisplay::flipScreenVertically() bool TFTDisplay::hasTouch(void) { #ifdef RAK14014 + return true; #elif !defined(M5STACK) return tft->touch() != nullptr; #else @@ -667,6 +680,15 @@ bool TFTDisplay::hasTouch(void) bool TFTDisplay::getTouch(int16_t *x, int16_t *y) { #ifdef RAK14014 + if(_rak14014_touch_int) { + _rak14014_touch_int = false; + /* The X and Y axes have to be switched */ + *y = ft6336u.read_touch1_x(); + *x = TFT_HEIGHT - ft6336u.read_touch1_y(); + return true; + } else { + return false; + } #elif !defined(M5STACK) return tft->getTouch(x, y); #else @@ -717,6 +739,9 @@ bool TFTDisplay::connect() tft->setRotation(1); tft->setSwapBytes(true); // tft->fillScreen(TFT_BLACK); + ft6336u.begin(); + pinMode(SCREEN_TOUCH_INT, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(SCREEN_TOUCH_INT), rak14014_tpIntHandle, FALLING); #elif defined(T_DECK) || defined(PICOMPUTER_S3) || defined(CHATTER_2) tft->setRotation(1); // T-Deck has the TFT in landscape #elif defined(T_WATCH_S3) diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index 9b993ae5a3..f513e045f4 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -49,7 +49,7 @@ CannedMessageModule::CannedMessageModule() LOG_INFO("CannedMessageModule is enabled\n"); // T-Watch interface currently has no way to select destination type, so default to 'node' -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE; #endif @@ -75,7 +75,7 @@ int CannedMessageModule::splitConfiguredMessages() String messages = cannedMessageModuleConfig.messages; -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) String separator = messages.length() ? "|" : ""; messages = "[---- Free Text ----]" + separator + messages; @@ -144,7 +144,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT)) { -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) if (this->currentMessageIndex == 0) { this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT; @@ -170,7 +170,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) e.frameChanged = true; this->currentMessageIndex = -1; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->freetext = ""; // clear freetext this->cursor = 0; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; @@ -183,7 +183,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) || (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) { -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) { this->payload = 0xb4; } else if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) { @@ -283,7 +283,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } } -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { String keyTapped = keyForCoordinates(event->touchX, event->touchY); @@ -404,7 +404,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -417,7 +417,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -437,7 +437,7 @@ int32_t CannedMessageModule::runOnce() powerFSM.trigger(EVENT_PRESS); return INT32_MAX; } else { -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) sendText(this->dest, indexChannels[this->channel], this->messages[this->currentMessageIndex], true); #else sendText(NODENUM_BROADCAST, channels.getPrimaryIndex(), this->messages[this->currentMessageIndex], true); @@ -454,7 +454,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -471,7 +471,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -484,7 +484,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#ifndef T_WATCH_S3 +#if !defined(T_WATCH_S3) && !defined(RAK14014) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -714,7 +714,7 @@ void CannedMessageModule::showTemporaryMessage(const String &message) setIntervalFromNow(2000); } -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) String CannedMessageModule::keyForCoordinates(uint x, uint y) { @@ -949,7 +949,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st display->drawString(10 + x, 0 + y + FONT_HEIGHT_SMALL, "Canned Message\nModule disabled."); } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(RAK14014) drawKeyboard(display, state, 0, 0); #else diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h index 43897e782b..00e8c2bf9a 100644 --- a/src/modules/CannedMessageModule.h +++ b/src/modules/CannedMessageModule.h @@ -98,7 +98,7 @@ class CannedMessageModule : public SinglePortModule, public Observable Date: Fri, 14 Jun 2024 19:53:47 -0500 Subject: [PATCH 029/211] Trunk --- src/graphics/TFTDisplay.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index 39099bd737..8ea90c5232 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -117,8 +117,8 @@ class LGFX : public lgfx::LGFX_Device static LGFX *tft = nullptr; #elif defined(RAK14014) -#include #include +#include TFT_eSPI *tft = nullptr; FT6336U ft6336u; @@ -651,7 +651,7 @@ void TFTDisplay::sendCommand(uint8_t com) void TFTDisplay::setDisplayBrightness(uint8_t _brightness) { #ifdef RAK14014 - //todo + // todo #else tft->setBrightness(_brightness); LOG_DEBUG("Brightness is set to value: %i \n", _brightness); @@ -680,7 +680,7 @@ bool TFTDisplay::hasTouch(void) bool TFTDisplay::getTouch(int16_t *x, int16_t *y) { #ifdef RAK14014 - if(_rak14014_touch_int) { + if (_rak14014_touch_int) { _rak14014_touch_int = false; /* The X and Y axes have to be switched */ *y = ft6336u.read_touch1_x(); @@ -738,7 +738,7 @@ bool TFTDisplay::connect() #elif defined(RAK14014) tft->setRotation(1); tft->setSwapBytes(true); -// tft->fillScreen(TFT_BLACK); + // tft->fillScreen(TFT_BLACK); ft6336u.begin(); pinMode(SCREEN_TOUCH_INT, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(SCREEN_TOUCH_INT), rak14014_tpIntHandle, FALLING); From 21d47adb8d23be4e1f5054b3b89b12b13205149f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 15 Jun 2024 09:45:33 -0500 Subject: [PATCH 030/211] [create-pull-request] automated change (#4114) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/admin.pb.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index ab576a4a12..dc066c89f7 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit ab576a4a122c1a1d0a3c2235b0a0cf3bd4a83c65 +Subproject commit dc066c89f73fce882e5a47648cba18a1967a7f56 diff --git a/src/mesh/generated/meshtastic/admin.pb.h b/src/mesh/generated/meshtastic/admin.pb.h index 2a209ad0a9..d0e643dffc 100644 --- a/src/mesh/generated/meshtastic/admin.pb.h +++ b/src/mesh/generated/meshtastic/admin.pb.h @@ -135,6 +135,8 @@ typedef struct _meshtastic_AdminMessage { bool enter_dfu_mode_request; /* Delete the file by the specified path from the device */ char delete_file_request[201]; + /* Set zero and offset for scale chips */ + uint32_t set_scale; /* Set the owner for this node */ meshtastic_User set_owner; /* Set channels (using the new API). @@ -238,6 +240,7 @@ extern "C" { #define meshtastic_AdminMessage_get_node_remote_hardware_pins_response_tag 20 #define meshtastic_AdminMessage_enter_dfu_mode_request_tag 21 #define meshtastic_AdminMessage_delete_file_request_tag 22 +#define meshtastic_AdminMessage_set_scale_tag 23 #define meshtastic_AdminMessage_set_owner_tag 32 #define meshtastic_AdminMessage_set_channel_tag 33 #define meshtastic_AdminMessage_set_config_tag 34 @@ -281,6 +284,7 @@ X(a, STATIC, ONEOF, BOOL, (payload_variant,get_node_remote_hardware_pin X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_node_remote_hardware_pins_response,get_node_remote_hardware_pins_response), 20) \ X(a, STATIC, ONEOF, BOOL, (payload_variant,enter_dfu_mode_request,enter_dfu_mode_request), 21) \ X(a, STATIC, ONEOF, STRING, (payload_variant,delete_file_request,delete_file_request), 22) \ +X(a, STATIC, ONEOF, UINT32, (payload_variant,set_scale,set_scale), 23) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_owner,set_owner), 32) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 33) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34) \ From 32702e2750cd8b85d2855fb443218beff920e039 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 15 Jun 2024 09:46:15 -0500 Subject: [PATCH 031/211] Fix compiler warnings (#4112) --- src/AccelerometerThread.h | 1 + src/gps/GPS.h | 2 +- variants/rak4631/platformio.ini | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h index f03752cad7..f45511cca3 100644 --- a/src/AccelerometerThread.h +++ b/src/AccelerometerThread.h @@ -138,6 +138,7 @@ class AccelerometerThread : public concurrency::OSThread float heading = FusionCompassCalculateHeading(FusionConventionNed, ga, ma); switch (config.display.compass_orientation) { + case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0_INVERTED: case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_0: break; case meshtastic_Config_DisplayConfig_CompassOrientation_DEGREES_90: diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 34e1844c35..55bd42d0fb 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -73,7 +73,7 @@ class GPS : private concurrency::OSThread uint32_t rx_gpio = 0; uint32_t tx_gpio = 0; uint32_t en_gpio = 0; - int32_t predictedLockTime = 0; + uint32_t predictedLockTime = 0; uint32_t GPSCycles = 0; int speedSelect = 0; diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 24f209b01a..4870d4b68e 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -16,7 +16,7 @@ lib_deps = melopero/Melopero RV3028@^1.1.0 https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2 rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 - beegee-tokyo/RAKwireless RAK12034@^1.0.0 + https://github.com/meshtastic/RAK12034-BMX160.git#4821355fb10390ba8557dc43ca29a023bcfbb9d9 debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ;upload_protocol = jlink \ No newline at end of file From b1cf5778b4bc07ba5132125d491c8f817651781c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 15 Jun 2024 09:46:31 -0500 Subject: [PATCH 032/211] Update nrf52 platform to 10.5.0 (#4113) --- arch/nrf52/nrf52.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index f41ef0edc2..1a371e9208 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -1,6 +1,6 @@ [nrf52_base] ; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files -platform = platformio/nordicnrf52@^10.4.0 +platform = platformio/nordicnrf52@^10.5.0 extends = arduino_base build_type = debug From 96be051bff6d18c45218d39d1a668e6a56cef8a0 Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Sun, 16 Jun 2024 07:58:46 +1200 Subject: [PATCH 033/211] Screensaver validates short name (#4115) --- src/graphics/Screen.cpp | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 5a892bbfbf..60168cffcf 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -277,6 +277,30 @@ static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state) } } +/// Check if the display can render a string (detect special chars; emoji) +static bool haveGlyphs(const char *str) +{ +#if defined(OLED_UA) || defined(OLED_RU) + // Don't want to make any assumptions about custom language support + return true; +#endif + + // Check each character with the lookup function for the OLED library + // We're not really meant to use this directly.. + bool have = true; + for (uint16_t i = 0; i < strlen(str); i++) { + uint8_t result = Screen::customFontTableLookup((uint8_t)str[i]); + // If font doesn't support a character, it is substituted for ¿ + if (result == 191 && (uint8_t)str[i] != 191) { + have = false; + break; + } + } + + LOG_DEBUG("haveGlyphs=%d\n", have); + return have; +} + #ifdef USE_EINK /// Used on eink displays while in deep sleep static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) @@ -301,14 +325,15 @@ static void drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState *sta display->setTextAlignment(TEXT_ALIGN_LEFT); const char *pauseText = "Screen Paused"; const char *idText = owner.short_name; + const bool useId = haveGlyphs(idText); // This bool is used to hide the idText box if we can't render the short name constexpr uint16_t padding = 5; constexpr uint8_t dividerGap = 1; constexpr uint8_t imprecision = 5; // How far the box origins can drift from center. Combat burn-in. // Dimensions - const uint16_t idTextWidth = display->getStringWidth(idText, strlen(idText)); + const uint16_t idTextWidth = display->getStringWidth(idText, strlen(idText), true); // "true": handle utf8 chars const uint16_t pauseTextWidth = display->getStringWidth(pauseText, strlen(pauseText)); - const uint16_t boxWidth = padding + idTextWidth + padding + padding + pauseTextWidth + padding; + const uint16_t boxWidth = padding + (useId ? idTextWidth + padding + padding : 0) + pauseTextWidth + padding; const uint16_t boxHeight = padding + FONT_HEIGHT_SMALL + padding; // Position @@ -318,7 +343,7 @@ static void drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState *sta const int16_t boxBottom = boxTop + boxHeight - 1; const int16_t idTextLeft = boxLeft + padding; const int16_t idTextTop = boxTop + padding; - const int16_t pauseTextLeft = boxLeft + padding + idTextWidth + padding + padding; + const int16_t pauseTextLeft = boxLeft + (useId ? padding + idTextWidth + padding : 0) + padding; const int16_t pauseTextTop = boxTop + padding; const int16_t dividerX = boxLeft + padding + idTextWidth + padding; const int16_t dividerTop = boxTop + 1 + dividerGap; @@ -331,12 +356,14 @@ static void drawScreensaverOverlay(OLEDDisplay *display, OLEDDisplayUiState *sta display->drawRect(boxLeft, boxTop, boxWidth, boxHeight); // Draw: Text - display->drawString(idTextLeft, idTextTop, idText); + if (useId) + display->drawString(idTextLeft, idTextTop, idText); display->drawString(pauseTextLeft, pauseTextTop, pauseText); display->drawString(pauseTextLeft + 1, pauseTextTop, pauseText); // Faux bold // Draw: divider - display->drawLine(dividerX, dividerTop, dividerX, dividerBottom); + if (useId) + display->drawLine(dividerX, dividerTop, dividerX, dividerBottom); } #endif From a38a18da0d1b8b69b092b04e2de5daf205d89f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 02:59:22 +0200 Subject: [PATCH 034/211] WIP: add NAU7802 based scale controller. (#4092) * WIP: add NAU7802 based scale controller. Needs proto commit * WIP: add NAU7802 based scale controller. Needs proto commit * telemetry uses kg, scale internally g * add sensor calibration setters --- platformio.ini | 18 ++- src/configuration.h | 1 + src/detect/ScanI2C.h | 3 +- src/detect/ScanI2CTwoWire.cpp | 1 + .../Telemetry/EnvironmentTelemetry.cpp | 121 ++++++++++++++- src/modules/Telemetry/EnvironmentTelemetry.h | 4 + .../Telemetry/Sensor/NAU7802Sensor.cpp | 143 ++++++++++++++++++ src/modules/Telemetry/Sensor/NAU7802Sensor.h | 31 ++++ .../Telemetry/Sensor/TelemetrySensor.h | 7 + 9 files changed, 318 insertions(+), 11 deletions(-) create mode 100644 src/modules/Telemetry/Sensor/NAU7802Sensor.cpp create mode 100644 src/modules/Telemetry/Sensor/NAU7802Sensor.h diff --git a/platformio.ini b/platformio.ini index 0de3e25c92..d8d398775a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -122,10 +122,7 @@ lib_deps = adafruit/Adafruit BMP280 Library@^2.6.8 adafruit/Adafruit BMP085 Library@^1.2.4 adafruit/Adafruit BME280 Library@^2.2.2 - https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502 - boschsensortec/BME68x Sensor Library@^1.1.40407 adafruit/Adafruit MCP9808 Library@^2.0.0 - https://github.com/KodinLanewave/INA3221@^1.0.0 adafruit/Adafruit INA260 Library@^1.5.0 adafruit/Adafruit INA219@^1.2.0 adafruit/Adafruit SHTC3 Library@^1.0.0 @@ -135,13 +132,22 @@ lib_deps = adafruit/Adafruit MPU6050@^2.2.4 adafruit/Adafruit LIS3DH@^1.2.4 adafruit/Adafruit AHTX0@^2.0.5 - lewisxhe/SensorLib@^0.2.0 adafruit/Adafruit LSM6DS@^4.7.2 - mprograms/QMC5883LCompass@^1.2.0 adafruit/Adafruit VEML7700 Library@^2.1.6 adafruit/Adafruit SHT4x Library@^1.0.4 adafruit/Adafruit TSL2591 Library@^1.4.5 + sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@^1.0.5 ClosedCube OPT3001@^1.1.2 emotibit/EmotiBit MLX90632@^1.0.8 dfrobot/DFRobot_RTU@^1.0.3 - https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee \ No newline at end of file + + + https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502 + boschsensortec/BME68x Sensor Library@^1.1.40407 + https://github.com/KodinLanewave/INA3221@^1.0.0 + lewisxhe/SensorLib@^0.2.0 + mprograms/QMC5883LCompass@^1.2.0 + + + https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee + diff --git a/src/configuration.h b/src/configuration.h index 62c48a205f..1149f344ce 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -136,6 +136,7 @@ along with this program. If not, see . #define OPT3001_ADDR_ALT 0x44 #define MLX90632_ADDR 0x3A #define DFROBOT_LARK_ADDR 0x42 +#define NAU7802_ADDR 0x2A // ----------------------------------------------------------------------------- // ACCELEROMETER diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 20994ede1d..dcc1f40ae3 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -50,7 +50,8 @@ class ScanI2C MLX90632, AHT10, BMX160, - DFROBOT_LARK + DFROBOT_LARK, + NAU7802 } DeviceType; // typedef uint8_t DeviceAddress; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index f800a9963f..6766db014f 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -350,6 +350,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port) SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591 light sensor found\n"); SCAN_SIMPLE_CASE(OPT3001_ADDR, OPT3001, "OPT3001 light sensor found\n"); SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632 IR temp sensor found\n"); + SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802 based scale found\n"); default: LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address); diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 46b8a1ad80..ff32020675 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -27,6 +27,7 @@ #include "Sensor/LPS22HBSensor.h" #include "Sensor/MCP9808Sensor.h" #include "Sensor/MLX90632Sensor.h" +#include "Sensor/NAU7802Sensor.h" #include "Sensor/OPT3001Sensor.h" #include "Sensor/RCWL9620Sensor.h" #include "Sensor/SHT31Sensor.h" @@ -51,6 +52,7 @@ RCWL9620Sensor rcwl9620Sensor; AHT10Sensor aht10Sensor; MLX90632Sensor mlx90632Sensor; DFRobotLarkSensor dfRobotLarkSensor; +NAU7802Sensor nau7802Sensor; #define FAILED_STATE_SENSOR_READ_MULTIPLIER 10 #define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true @@ -125,6 +127,8 @@ int32_t EnvironmentTelemetryModule::runOnce() result = aht10Sensor.runOnce(); if (mlx90632Sensor.hasSensor()) result = mlx90632Sensor.runOnce(); + if (nau7802Sensor.hasSensor()) + result = nau7802Sensor.runOnce(); } return result; } else { @@ -223,12 +227,18 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt "Volt/Cur: " + String(lastMeasurement.variant.environment_metrics.voltage, 0) + "V / " + String(lastMeasurement.variant.environment_metrics.current, 0) + "mA"); } + if (lastMeasurement.variant.environment_metrics.iaq != 0) { display->drawString(x, y += fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq)); } + if (lastMeasurement.variant.environment_metrics.distance != 0) display->drawString(x, y += fontHeight(FONT_SMALL), "Water Level: " + String(lastMeasurement.variant.environment_metrics.distance, 0) + "mm"); + + if (lastMeasurement.variant.environment_metrics.weight != 0) + display->drawString(x, y += fontHeight(FONT_SMALL), + "Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg"); } bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t) @@ -245,8 +255,9 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac LOG_INFO("(Received from %s): voltage=%f, IAQ=%d, distance=%f, lux=%f\n", sender, t->variant.environment_metrics.voltage, t->variant.environment_metrics.iaq, t->variant.environment_metrics.distance, t->variant.environment_metrics.lux); - LOG_INFO("(Received from %s): wind speed=%fm/s, direction=%d degrees\n", sender, - t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction); + LOG_INFO("(Received from %s): wind speed=%fm/s, direction=%d degrees, weight=%fkg\n", sender, + t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction, + t->variant.environment_metrics.weight); #endif // release previous packet before occupying a new spot @@ -331,6 +342,10 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) valid = valid && rcwl9620Sensor.getMetrics(&m); hasSensor = true; } + if (nau7802Sensor.hasSensor()) { + valid = valid && nau7802Sensor.getMetrics(&m); + hasSensor = true; + } if (aht10Sensor.hasSensor()) { if (!bmp280Sensor.hasSensor()) { valid = valid && aht10Sensor.getMetrics(&m); @@ -354,8 +369,8 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) LOG_INFO("(Sending): voltage=%f, IAQ=%d, distance=%f, lux=%f\n", m.variant.environment_metrics.voltage, m.variant.environment_metrics.iaq, m.variant.environment_metrics.distance, m.variant.environment_metrics.lux); - LOG_INFO("(Sending): wind speed=%fm/s, direction=%d degrees\n", m.variant.environment_metrics.wind_speed, - m.variant.environment_metrics.wind_direction); + LOG_INFO("(Sending): wind speed=%fm/s, direction=%d degrees, weight=%fkg\n", m.variant.environment_metrics.wind_speed, + m.variant.environment_metrics.wind_direction, m.variant.environment_metrics.weight); sensor_read_error_count = 0; @@ -388,4 +403,102 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) return valid; } +AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule(const meshtastic_MeshPacket &mp, + meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) +{ + AdminMessageHandleResult result = AdminMessageHandleResult::NOT_HANDLED; + if (dfRobotLarkSensor.hasSensor()) { + result = dfRobotLarkSensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (sht31Sensor.hasSensor()) { + result = sht31Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (lps22hbSensor.hasSensor()) { + result = lps22hbSensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (shtc3Sensor.hasSensor()) { + result = shtc3Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (bmp085Sensor.hasSensor()) { + result = bmp085Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (bmp280Sensor.hasSensor()) { + result = bmp280Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (bme280Sensor.hasSensor()) { + result = bme280Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (bme680Sensor.hasSensor()) { + result = bme680Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (mcp9808Sensor.hasSensor()) { + result = mcp9808Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (ina219Sensor.hasSensor()) { + result = ina219Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (ina260Sensor.hasSensor()) { + result = ina260Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (veml7700Sensor.hasSensor()) { + result = veml7700Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (tsl2591Sensor.hasSensor()) { + result = tsl2591Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (opt3001Sensor.hasSensor()) { + result = opt3001Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (mlx90632Sensor.hasSensor()) { + result = mlx90632Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (rcwl9620Sensor.hasSensor()) { + result = rcwl9620Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (nau7802Sensor.hasSensor()) { + result = nau7802Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + if (aht10Sensor.hasSensor()) { + result = aht10Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } + return result; +} + #endif \ No newline at end of file diff --git a/src/modules/Telemetry/EnvironmentTelemetry.h b/src/modules/Telemetry/EnvironmentTelemetry.h index cdd9491d41..ca150347e7 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.h +++ b/src/modules/Telemetry/EnvironmentTelemetry.h @@ -37,6 +37,10 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu */ bool sendTelemetry(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + virtual AdminMessageHandleResult handleAdminMessageForModule(const meshtastic_MeshPacket &mp, + meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) override; + private: float CelsiusToFahrenheit(float c); bool firstTime = 1; diff --git a/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp new file mode 100644 index 0000000000..39ac4b08b8 --- /dev/null +++ b/src/modules/Telemetry/Sensor/NAU7802Sensor.cpp @@ -0,0 +1,143 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "FSCommon.h" +#include "NAU7802Sensor.h" +#include "TelemetrySensor.h" +#include +#include + +meshtastic_Nau7802Config nau7802config = meshtastic_Nau7802Config_init_zero; + +NAU7802Sensor::NAU7802Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_NAU7802, "NAU7802") {} + +int32_t NAU7802Sensor::runOnce() +{ + LOG_INFO("Init sensor: %s\n", sensorName); + if (!hasSensor()) { + return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + } + status = nau7802.begin(*nodeTelemetrySensorsMap[sensorType].second); + nau7802.setSampleRate(NAU7802_SPS_320); + if (!loadCalibrationData()) { + LOG_ERROR("Failed to load calibration data\n"); + } + nau7802.calibrateAFE(); + LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor()); + return initI2CSensor(); +} + +void NAU7802Sensor::setup() {} + +bool NAU7802Sensor::getMetrics(meshtastic_Telemetry *measurement) +{ + LOG_DEBUG("NAU7802Sensor::getMetrics\n"); + nau7802.powerUp(); + // Wait for the sensor to become ready for one second max + uint32_t start = millis(); + while (!nau7802.available()) { + delay(100); + if (millis() - start > 1000) { + nau7802.powerDown(); + return false; + } + } + // Check if we have correct calibration values after powerup + LOG_DEBUG("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor()); + measurement->variant.environment_metrics.weight = nau7802.getWeight() / 1000; // sample is in kg + nau7802.powerDown(); + return true; +} + +void NAU7802Sensor::calibrate(float weight) +{ + nau7802.calculateCalibrationFactor(weight * 1000, 64); // internal sample is in grams + if (!saveCalibrationData()) { + LOG_WARN("Failed to save calibration data\n"); + } + LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor()); +} + +AdminMessageHandleResult NAU7802Sensor::handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) +{ + AdminMessageHandleResult result; + + switch (request->which_payload_variant) { + case meshtastic_AdminMessage_set_scale_tag: + if (request->set_scale == 0) { + this->tare(); + LOG_DEBUG("Client requested to tare scale\n"); + } else { + this->calibrate(request->set_scale); + LOG_DEBUG("Client requested to calibrate to %d kg\n", request->set_scale); + } + result = AdminMessageHandleResult::HANDLED; + break; + + default: + result = AdminMessageHandleResult::NOT_HANDLED; + } + + return result; +} + +void NAU7802Sensor::tare() +{ + nau7802.calculateZeroOffset(64); + if (!saveCalibrationData()) { + LOG_WARN("Failed to save calibration data\n"); + } + LOG_INFO("Offset: %d, Calibration factor: %.2f\n", nau7802.getZeroOffset(), nau7802.getCalibrationFactor()); +} + +bool NAU7802Sensor::saveCalibrationData() +{ + if (FSCom.exists(nau7802ConfigFileName) && !FSCom.remove(nau7802ConfigFileName)) { + LOG_WARN("Can't remove old state file\n"); + } + auto file = FSCom.open(nau7802ConfigFileName, FILE_O_WRITE); + nau7802config.zeroOffset = nau7802.getZeroOffset(); + nau7802config.calibrationFactor = nau7802.getCalibrationFactor(); + bool okay = false; + if (file) { + LOG_INFO("%s state write to %s.\n", sensorName, nau7802ConfigFileName); + pb_ostream_t stream = {&writecb, &file, meshtastic_Nau7802Config_size}; + + if (!pb_encode(&stream, &meshtastic_Nau7802Config_msg, &nau7802config)) { + LOG_ERROR("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream)); + } else { + okay = true; + } + file.flush(); + file.close(); + } else { + LOG_INFO("Can't write %s state (File: %s).\n", sensorName, nau7802ConfigFileName); + } + return okay; +} + +bool NAU7802Sensor::loadCalibrationData() +{ + auto file = FSCom.open(nau7802ConfigFileName, FILE_O_READ); + bool okay = false; + if (file) { + LOG_INFO("%s state read from %s.\n", sensorName, nau7802ConfigFileName); + pb_istream_t stream = {&readcb, &file, meshtastic_Nau7802Config_size}; + if (!pb_decode(&stream, &meshtastic_Nau7802Config_msg, &nau7802config)) { + LOG_ERROR("Error: can't decode protobuf %s\n", PB_GET_ERROR(&stream)); + } else { + nau7802.setZeroOffset(nau7802config.zeroOffset); + nau7802.setCalibrationFactor(nau7802config.calibrationFactor); + okay = true; + } + file.close(); + } else { + LOG_INFO("No %s state found (File: %s).\n", sensorName, nau7802ConfigFileName); + } + return okay; +} + +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/NAU7802Sensor.h b/src/modules/Telemetry/Sensor/NAU7802Sensor.h new file mode 100644 index 0000000000..c53a3b31a7 --- /dev/null +++ b/src/modules/Telemetry/Sensor/NAU7802Sensor.h @@ -0,0 +1,31 @@ +#include "MeshModule.h" +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include + +class NAU7802Sensor : public TelemetrySensor +{ + private: + NAU7802 nau7802; + + protected: + virtual void setup() override; + const char *nau7802ConfigFileName = "/prefs/nau7802.dat"; + bool saveCalibrationData(); + bool loadCalibrationData(); + + public: + NAU7802Sensor(); + virtual int32_t runOnce() override; + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + void tare(); + void calibrate(float weight); + AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) override; +}; + +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/TelemetrySensor.h b/src/modules/Telemetry/Sensor/TelemetrySensor.h index 35cb7965d3..da376ad31a 100644 --- a/src/modules/Telemetry/Sensor/TelemetrySensor.h +++ b/src/modules/Telemetry/Sensor/TelemetrySensor.h @@ -4,6 +4,7 @@ #pragma once #include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "MeshModule.h" #include "NodeDB.h" #include @@ -42,6 +43,12 @@ class TelemetrySensor virtual void setup(); public: + virtual AdminMessageHandleResult handleAdminMessage(const meshtastic_MeshPacket &mp, meshtastic_AdminMessage *request, + meshtastic_AdminMessage *response) + { + return AdminMessageHandleResult::NOT_HANDLED; + } + bool hasSensor() { return nodeTelemetrySensorsMap[sensorType].first > 0; } virtual int32_t runOnce() = 0; From d7c52c33b93101c1ce15cdb6471f8513516b1cbe Mon Sep 17 00:00:00 2001 From: beegee-tokyo Date: Sun, 16 Jun 2024 14:24:36 +0800 Subject: [PATCH 035/211] Add RAK2560/RAK9154 --- .vscode/extensions.json | 7 +- platformio.ini | 1 + src/Power.cpp | 33 +++ .../Telemetry/Sensor/RAK9154Sensor.cpp | 189 ++++++++++++++++++ src/modules/Telemetry/Sensor/RAK9154Sensor.h | 18 ++ src/power.h | 5 + variants/rak2560/create_uf2.py | 105 ++++++++++ variants/rak2560/platformio.ini | 27 +++ variants/rak4631/variant.h | 32 ++- 9 files changed, 410 insertions(+), 7 deletions(-) create mode 100644 src/modules/Telemetry/Sensor/RAK9154Sensor.cpp create mode 100644 src/modules/Telemetry/Sensor/RAK9154Sensor.h create mode 100644 variants/rak2560/create_uf2.py create mode 100644 variants/rak2560/platformio.ini diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 4fc84fa780..080e70d08b 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,8 +2,9 @@ // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ - "ms-vscode.cpptools", - "platformio.platformio-ide", - "trunk.io" + "platformio.platformio-ide" ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] } diff --git a/platformio.ini b/platformio.ini index d8d398775a..a1beb8e7c5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -29,6 +29,7 @@ default_envs = tbeam ;default_envs = meshtastic-dr-dev ;default_envs = m5stack-coreink ;default_envs = rak4631 +;default_envs = rak2560 ;default_envs = rak10701 ;default_envs = wio-e5 ;default_envs = radiomaster_900_bandit_nano diff --git a/src/Power.cpp b/src/Power.cpp index d80bfd55cd..18dbfebe4d 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -75,6 +75,10 @@ INA219Sensor ina219Sensor; INA3221Sensor ina3221Sensor; #endif +#if HAS_RAKPROT && !defined(ARCH_PORTDUINO) +RAK9154Sensor rak9154Sensor; +#endif + #ifdef HAS_PMU #include "XPowersAXP192.tpp" #include "XPowersAXP2101.tpp" @@ -145,6 +149,12 @@ class AnalogBatteryLevel : public HasBatteryLevel */ virtual int getBatteryPercent() override { +#if defined(HAS_RAKPROT) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) + if (hasRAK()) { + return rak9154Sensor.getBusBatteryPercent(); + } +#endif + float v = getBattVoltage(); if (v < noBatVolt) @@ -184,6 +194,12 @@ class AnalogBatteryLevel : public HasBatteryLevel virtual uint16_t getBattVoltage() override { +#if defined(HAS_RAKPROT) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) + if (hasRAK()) { + return getRAKVoltage(); + } +#endif + #if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR if (hasINA()) { LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address); @@ -356,6 +372,11 @@ class AnalogBatteryLevel : public HasBatteryLevel /// we can't be smart enough to say 'full'? virtual bool isCharging() override { +#if defined(HAS_RAKPROT) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) + if (hasRAK()) { + return (rak9154Sensor.isCharging()) ? OptTrue : OptFalse; + } +#endif #ifdef EXT_CHRG_DETECT return digitalRead(EXT_CHRG_DETECT) == ext_chrg_detect_value; #else @@ -379,6 +400,18 @@ class AnalogBatteryLevel : public HasBatteryLevel float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS); uint32_t last_read_time_ms = 0; +#if defined(HAS_RAKPROT) + + uint16_t getRAKVoltage() { return rak9154Sensor.getBusVoltageMv(); } + + bool hasRAK() + { + if (!rak9154Sensor.isInitialized()) + return rak9154Sensor.runOnce() > 0; + return rak9154Sensor.isRunning(); + } +#endif + #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO) uint16_t getINAVoltage() { diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp b/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp new file mode 100644 index 0000000000..52d8190070 --- /dev/null +++ b/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp @@ -0,0 +1,189 @@ +#include "RAK9154Sensor.h" +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include "configuration.h" + +#include +#include "concurrency/Periodic.h" + +using namespace concurrency; + +#define BOOT_DATA_REQ + +RAK9154Sensor::RAK9154Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SENSOR_UNSET, "RAK1954") {} + +static Periodic *onewirePeriodic; + +static SoftwareHalfSerial mySerial(HALF_UART_PIN); // Wire pin P0.15 + +static uint8_t buff[0x100]; +static uint16_t bufflen = 0; + +static int16_t dc_cur = 0; +static uint16_t dc_vol = 0; +static uint8_t dc_prec = 0; +static uint8_t provision = 0; + +static void onewire_evt(const uint8_t pid, const uint8_t sid, const SNHUBAPI_EVT_E eid, uint8_t *msg, uint16_t len) +{ + switch (eid) + { + case SNHUBAPI_EVT_RECV_REQ: + case SNHUBAPI_EVT_RECV_RSP: + break; + + case SNHUBAPI_EVT_QSEND: + mySerial.write(msg, len); + break; + + case SNHUBAPI_EVT_ADD_SID: + // LOG_INFO("+ADD:SID:[%02x]\r\n", msg[0]); + break; + + case SNHUBAPI_EVT_ADD_PID: + // LOG_INFO("+ADD:PID:[%02x]\r\n", msg[0]); +#ifdef BOOT_DATA_REQ + provision = msg[0]; +#endif + break; + + case SNHUBAPI_EVT_GET_INTV: + break; + + case SNHUBAPI_EVT_GET_ENABLE: + break; + + case SNHUBAPI_EVT_SDATA_REQ: + + // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); + // for( uint16_t i=1; i 100) + { + dc_prec = 100; + } + break; + case RAK_IPSO_DC_CURRENT: + dc_cur = (msg[2] << 8) + msg[1]; + break; + case RAK_IPSO_DC_VOLTAGE: + dc_vol = (msg[2] << 8) + msg[1]; + dc_vol *= 10; + break; + default: + break; + } + + break; + case SNHUBAPI_EVT_REPORT: + + // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); + // for( uint16_t i=1; i 100) + { + dc_prec = 100; + } + break; + case RAK_IPSO_DC_CURRENT: + dc_cur = (msg[1] << 8) + msg[2]; + break; + case RAK_IPSO_DC_VOLTAGE: + dc_vol = (msg[1] << 8) + msg[2]; + dc_vol *= 10; + break; + default: + break; + } + + break; + + case SNHUBAPI_EVT_CHKSUM_ERR: + LOG_INFO("+ERR:CHKSUM\r\n"); + break; + + case SNHUBAPI_EVT_SEQ_ERR: + LOG_INFO("+ERR:SEQUCE\r\n"); + break; + + default: + break; + } +} + +static int32_t onewireHandle() +{ + if (provision != 0) + { + RakSNHub_Protocl_API.get.data(provision); + provision = 0; + } + + while (mySerial.available()) + { + char a = mySerial.read(); + buff[bufflen++] = a; + delay(2); // continue data, timeout=2ms + } + + if (bufflen != 0) + { + RakSNHub_Protocl_API.process((uint8_t *)buff, bufflen); + bufflen = 0; + } + + return 50; +} + +int32_t RAK9154Sensor::runOnce() +{ + onewirePeriodic = new Periodic("onewireHandle", onewireHandle); + + mySerial.begin(9600); + + RakSNHub_Protocl_API.init(onewire_evt); + + status = true; + initialized = true; + return 0; +} + +void RAK9154Sensor::setup() +{ + // Set up oversampling and filter initialization +} + +bool RAK9154Sensor::getMetrics(meshtastic_Telemetry *measurement) +{ + return true; +} + +uint16_t RAK9154Sensor::getBusVoltageMv() +{ + return dc_vol; +} + +int RAK9154Sensor::getBusBatteryPercent() +{ + return (int)dc_prec; +} + +bool RAK9154Sensor::isCharging() +{ + return (dc_cur > 0) ? true : false; +} diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.h b/src/modules/Telemetry/Sensor/RAK9154Sensor.h new file mode 100644 index 0000000000..cfe31780a9 --- /dev/null +++ b/src/modules/Telemetry/Sensor/RAK9154Sensor.h @@ -0,0 +1,18 @@ +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include "VoltageSensor.h" + +class RAK9154Sensor : public TelemetrySensor, VoltageSensor +{ + private: + protected: + virtual void setup() override; + + public: + RAK9154Sensor(); + virtual int32_t runOnce() override; + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual uint16_t getBusVoltageMv() override; + int getBusBatteryPercent(); + bool isCharging(); +}; \ No newline at end of file diff --git a/src/power.h b/src/power.h index 8d14ed7f8d..94bf21cc2e 100644 --- a/src/power.h +++ b/src/power.h @@ -46,6 +46,11 @@ extern INA219Sensor ina219Sensor; extern INA3221Sensor ina3221Sensor; #endif +#if HAS_RAKPROT && !defined(ARCH_PORTDUINO) +#include "modules/Telemetry/Sensor/RAK9154Sensor.h" +extern RAK9154Sensor rak9154Sensor; +#endif + class Power : private concurrency::OSThread { diff --git a/variants/rak2560/create_uf2.py b/variants/rak2560/create_uf2.py new file mode 100644 index 0000000000..d14eaea029 --- /dev/null +++ b/variants/rak2560/create_uf2.py @@ -0,0 +1,105 @@ +import sys +import struct + +Import("env") + +# Parse input and create UF2 file +def create_uf2(source, target, env): + # source_hex = target[0].get_abspath() + source_hex = target[0].get_string(False) + source_hex = '.\\'+source_hex + print("#########################################################") + print("Create UF2 from "+source_hex) + print("#########################################################") + # print("Source: " + source_hex) + target = source_hex.replace(".hex", "") + target = target + ".uf2" + # print("Target: " + target) + + with open(source_hex, mode='rb') as f: + inpbuf = f.read() + + outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8")) + + write_file(target, outbuf) + print("#########################################################") + print(target + " is ready to flash to target device") + print("#########################################################") + + +# Add callback after .hex file was created +env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", create_uf2) + +# UF2 creation taken from uf2conv.py +UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" +UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected +UF2_MAGIC_END = 0x0AB16F30 # Ditto + +familyid = 0xADA52840 + + +class Block: + def __init__(self, addr): + self.addr = addr + self.bytes = bytearray(256) + + def encode(self, blockno, numblocks): + global familyid + flags = 0x0 + if familyid: + flags |= 0x2000 + hd = struct.pack(" + + + +lib_deps = + ${nrf52840_base.lib_deps} + ${networking_base.lib_deps} + melopero/Melopero RV3028@^1.1.0 + https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2 + rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 + beegee-tokyo/RAKwireless RAK12034@^1.0.0 + https://github.com/beegee-tokyo/RAK-OneWireSerial.git +debug_tool = jlink +; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) +;upload_protocol = jlink +extra_scripts = + ${env.extra_scripts} + ../firmware/variants/rak2560/create_uf2.py \ No newline at end of file diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h index bc55413368..e9f1a18651 100644 --- a/variants/rak4631/variant.h +++ b/variants/rak4631/variant.h @@ -100,9 +100,9 @@ static const uint8_t AREF = PIN_AREF; #define PIN_SERIAL1_RX (15) #define PIN_SERIAL1_TX (16) -// Connected to Jlink CDC -#define PIN_SERIAL2_RX (8) -#define PIN_SERIAL2_TX (6) +// Connected to Serial 2 +#define PIN_SERIAL2_RX (19) +#define PIN_SERIAL2_TX (20) /* * SPI Interfaces @@ -228,9 +228,18 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG // #define PIN_GPS_EN PIN_3V3_EN #define PIN_GPS_PPS (17) // Pulse per second input from the GPS +// On RAK2560 the GPS is be on a different UART +#ifdef HAS_RAKPROT +// #define GPS_RX_PIN PIN_SERIAL2_RX +// #define GPS_TX_PIN PIN_SERIAL2_TX +// #define PIN_GPS_EN PIN_3V3_EN +// Disable GPS +#define MESHTASTIC_EXCLUDE_GPS 1 +#else + // Enable GPS #define GPS_RX_PIN PIN_SERIAL1_RX #define GPS_TX_PIN PIN_SERIAL1_TX - +#endif // Define pin to enable GPS toggle (set GPIO to LOW) via user button triple press // RAK12002 RTC Module @@ -257,6 +266,21 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG #define RAK_4631 1 +#ifdef HAS_RAKPROT + +#define HALF_UART_PIN PIN_SERIAL1_RX + +#if defined(GPS_RX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) +#error pin 15 collision + +#endif + +#if defined(GPS_TX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) +#error pin 15 collision +#endif + +#endif + #define PIN_ETHERNET_RESET 21 #define PIN_ETHERNET_SS PIN_EINK_CS #define ETH_SPI_PORT SPI1 From 5e01b4251fd8848deb9b5896a841eaa0e6f29585 Mon Sep 17 00:00:00 2001 From: beegee-tokyo Date: Sun, 16 Jun 2024 15:46:37 +0800 Subject: [PATCH 036/211] Fix build error for none RAK2560 devices --- src/modules/Telemetry/Sensor/RAK9154Sensor.cpp | 2 ++ src/modules/Telemetry/Sensor/RAK9154Sensor.h | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp b/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp index 52d8190070..4a317045bb 100644 --- a/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp +++ b/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp @@ -1,3 +1,4 @@ +#ifdef HAS_RAKPROT #include "RAK9154Sensor.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "TelemetrySensor.h" @@ -187,3 +188,4 @@ bool RAK9154Sensor::isCharging() { return (dc_cur > 0) ? true : false; } +#endif // HAS_RAKPROT \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.h b/src/modules/Telemetry/Sensor/RAK9154Sensor.h index cfe31780a9..5f5a927412 100644 --- a/src/modules/Telemetry/Sensor/RAK9154Sensor.h +++ b/src/modules/Telemetry/Sensor/RAK9154Sensor.h @@ -1,3 +1,4 @@ +#ifdef HAS_RAKPROT #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "TelemetrySensor.h" #include "VoltageSensor.h" @@ -15,4 +16,5 @@ class RAK9154Sensor : public TelemetrySensor, VoltageSensor virtual uint16_t getBusVoltageMv() override; int getBusBatteryPercent(); bool isCharging(); -}; \ No newline at end of file +}; +#endif // HAS_RAKPROT \ No newline at end of file From 27bb3506d390c2a77cd52a8ceae7f04c60cafce4 Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sat, 18 May 2024 22:14:22 -0400 Subject: [PATCH 037/211] Added fix for ESP32 --- src/detect/ScanI2C.cpp | 30 +++++++++++++++++++++++++++++- src/detect/ScanI2C.h | 1 + src/main.cpp | 3 +++ src/main.h | 3 ++- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 3231f70545..ad0171118e 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,4 +1,6 @@ #include "ScanI2C.h" +#include "main.h" +#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -27,7 +29,33 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } - +bool performScanForCardKB() { + // Example I2C scan code for CardKB (adjust as needed) + Wire.beginTransmission(CARDKB_I2C_ADDRESS); + if (Wire.endTransmission() == 0) { + return true; // CardKB detected + } + return false; // CardKB not detected +} +void scanForCardKB() { + const int maxRetries = 10; // Maximum number of retries + const int retryDelay = 100; // Delay between retries in milliseconds + + for (int i = 0; i < maxRetries; ++i) { + // Perform the scan (example scan code, adjust as needed) + cardKBDetected = performScanForCardKB(); + + if (cardKBDetected) { + Serial.println("CardKB Keyboard detected."); + break; + } + + delay(retryDelay); // Wait before the next retry + } + if (!cardKBDetected) { + Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); + } +} ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index dcc1f40ae3..ee691e8648 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,6 +2,7 @@ #include #include +bool performScanForCardKB(); class ScanI2C { diff --git a/src/main.cpp b/src/main.cpp index 6797c83759..9529ca7b31 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,8 @@ #include // #include +bool cardKBDetected = false; +void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -376,6 +378,7 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif +scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index 2ef7edb3a9..b1e1ac4645 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif - +extern bool cardKBDetected; #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,6 +39,7 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; +#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From dbb254ba7a5c442aab440af19c2ea1a20327a48d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 19 May 2024 19:32:08 +0200 Subject: [PATCH 038/211] change the main scan class so they scan only for wanted bits - UNTESTED --- src/detect/ScanI2C.cpp | 31 ++--------------------------- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 11 ++++++++++- src/detect/ScanI2CTwoWire.h | 4 +++- src/input/kbI2cBase.cpp | 37 +++++++++++++++++++++++++++++++++-- src/main.cpp | 3 --- src/main.h | 3 +-- 7 files changed, 52 insertions(+), 39 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index ad0171118e..9c3a186441 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,6 +1,4 @@ #include "ScanI2C.h" -#include "main.h" -#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -8,6 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, int *address) {} void ScanI2C::setSuppressScreen() { @@ -29,33 +28,7 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } -bool performScanForCardKB() { - // Example I2C scan code for CardKB (adjust as needed) - Wire.beginTransmission(CARDKB_I2C_ADDRESS); - if (Wire.endTransmission() == 0) { - return true; // CardKB detected - } - return false; // CardKB not detected -} -void scanForCardKB() { - const int maxRetries = 10; // Maximum number of retries - const int retryDelay = 100; // Delay between retries in milliseconds - - for (int i = 0; i < maxRetries; ++i) { - // Perform the scan (example scan code, adjust as needed) - cardKBDetected = performScanForCardKB(); - - if (cardKBDetected) { - Serial.println("CardKB Keyboard detected."); - break; - } - - delay(retryDelay); // Wait before the next retry - } - if (!cardKBDetected) { - Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); - } -} + ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index ee691e8648..1facb897a2 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,7 +2,6 @@ #include #include -bool performScanForCardKB(); class ScanI2C { @@ -89,6 +88,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); + virtual void scanPort(ScanI2C::I2CPort, int *); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 6766db014f..dd70db8b77 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -135,7 +135,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port) +void ScanI2CTwoWire::scanPort(I2CPort port, int *address) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,6 +163,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port) #endif for (addr.address = 1; addr.address < 127; addr.address++) { + // Skip the address if it is not requested oon a partial scan + if (sizeof(address) > 0 && addr.address != *address) { + continue; + } i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -367,6 +371,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port) } } +void ScanI2CTwoWire::scanPort(I2CPort port) +{ + scanPort(port, nullptr); +} + TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const { if (address.port == ScanI2C::I2CPort::WIRE) { diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 9acd736d2e..a7c19c7791 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,6 +16,8 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; + void scanPort(ScanI2C::I2CPort, int *) override; + ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const; @@ -53,4 +55,4 @@ class ScanI2CTwoWire : public ScanI2C uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const; DeviceType probeOLED(ScanI2C::DeviceAddress) const; -}; +}; \ No newline at end of file diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index af7c96b206..55f435fda7 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -1,6 +1,7 @@ #include "kbI2cBase.h" #include "configuration.h" #include "detect/ScanI2C.h" +#include "detect/ScanI2CTwoWire.h" extern ScanI2C::DeviceAddress cardkb_found; extern uint8_t kb_model; @@ -30,8 +31,40 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len int32_t KbI2cBase::runOnce() { if (cardkb_found.address == 0x00) { - // Input device is not detected. - return INT32_MAX; + // Input device is not detected. Rescan now. + auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); + int i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; +#if defined(I2C_SDA1) + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); +#endif + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan); + auto kb_info = i2cScanner->firstKeyboard(); + + if (kb_info.type != ScanI2C::DeviceType::NONE) { + cardkb_found = kb_info.address; + switch (kb_info.type) { + case ScanI2C::DeviceType::RAK14004: + kb_model = 0x02; + break; + case ScanI2C::DeviceType::CARDKB: + kb_model = 0x00; + break; + case ScanI2C::DeviceType::TDECKKB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x10; + break; + case ScanI2C::DeviceType::BBQ10KB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x11; + break; + default: + // use this as default since it's also just zero + LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type); + kb_model = 0x00; + } + } + if (cardkb_found.address == 0x00) + return INT32_MAX; } if (!i2cBus) { diff --git a/src/main.cpp b/src/main.cpp index 9529ca7b31..6797c83759 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,8 +35,6 @@ #include // #include -bool cardKBDetected = false; -void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -378,7 +376,6 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif -scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index b1e1ac4645..2ef7edb3a9 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif -extern bool cardKBDetected; + #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,7 +39,6 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; -#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From ce9e63a2cb21ad943d708ae69fc6a0cbb62e5807 Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sat, 18 May 2024 22:14:22 -0400 Subject: [PATCH 039/211] Added fix for ESP32 --- src/detect/ScanI2C.cpp | 30 +++++++++++++++++++++++++++++- src/detect/ScanI2C.h | 1 + src/main.cpp | 3 +++ src/main.h | 3 ++- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 9c3a186441..51718b15fa 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,4 +1,6 @@ #include "ScanI2C.h" +#include "main.h" +#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -28,7 +30,33 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } - +bool performScanForCardKB() { + // Example I2C scan code for CardKB (adjust as needed) + Wire.beginTransmission(CARDKB_I2C_ADDRESS); + if (Wire.endTransmission() == 0) { + return true; // CardKB detected + } + return false; // CardKB not detected +} +void scanForCardKB() { + const int maxRetries = 10; // Maximum number of retries + const int retryDelay = 100; // Delay between retries in milliseconds + + for (int i = 0; i < maxRetries; ++i) { + // Perform the scan (example scan code, adjust as needed) + cardKBDetected = performScanForCardKB(); + + if (cardKBDetected) { + Serial.println("CardKB Keyboard detected."); + break; + } + + delay(retryDelay); // Wait before the next retry + } + if (!cardKBDetected) { + Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); + } +} ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 1facb897a2..1c2fe73c6c 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,6 +2,7 @@ #include #include +bool performScanForCardKB(); class ScanI2C { diff --git a/src/main.cpp b/src/main.cpp index 6797c83759..9529ca7b31 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,6 +35,8 @@ #include // #include +bool cardKBDetected = false; +void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -376,6 +378,7 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif +scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index 2ef7edb3a9..b1e1ac4645 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif - +extern bool cardKBDetected; #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,6 +39,7 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; +#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From 2eb3cfd5e033afb27c687bba0b194b94036d3cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 19 May 2024 19:32:08 +0200 Subject: [PATCH 040/211] change the main scan class so they scan only for wanted bits - UNTESTED --- src/detect/ScanI2C.cpp | 30 +----------------------------- src/detect/ScanI2C.h | 1 - src/main.cpp | 3 --- src/main.h | 3 +-- 4 files changed, 2 insertions(+), 35 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 51718b15fa..9c3a186441 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -1,6 +1,4 @@ #include "ScanI2C.h" -#include "main.h" -#include const ScanI2C::DeviceAddress ScanI2C::ADDRESS_NONE = ScanI2C::DeviceAddress(); const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ADDRESS_NONE); @@ -30,33 +28,7 @@ ScanI2C::FoundDevice ScanI2C::firstRTC() const ScanI2C::DeviceType types[] = {RTC_RV3028, RTC_PCF8563}; return firstOfOrNONE(2, types); } -bool performScanForCardKB() { - // Example I2C scan code for CardKB (adjust as needed) - Wire.beginTransmission(CARDKB_I2C_ADDRESS); - if (Wire.endTransmission() == 0) { - return true; // CardKB detected - } - return false; // CardKB not detected -} -void scanForCardKB() { - const int maxRetries = 10; // Maximum number of retries - const int retryDelay = 100; // Delay between retries in milliseconds - - for (int i = 0; i < maxRetries; ++i) { - // Perform the scan (example scan code, adjust as needed) - cardKBDetected = performScanForCardKB(); - - if (cardKBDetected) { - Serial.println("CardKB Keyboard detected."); - break; - } - - delay(retryDelay); // Wait before the next retry - } - if (!cardKBDetected) { - Serial.println("CardKB Keyboard not detected. Canned Message Module Disabled."); - } -} + ScanI2C::FoundDevice ScanI2C::firstKeyboard() const { ScanI2C::DeviceType types[] = {CARDKB, TDECKKB, BBQ10KB, RAK14004}; diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 1c2fe73c6c..1facb897a2 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -2,7 +2,6 @@ #include #include -bool performScanForCardKB(); class ScanI2C { diff --git a/src/main.cpp b/src/main.cpp index 9529ca7b31..6797c83759 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,8 +35,6 @@ #include // #include -bool cardKBDetected = false; -void scanForCardKB(); #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_WEBSERVER #include "mesh/http/WebServer.h" @@ -378,7 +376,6 @@ void setup() // otherwise keyboard and touch screen will not work delay(800); #endif -scanForCardKB(); // Initial scan for CardKB // Currently only the tbeam has a PMU // PMU initialization needs to be placed before i2c scanning diff --git a/src/main.h b/src/main.h index b1e1ac4645..2ef7edb3a9 100644 --- a/src/main.h +++ b/src/main.h @@ -21,7 +21,7 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif -extern bool cardKBDetected; + #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; extern HardwareSPI *LoraSPI; @@ -39,7 +39,6 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; -#define CARDKB_I2C_ADDRESS 0x5F // Replace 0x5F with the actual address if different #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) extern ATECCX08A atecc; #endif From ba14ffb8d393662f59481489af7c252a28dd60ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 24 May 2024 22:59:31 +0200 Subject: [PATCH 041/211] change type to 8 bit uint --- src/detect/ScanI2C.cpp | 2 +- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 6 +++--- src/detect/ScanI2CTwoWire.h | 2 +- src/input/kbI2cBase.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 9c3a186441..03b93e0685 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -6,7 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} -void ScanI2C::scanPort(ScanI2C::I2CPort port, int *address) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address) {} void ScanI2C::setSuppressScreen() { diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 1facb897a2..5c75a9deeb 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -88,7 +88,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); - virtual void scanPort(ScanI2C::I2CPort, int *); + virtual void scanPort(ScanI2C::I2CPort, uint8_t *); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index dd70db8b77..95e273b85f 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -135,7 +135,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port, int *address) +void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,8 +163,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port, int *address) #endif for (addr.address = 1; addr.address < 127; addr.address++) { - // Skip the address if it is not requested oon a partial scan - if (sizeof(address) > 0 && addr.address != *address) { + // Skip the address if it is not requested on a partial scan + if (address != nullptr && *address != addr.address) { continue; } i2cBus->beginTransmission(addr.address); diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index a7c19c7791..332afbf64e 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,7 +16,7 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; - void scanPort(ScanI2C::I2CPort, int *) override; + void scanPort(ScanI2C::I2CPort, uint8_t *) override; ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index 55f435fda7..135de17166 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -33,7 +33,7 @@ int32_t KbI2cBase::runOnce() if (cardkb_found.address == 0x00) { // Input device is not detected. Rescan now. auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); - int i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; + uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; #if defined(I2C_SDA1) i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); #endif From a453d7f52c80ea6887714b2415c1cac8f138806e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 25 May 2024 12:37:55 +0200 Subject: [PATCH 042/211] Iterate through uint array --- src/detect/ScanI2C.cpp | 2 +- src/detect/ScanI2C.h | 2 +- src/detect/ScanI2CTwoWire.cpp | 21 +++++++++++++++------ src/detect/ScanI2CTwoWire.h | 2 +- src/input/kbI2cBase.cpp | 5 +++-- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 03b93e0685..73bdf973b0 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -6,7 +6,7 @@ const ScanI2C::FoundDevice ScanI2C::DEVICE_NONE = ScanI2C::FoundDevice(ScanI2C:: ScanI2C::ScanI2C() = default; void ScanI2C::scanPort(ScanI2C::I2CPort port) {} -void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address) {} +void ScanI2C::scanPort(ScanI2C::I2CPort port, uint8_t *address, uint8_t asize) {} void ScanI2C::setSuppressScreen() { diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 5c75a9deeb..711e8bee54 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -88,7 +88,7 @@ class ScanI2C ScanI2C(); virtual void scanPort(ScanI2C::I2CPort); - virtual void scanPort(ScanI2C::I2CPort, uint8_t *); + virtual void scanPort(ScanI2C::I2CPort, uint8_t *, uint8_t); /* * A bit of a hack, this tells the scanner not to tell later systems there is a screen to avoid enabling it. diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 95e273b85f..b045905098 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -14,6 +14,15 @@ #define XPOWERS_AXP192_AXP2101_ADDRESS 0x34 #endif +bool in_array(uint8_t *array, int size, uint8_t lookfor) +{ + int i; + for (i = 0; i < size; i++) + if (lookfor == array[i]) + return true; + return false; +} + ScanI2C::FoundDevice ScanI2CTwoWire::find(ScanI2C::DeviceType type) const { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -135,7 +144,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation type = T; \ break; -void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) +void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) { concurrency::LockGuard guard((concurrency::Lock *)&lock); @@ -163,10 +172,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) #endif for (addr.address = 1; addr.address < 127; addr.address++) { - // Skip the address if it is not requested on a partial scan - if (address != nullptr && *address != addr.address) { - continue; - } + if (asize != 0) + if (in_array(address, asize, addr.address)) + continue; + i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -373,7 +382,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address) void ScanI2CTwoWire::scanPort(I2CPort port) { - scanPort(port, nullptr); + scanPort(port, nullptr, 0); } TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 332afbf64e..82b48f6b47 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -16,7 +16,7 @@ class ScanI2CTwoWire : public ScanI2C public: void scanPort(ScanI2C::I2CPort) override; - void scanPort(ScanI2C::I2CPort, uint8_t *) override; + void scanPort(ScanI2C::I2CPort, uint8_t *, uint8_t) override; ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override; diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index 135de17166..ce22edb93d 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -34,10 +34,11 @@ int32_t KbI2cBase::runOnce() // Input device is not detected. Rescan now. auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; + uint8_t i2caddr_asize = 3; #if defined(I2C_SDA1) - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan); + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize); #endif - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan); + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize); auto kb_info = i2cScanner->firstKeyboard(); if (kb_info.type != ScanI2C::DeviceType::NONE) { From 85d621d9c6d2c54117559e24a2c7c33c21fe80fa Mon Sep 17 00:00:00 2001 From: beegee-tokyo Date: Sun, 16 Jun 2024 19:45:17 +0800 Subject: [PATCH 043/211] Move RAK9154 to variants, fix json --- .vscode/extensions.json | 7 ++-- platformio.ini | 4 +- src/power.h | 42 ++++++++++--------- .../rak2560}/RAK9154Sensor.cpp | 6 +-- .../rak2560}/RAK9154Sensor.h | 7 +++- variants/rak2560/platformio.ini | 2 +- 6 files changed, 36 insertions(+), 32 deletions(-) rename {src/modules/Telemetry/Sensor => variants/rak2560}/RAK9154Sensor.cpp (96%) rename {src/modules/Telemetry/Sensor => variants/rak2560}/RAK9154Sensor.h (71%) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 080e70d08b..b50c95349d 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -2,9 +2,8 @@ // See http://go.microsoft.com/fwlink/?LinkId=827846 // for the documentation about the extensions.json format "recommendations": [ - "platformio.platformio-ide" + "ms-vscode.cpptools", + "platformio.platformio-ide", + "trunk.io" ], - "unwantedRecommendations": [ - "ms-vscode.cpptools-extension-pack" - ] } diff --git a/platformio.ini b/platformio.ini index a1beb8e7c5..55329e5787 100644 --- a/platformio.ini +++ b/platformio.ini @@ -2,7 +2,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -default_envs = tbeam +;default_envs = tbeam ;default_envs = pico ;default_envs = tbeam-s3-core ;default_envs = tbeam0.7 @@ -29,7 +29,7 @@ default_envs = tbeam ;default_envs = meshtastic-dr-dev ;default_envs = m5stack-coreink ;default_envs = rak4631 -;default_envs = rak2560 +default_envs = rak2560 ;default_envs = rak10701 ;default_envs = wio-e5 ;default_envs = radiomaster_900_bandit_nano diff --git a/src/power.h b/src/power.h index 94bf21cc2e..c343a45ebd 100644 --- a/src/power.h +++ b/src/power.h @@ -2,6 +2,8 @@ #include "PowerStatus.h" #include "concurrency/OSThread.h" #include "configuration.h" +#include "../variants/rak2560/RAK9154Sensor.h" + #ifdef ARCH_ESP32 #include #include @@ -47,38 +49,38 @@ extern INA3221Sensor ina3221Sensor; #endif #if HAS_RAKPROT && !defined(ARCH_PORTDUINO) -#include "modules/Telemetry/Sensor/RAK9154Sensor.h" +#include "../variants/rak2560/RAK9154Sensor.h" extern RAK9154Sensor rak9154Sensor; #endif class Power : private concurrency::OSThread { - public: - Observable newStatus; +public: + Observable newStatus; - Power(); + Power(); - void shutdown(); - void readPowerStatus(); - virtual bool setup(); - virtual int32_t runOnce() override; - void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; } - const uint16_t OCV[11] = {OCV_ARRAY}; + void shutdown(); + void readPowerStatus(); + virtual bool setup(); + virtual int32_t runOnce() override; + void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; } + const uint16_t OCV[11] = {OCV_ARRAY}; - protected: - meshtastic::PowerStatus *statusHandler; +protected: + meshtastic::PowerStatus *statusHandler; - /// Setup a xpowers chip axp192/axp2101, return true if found - bool axpChipInit(); - /// Setup a simple ADC input based battery sensor - bool analogInit(); + /// Setup a xpowers chip axp192/axp2101, return true if found + bool axpChipInit(); + /// Setup a simple ADC input based battery sensor + bool analogInit(); - private: - // open circuit voltage lookup table - uint8_t low_voltage_counter; +private: + // open circuit voltage lookup table + uint8_t low_voltage_counter; #ifdef DEBUG_HEAP - uint32_t lastheap; + uint32_t lastheap; #endif }; diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp b/variants/rak2560/RAK9154Sensor.cpp similarity index 96% rename from src/modules/Telemetry/Sensor/RAK9154Sensor.cpp rename to variants/rak2560/RAK9154Sensor.cpp index 4a317045bb..15a172c182 100644 --- a/src/modules/Telemetry/Sensor/RAK9154Sensor.cpp +++ b/variants/rak2560/RAK9154Sensor.cpp @@ -1,7 +1,7 @@ -#ifdef HAS_RAKPROT -#include "RAK9154Sensor.h" +#ifdef HAS_RAKPROT +#include "../variants/rak2560/RAK9154Sensor.h" #include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "TelemetrySensor.h" +#include "../modules/Telemetry/Sensor/TelemetrySensor.h" #include "configuration.h" #include diff --git a/src/modules/Telemetry/Sensor/RAK9154Sensor.h b/variants/rak2560/RAK9154Sensor.h similarity index 71% rename from src/modules/Telemetry/Sensor/RAK9154Sensor.h rename to variants/rak2560/RAK9154Sensor.h index 5f5a927412..6c6f304d67 100644 --- a/src/modules/Telemetry/Sensor/RAK9154Sensor.h +++ b/variants/rak2560/RAK9154Sensor.h @@ -1,7 +1,9 @@ #ifdef HAS_RAKPROT +#ifndef _RAK9154SENSOR_H +#define _RAK9154SENSOR_H 1 #include "../mesh/generated/meshtastic/telemetry.pb.h" -#include "TelemetrySensor.h" -#include "VoltageSensor.h" +#include "../modules/Telemetry/Sensor/TelemetrySensor.h" +#include "../modules/Telemetry/Sensor/VoltageSensor.h" class RAK9154Sensor : public TelemetrySensor, VoltageSensor { @@ -17,4 +19,5 @@ class RAK9154Sensor : public TelemetrySensor, VoltageSensor int getBusBatteryPercent(); bool isCharging(); }; +#endif // _RAK9154SENSOR_H #endif // HAS_RAKPROT \ No newline at end of file diff --git a/variants/rak2560/platformio.ini b/variants/rak2560/platformio.ini index b33f7dcef5..1734bc75c8 100644 --- a/variants/rak2560/platformio.ini +++ b/variants/rak2560/platformio.ini @@ -10,7 +10,7 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631 -D RAK_4631 -DEINK_WIDTH=250 -DEINK_HEIGHT=122 -DHAS_RAKPROT=1 ; Define if RAk OneWireSerial is used (disables GPS) -build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> + + + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> +<../variants/rak2560> + + + lib_deps = ${nrf52840_base.lib_deps} ${networking_base.lib_deps} From 471ee78a5e86fa8b5b61705d61606ce9216f7f06 Mon Sep 17 00:00:00 2001 From: thebentern <9000580+thebentern@users.noreply.github.com> Date: Sun, 16 Jun 2024 12:25:52 +0000 Subject: [PATCH 044/211] [create-pull-request] automated change --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index dc066c89f7..0c90a6814f 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit dc066c89f73fce882e5a47648cba18a1967a7f56 +Subproject commit 0c90a6814fdd959a35bb6cf8e958e74d48e8a601 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 0e9e6a28d7..f5fc8661af 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -67,6 +67,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_WIPHONE = 20, /* WIO Tracker WM1110 family from Seeed Studio. Includes wio-1110-tracker and wio-1110-sdk */ meshtastic_HardwareModel_WIO_WM1110 = 21, + /* RAK2560 Solar base station based on RAK4630 */ + meshtastic_HardwareModel_RAK2560 = 22, /* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */ meshtastic_HardwareModel_STATION_G1 = 25, /* RAK11310 (RP2040 + SX1262) */ From f50073ed9f351c4b59f8756125efda40452e9562 Mon Sep 17 00:00:00 2001 From: beegee-tokyo Date: Sun, 16 Jun 2024 21:06:38 +0800 Subject: [PATCH 045/211] Separate RAK4631 and RAK2560 variants --- platformio.ini | 4 +- variants/rak2560/platformio.ini | 7 +- variants/rak2560/variant.cpp | 45 +++++ variants/rak2560/variant.h | 280 ++++++++++++++++++++++++++++++++ variants/rak4631/variant.h | 149 +++++++---------- 5 files changed, 392 insertions(+), 93 deletions(-) create mode 100644 variants/rak2560/variant.cpp create mode 100644 variants/rak2560/variant.h diff --git a/platformio.ini b/platformio.ini index 55329e5787..a1beb8e7c5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -2,7 +2,7 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -;default_envs = tbeam +default_envs = tbeam ;default_envs = pico ;default_envs = tbeam-s3-core ;default_envs = tbeam0.7 @@ -29,7 +29,7 @@ ;default_envs = meshtastic-dr-dev ;default_envs = m5stack-coreink ;default_envs = rak4631 -default_envs = rak2560 +;default_envs = rak2560 ;default_envs = rak10701 ;default_envs = wio-e5 ;default_envs = radiomaster_900_bandit_nano diff --git a/variants/rak2560/platformio.ini b/variants/rak2560/platformio.ini index 1734bc75c8..71b235aaca 100644 --- a/variants/rak2560/platformio.ini +++ b/variants/rak2560/platformio.ini @@ -3,14 +3,11 @@ extends = nrf52840_base board = wiscore_rak4631 board_check = true -build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631 -D RAK_4631 +build_flags = ${nrf52840_base.build_flags} -Ivariants/rak2560 -D RAK_4631 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. - -DEINK_DISPLAY_MODEL=GxEPD2_213_BN - -DEINK_WIDTH=250 - -DEINK_HEIGHT=122 -DHAS_RAKPROT=1 ; Define if RAk OneWireSerial is used (disables GPS) -build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> +<../variants/rak2560> + + + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak2560> + + + lib_deps = ${nrf52840_base.lib_deps} ${networking_base.lib_deps} diff --git a/variants/rak2560/variant.cpp b/variants/rak2560/variant.cpp new file mode 100644 index 0000000000..e84b60b3b9 --- /dev/null +++ b/variants/rak2560/variant.cpp @@ -0,0 +1,45 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); + + // 3V3 Power Rail + pinMode(PIN_3V3_EN, OUTPUT); + digitalWrite(PIN_3V3_EN, HIGH); +} diff --git a/variants/rak2560/variant.h b/variants/rak2560/variant.h new file mode 100644 index 0000000000..7187c8a50b --- /dev/null +++ b/variants/rak2560/variant.h @@ -0,0 +1,280 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_RAK4630_ +#define _VARIANT_RAK4630_ + +#define RAK4630 + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (6) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (35) +#define PIN_LED2 (36) + +#define LED_BUILTIN PIN_LED1 +#define LED_CONN PIN_LED2 + +#define LED_GREEN PIN_LED1 +#define LED_BLUE PIN_LED2 + +#define LED_STATE_ON 1 // State when LED is litted + +/* + * Buttons + */ + +#define PIN_BUTTON1 9 // Pin for button on E-ink button module or IO expansion +#define BUTTON_NEED_PULLUP +#define PIN_BUTTON2 12 +#define PIN_BUTTON3 24 +#define PIN_BUTTON4 25 + +/* + * Analog pins + */ +#define PIN_A0 (5) +#define PIN_A1 (31) +#define PIN_A2 (28) +#define PIN_A3 (29) +#define PIN_A4 (30) +#define PIN_A5 (31) +#define PIN_A6 (0xff) +#define PIN_A7 (0xff) + +static const uint8_t A0 = PIN_A0; +static const uint8_t A1 = PIN_A1; +static const uint8_t A2 = PIN_A2; +static const uint8_t A3 = PIN_A3; +static const uint8_t A4 = PIN_A4; +static const uint8_t A5 = PIN_A5; +static const uint8_t A6 = PIN_A6; +static const uint8_t A7 = PIN_A7; +#define ADC_RESOLUTION 14 + +// Other pins +#define PIN_AREF (2) +#define PIN_NFC1 (9) +#define PIN_NFC2 (10) + +static const uint8_t AREF = PIN_AREF; + +/* + * Serial interfaces + */ +#define PIN_SERIAL1_RX (15) +#define PIN_SERIAL1_TX (16) + +// Connected to Serial 2 +#define PIN_SERIAL2_RX (19) +#define PIN_SERIAL2_TX (20) + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO (45) +#define PIN_SPI_MOSI (44) +#define PIN_SPI_SCK (43) + +#define PIN_SPI1_MISO (29) // (0 + 29) +#define PIN_SPI1_MOSI (30) // (0 + 30) +#define PIN_SPI1_SCK (3) // (0 + 3) + +static const uint8_t SS = 42; +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +/* + * eink display pins + */ + +#define PIN_EINK_CS (0 + 26) +#define PIN_EINK_BUSY (0 + 4) +#define PIN_EINK_DC (0 + 17) +#define PIN_EINK_RES (-1) +#define PIN_EINK_SCLK (0 + 3) +#define PIN_EINK_MOSI (0 + 30) // also called SDI + +// #define USE_EINK + +/* + * Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (13) +#define PIN_WIRE_SCL (14) + +// QSPI Pins +#define PIN_QSPI_SCK 3 +#define PIN_QSPI_CS 26 +#define PIN_QSPI_IO0 30 +#define PIN_QSPI_IO1 29 +#define PIN_QSPI_IO2 28 +#define PIN_QSPI_IO3 2 + +/* @note RAK5005-O GPIO mapping to RAK4631 GPIO ports + RAK5005-O <-> nRF52840 + IO1 <-> P0.17 (Arduino GPIO number 17) + IO2 <-> P1.02 (Arduino GPIO number 34) + IO3 <-> P0.21 (Arduino GPIO number 21) + IO4 <-> P0.04 (Arduino GPIO number 4) + IO5 <-> P0.09 (Arduino GPIO number 9) + IO6 <-> P0.10 (Arduino GPIO number 10) + IO7 <-> P0.28 (Arduino GPIO number 28) + SW1 <-> P0.01 (Arduino GPIO number 1) + A0 <-> P0.04/AIN2 (Arduino Analog A2 + A1 <-> P0.31/AIN7 (Arduino Analog A7 + SPI_CS <-> P0.26 (Arduino GPIO number 26) + */ + +// RAK4630 LoRa module + +/* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ ) + +P1.10 NSS SPI NSS (Arduino GPIO number 42) +P1.11 SCK SPI CLK (Arduino GPIO number 43) +P1.12 MOSI SPI MOSI (Arduino GPIO number 44) +P1.13 MISO SPI MISO (Arduino GPIO number 45) +P1.14 BUSY BUSY signal (Arduino GPIO number 46) +P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47) +P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38) + +Important for successful SX1262 initialization: + +* Setup DIO2 to control the antenna switch +* Setup DIO3 to control the TCXO power supply +* Setup the SX1262 to use it's DCDC regulator and not the LDO +* RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the +control of the antenna switch + +SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG + +*/ + +#define DETECTION_SENSOR_EN 4 + +#define USE_SX1262 +#define SX126X_CS (42) +#define SX126X_DIO1 (47) +#define SX126X_BUSY (46) +#define SX126X_RESET (38) +// #define SX126X_TXEN (39) +// #define SX126X_RXEN (37) +#define SX126X_POWER_EN (37) +// DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3 +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +// Testing USB detection +#define NRF_APM + +// enables 3.3V periphery like GPS or IO Module +// Do not toggle this for GPS power savings +#define PIN_3V3_EN (34) + +// RAK1910 GPS module +// If using the wisblock GPS module and pluged into Port A on WisBlock base +// IO1 is hooked to PPS (pin 12 on header) = gpio 17 +// IO2 is hooked to GPS RESET = gpio 34, but it can not be used to this because IO2 is ALSO used to control 3V3_S power (1 is on). +// Therefore must be 1 to keep peripherals powered +// Power is on the controllable 3V3_S rail +// #define PIN_GPS_RESET (34) +// #define PIN_GPS_EN PIN_3V3_EN +#define PIN_GPS_PPS (17) // Pulse per second input from the GPS + +// On RAK2560 the GPS is be on a different UART +// #define GPS_RX_PIN PIN_SERIAL2_RX +// #define GPS_TX_PIN PIN_SERIAL2_TX +// #define PIN_GPS_EN PIN_3V3_EN +// Disable GPS +#define MESHTASTIC_EXCLUDE_GPS 1 +// Define pin to enable GPS toggle (set GPIO to LOW) via user button triple press + +// RAK12002 RTC Module +#define RV3028_RTC (uint8_t)0b1010010 + +// RAK18001 Buzzer in Slot C +// #define PIN_BUZZER 21 // IO3 is PWM2 +// NEW: set this via protobuf instead! + +// Battery +// The battery sense is hooked to pin A0 (5) +#define BATTERY_PIN PIN_A0 +// and has 12 bit resolution +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define BATTERY_SENSE_RESOLUTION 4096.0 +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER 1.73 + +#define HAS_RTC 1 + +#define HAS_ETHERNET 1 + +#define RAK_4631 1 + +#define HALF_UART_PIN PIN_SERIAL1_RX + +#if defined(GPS_RX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) +#error pin 15 collision + +#endif + +#if defined(GPS_TX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) +#error pin 15 collision +#endif + +#define PIN_ETHERNET_RESET 21 +#define PIN_ETHERNET_SS PIN_EINK_CS +#define ETH_SPI_PORT SPI1 +#define AQ_SET_PIN 10 + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif \ No newline at end of file diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h index e9f1a18651..2ce1b960aa 100644 --- a/variants/rak4631/variant.h +++ b/variants/rak4631/variant.h @@ -34,7 +34,8 @@ #include "WVariant.h" #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif // __cplusplus // Number of pins defined in PinDescription array @@ -55,9 +56,9 @@ extern "C" { #define LED_STATE_ON 1 // State when LED is litted -/* - * Buttons - */ + /* + * Buttons + */ #define PIN_BUTTON1 9 // Pin for button on E-ink button module or IO expansion #define BUTTON_NEED_PULLUP @@ -77,14 +78,14 @@ extern "C" { #define PIN_A6 (0xff) #define PIN_A7 (0xff) -static const uint8_t A0 = PIN_A0; -static const uint8_t A1 = PIN_A1; -static const uint8_t A2 = PIN_A2; -static const uint8_t A3 = PIN_A3; -static const uint8_t A4 = PIN_A4; -static const uint8_t A5 = PIN_A5; -static const uint8_t A6 = PIN_A6; -static const uint8_t A7 = PIN_A7; + static const uint8_t A0 = PIN_A0; + static const uint8_t A1 = PIN_A1; + static const uint8_t A2 = PIN_A2; + static const uint8_t A3 = PIN_A3; + static const uint8_t A4 = PIN_A4; + static const uint8_t A5 = PIN_A5; + static const uint8_t A6 = PIN_A6; + static const uint8_t A7 = PIN_A7; #define ADC_RESOLUTION 14 // Other pins @@ -92,7 +93,7 @@ static const uint8_t A7 = PIN_A7; #define PIN_NFC1 (9) #define PIN_NFC2 (10) -static const uint8_t AREF = PIN_AREF; + static const uint8_t AREF = PIN_AREF; /* * Serial interfaces @@ -100,9 +101,9 @@ static const uint8_t AREF = PIN_AREF; #define PIN_SERIAL1_RX (15) #define PIN_SERIAL1_TX (16) -// Connected to Serial 2 -#define PIN_SERIAL2_RX (19) -#define PIN_SERIAL2_TX (20) +// Connected to Jlink CDC +#define PIN_SERIAL2_RX (8) +#define PIN_SERIAL2_TX (6) /* * SPI Interfaces @@ -117,14 +118,14 @@ static const uint8_t AREF = PIN_AREF; #define PIN_SPI1_MOSI (30) // (0 + 30) #define PIN_SPI1_SCK (3) // (0 + 3) -static const uint8_t SS = 42; -static const uint8_t MOSI = PIN_SPI_MOSI; -static const uint8_t MISO = PIN_SPI_MISO; -static const uint8_t SCK = PIN_SPI_SCK; + static const uint8_t SS = 42; + static const uint8_t MOSI = PIN_SPI_MOSI; + static const uint8_t MISO = PIN_SPI_MISO; + static const uint8_t SCK = PIN_SPI_SCK; -/* - * eink display pins - */ + /* + * eink display pins + */ #define PIN_EINK_CS (0 + 26) #define PIN_EINK_BUSY (0 + 4) @@ -158,44 +159,44 @@ static const uint8_t SCK = PIN_SPI_SCK; #define EXTERNAL_FLASH_DEVICES IS25LP080D #define EXTERNAL_FLASH_USE_QSPI -/* @note RAK5005-O GPIO mapping to RAK4631 GPIO ports - RAK5005-O <-> nRF52840 - IO1 <-> P0.17 (Arduino GPIO number 17) - IO2 <-> P1.02 (Arduino GPIO number 34) - IO3 <-> P0.21 (Arduino GPIO number 21) - IO4 <-> P0.04 (Arduino GPIO number 4) - IO5 <-> P0.09 (Arduino GPIO number 9) - IO6 <-> P0.10 (Arduino GPIO number 10) - IO7 <-> P0.28 (Arduino GPIO number 28) - SW1 <-> P0.01 (Arduino GPIO number 1) - A0 <-> P0.04/AIN2 (Arduino Analog A2 - A1 <-> P0.31/AIN7 (Arduino Analog A7 - SPI_CS <-> P0.26 (Arduino GPIO number 26) - */ - -// RAK4630 LoRa module - -/* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ ) - -P1.10 NSS SPI NSS (Arduino GPIO number 42) -P1.11 SCK SPI CLK (Arduino GPIO number 43) -P1.12 MOSI SPI MOSI (Arduino GPIO number 44) -P1.13 MISO SPI MISO (Arduino GPIO number 45) -P1.14 BUSY BUSY signal (Arduino GPIO number 46) -P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47) -P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38) - -Important for successful SX1262 initialization: - -* Setup DIO2 to control the antenna switch -* Setup DIO3 to control the TCXO power supply -* Setup the SX1262 to use it's DCDC regulator and not the LDO -* RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the -control of the antenna switch - -SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG - -*/ + /* @note RAK5005-O GPIO mapping to RAK4631 GPIO ports + RAK5005-O <-> nRF52840 + IO1 <-> P0.17 (Arduino GPIO number 17) + IO2 <-> P1.02 (Arduino GPIO number 34) + IO3 <-> P0.21 (Arduino GPIO number 21) + IO4 <-> P0.04 (Arduino GPIO number 4) + IO5 <-> P0.09 (Arduino GPIO number 9) + IO6 <-> P0.10 (Arduino GPIO number 10) + IO7 <-> P0.28 (Arduino GPIO number 28) + SW1 <-> P0.01 (Arduino GPIO number 1) + A0 <-> P0.04/AIN2 (Arduino Analog A2 + A1 <-> P0.31/AIN7 (Arduino Analog A7 + SPI_CS <-> P0.26 (Arduino GPIO number 26) + */ + + // RAK4630 LoRa module + + /* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ ) + + P1.10 NSS SPI NSS (Arduino GPIO number 42) + P1.11 SCK SPI CLK (Arduino GPIO number 43) + P1.12 MOSI SPI MOSI (Arduino GPIO number 44) + P1.13 MISO SPI MISO (Arduino GPIO number 45) + P1.14 BUSY BUSY signal (Arduino GPIO number 46) + P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47) + P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38) + + Important for successful SX1262 initialization: + + * Setup DIO2 to control the antenna switch + * Setup DIO3 to control the TCXO power supply + * Setup the SX1262 to use it's DCDC regulator and not the LDO + * RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the + control of the antenna switch + + SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG + + */ #define DETECTION_SENSOR_EN 4 @@ -228,18 +229,9 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG // #define PIN_GPS_EN PIN_3V3_EN #define PIN_GPS_PPS (17) // Pulse per second input from the GPS -// On RAK2560 the GPS is be on a different UART -#ifdef HAS_RAKPROT -// #define GPS_RX_PIN PIN_SERIAL2_RX -// #define GPS_TX_PIN PIN_SERIAL2_TX -// #define PIN_GPS_EN PIN_3V3_EN -// Disable GPS -#define MESHTASTIC_EXCLUDE_GPS 1 -#else - // Enable GPS #define GPS_RX_PIN PIN_SERIAL1_RX #define GPS_TX_PIN PIN_SERIAL1_TX -#endif + // Define pin to enable GPS toggle (set GPIO to LOW) via user button triple press // RAK12002 RTC Module @@ -266,21 +258,6 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG #define RAK_4631 1 -#ifdef HAS_RAKPROT - -#define HALF_UART_PIN PIN_SERIAL1_RX - -#if defined(GPS_RX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) -#error pin 15 collision - -#endif - -#if defined(GPS_TX_PIN) && (GPS_RX_PIN == HALF_UART_PIN) -#error pin 15 collision -#endif - -#endif - #define PIN_ETHERNET_RESET 21 #define PIN_ETHERNET_SS PIN_EINK_CS #define ETH_SPI_PORT SPI1 From ceb884cf1827ac13205b1bc605c42cced4d5a95e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 16:29:45 +0200 Subject: [PATCH 046/211] trunk fmt --- src/Power.cpp | 36 ++--- src/power.h | 40 ++--- variants/rak2560/RAK9154Sensor.cpp | 248 ++++++++++++++--------------- variants/rak2560/create_uf2.py | 35 ++-- variants/rak4631/variant.h | 117 +++++++------- 5 files changed, 238 insertions(+), 238 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 18dbfebe4d..18a527cee7 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -351,19 +351,19 @@ class AnalogBatteryLevel : public HasBatteryLevel virtual bool isVbusIn() override { #ifdef EXT_PWR_DETECT - #ifdef HELTEC_CAPSULE_SENSOR_V3 - // if external powered that pin will be pulled down - if (digitalRead(EXT_PWR_DETECT) == LOW) { - return true; - } - // if it's not LOW - check the battery - #else - // if external powered that pin will be pulled up - if (digitalRead(EXT_PWR_DETECT) == HIGH) { - return true; - } - // if it's not HIGH - check the battery - #endif +#ifdef HELTEC_CAPSULE_SENSOR_V3 + // if external powered that pin will be pulled down + if (digitalRead(EXT_PWR_DETECT) == LOW) { + return true; + } + // if it's not LOW - check the battery +#else + // if external powered that pin will be pulled up + if (digitalRead(EXT_PWR_DETECT) == HIGH) { + return true; + } + // if it's not HIGH - check the battery +#endif #endif return getBattVoltage() > chargingVolt; } @@ -461,11 +461,11 @@ Power::Power() : OSThread("Power") bool Power::analogInit() { #ifdef EXT_PWR_DETECT - #ifdef HELTEC_CAPSULE_SENSOR_V3 - pinMode(EXT_PWR_DETECT, INPUT_PULLUP); - #else - pinMode(EXT_PWR_DETECT, INPUT); - #endif +#ifdef HELTEC_CAPSULE_SENSOR_V3 + pinMode(EXT_PWR_DETECT, INPUT_PULLUP); +#else + pinMode(EXT_PWR_DETECT, INPUT); +#endif #endif #ifdef EXT_CHRG_DETECT pinMode(EXT_CHRG_DETECT, ext_chrg_detect_mode); diff --git a/src/power.h b/src/power.h index c343a45ebd..b970dfeafd 100644 --- a/src/power.h +++ b/src/power.h @@ -1,8 +1,8 @@ #pragma once +#include "../variants/rak2560/RAK9154Sensor.h" #include "PowerStatus.h" #include "concurrency/OSThread.h" #include "configuration.h" -#include "../variants/rak2560/RAK9154Sensor.h" #ifdef ARCH_ESP32 #include @@ -56,31 +56,31 @@ extern RAK9154Sensor rak9154Sensor; class Power : private concurrency::OSThread { -public: - Observable newStatus; + public: + Observable newStatus; - Power(); + Power(); - void shutdown(); - void readPowerStatus(); - virtual bool setup(); - virtual int32_t runOnce() override; - void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; } - const uint16_t OCV[11] = {OCV_ARRAY}; + void shutdown(); + void readPowerStatus(); + virtual bool setup(); + virtual int32_t runOnce() override; + void setStatusHandler(meshtastic::PowerStatus *handler) { statusHandler = handler; } + const uint16_t OCV[11] = {OCV_ARRAY}; -protected: - meshtastic::PowerStatus *statusHandler; + protected: + meshtastic::PowerStatus *statusHandler; - /// Setup a xpowers chip axp192/axp2101, return true if found - bool axpChipInit(); - /// Setup a simple ADC input based battery sensor - bool analogInit(); + /// Setup a xpowers chip axp192/axp2101, return true if found + bool axpChipInit(); + /// Setup a simple ADC input based battery sensor + bool analogInit(); -private: - // open circuit voltage lookup table - uint8_t low_voltage_counter; + private: + // open circuit voltage lookup table + uint8_t low_voltage_counter; #ifdef DEBUG_HEAP - uint32_t lastheap; + uint32_t lastheap; #endif }; diff --git a/variants/rak2560/RAK9154Sensor.cpp b/variants/rak2560/RAK9154Sensor.cpp index 15a172c182..9f660947e8 100644 --- a/variants/rak2560/RAK9154Sensor.cpp +++ b/variants/rak2560/RAK9154Sensor.cpp @@ -4,8 +4,8 @@ #include "../modules/Telemetry/Sensor/TelemetrySensor.h" #include "configuration.h" -#include #include "concurrency/Periodic.h" +#include using namespace concurrency; @@ -27,165 +27,157 @@ static uint8_t provision = 0; static void onewire_evt(const uint8_t pid, const uint8_t sid, const SNHUBAPI_EVT_E eid, uint8_t *msg, uint16_t len) { - switch (eid) - { - case SNHUBAPI_EVT_RECV_REQ: - case SNHUBAPI_EVT_RECV_RSP: - break; - - case SNHUBAPI_EVT_QSEND: - mySerial.write(msg, len); - break; - - case SNHUBAPI_EVT_ADD_SID: - // LOG_INFO("+ADD:SID:[%02x]\r\n", msg[0]); - break; - - case SNHUBAPI_EVT_ADD_PID: - // LOG_INFO("+ADD:PID:[%02x]\r\n", msg[0]); + switch (eid) { + case SNHUBAPI_EVT_RECV_REQ: + case SNHUBAPI_EVT_RECV_RSP: + break; + + case SNHUBAPI_EVT_QSEND: + mySerial.write(msg, len); + break; + + case SNHUBAPI_EVT_ADD_SID: + // LOG_INFO("+ADD:SID:[%02x]\r\n", msg[0]); + break; + + case SNHUBAPI_EVT_ADD_PID: + // LOG_INFO("+ADD:PID:[%02x]\r\n", msg[0]); #ifdef BOOT_DATA_REQ - provision = msg[0]; + provision = msg[0]; #endif - break; - - case SNHUBAPI_EVT_GET_INTV: - break; - - case SNHUBAPI_EVT_GET_ENABLE: - break; - - case SNHUBAPI_EVT_SDATA_REQ: - - // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); - // for( uint16_t i=1; i 100) - { - dc_prec = 100; - } - break; - case RAK_IPSO_DC_CURRENT: - dc_cur = (msg[2] << 8) + msg[1]; - break; - case RAK_IPSO_DC_VOLTAGE: - dc_vol = (msg[2] << 8) + msg[1]; - dc_vol *= 10; - break; - default: - break; - } - - break; - case SNHUBAPI_EVT_REPORT: - - // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); - // for( uint16_t i=1; i 100) - { - dc_prec = 100; - } - break; - case RAK_IPSO_DC_CURRENT: - dc_cur = (msg[1] << 8) + msg[2]; - break; - case RAK_IPSO_DC_VOLTAGE: - dc_vol = (msg[1] << 8) + msg[2]; - dc_vol *= 10; - break; - default: - break; - } - - break; - - case SNHUBAPI_EVT_CHKSUM_ERR: - LOG_INFO("+ERR:CHKSUM\r\n"); - break; - - case SNHUBAPI_EVT_SEQ_ERR: - LOG_INFO("+ERR:SEQUCE\r\n"); - break; - - default: - break; - } + break; + + case SNHUBAPI_EVT_GET_INTV: + break; + + case SNHUBAPI_EVT_GET_ENABLE: + break; + + case SNHUBAPI_EVT_SDATA_REQ: + + // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); + // for( uint16_t i=1; i 100) { + dc_prec = 100; + } + break; + case RAK_IPSO_DC_CURRENT: + dc_cur = (msg[2] << 8) + msg[1]; + break; + case RAK_IPSO_DC_VOLTAGE: + dc_vol = (msg[2] << 8) + msg[1]; + dc_vol *= 10; + break; + default: + break; + } + + break; + case SNHUBAPI_EVT_REPORT: + + // LOG_INFO("+EVT:PID[%02x],IPSO[%02x]\r\n",pid,msg[0]); + // for( uint16_t i=1; i 100) { + dc_prec = 100; + } + break; + case RAK_IPSO_DC_CURRENT: + dc_cur = (msg[1] << 8) + msg[2]; + break; + case RAK_IPSO_DC_VOLTAGE: + dc_vol = (msg[1] << 8) + msg[2]; + dc_vol *= 10; + break; + default: + break; + } + + break; + + case SNHUBAPI_EVT_CHKSUM_ERR: + LOG_INFO("+ERR:CHKSUM\r\n"); + break; + + case SNHUBAPI_EVT_SEQ_ERR: + LOG_INFO("+ERR:SEQUCE\r\n"); + break; + + default: + break; + } } static int32_t onewireHandle() { - if (provision != 0) - { - RakSNHub_Protocl_API.get.data(provision); - provision = 0; - } - - while (mySerial.available()) - { - char a = mySerial.read(); - buff[bufflen++] = a; - delay(2); // continue data, timeout=2ms - } - - if (bufflen != 0) - { - RakSNHub_Protocl_API.process((uint8_t *)buff, bufflen); - bufflen = 0; - } - - return 50; + if (provision != 0) { + RakSNHub_Protocl_API.get.data(provision); + provision = 0; + } + + while (mySerial.available()) { + char a = mySerial.read(); + buff[bufflen++] = a; + delay(2); // continue data, timeout=2ms + } + + if (bufflen != 0) { + RakSNHub_Protocl_API.process((uint8_t *)buff, bufflen); + bufflen = 0; + } + + return 50; } int32_t RAK9154Sensor::runOnce() { - onewirePeriodic = new Periodic("onewireHandle", onewireHandle); + onewirePeriodic = new Periodic("onewireHandle", onewireHandle); - mySerial.begin(9600); + mySerial.begin(9600); - RakSNHub_Protocl_API.init(onewire_evt); + RakSNHub_Protocl_API.init(onewire_evt); - status = true; - initialized = true; - return 0; + status = true; + initialized = true; + return 0; } void RAK9154Sensor::setup() { - // Set up oversampling and filter initialization + // Set up oversampling and filter initialization } bool RAK9154Sensor::getMetrics(meshtastic_Telemetry *measurement) { - return true; + return true; } uint16_t RAK9154Sensor::getBusVoltageMv() { - return dc_vol; + return dc_vol; } int RAK9154Sensor::getBusBatteryPercent() { - return (int)dc_prec; + return (int)dc_prec; } bool RAK9154Sensor::isCharging() { - return (dc_cur > 0) ? true : false; + return (dc_cur > 0) ? true : false; } #endif // HAS_RAKPROT \ No newline at end of file diff --git a/variants/rak2560/create_uf2.py b/variants/rak2560/create_uf2.py index d14eaea029..cf6b11606b 100644 --- a/variants/rak2560/create_uf2.py +++ b/variants/rak2560/create_uf2.py @@ -1,22 +1,23 @@ -import sys import struct +import sys Import("env") + # Parse input and create UF2 file def create_uf2(source, target, env): # source_hex = target[0].get_abspath() source_hex = target[0].get_string(False) - source_hex = '.\\'+source_hex + source_hex = ".\\" + source_hex print("#########################################################") - print("Create UF2 from "+source_hex) + print("Create UF2 from " + source_hex) print("#########################################################") # print("Source: " + source_hex) target = source_hex.replace(".hex", "") target = target + ".uf2" # print("Target: " + target) - with open(source_hex, mode='rb') as f: + with open(source_hex, mode="rb") as f: inpbuf = f.read() outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8")) @@ -48,9 +49,17 @@ def encode(self, blockno, numblocks): flags = 0x0 if familyid: flags |= 0x2000 - hd = struct.pack(" nRF52840 - IO1 <-> P0.17 (Arduino GPIO number 17) - IO2 <-> P1.02 (Arduino GPIO number 34) - IO3 <-> P0.21 (Arduino GPIO number 21) - IO4 <-> P0.04 (Arduino GPIO number 4) - IO5 <-> P0.09 (Arduino GPIO number 9) - IO6 <-> P0.10 (Arduino GPIO number 10) - IO7 <-> P0.28 (Arduino GPIO number 28) - SW1 <-> P0.01 (Arduino GPIO number 1) - A0 <-> P0.04/AIN2 (Arduino Analog A2 - A1 <-> P0.31/AIN7 (Arduino Analog A7 - SPI_CS <-> P0.26 (Arduino GPIO number 26) - */ - - // RAK4630 LoRa module - - /* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ ) - - P1.10 NSS SPI NSS (Arduino GPIO number 42) - P1.11 SCK SPI CLK (Arduino GPIO number 43) - P1.12 MOSI SPI MOSI (Arduino GPIO number 44) - P1.13 MISO SPI MISO (Arduino GPIO number 45) - P1.14 BUSY BUSY signal (Arduino GPIO number 46) - P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47) - P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38) - - Important for successful SX1262 initialization: - - * Setup DIO2 to control the antenna switch - * Setup DIO3 to control the TCXO power supply - * Setup the SX1262 to use it's DCDC regulator and not the LDO - * RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the - control of the antenna switch - - SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG - - */ +/* @note RAK5005-O GPIO mapping to RAK4631 GPIO ports + RAK5005-O <-> nRF52840 + IO1 <-> P0.17 (Arduino GPIO number 17) + IO2 <-> P1.02 (Arduino GPIO number 34) + IO3 <-> P0.21 (Arduino GPIO number 21) + IO4 <-> P0.04 (Arduino GPIO number 4) + IO5 <-> P0.09 (Arduino GPIO number 9) + IO6 <-> P0.10 (Arduino GPIO number 10) + IO7 <-> P0.28 (Arduino GPIO number 28) + SW1 <-> P0.01 (Arduino GPIO number 1) + A0 <-> P0.04/AIN2 (Arduino Analog A2 + A1 <-> P0.31/AIN7 (Arduino Analog A7 + SPI_CS <-> P0.26 (Arduino GPIO number 26) + */ + +// RAK4630 LoRa module + +/* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ ) + +P1.10 NSS SPI NSS (Arduino GPIO number 42) +P1.11 SCK SPI CLK (Arduino GPIO number 43) +P1.12 MOSI SPI MOSI (Arduino GPIO number 44) +P1.13 MISO SPI MISO (Arduino GPIO number 45) +P1.14 BUSY BUSY signal (Arduino GPIO number 46) +P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47) +P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38) + +Important for successful SX1262 initialization: + +* Setup DIO2 to control the antenna switch +* Setup DIO3 to control the TCXO power supply +* Setup the SX1262 to use it's DCDC regulator and not the LDO +* RAK4630 schematics show GPIO P1.07 connected to the antenna switch, but it should not be initialized, as DIO2 will do the +control of the antenna switch + +SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG + +*/ #define DETECTION_SENSOR_EN 4 From 11c3ca541fbf8bc7fcbddd97ac2e408a2e16886e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 20:03:45 +0200 Subject: [PATCH 047/211] add proper RAK variant and change pathspec --- src/platform/nrf52/architecture.h | 2 ++ variants/rak2560/platformio.ini | 2 +- variants/rak2560/variant.h | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index 18a4d75f57..b66552a284 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -42,6 +42,8 @@ #define HW_VENDOR meshtastic_HardwareModel_NRF52840DK #elif defined(ARDUINO_NRF52840_PPR) #define HW_VENDOR meshtastic_HardwareModel_PPR +#elif defined(RAK2560) +#define HW_VENDOR meshtastic_HardwareModel_RAK2560 #elif defined(RAK4630) #define HW_VENDOR meshtastic_HardwareModel_RAK4631 #elif defined(TTGO_T_ECHO) diff --git a/variants/rak2560/platformio.ini b/variants/rak2560/platformio.ini index 71b235aaca..ff667aadfa 100644 --- a/variants/rak2560/platformio.ini +++ b/variants/rak2560/platformio.ini @@ -21,4 +21,4 @@ debug_tool = jlink ;upload_protocol = jlink extra_scripts = ${env.extra_scripts} - ../firmware/variants/rak2560/create_uf2.py \ No newline at end of file + ./variants/rak2560/create_uf2.py \ No newline at end of file diff --git a/variants/rak2560/variant.h b/variants/rak2560/variant.h index 7187c8a50b..0c1c9aed90 100644 --- a/variants/rak2560/variant.h +++ b/variants/rak2560/variant.h @@ -16,10 +16,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _VARIANT_RAK4630_ -#define _VARIANT_RAK4630_ +#ifndef _VARIANT_RAK2560_ +#define _VARIANT_RAK2560_ #define RAK4630 +#define RAK2560 /** Master clock frequency */ #define VARIANT_MCK (64000000ul) From 4fe281cf7fb07aec5e7a0f0e20e13651a721c3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 20:11:58 +0200 Subject: [PATCH 048/211] tryfix linter error --- variants/rak2560/create_uf2.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/variants/rak2560/create_uf2.py b/variants/rak2560/create_uf2.py index cf6b11606b..af78f3e097 100644 --- a/variants/rak2560/create_uf2.py +++ b/variants/rak2560/create_uf2.py @@ -1,7 +1,6 @@ import struct -import sys -Import("env") +Import("env") # noqa: F821 # Parse input and create UF2 file @@ -29,7 +28,7 @@ def create_uf2(source, target, env): # Add callback after .hex file was created -env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", create_uf2) +env.AddPostAction("$BUILD_DIR/${PROGNAME}.hex", create_uf2) # noqa: F821 # UF2 creation taken from uf2conv.py UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" @@ -97,7 +96,7 @@ def convert_from_hex_to_uf2(buf): break elif tp == 0: addr = upper | (rec[1] << 8) | rec[2] - if appstartaddr == None: + if appstartaddr is None: appstartaddr = addr i = 4 while i < len(rec) - 1: From aca0807acfbd286473fa66c603fd34b1bd0f7de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 20:41:23 +0200 Subject: [PATCH 049/211] more try more fix --- .trunk/configs/.bandit | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .trunk/configs/.bandit diff --git a/.trunk/configs/.bandit b/.trunk/configs/.bandit new file mode 100644 index 0000000000..d286ded897 --- /dev/null +++ b/.trunk/configs/.bandit @@ -0,0 +1,2 @@ +[bandit] +skips = B101 \ No newline at end of file From 369d3797200ba27cbb93929d05bb2368e913d8c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 21:08:34 +0200 Subject: [PATCH 050/211] CI is creating the uf2 file during build --- variants/rak2560/platformio.ini | 3 --- 1 file changed, 3 deletions(-) diff --git a/variants/rak2560/platformio.ini b/variants/rak2560/platformio.ini index ff667aadfa..96c1bfa92b 100644 --- a/variants/rak2560/platformio.ini +++ b/variants/rak2560/platformio.ini @@ -19,6 +19,3 @@ lib_deps = debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ;upload_protocol = jlink -extra_scripts = - ${env.extra_scripts} - ./variants/rak2560/create_uf2.py \ No newline at end of file From 7aea056ac0bdaf0e101202549796a749f6589273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 16 Jun 2024 22:43:16 +0200 Subject: [PATCH 051/211] exclude debs from release zip --- .github/workflows/main_matrix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 89b71acb84..25a0fbad22 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -254,7 +254,7 @@ jobs: chmod +x ./output/device-update.sh - name: Zip firmware - run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output + run: zip -j -9 -r ./firmware-${{ steps.version.outputs.version }}.zip ./output -x *.deb - uses: actions/download-artifact@v4 with: From ea69b999f9b602c7baba6508d63c27985872e18d Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 16 Jun 2024 13:59:38 -0700 Subject: [PATCH 052/211] Add rak4631_dap variant for debugging with NanoDAP debug probe device. --- variants/rak4631/platformio.ini | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 4870d4b68e..b9bf42655d 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -18,5 +18,33 @@ lib_deps = rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 https://github.com/meshtastic/RAK12034-BMX160.git#4821355fb10390ba8557dc43ca29a023bcfbb9d9 debug_tool = jlink + ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink \ No newline at end of file +; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds +;upload_protocol = jlink + +; Allows programming and debug via the RAK NanoDAP as the default debugger tool for the RAK4631 (it is only $10!) +; programming time is about the same as the bootloader version. +; For information on this see the meshtastic developers documentation for "Development on the NRF52" +[env:rak4631_dap] +extends = env:rak4631 +; pyocd pack --i nrf52840 +; eventually use platformio/tool-pyocd@^2.3600.0 instad +upload_protocol = custom +upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE + +; Only reprogram the board if the code has changed +debug_load_mode = modified +;debug_load_mode = manual +debug_tool = custom +; We manually pass in the elf file so that pyocd can reverse engineer FreeRTOS data (running threads, etc...) +debug_server = + pyocd + gdbserver + -t + nrf52840 + --elf + ${platformio.build_dir}/${this.__env__}/firmware.elf +; The following is not needed because it automatically tries do this +;debug_server_ready_pattern = -.*GDB server started on port \d+.* +;debug_port = localhost:3333 \ No newline at end of file From 163a732ddc5f904685091fd571328ee54a6f74b0 Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 16 Jun 2024 17:17:19 -0700 Subject: [PATCH 053/211] Turn off vscode cmake prompt - we don't use cmake on meshtastic (#4122) --- .vscode/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e86d31c7d1..07e198f0a7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,6 @@ "editor.defaultFormatter": "trunk.io", "trunk.enableWindows": true, "files.insertFinalNewline": false, - "files.trimFinalNewlines": false + "files.trimFinalNewlines": false, + "cmake.configureOnOpen": false } From 7afa8107ae5f8f5c8d9a9fba5173d1450c54b8b1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 16 Jun 2024 19:22:51 -0500 Subject: [PATCH 054/211] [create-pull-request] automated change (#4121) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index a26da1996d..268987418b 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 13 +build = 14 From 15250a566a3bce90a3449481f5a1d0ff513441de Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 16 Jun 2024 17:17:19 -0700 Subject: [PATCH 055/211] Turn off vscode cmake prompt - we don't use cmake on meshtastic (#4122) --- .vscode/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index e86d31c7d1..07e198f0a7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,6 @@ "editor.defaultFormatter": "trunk.io", "trunk.enableWindows": true, "files.insertFinalNewline": false, - "files.trimFinalNewlines": false + "files.trimFinalNewlines": false, + "cmake.configureOnOpen": false } From c593e7ce56a804b4526f4778e8c7c400c5511235 Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 16 Jun 2024 13:59:38 -0700 Subject: [PATCH 056/211] Add rak4631_dap variant for debugging with NanoDAP debug probe device. use board_level = extra --- variants/rak4631/platformio.ini | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 4870d4b68e..58a8eb5e46 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -18,5 +18,34 @@ lib_deps = rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 https://github.com/meshtastic/RAK12034-BMX160.git#4821355fb10390ba8557dc43ca29a023bcfbb9d9 debug_tool = jlink + ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink \ No newline at end of file +; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds +;upload_protocol = jlink + +; Allows programming and debug via the RAK NanoDAP as the default debugger tool for the RAK4631 (it is only $10!) +; programming time is about the same as the bootloader version. +; For information on this see the meshtastic developers documentation for "Development on the NRF52" +[env:rak4631_dap] +extends = env:rak4631 +board_level = extra +; pyocd pack --i nrf52840 +; eventually use platformio/tool-pyocd@^2.3600.0 instad +upload_protocol = custom +upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE + +; Only reprogram the board if the code has changed +debug_load_mode = modified +;debug_load_mode = manual +debug_tool = custom +; We manually pass in the elf file so that pyocd can reverse engineer FreeRTOS data (running threads, etc...) +debug_server = + pyocd + gdbserver + -t + nrf52840 + --elf + ${platformio.build_dir}/${this.__env__}/firmware.elf +; The following is not needed because it automatically tries do this +;debug_server_ready_pattern = -.*GDB server started on port \d+.* +;debug_port = localhost:3333 \ No newline at end of file From 12b8dc1918592baaaf72111d57cb98558eb24f3f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 17 Jun 2024 06:09:50 -0500 Subject: [PATCH 057/211] Revert "[create-pull-request] automated change (#4121)" (#4124) This reverts commit 7afa8107ae5f8f5c8d9a9fba5173d1450c54b8b1. --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 268987418b..a26da1996d 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 14 +build = 13 From 83f5ba0161725a597591c530ff509f2a5da27461 Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Mon, 17 Jun 2024 23:14:20 +1200 Subject: [PATCH 058/211] Update OLED ref (#4125) Upstream changes to the library temporarily reverted to restore debug info frame --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index a1beb8e7c5..83c4924c45 100644 --- a/platformio.ini +++ b/platformio.ini @@ -80,7 +80,7 @@ monitor_speed = 115200 lib_deps = jgromes/RadioLib@~6.6.0 - https://github.com/meshtastic/esp8266-oled-ssd1306.git#69ba98fa30e67b12d4577b121f210f3eb7049d6b ; ESP8266_SSD1306 + https://github.com/meshtastic/esp8266-oled-ssd1306.git#dcacac5d2c7942376bc17f7079cced6a73cb659f ; ESP8266_SSD1306 mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4 From 5d2f7d1962de15b811c34f34909e50f571b030da Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 07:17:36 -0500 Subject: [PATCH 059/211] [create-pull-request] automated change (#4127) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index a26da1996d..268987418b 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 13 +build = 14 From b6066a78c1983ffd3be6034115261916b2232dbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 17 Jun 2024 15:09:38 +0200 Subject: [PATCH 060/211] WIP --- src/detect/ScanI2CTwoWire.cpp | 11 ++++----- src/input/cardKbI2cImpl.cpp | 42 +++++++++++++++++++++++++++++++++-- src/input/kbI2cBase.cpp | 38 ------------------------------- 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index b045905098..86408b8d2e 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -148,7 +148,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) { concurrency::LockGuard guard((concurrency::Lock *)&lock); - LOG_DEBUG("Scanning for i2c devices on port %d\n", port); + LOG_DEBUG("Scanning for I2C devices on port %d\n", port); uint8_t err; @@ -172,10 +172,11 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) #endif for (addr.address = 1; addr.address < 127; addr.address++) { - if (asize != 0) - if (in_array(address, asize, addr.address)) + if (asize != 0) { + if (!in_array(address, asize, addr.address)) continue; - + LOG_DEBUG("Scanning address 0x%x\n", addr.address); + } i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO if (i2cBus->read() != -1) @@ -369,7 +370,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) LOG_INFO("Device found at address 0x%x was not able to be enumerated\n", addr.address); } } else if (err == 4) { - LOG_ERROR("Unknown error at address 0x%x\n", addr); + LOG_ERROR("Unknown error at address 0x%x\n", addr.address); } // Check if a type was found for the enumerated device - save, if so diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp index e000f36eb0..d10f1118fc 100644 --- a/src/input/cardKbI2cImpl.cpp +++ b/src/input/cardKbI2cImpl.cpp @@ -1,5 +1,7 @@ #include "cardKbI2cImpl.h" #include "InputBroker.h" +#include "detect/ScanI2C.h" +#include "detect/ScanI2CTwoWire.h" CardKbI2cImpl *cardKbI2cImpl; @@ -8,8 +10,44 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {} void CardKbI2cImpl::init() { if (cardkb_found.address == 0x00) { - disable(); - return; + LOG_DEBUG("Rescanning for I2C keyboard\n"); + uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; + uint8_t i2caddr_asize = 3; + auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); + +#if defined(I2C_SDA1) + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize); +#endif + i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize); + auto kb_info = i2cScanner->firstKeyboard(); + + if (kb_info.type != ScanI2C::DeviceType::NONE) { + cardkb_found = kb_info.address; + switch (kb_info.type) { + case ScanI2C::DeviceType::RAK14004: + kb_model = 0x02; + break; + case ScanI2C::DeviceType::CARDKB: + kb_model = 0x00; + break; + case ScanI2C::DeviceType::TDECKKB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x10; + break; + case ScanI2C::DeviceType::BBQ10KB: + // assign an arbitrary value to distinguish from other models + kb_model = 0x11; + break; + default: + // use this as default since it's also just zero + LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type); + kb_model = 0x00; + } + } + if (cardkb_found.address == 0x00) { + disable(); + return; + } } inputBroker->registerSource(this); diff --git a/src/input/kbI2cBase.cpp b/src/input/kbI2cBase.cpp index ce22edb93d..024b16b9ef 100644 --- a/src/input/kbI2cBase.cpp +++ b/src/input/kbI2cBase.cpp @@ -30,44 +30,6 @@ uint8_t read_from_14004(TwoWire *i2cBus, uint8_t reg, uint8_t *data, uint8_t len int32_t KbI2cBase::runOnce() { - if (cardkb_found.address == 0x00) { - // Input device is not detected. Rescan now. - auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); - uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; - uint8_t i2caddr_asize = 3; -#if defined(I2C_SDA1) - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE1, i2caddr_scan, i2caddr_asize); -#endif - i2cScanner->scanPort(ScanI2C::I2CPort::WIRE, i2caddr_scan, i2caddr_asize); - auto kb_info = i2cScanner->firstKeyboard(); - - if (kb_info.type != ScanI2C::DeviceType::NONE) { - cardkb_found = kb_info.address; - switch (kb_info.type) { - case ScanI2C::DeviceType::RAK14004: - kb_model = 0x02; - break; - case ScanI2C::DeviceType::CARDKB: - kb_model = 0x00; - break; - case ScanI2C::DeviceType::TDECKKB: - // assign an arbitrary value to distinguish from other models - kb_model = 0x10; - break; - case ScanI2C::DeviceType::BBQ10KB: - // assign an arbitrary value to distinguish from other models - kb_model = 0x11; - break; - default: - // use this as default since it's also just zero - LOG_WARN("kb_info.type is unknown(0x%02x), setting kb_model=0x00\n", kb_info.type); - kb_model = 0x00; - } - } - if (cardkb_found.address == 0x00) - return INT32_MAX; - } - if (!i2cBus) { switch (cardkb_found.port) { case ScanI2C::WIRE1: From 7a25e0b69ae571555605b9b9fd1a620a083889e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 17 Jun 2024 17:03:32 +0200 Subject: [PATCH 061/211] don't close the wire when we didn't find anything. We might rescan later. --- src/main.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6797c83759..3b009a179b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -421,10 +421,6 @@ void setup() auto i2cCount = i2cScanner->countDevices(); if (i2cCount == 0) { LOG_INFO("No I2C devices found\n"); - Wire.end(); -#ifdef I2C_SDA1 - Wire1.end(); -#endif } else { LOG_INFO("%i I2C devices found\n", i2cCount); } From 9d8a5221a97f13b64c5f3fe585eb8284c3224fef Mon Sep 17 00:00:00 2001 From: mverch67 Date: Mon, 17 Jun 2024 20:17:56 +0200 Subject: [PATCH 062/211] fix for MESHTASTIC_EXCLUDE_INPUTBROKER --- src/input/InputBroker.cpp | 2 +- src/input/cardKbI2cImpl.cpp | 1 + src/input/cardKbI2cImpl.h | 1 - src/modules/Modules.cpp | 1 + src/modules/Telemetry/Sensor/OPT3001Sensor.cpp | 11 ++++++++--- src/modules/Telemetry/Sensor/OPT3001Sensor.h | 9 ++++++++- 6 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/input/InputBroker.cpp b/src/input/InputBroker.cpp index b06c7400f5..cb73e32bad 100644 --- a/src/input/InputBroker.cpp +++ b/src/input/InputBroker.cpp @@ -1,7 +1,7 @@ #include "InputBroker.h" #include "PowerFSM.h" // needed for event trigger -InputBroker *inputBroker; +InputBroker *inputBroker = nullptr; InputBroker::InputBroker(){}; diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp index e000f36eb0..3cc70fa152 100644 --- a/src/input/cardKbI2cImpl.cpp +++ b/src/input/cardKbI2cImpl.cpp @@ -1,5 +1,6 @@ #include "cardKbI2cImpl.h" #include "InputBroker.h" +#include "main.h" CardKbI2cImpl *cardKbI2cImpl; diff --git a/src/input/cardKbI2cImpl.h b/src/input/cardKbI2cImpl.h index 1e6e87dfd3..811a0558c8 100644 --- a/src/input/cardKbI2cImpl.h +++ b/src/input/cardKbI2cImpl.h @@ -1,6 +1,5 @@ #pragma once #include "kbI2cBase.h" -#include "main.h" /** * @brief The idea behind this class to have static methods for the event handlers. diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 1b4bbc3b4a..ba1f5c11ea 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -42,6 +42,7 @@ #include "modules/Telemetry/DeviceTelemetry.h" #endif #if HAS_SENSOR && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR +#include "main.h" #include "modules/Telemetry/AirQualityTelemetry.h" #include "modules/Telemetry/EnvironmentTelemetry.h" #endif diff --git a/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp b/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp index 0d76e2897f..d0e38bf889 100644 --- a/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp +++ b/src/modules/Telemetry/Sensor/OPT3001Sensor.cpp @@ -1,7 +1,10 @@ -#include "OPT3001Sensor.h" +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + #include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "OPT3001Sensor.h" #include "TelemetrySensor.h" -#include "configuration.h" #include OPT3001Sensor::OPT3001Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_OPT3001, "OPT3001") {} @@ -41,4 +44,6 @@ bool OPT3001Sensor::getMetrics(meshtastic_Telemetry *measurement) LOG_INFO("Lux: %f\n", measurement->variant.environment_metrics.lux); return true; -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/OPT3001Sensor.h b/src/modules/Telemetry/Sensor/OPT3001Sensor.h index 4a8deef218..2ac149319a 100644 --- a/src/modules/Telemetry/Sensor/OPT3001Sensor.h +++ b/src/modules/Telemetry/Sensor/OPT3001Sensor.h @@ -1,3 +1,8 @@ +#pragma once +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + #include "../mesh/generated/meshtastic/telemetry.pb.h" #include "TelemetrySensor.h" #include @@ -14,4 +19,6 @@ class OPT3001Sensor : public TelemetrySensor OPT3001Sensor(); virtual int32_t runOnce() override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override; -}; \ No newline at end of file +}; + +#endif \ No newline at end of file From cd60ee80bdd0f6ab73f3ce9b26ce251819c8b9a4 Mon Sep 17 00:00:00 2001 From: mverch67 Date: Mon, 17 Jun 2024 21:17:25 +0200 Subject: [PATCH 063/211] fix wrong include file exclusion --- src/main.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6797c83759..57009ae46a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,13 +41,14 @@ #endif #if !MESHTASTIC_EXCLUDE_BLUETOOTH #include "nimble/NimbleBluetooth.h" -NimbleBluetooth *nimbleBluetooth; +NimbleBluetooth *nimbleBluetooth = nullptr; #endif #endif #ifdef ARCH_NRF52 #include "NRF52Bluetooth.h" -NRF52Bluetooth *nrf52Bluetooth; +NRF52Bluetooth *nrf52Bluetooth = nullptr; +; #endif #if HAS_WIFI @@ -94,23 +95,26 @@ NRF52Bluetooth *nrf52Bluetooth; #include "ButtonThread.h" #endif +#include "AmbientLightingThread.h" #include "PowerFSMThread.h" #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR #include "AccelerometerThread.h" -#include "AmbientLightingThread.h" -AccelerometerThread *accelerometerThread; +AccelerometerThread *accelerometerThread = nullptr; +; #endif #ifdef HAS_I2S #include "AudioThread.h" -AudioThread *audioThread; +AudioThread *audioThread = nullptr; +; #endif using namespace concurrency; // We always create a screen object, but we only init it if we find the hardware -graphics::Screen *screen; +graphics::Screen *screen = nullptr; +; // Global power status meshtastic::PowerStatus *powerStatus = new meshtastic::PowerStatus(); From 5e92136ed043cd7b647523ff593a982ce52f033c Mon Sep 17 00:00:00 2001 From: mverch67 Date: Mon, 17 Jun 2024 21:19:36 +0200 Subject: [PATCH 064/211] semi colon --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 57009ae46a..5ee895c9cb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -101,7 +101,6 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr; #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR #include "AccelerometerThread.h" AccelerometerThread *accelerometerThread = nullptr; -; #endif #ifdef HAS_I2S From e822525ce5d2252b8a9fa2eb562044be4fb1a948 Mon Sep 17 00:00:00 2001 From: mverch67 Date: Mon, 17 Jun 2024 21:23:07 +0200 Subject: [PATCH 065/211] more semi colons >_< --- src/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5ee895c9cb..a81f9206c9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -106,14 +106,12 @@ AccelerometerThread *accelerometerThread = nullptr; #ifdef HAS_I2S #include "AudioThread.h" AudioThread *audioThread = nullptr; -; #endif using namespace concurrency; // We always create a screen object, but we only init it if we find the hardware graphics::Screen *screen = nullptr; -; // Global power status meshtastic::PowerStatus *powerStatus = new meshtastic::PowerStatus(); From 5cebe4a0a7a80e540a3568ea45c99b8d7f47f3dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 17 Jun 2024 23:24:27 +0200 Subject: [PATCH 066/211] trunk fmt --- src/input/cardKbI2cImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp index af0958f947..4bc5ee4ead 100644 --- a/src/input/cardKbI2cImpl.cpp +++ b/src/input/cardKbI2cImpl.cpp @@ -1,7 +1,7 @@ #include "cardKbI2cImpl.h" #include "InputBroker.h" -#include "main.h" #include "detect/ScanI2CTwoWire.h" +#include "main.h" CardKbI2cImpl *cardKbI2cImpl; From 8fa0911ec8b4c4a48083c23f2fefdb4bcedc2dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Tue, 18 Jun 2024 22:59:47 +0200 Subject: [PATCH 067/211] speed up OLED Display by transferring bigger chunks (#4138) --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 83c4924c45..23ff53a102 100644 --- a/platformio.ini +++ b/platformio.ini @@ -80,7 +80,7 @@ monitor_speed = 115200 lib_deps = jgromes/RadioLib@~6.6.0 - https://github.com/meshtastic/esp8266-oled-ssd1306.git#dcacac5d2c7942376bc17f7079cced6a73cb659f ; ESP8266_SSD1306 + https://github.com/meshtastic/esp8266-oled-ssd1306.git#2b40affbe7f7dc63b6c00fa88e7e12ed1f8e1719 ; ESP8266_SSD1306 mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4 From 3c4fa2101f1d2739a555e4e41040960a1fe151bc Mon Sep 17 00:00:00 2001 From: caveman99 <25002+caveman99@users.noreply.github.com> Date: Wed, 19 Jun 2024 19:31:05 +0000 Subject: [PATCH 068/211] [create-pull-request] automated change --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 0c90a6814f..005d7231e5 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 0c90a6814fdd959a35bb6cf8e958e74d48e8a601 +Subproject commit 005d7231e59fdbadd74065230132b9ee176f2c87 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index f5fc8661af..0641158155 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -69,6 +69,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_WIO_WM1110 = 21, /* RAK2560 Solar base station based on RAK4630 */ meshtastic_HardwareModel_RAK2560 = 22, + /* Heltec HRU-3601: https://heltec.org/project/hru-3601/ */ + meshtastic_HardwareModel_HELTEC_HRU_3601 = 23, /* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */ meshtastic_HardwareModel_STATION_G1 = 25, /* RAK11310 (RP2040 + SX1262) */ From f79039fe579d9f373f73447b973940c673db0d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Wed, 19 Jun 2024 21:46:29 +0200 Subject: [PATCH 069/211] mask the rescan for portduino --- src/input/cardKbI2cImpl.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp index 4bc5ee4ead..1bff494751 100644 --- a/src/input/cardKbI2cImpl.cpp +++ b/src/input/cardKbI2cImpl.cpp @@ -9,6 +9,7 @@ CardKbI2cImpl::CardKbI2cImpl() : KbI2cBase("cardKB") {} void CardKbI2cImpl::init() { +#ifndef ARCH_PORTDUINO if (cardkb_found.address == 0x00) { LOG_DEBUG("Rescanning for I2C keyboard\n"); uint8_t i2caddr_scan[] = {CARDKB_ADDR, TDECK_KB_ADDR, BBQ10_KB_ADDR}; @@ -49,6 +50,11 @@ void CardKbI2cImpl::init() return; } } - +#else + if (cardkb_found.address == 0x00) { + disable(); + return; + } +#endif inputBroker->registerSource(this); } From c59cb3c29217d3e33197ee4f6ab78df70ed244ce Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 14:48:46 -0500 Subject: [PATCH 070/211] [create-pull-request] automated change (#4145) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/config.pb.h | 12 ++++++++---- src/mesh/generated/meshtastic/deviceonly.pb.h | 2 +- src/mesh/generated/meshtastic/localonly.pb.h | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/protobufs b/protobufs index 005d7231e5..1c3029f286 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 005d7231e59fdbadd74065230132b9ee176f2c87 +Subproject commit 1c3029f2868e5fc49809fd378f6c0c66aee0eaf4 diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 781538d11e..5a78f13668 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -511,6 +511,8 @@ typedef struct _meshtastic_Config_BluetoothConfig { meshtastic_Config_BluetoothConfig_PairingMode mode; /* Specified PIN for PairingMode.FixedPin */ uint32_t fixed_pin; + /* Enables device (serial style logs) over Bluetooth */ + bool device_logging_enabled; } meshtastic_Config_BluetoothConfig; typedef struct _meshtastic_Config { @@ -615,7 +617,7 @@ extern "C" { #define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} #define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} -#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} +#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} #define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}} #define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} #define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} @@ -624,7 +626,7 @@ extern "C" { #define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} #define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} -#define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0} +#define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} /* Field tags (for use in manual encoding/decoding) */ #define meshtastic_Config_DeviceConfig_role_tag 1 @@ -702,6 +704,7 @@ extern "C" { #define meshtastic_Config_BluetoothConfig_enabled_tag 1 #define meshtastic_Config_BluetoothConfig_mode_tag 2 #define meshtastic_Config_BluetoothConfig_fixed_pin_tag 3 +#define meshtastic_Config_BluetoothConfig_device_logging_enabled_tag 4 #define meshtastic_Config_device_tag 1 #define meshtastic_Config_position_tag 2 #define meshtastic_Config_power_tag 3 @@ -833,7 +836,8 @@ X(a, STATIC, SINGULAR, BOOL, ignore_mqtt, 104) #define meshtastic_Config_BluetoothConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ X(a, STATIC, SINGULAR, UENUM, mode, 2) \ -X(a, STATIC, SINGULAR, UINT32, fixed_pin, 3) +X(a, STATIC, SINGULAR, UINT32, fixed_pin, 3) \ +X(a, STATIC, SINGULAR, BOOL, device_logging_enabled, 4) #define meshtastic_Config_BluetoothConfig_CALLBACK NULL #define meshtastic_Config_BluetoothConfig_DEFAULT NULL @@ -860,7 +864,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size -#define meshtastic_Config_BluetoothConfig_size 10 +#define meshtastic_Config_BluetoothConfig_size 12 #define meshtastic_Config_DeviceConfig_size 100 #define meshtastic_Config_DisplayConfig_size 30 #define meshtastic_Config_LoRaConfig_size 80 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 0e3e28ba1b..5e291ee947 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -308,7 +308,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size #define meshtastic_ChannelFile_size 718 #define meshtastic_NodeInfoLite_size 166 -#define meshtastic_OEMStore_size 3370 +#define meshtastic_OEMStore_size 3372 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 160202d9bd..96a9976f03 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -181,7 +181,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size -#define meshtastic_LocalConfig_size 539 +#define meshtastic_LocalConfig_size 541 #define meshtastic_LocalModuleConfig_size 685 #ifdef __cplusplus From 3e9e0fdd49a0e52090d3136406eda5423cfa485f Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Tue, 18 Jun 2024 21:26:45 +0800 Subject: [PATCH 071/211] Remove TTGO_T_ECHO gating for PIN_POWER_EN Signed-off-by: Andrew Yong --- src/main.cpp | 2 +- src/sleep.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index b5707c8dea..ddb99568da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -242,7 +242,7 @@ void setup() initDeepSleep(); // power on peripherals -#if defined(TTGO_T_ECHO) && defined(PIN_POWER_EN) +#if defined(PIN_POWER_EN) pinMode(PIN_POWER_EN, OUTPUT); digitalWrite(PIN_POWER_EN, HIGH); // digitalWrite(PIN_POWER_EN1, INPUT); diff --git a/src/sleep.cpp b/src/sleep.cpp index 590610e6c8..c9c45bf67e 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -231,12 +231,10 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) nodeDB->saveToDisk(); -#ifdef TTGO_T_ECHO #ifdef PIN_POWER_EN pinMode(PIN_POWER_EN, INPUT); // power off peripherals // pinMode(PIN_POWER_EN1, INPUT_PULLDOWN); #endif -#endif #if HAS_GPS // Kill GPS power completely (even if previously we just had it in sleep mode) if (gps) From 1515c8e76300621e7240f5144bb74833f5ae4ae6 Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Tue, 18 Jun 2024 22:07:32 +0800 Subject: [PATCH 072/211] Add support for Heltec HRU-3601 Board is very similar to the Heltec HT-C62 based boards (Heltec HT62 variant) but due to wiring of SK6812 Neopixel LED to GPIO2 it becomes incompatible due to the regular HT-C62 dev board using a simple LED on the same GPIO. Depends on [protobufs#521](https://github.com/meshtastic/protobufs/pull/521). Works: * SK6812 Neopixel on GPIO2 * [GXCAS GXHTV3](https://www.lcsc.com/product-detail/Temperature-Sensors_GXCAS-GXHTV3C_C5441730.html) (SHTC3 compatible) Won't fix: * Battery reading - Board has no voltage divider on VBAT (board has a 1.25mm pitch "JST" style connector and a TP4054 charge IC) * Main thread LED - Board has no LED on simple GPIO Board schematic: [HRU3601.pdf](https://github.com/user-attachments/files/15874850/HRU3601.pdf) Signed-off-by: Andrew Yong --- src/platform/esp32/architecture.h | 2 ++ variants/heltec_hru_3601/pins_arduino.h | 25 ++++++++++++++++ variants/heltec_hru_3601/platformio.ini | 9 ++++++ variants/heltec_hru_3601/variant.h | 40 +++++++++++++++++++++++++ 4 files changed, 76 insertions(+) create mode 100644 variants/heltec_hru_3601/pins_arduino.h create mode 100644 variants/heltec_hru_3601/platformio.ini create mode 100644 variants/heltec_hru_3601/variant.h diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index c979d016cb..5565b64686 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -101,6 +101,8 @@ #define HW_VENDOR meshtastic_HardwareModel_STATION_G1 #elif defined(DR_DEV) #define HW_VENDOR meshtastic_HardwareModel_DR_DEV +#elif defined(HELTEC_HRU_3601) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_HRU_3601 #elif defined(HELTEC_V3) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_V3 #elif defined(HELTEC_WSL_V3) diff --git a/variants/heltec_hru_3601/pins_arduino.h b/variants/heltec_hru_3601/pins_arduino.h new file mode 100644 index 0000000000..625c57cedb --- /dev/null +++ b/variants/heltec_hru_3601/pins_arduino.h @@ -0,0 +1,25 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include +#include + +static const uint8_t TX = UART_TX; +static const uint8_t RX = UART_RX; + +static const uint8_t SDA = I2C_SDA; +static const uint8_t SCL = I2C_SCL; + +static const uint8_t SS = 8; +static const uint8_t MOSI = 7; +static const uint8_t MISO = 6; +static const uint8_t SCK = 10; + +static const uint8_t A0 = 0; +static const uint8_t A1 = 1; +static const uint8_t A2 = 2; +static const uint8_t A3 = 3; +static const uint8_t A4 = 4; +static const uint8_t A5 = 5; + +#endif /* Pins_Arduino_h */ diff --git a/variants/heltec_hru_3601/platformio.ini b/variants/heltec_hru_3601/platformio.ini new file mode 100644 index 0000000000..3668e72b7b --- /dev/null +++ b/variants/heltec_hru_3601/platformio.ini @@ -0,0 +1,9 @@ +[env:heltec-hru-3601] +extends = esp32c3_base +board = adafruit_qtpy_esp32c3 +build_flags = + ${esp32_base.build_flags} + -D HELTEC_HRU_3601 + -I variants/heltec_hru_3601 +lib_deps = ${esp32c3_base.lib_deps} + adafruit/Adafruit NeoPixel @ ^1.12.0 diff --git a/variants/heltec_hru_3601/variant.h b/variants/heltec_hru_3601/variant.h new file mode 100644 index 0000000000..31783ec359 --- /dev/null +++ b/variants/heltec_hru_3601/variant.h @@ -0,0 +1,40 @@ +#define BUTTON_PIN 9 + +#define HAS_SCREEN 0 +#define HAS_GPS 0 +#undef GPS_RX_PIN +#undef GPS_TX_PIN + +#define USE_SX1262 +#define LORA_SCK 10 +#define LORA_MISO 6 +#define LORA_MOSI 7 +#define LORA_CS 8 +#define LORA_DIO0 RADIOLIB_NC +#define LORA_RESET 5 +#define LORA_DIO1 3 +#define LORA_DIO2 RADIOLIB_NC +#define LORA_BUSY 4 +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_BUSY +#define SX126X_RESET LORA_RESET +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +// Vext_Ctrl pin controls 3.3V LDO (U2) which provides power to I2C peripheral +#define PIN_POWER_EN 1 + +// Board has I2C connected to UART0 pins, and no other hardware serial port +#define UART_TX -1 +#define UART_RX -1 + +// Board has I2C connected to U0RXD and U0TXD +#define I2C_SDA 21 +#define I2C_SCL 20 + +// Board has RGB LED on GPIO2 +#define HAS_NEOPIXEL // Enable the use of neopixels +#define NEOPIXEL_COUNT 1 // How many neopixels are connected +#define NEOPIXEL_DATA 2 // gpio pin used to send data to the neopixels +#define NEOPIXEL_TYPE (NEO_GRB + NEO_KHZ800) // type of neopixels in use From ecf5519b56cbfcd7fd7e70bba5fca99d4b726883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Thu, 20 Jun 2024 16:26:04 +0200 Subject: [PATCH 073/211] Moar LR1110 Targets --- boards/wio-sdk-wm1110.json | 6 +- boards/wio-t1000-s.json | 58 +++++++ boards/wio-tracker-wm1110.json | 6 +- src/ButtonThread.cpp | 8 +- src/SerialConsole.cpp | 4 + src/gps/GPS.cpp | 69 +++++++- src/gps/GPS.h | 2 +- .../Telemetry/EnvironmentTelemetry.cpp | 16 +- src/modules/Telemetry/Sensor/T1000xSensor.cpp | 116 +++++++++++++ src/modules/Telemetry/Sensor/T1000xSensor.h | 22 +++ src/platform/nrf52/BLEDfuScure.cpp | 144 ++++++++++++++++ src/platform/nrf52/BLEDfuSecure.h | 55 ++++++ src/platform/nrf52/NRF52Bluetooth.cpp | 14 +- .../platform/nrf52}/nrf52840_s140_v7.ld | 0 .../platform/nrf52}/softdevice/ble.h | 0 .../platform/nrf52}/softdevice/ble_err.h | 0 .../platform/nrf52}/softdevice/ble_gap.h | 0 .../platform/nrf52}/softdevice/ble_gatt.h | 0 .../platform/nrf52}/softdevice/ble_gattc.h | 0 .../platform/nrf52}/softdevice/ble_gatts.h | 0 .../platform/nrf52}/softdevice/ble_hci.h | 0 .../platform/nrf52}/softdevice/ble_l2cap.h | 0 .../platform/nrf52}/softdevice/ble_ranges.h | 0 .../platform/nrf52}/softdevice/ble_types.h | 0 .../nrf52}/softdevice/nrf52/nrf_mbr.h | 0 .../platform/nrf52}/softdevice/nrf_error.h | 0 .../nrf52}/softdevice/nrf_error_sdm.h | 0 .../nrf52}/softdevice/nrf_error_soc.h | 0 .../platform/nrf52}/softdevice/nrf_nvic.h | 0 .../platform/nrf52}/softdevice/nrf_sdm.h | 0 .../platform/nrf52}/softdevice/nrf_soc.h | 0 .../platform/nrf52}/softdevice/nrf_svc.h | 0 src/sleep.cpp | 18 ++ variants/wio-sdk-wm1110/platformio.ini | 6 +- variants/wio-t1000-s/platformio.ini | 15 ++ variants/wio-t1000-s/variant.cpp | 64 +++++++ variants/wio-t1000-s/variant.h | 161 ++++++++++++++++++ variants/wio-tracker-wm1110/platformio.ini | 6 +- variants/xiao_ble/platformio.ini | 4 +- 39 files changed, 772 insertions(+), 22 deletions(-) create mode 100644 boards/wio-t1000-s.json create mode 100644 src/modules/Telemetry/Sensor/T1000xSensor.cpp create mode 100644 src/modules/Telemetry/Sensor/T1000xSensor.h create mode 100644 src/platform/nrf52/BLEDfuScure.cpp create mode 100644 src/platform/nrf52/BLEDfuSecure.h rename {variants/xiao_ble => src/platform/nrf52}/nrf52840_s140_v7.ld (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_err.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_gap.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_gatt.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_gattc.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_gatts.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_hci.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_l2cap.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_ranges.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_types.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf52/nrf_mbr.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_error.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_error_sdm.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_error_soc.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_nvic.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_sdm.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_soc.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_svc.h (100%) create mode 100644 variants/wio-t1000-s/platformio.ini create mode 100644 variants/wio-t1000-s/variant.cpp create mode 100644 variants/wio-t1000-s/variant.h diff --git a/boards/wio-sdk-wm1110.json b/boards/wio-sdk-wm1110.json index 029c9c085e..04db525188 100644 --- a/boards/wio-sdk-wm1110.json +++ b/boards/wio-sdk-wm1110.json @@ -1,7 +1,7 @@ { "build": { "arduino": { - "ldscript": "nrf52840_s140_v6.ld" + "ldscript": "nrf52840_s140_v7.ld" }, "core": "nRF5", "cpu": "cortex-m4", @@ -22,8 +22,8 @@ "softdevice": { "sd_flags": "-DS140", "sd_name": "s140", - "sd_version": "6.1.1", - "sd_fwid": "0x00B6" + "sd_version": "7.3.0", + "sd_fwid": "0x0123" }, "bootloader": { "settings_addr": "0xFF000" diff --git a/boards/wio-t1000-s.json b/boards/wio-t1000-s.json new file mode 100644 index 0000000000..654a8f73dc --- /dev/null +++ b/boards/wio-t1000-s.json @@ -0,0 +1,58 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v7.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + ["0x239A", "0x8029"], + ["0x239A", "0x0029"], + ["0x239A", "0x002A"], + ["0x239A", "0x802A"] + ], + "usb_product": "WIO-BOOT", + "mcu": "nrf52840", + "variant": "Seeed_WIO_WM1110", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "7.3.0", + "sd_fwid": "0x0123" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": ["bluetooth"], + "debug": { + "jlink_device": "nRF52840_xxAA", + "svd_path": "nrf52840.svd" + }, + "frameworks": ["arduino"], + "name": "Seeed WIO WM1110", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "stlink", + "cmsis-dap", + "blackmagic" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://www.seeedstudio.com/LoRaWAN-Tracker-c-1938.html", + "vendor": "Seeed Studio" +} diff --git a/boards/wio-tracker-wm1110.json b/boards/wio-tracker-wm1110.json index 029c9c085e..b4ab8db118 100644 --- a/boards/wio-tracker-wm1110.json +++ b/boards/wio-tracker-wm1110.json @@ -1,7 +1,7 @@ { "build": { "arduino": { - "ldscript": "nrf52840_s140_v6.ld" + "ldscript": "nrf52840_s140_v7.ld" }, "core": "nRF5", "cpu": "cortex-m4", @@ -22,7 +22,7 @@ "softdevice": { "sd_flags": "-DS140", "sd_name": "s140", - "sd_version": "6.1.1", + "sd_version": "7.3.0", "sd_fwid": "0x00B6" }, "bootloader": { @@ -53,6 +53,6 @@ "require_upload_port": true, "wait_for_upload_port": true }, - "url": "https://www.seeedstudio.com/Wio-WM1110-Dev-Kit-p-5677.html", + "url": "https://www.seeedstudio.com/Wio-Tracker-1110-Dev-Board-p-5799.html", "vendor": "Seeed Studio" } diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index 4b3bb3fbc5..dc062fce46 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -43,6 +43,8 @@ ButtonThread::ButtonThread() : OSThread("Button") int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin #if defined(HELTEC_CAPSULE_SENSOR_V3) this->userButton = OneButton(pin, false, false); +#elif defined(BUTTON_ACTIVE_LOW) // change by WayenWeng + this->userButton = OneButton(pin, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP); #else this->userButton = OneButton(pin, true, true); #endif @@ -51,8 +53,12 @@ ButtonThread::ButtonThread() : OSThread("Button") #ifdef INPUT_PULLUP_SENSE // Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did +#ifdef BUTTON_SENSE_TYPE // change by WayenWeng + pinMode(pin, BUTTON_SENSE_TYPE); +#else pinMode(pin, INPUT_PULLUP_SENSE); #endif +#endif #if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) userButton.attachClick(userButtonPressed); @@ -322,4 +328,4 @@ void ButtonThread::userButtonPressedLongStop() if (millis() > c_holdOffTime) { btnEvent = BUTTON_EVENT_LONG_RELEASED; } -} +} \ No newline at end of file diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index 53ece0fa3d..cf6375585c 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -7,8 +7,12 @@ #ifdef RP2040_SLOW_CLOCK #define Port Serial2 #else +#ifdef USER_DEBUG_PORT // change by WayenWeng +#define Port USER_DEBUG_PORT +#else #define Port Serial #endif +#endif // Defaulting to the formerly removed phone_timeout_secs value of 15 minutes #define SERIAL_CONNECTION_TIMEOUT (15 * 60) * 1000UL diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 8d46742baa..40ee4ea032 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -390,8 +390,13 @@ bool GPS::setup() int msglen = 0; if (!didSerialInit) { +#ifdef GNSS_Airoha // change by WayenWeng + if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) { + probe(GPS_BAUDRATE); + LOG_INFO("GPS setting to %d.\n", GPS_BAUDRATE); + } +#else #if !defined(GPS_UC6580) - if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) { LOG_DEBUG("Probing for GPS at %d \n", serialSpeeds[speedSelect]); gnssModel = probe(serialSpeeds[speedSelect]); @@ -762,6 +767,7 @@ bool GPS::setup() LOG_INFO("GNSS module configuration saved!\n"); } } +#endif // !GNSS_Airoha didSerialInit = true; } @@ -869,6 +875,14 @@ void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) } gps->_serial_gps->write(gps->UBXscratch, msglen); } +#ifdef GNSS_Airoha // add by WayenWeng + else { + if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) { + // TODO, send rtc mode command + digitalWrite(PIN_GPS_EN, LOW); + } + } +#endif } else { if (gnssModel == GNSS_MODEL_UBLOX) { gps->_serial_gps->write(0xFF); @@ -908,6 +922,9 @@ void GPS::setAwake(bool wantAwake) if (wantAwake) { // Record the time we start looking for a lock lastWakeStartMsec = millis(); +#ifdef GNSS_Airoha + lastFixStartMsec = 0; +#endif } else { // Record by how much we missed our ideal target postion.gps_update_interval (for logging only) // Need to calculate this before we update lastSleepStartMsec, to make the new prediction @@ -1147,6 +1164,9 @@ GnssModel_t GPS::probe(int serialSpeed) _serial_gps->updateBaudRate(serialSpeed); } #endif +#ifdef GNSS_Airoha // add by WayenWeng + return GNSS_MODEL_UNKNOWN; +#else #ifdef GPS_DEBUG for (int i = 0; i < 20; i++) { getACK("$GP", 200); @@ -1293,6 +1313,7 @@ GnssModel_t GPS::probe(int serialSpeed) } return GNSS_MODEL_UBLOX; +#endif // !GNSS_Airoha } GPS *GPS::createGps() @@ -1460,6 +1481,25 @@ bool GPS::factoryReset() */ bool GPS::lookForTime() { +#ifdef GNSS_Airoha // add by WayenWeng + uint8_t fix = reader.fixQuality(); + uint32_t now = millis(); + if (fix > 0) { + if (lastFixStartMsec > 0) { + if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) { + return false; + } else { + clearBuffer(); + } + } else { + lastFixStartMsec = now; + return false; + } + } else { + return false; + } +#endif + auto ti = reader.time; auto d = reader.date; if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed @@ -1494,6 +1534,27 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s */ bool GPS::lookForLocation() { +#ifdef GNSS_Airoha // add by WayenWeng + if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) { + uint8_t fix = reader.fixQuality(); + uint32_t now = millis(); + if (fix > 0) { + if (lastFixStartMsec > 0) { + if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) { + return false; + } else { + clearBuffer(); + } + } else { + lastFixStartMsec = now; + return false; + } + } else { + return false; + } + } +#endif + // By default, TinyGPS++ does not parse GPGSA lines, which give us // the 2D/3D fixType (see NMEAGPS.h) // At a minimum, use the fixQuality indicator in GPGGA (FIXME?) @@ -1702,6 +1763,12 @@ void GPS::toggleGpsMode() if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED; LOG_DEBUG("Flag set to false for gps power. GpsMode: DISABLED\n"); +#ifdef GNSS_Airoha + if (powerState != GPS_ACTIVE) { + LOG_DEBUG("User power Off GPS\n"); + digitalWrite(PIN_GPS_EN, LOW); + } +#endif disable(); } else if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_DISABLED) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED; diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 55bd42d0fb..91548ce2cf 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -67,7 +67,7 @@ class GPS : private concurrency::OSThread uint8_t fixType = 0; // fix type from GPGSA #endif private: - uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0; + uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0; const int serialSpeeds[6] = {9600, 4800, 38400, 57600, 115200, 9600}; uint32_t rx_gpio = 0; diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index ff32020675..b1149799b5 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -33,6 +33,9 @@ #include "Sensor/SHT31Sensor.h" #include "Sensor/SHT4XSensor.h" #include "Sensor/SHTC3Sensor.h" +#ifdef T1000X_SENSOR_EN +#include "Sensor/T1000xSensor.h" +#endif #include "Sensor/TSL2591Sensor.h" #include "Sensor/VEML7700Sensor.h" @@ -53,6 +56,9 @@ AHT10Sensor aht10Sensor; MLX90632Sensor mlx90632Sensor; DFRobotLarkSensor dfRobotLarkSensor; NAU7802Sensor nau7802Sensor; +#ifdef T1000X_SENSOR_EN +T1000xSensor t1000xSensor; +#endif #define FAILED_STATE_SENSOR_READ_MULTIPLIER 10 #define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true @@ -91,6 +97,9 @@ int32_t EnvironmentTelemetryModule::runOnce() LOG_INFO("Environment Telemetry: Initializing\n"); // it's possible to have this module enabled, only for displaying values on the screen. // therefore, we should only enable the sensor loop if measurement is also enabled +#ifdef T1000X_SENSOR_EN // add by WayenWeng + result = t1000xSensor.runOnce(); +#else if (dfRobotLarkSensor.hasSensor()) result = dfRobotLarkSensor.runOnce(); if (bmp085Sensor.hasSensor()) @@ -129,6 +138,7 @@ int32_t EnvironmentTelemetryModule::runOnce() result = mlx90632Sensor.runOnce(); if (nau7802Sensor.hasSensor()) result = nau7802Sensor.runOnce(); +#endif } return result; } else { @@ -278,6 +288,10 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) m.time = getTime(); m.which_variant = meshtastic_Telemetry_environment_metrics_tag; +#ifdef T1000X_SENSOR_EN // add by WayenWeng + valid = valid && t1000xSensor.getMetrics(&m); + hasSensor = true; +#else if (dfRobotLarkSensor.hasSensor()) { valid = valid && dfRobotLarkSensor.getMetrics(&m); hasSensor = true; @@ -358,7 +372,7 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) m.variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity; } } - +#endif valid = valid && hasSensor; if (valid) { diff --git a/src/modules/Telemetry/Sensor/T1000xSensor.cpp b/src/modules/Telemetry/Sensor/T1000xSensor.cpp new file mode 100644 index 0000000000..e544d0dc5b --- /dev/null +++ b/src/modules/Telemetry/Sensor/T1000xSensor.cpp @@ -0,0 +1,116 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(T1000X_SENSOR_EN) + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "T1000xSensor.h" +#include "TelemetrySensor.h" +#include + +#define T1000X_SENSE_SAMPLES 15 +#define T1000X_LIGHT_REF_VCC 2400 + +#define HEATER_NTC_BX 4250 // thermistor coefficient B +#define HEATER_NTC_RP 8250 // ohm, series resistance to thermistor +#define HEATER_NTC_KA 273.15 // 25 Celsius at Kelvin +#define NTC_REF_VCC 3000 // mV, output voltage of LDO + +// ntc res table +uint32_t ntc_res2[136] = { + 113347, 107565, 102116, 96978, 92132, 87559, 83242, 79166, 75316, 71677, 68237, 64991, 61919, 59011, 56258, 53650, 51178, + 48835, 46613, 44506, 42506, 40600, 38791, 37073, 35442, 33892, 32420, 31020, 29689, 28423, 27219, 26076, 24988, 23951, + 22963, 22021, 21123, 20267, 19450, 18670, 17926, 17214, 16534, 15886, 15266, 14674, 14108, 13566, 13049, 12554, 12081, + 11628, 11195, 10780, 10382, 10000, 9634, 9284, 8947, 8624, 8315, 8018, 7734, 7461, 7199, 6948, 6707, 6475, + 6253, 6039, 5834, 5636, 5445, 5262, 5086, 4917, 4754, 4597, 4446, 4301, 4161, 4026, 3896, 3771, 3651, + 3535, 3423, 3315, 3211, 3111, 3014, 2922, 2834, 2748, 2666, 2586, 2509, 2435, 2364, 2294, 2228, 2163, + 2100, 2040, 1981, 1925, 1870, 1817, 1766, 1716, 1669, 1622, 1578, 1535, 1493, 1452, 1413, 1375, 1338, + 1303, 1268, 1234, 1202, 1170, 1139, 1110, 1081, 1053, 1026, 999, 974, 949, 925, 902, 880, 858, +}; + +int8_t ntc_temp2[136] = { + -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, + -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, +}; + +T1000xSensor::T1000xSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SENSOR_UNSET, "T1000x") {} + +int32_t T1000xSensor::runOnce() +{ + LOG_INFO("Init sensor: %s\n", sensorName); + if (!hasSensor()) { + return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + } + return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; +} + +void T1000xSensor::setup() +{ + // Set up oversampling and filter initialization +} + +float T1000xSensor::getLux() +{ + uint32_t lux_vot = 0; + float lux_level = 0; + + for (uint32_t i = 0; i < T1000X_SENSE_SAMPLES; i++) { + lux_vot += analogRead(T1000X_LUX_PIN); + } + lux_vot = lux_vot / T1000X_SENSE_SAMPLES; + lux_vot = ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * lux_vot; + + if (lux_vot <= 80) + lux_level = 0; + else if (lux_vot >= 2480) + lux_level = 100; + else + lux_level = 100 * (lux_vot - 80) / T1000X_LIGHT_REF_VCC; + + return lux_level; +} + +float T1000xSensor::getTemp() +{ + uint32_t vcc_vot = 0, ntc_vot = 0; + + uint8_t u8i = 0; + float Vout = 0, Rt = 0, temp = 0; + float Temp = 0; + + for (uint32_t i = 0; i < T1000X_SENSE_SAMPLES; i++) { + vcc_vot += analogRead(T1000X_VCC_PIN); + } + vcc_vot = vcc_vot / T1000X_SENSE_SAMPLES; + vcc_vot = 2 * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * vcc_vot; + + for (uint32_t i = 0; i < T1000X_SENSE_SAMPLES; i++) { + ntc_vot += analogRead(T1000X_NTC_PIN); + } + ntc_vot = ntc_vot / T1000X_SENSE_SAMPLES; + ntc_vot = ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * ntc_vot; + + Vout = ntc_vot; + Rt = (HEATER_NTC_RP * vcc_vot) / Vout - HEATER_NTC_RP; + for (u8i = 0; u8i < 136; u8i++) { + if (Rt >= ntc_res2[u8i]) { + break; + } + } + temp = ntc_temp2[u8i - 1] + 1 * (ntc_res2[u8i - 1] - Rt) / (float)(ntc_res2[u8i - 1] - ntc_res2[u8i]); + Temp = (temp * 100 + 5) / 100; // half adjust + + return Temp; +} + +bool T1000xSensor::getMetrics(meshtastic_Telemetry *measurement) +{ + measurement->variant.environment_metrics.temperature = getTemp(); + measurement->variant.environment_metrics.lux = getLux(); + return true; +} + +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/T1000xSensor.h b/src/modules/Telemetry/Sensor/T1000xSensor.h new file mode 100644 index 0000000000..127d2630c5 --- /dev/null +++ b/src/modules/Telemetry/Sensor/T1000xSensor.h @@ -0,0 +1,22 @@ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" + +class T1000xSensor : public TelemetrySensor +{ + private: + protected: + virtual void setup() override; + + public: + T1000xSensor(); + virtual int32_t runOnce() override; + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; + virtual float getLux(); + virtual float getTemp(); +}; + +#endif \ No newline at end of file diff --git a/src/platform/nrf52/BLEDfuScure.cpp b/src/platform/nrf52/BLEDfuScure.cpp new file mode 100644 index 0000000000..8f7a327c4f --- /dev/null +++ b/src/platform/nrf52/BLEDfuScure.cpp @@ -0,0 +1,144 @@ +/**************************************************************************/ +/*! + @file BLEDfu.cpp + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ + +#include "BLEDfuSecure.h" +#include "bluefruit.h" + +#define DFU_REV_APPMODE 0x0001 + +const uint16_t UUID16_SVC_DFU_OTA = 0xFE59; + +const uint8_t UUID128_CHR_DFU_CONTROL[16] = {0x50, 0xEA, 0xDA, 0x30, 0x88, 0x83, 0xB8, 0x9F, + 0x60, 0x4F, 0x15, 0xF3, 0x03, 0x00, 0xC9, 0x8E}; + +extern "C" void bootloader_util_app_start(uint32_t start_addr); + +static uint16_t crc16(const uint8_t *data_p, uint8_t length) +{ + uint8_t x; + uint16_t crc = 0xFFFF; + + while (length--) { + x = crc >> 8 ^ *data_p++; + x ^= x >> 4; + crc = (crc << 8) ^ ((uint16_t)(x << 12)) ^ ((uint16_t)(x << 5)) ^ ((uint16_t)x); + } + return crc; +} + +static void bledfu_control_wr_authorize_cb(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_write_t *request) +{ + if ((request->handle == chr->handles().value_handle) && (request->op != BLE_GATTS_OP_PREP_WRITE_REQ) && + (request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) && (request->op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)) { + BLEConnection *conn = Bluefruit.Connection(conn_hdl); + + ble_gatts_rw_authorize_reply_params_t reply = {.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE}; + + if (!chr->indicateEnabled(conn_hdl)) { + reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR; + sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply); + return; + } + + reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply); + + enum { START_DFU = 1 }; + if (request->data[0] == START_DFU) { + // Peer data information so that bootloader could re-connect after reboot + typedef struct { + ble_gap_addr_t addr; + ble_gap_irk_t irk; + ble_gap_enc_key_t enc_key; + uint8_t sys_attr[8]; + uint16_t crc16; + } peer_data_t; + + VERIFY_STATIC(offsetof(peer_data_t, crc16) == 60); + + /* Save Peer data + * Peer data address is defined in bootloader linker @0x20007F80 + * - If bonded : save Security information + * - Otherwise : save Address for direct advertising + * + * TODO may force bonded only for security reason + */ + peer_data_t *peer_data = (peer_data_t *)(0x20007F80UL); + varclr(peer_data); + + // Get CCCD + uint16_t sysattr_len = sizeof(peer_data->sys_attr); + sd_ble_gatts_sys_attr_get(conn_hdl, peer_data->sys_attr, &sysattr_len, BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS); + + // Get Bond Data or using Address if not bonded + peer_data->addr = conn->getPeerAddr(); + + if (conn->secured()) { + bond_keys_t bkeys; + if (conn->loadBondKey(&bkeys)) { + peer_data->addr = bkeys.peer_id.id_addr_info; + peer_data->irk = bkeys.peer_id.id_info; + peer_data->enc_key = bkeys.own_enc; + } + } + + // Calculate crc + peer_data->crc16 = crc16((uint8_t *)peer_data, offsetof(peer_data_t, crc16)); + + // Initiate DFU Sequence and reboot into DFU OTA mode + Bluefruit.Advertising.restartOnDisconnect(false); + conn->disconnect(); + + NRF_POWER->GPREGRET = 0xB1; + NVIC_SystemReset(); + } + } +} + +BLEDfuSecure::BLEDfuSecure(void) : BLEService(UUID16_SVC_DFU_OTA), _chr_control(UUID128_CHR_DFU_CONTROL) {} + +err_t BLEDfuSecure::begin(void) +{ + // Invoke base class begin() + VERIFY_STATUS(BLEService::begin()); + + _chr_control.setProperties(CHR_PROPS_WRITE | CHR_PROPS_INDICATE); + _chr_control.setMaxLen(23); + _chr_control.setWriteAuthorizeCallback(bledfu_control_wr_authorize_cb); + VERIFY_STATUS(_chr_control.begin()); + + return ERROR_NONE; +} diff --git a/src/platform/nrf52/BLEDfuSecure.h b/src/platform/nrf52/BLEDfuSecure.h new file mode 100644 index 0000000000..bd5d910e8f --- /dev/null +++ b/src/platform/nrf52/BLEDfuSecure.h @@ -0,0 +1,55 @@ +/**************************************************************************/ +/*! + @file BLEDfu.h + @author hathach (tinyusb.org) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2018, Adafruit Industries (adafruit.com) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/**************************************************************************/ +#ifndef BLEDFUSECURE_H_ +#define BLEDFUSECURE_H_ + +#include "bluefruit_common.h" + +#include "BLECharacteristic.h" +#include "BLEService.h" + +class BLEDfuSecure : public BLEService +{ + protected: + BLECharacteristic _chr_control; + + public: + BLEDfuSecure(void); + + virtual err_t begin(void); +}; + +#endif /* BLEDFUSECURE_H_ */ diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 4c25f38ea3..8b817f51b4 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -1,4 +1,5 @@ #include "NRF52Bluetooth.h" +#include "BLEDfuSecure.h" #include "BluetoothCommon.h" #include "PowerFSM.h" #include "configuration.h" @@ -13,9 +14,10 @@ static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16)); static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16)); static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16)); -static BLEDis bledis; // DIS (Device Information Service) helper class instance -static BLEBas blebas; // BAS (Battery Service) helper class instance -static BLEDfu bledfu; // DFU software update helper service +static BLEDis bledis; // DIS (Device Information Service) helper class instance +static BLEBas blebas; // BAS (Battery Service) helper class instance +static BLEDfu bledfu; // DFU software update helper service +static BLEDfuSecure bledfusecure; // DFU software update helper service // This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in // process at once @@ -273,9 +275,13 @@ void NRF52Bluetooth::setup() Bluefruit.Periph.setConnectCallback(onConnect); Bluefruit.Periph.setDisconnectCallback(onDisconnect); +#ifndef BLE_DFU_SECURE bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); bledfu.begin(); // Install the DFU helper - +#else + bledfusecure.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); // add by WayenWeng + bledfusecure.begin(); // Install the DFU helper +#endif // Configure and Start the Device Information Service LOG_INFO("Configuring the Device Information Service\n"); bledis.setModel(optstr(HW_VERSION)); diff --git a/variants/xiao_ble/nrf52840_s140_v7.ld b/src/platform/nrf52/nrf52840_s140_v7.ld similarity index 100% rename from variants/xiao_ble/nrf52840_s140_v7.ld rename to src/platform/nrf52/nrf52840_s140_v7.ld diff --git a/variants/xiao_ble/softdevice/ble.h b/src/platform/nrf52/softdevice/ble.h similarity index 100% rename from variants/xiao_ble/softdevice/ble.h rename to src/platform/nrf52/softdevice/ble.h diff --git a/variants/xiao_ble/softdevice/ble_err.h b/src/platform/nrf52/softdevice/ble_err.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_err.h rename to src/platform/nrf52/softdevice/ble_err.h diff --git a/variants/xiao_ble/softdevice/ble_gap.h b/src/platform/nrf52/softdevice/ble_gap.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_gap.h rename to src/platform/nrf52/softdevice/ble_gap.h diff --git a/variants/xiao_ble/softdevice/ble_gatt.h b/src/platform/nrf52/softdevice/ble_gatt.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_gatt.h rename to src/platform/nrf52/softdevice/ble_gatt.h diff --git a/variants/xiao_ble/softdevice/ble_gattc.h b/src/platform/nrf52/softdevice/ble_gattc.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_gattc.h rename to src/platform/nrf52/softdevice/ble_gattc.h diff --git a/variants/xiao_ble/softdevice/ble_gatts.h b/src/platform/nrf52/softdevice/ble_gatts.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_gatts.h rename to src/platform/nrf52/softdevice/ble_gatts.h diff --git a/variants/xiao_ble/softdevice/ble_hci.h b/src/platform/nrf52/softdevice/ble_hci.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_hci.h rename to src/platform/nrf52/softdevice/ble_hci.h diff --git a/variants/xiao_ble/softdevice/ble_l2cap.h b/src/platform/nrf52/softdevice/ble_l2cap.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_l2cap.h rename to src/platform/nrf52/softdevice/ble_l2cap.h diff --git a/variants/xiao_ble/softdevice/ble_ranges.h b/src/platform/nrf52/softdevice/ble_ranges.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_ranges.h rename to src/platform/nrf52/softdevice/ble_ranges.h diff --git a/variants/xiao_ble/softdevice/ble_types.h b/src/platform/nrf52/softdevice/ble_types.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_types.h rename to src/platform/nrf52/softdevice/ble_types.h diff --git a/variants/xiao_ble/softdevice/nrf52/nrf_mbr.h b/src/platform/nrf52/softdevice/nrf52/nrf_mbr.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf52/nrf_mbr.h rename to src/platform/nrf52/softdevice/nrf52/nrf_mbr.h diff --git a/variants/xiao_ble/softdevice/nrf_error.h b/src/platform/nrf52/softdevice/nrf_error.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_error.h rename to src/platform/nrf52/softdevice/nrf_error.h diff --git a/variants/xiao_ble/softdevice/nrf_error_sdm.h b/src/platform/nrf52/softdevice/nrf_error_sdm.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_error_sdm.h rename to src/platform/nrf52/softdevice/nrf_error_sdm.h diff --git a/variants/xiao_ble/softdevice/nrf_error_soc.h b/src/platform/nrf52/softdevice/nrf_error_soc.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_error_soc.h rename to src/platform/nrf52/softdevice/nrf_error_soc.h diff --git a/variants/xiao_ble/softdevice/nrf_nvic.h b/src/platform/nrf52/softdevice/nrf_nvic.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_nvic.h rename to src/platform/nrf52/softdevice/nrf_nvic.h diff --git a/variants/xiao_ble/softdevice/nrf_sdm.h b/src/platform/nrf52/softdevice/nrf_sdm.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_sdm.h rename to src/platform/nrf52/softdevice/nrf_sdm.h diff --git a/variants/xiao_ble/softdevice/nrf_soc.h b/src/platform/nrf52/softdevice/nrf_soc.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_soc.h rename to src/platform/nrf52/softdevice/nrf_soc.h diff --git a/variants/xiao_ble/softdevice/nrf_svc.h b/src/platform/nrf52/softdevice/nrf_svc.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_svc.h rename to src/platform/nrf52/softdevice/nrf_svc.h diff --git a/src/sleep.cpp b/src/sleep.cpp index 590610e6c8..0e70453238 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -242,6 +242,24 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) if (gps) gps->setGPSPower(false, false, 0); #endif + +#ifdef GNSS_Airoha // add by WayenWeng + digitalWrite(GPS_VRTC_EN, LOW); + digitalWrite(PIN_GPS_RESET, LOW); + digitalWrite(GPS_SLEEP_INT, LOW); + digitalWrite(GPS_RTC_INT, LOW); + pinMode(GPS_RESETB_OUT, OUTPUT); + digitalWrite(GPS_RESETB_OUT, LOW); +#endif + +#ifdef BUZZER_EN_PIN // add by WayenWeng + digitalWrite(BUZZER_EN_PIN, LOW); +#endif + +#ifdef PIN_3V3_EN // add by WayenWeng + digitalWrite(PIN_3V3_EN, LOW); +#endif + setLed(false); #ifdef RESET_OLED diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini index 8b1433dd1f..9d9ea4c29f 100644 --- a/variants/wio-sdk-wm1110/platformio.ini +++ b/variants/wio-sdk-wm1110/platformio.ini @@ -1,12 +1,12 @@ -; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmware for 5005/19003, with or without OLED RAK 1921 +; The black Wio-WM1110 Dev Kit with sensors and the WM1110 module [env:wio-sdk-wm1110] extends = nrf52840_base board = wio-sdk-wm1110 board_level = extra -; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e -build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -DWIO_WM1110 +build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-sdk-wm1110> lib_deps = ${nrf52840_base.lib_deps} diff --git a/variants/wio-t1000-s/platformio.ini b/variants/wio-t1000-s/platformio.ini new file mode 100644 index 0000000000..cb1cf86f70 --- /dev/null +++ b/variants/wio-t1000-s/platformio.ini @@ -0,0 +1,15 @@ +; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmware for 5005/19003, with or without OLED RAK 1921 +[env:wio-t1000-s] +extends = nrf52840_base +board = wio-t1000-s +board_level = extra +build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-t1000-s -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 + -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" + -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-t1000-s> +lib_deps = + ${nrf52840_base.lib_deps} +debug_tool = jlink +; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) +upload_protocol = jlink \ No newline at end of file diff --git a/variants/wio-t1000-s/variant.cpp b/variants/wio-t1000-s/variant.cpp new file mode 100644 index 0000000000..85e0c44f39 --- /dev/null +++ b/variants/wio-t1000-s/variant.cpp @@ -0,0 +1,64 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + pinMode(PIN_3V3_EN, OUTPUT); + digitalWrite(PIN_3V3_EN, HIGH); + + pinMode(PIN_3V3_ACC_EN, OUTPUT); + digitalWrite(PIN_3V3_ACC_EN, LOW); + + pinMode(BUZZER_EN_PIN, OUTPUT); + digitalWrite(BUZZER_EN_PIN, HIGH); + + pinMode(PIN_GPS_EN, OUTPUT); + digitalWrite(PIN_GPS_EN, LOW); + + pinMode(GPS_VRTC_EN, OUTPUT); + digitalWrite(GPS_VRTC_EN, HIGH); + + pinMode(PIN_GPS_RESET, OUTPUT); + digitalWrite(PIN_GPS_RESET, LOW); + + pinMode(GPS_SLEEP_INT, OUTPUT); + digitalWrite(GPS_SLEEP_INT, HIGH); + + pinMode(GPS_RTC_INT, OUTPUT); + digitalWrite(GPS_RTC_INT, LOW); + + pinMode(GPS_RESETB_OUT, INPUT); +} \ No newline at end of file diff --git a/variants/wio-t1000-s/variant.h b/variants/wio-t1000-s/variant.h new file mode 100644 index 0000000000..86bd34f620 --- /dev/null +++ b/variants/wio-t1000-s/variant.h @@ -0,0 +1,161 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_WIO_SDK_WM1110_ +#define _VARIANT_WIO_SDK_WM1110_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF +// define USE_LFRC // Board uses RC for LF + +#define BLE_DFU_SECURE // we use the 7.x softdevice signing keys + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (6) +#define NUM_ANALOG_OUTPUTS (0) + +#define PIN_3V3_EN (32 + 6) // P1.6, Power to Sensors +#define PIN_3V3_ACC_EN (32 + 7) // P1.7, Power to Acc + +#define PIN_LED1 (0 + 24) // P0.24 +#define LED_PIN PIN_LED1 +#define LED_BUILTIN -1 +#define LED_BLUE -1 // Actually green +#define LED_STATE_ON 1 // State when LED is lit + +#define BUTTON_PIN (0 + 6) // P0.6 +#define BUTTON_ACTIVE_LOW false +#define BUTTON_ACTIVE_PULLUP false +#define BUTTON_SENSE_TYPE INPUT_SENSE_HIGH + +#define HAS_WIRE 0 + +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (0 + 26) // P0.26 +#define PIN_WIRE_SCL (0 + 27) // P0.27 + +/* + * Serial interfaces + */ +#define PIN_SERIAL1_RX (0 + 14) // P0.14 +#define PIN_SERIAL1_TX (0 + 13) // P0.13 + +#define PIN_SERIAL2_RX (0 + 17) // P0.17 +#define PIN_SERIAL2_TX (0 + 16) // P0.16 + +#define USER_DEBUG_PORT Serial2 + +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (32 + 8) // P1.08 +#define PIN_SPI_MOSI (32 + 9) // P1.09 +#define PIN_SPI_SCK (0 + 11) // P0.11 +#define PIN_SPI_NSS (0 + 12) // P0.12 + +#define LORA_RESET (32 + 10) // P1.10 // RST +#define LORA_DIO1 (32 + 1) // P1.01 // IRQ +#define LORA_DIO2 (0 + 7) // P0.07 // BUSY +#define LORA_SCK PIN_SPI_SCK +#define LORA_MISO PIN_SPI_MISO +#define LORA_MOSI PIN_SPI_MOSI +#define LORA_CS PIN_SPI_NSS + +// supported modules list +#define USE_LR1110 + +#define LR1110_IRQ_PIN LORA_DIO1 +#define LR1110_NRESER_PIN LORA_RESET +#define LR1110_BUSY_PIN LORA_DIO2 +#define LR1110_SPI_NSS_PIN LORA_CS +#define LR1110_SPI_SCK_PIN LORA_SCK +#define LR1110_SPI_MOSI_PIN LORA_MOSI +#define LR1110_SPI_MISO_PIN LORA_MISO + +#define LR11X0_DIO3_TCXO_VOLTAGE 1.6 +#define LR11X0_DIO_AS_RF_SWITCH +#define LR11X0_DIO_RF_SWITCH_CONFIG 0x0f, 0x0, 0x09, 0x0B, 0x0A, 0x0, 0x4, 0x0 + +#define HAS_GPS 1 +#define GNSS_Airoha +#define GPS_RX_PIN PIN_SERIAL1_RX +#define GPS_TX_PIN PIN_SERIAL1_TX + +#define GPS_BAUDRATE 115200 + +#define PIN_GPS_EN (32 + 11) // P1.11 +#define GPS_EN_ACTIVE HIGH + +#define PIN_GPS_RESET (32 + 15) // P1.15 +#define GPS_RESET_MODE HIGH + +#define GPS_VRTC_EN (0 + 8) // P0.8, awlays high +#define GPS_SLEEP_INT (32 + 12) // P1.12, awlays high +#define GPS_RTC_INT (0 + 15) // P0.15, normal is LOW, wake by HIGH +#define GPS_RESETB_OUT (32 + 14) // P1.14, awlays input pull_up + +// #define GPS_THREAD_INTERVAL 50 +#define GPS_FIX_HOLD_TIME 15000 // ms + +#define BATTERY_PIN 2 +// #define ADC_CHANNEL ADC1_GPIO2_CHANNEL +#define ADC_MULTIPLIER (2.0F) + +#define ADC_RESOLUTION 14 +#define BATTERY_SENSE_RESOLUTION_BITS 12 +// #define BATTERY_SENSE_RESOLUTION 4096.0 + +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 + +// #define ADC_CTRL (32 + 6) +// #define ADC_CTRL_ENABLED HIGH + +// Buzzer +#define BUZZER_EN_PIN (32 + 5) // P1.05, awlays high +#define PIN_BUZZER (0 + 25) // P0.25, pwm output + +#define T1000X_SENSOR_EN +#define T1000X_VCC_PIN (0 + 4) // P0.4 +#define T1000X_NTC_PIN (0 + 31) // P0.31 +#define T1000X_LUX_PIN (0 + 29) // P0.29 + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif // _VARIANT_WIO_SDK_WM1110_ diff --git a/variants/wio-tracker-wm1110/platformio.ini b/variants/wio-tracker-wm1110/platformio.ini index cba1b87414..03d7d047a7 100644 --- a/variants/wio-tracker-wm1110/platformio.ini +++ b/variants/wio-tracker-wm1110/platformio.ini @@ -1,11 +1,11 @@ -; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmware for 5005/19003, with or without OLED RAK 1921 +; The red tracker Dev Board with the WM1110 module [env:wio-tracker-wm1110] extends = nrf52840_base board = wio-tracker-wm1110 -; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e -build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-tracker-wm1110 -DWIO_WM1110 +build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-tracker-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-tracker-wm1110> lib_deps = ${nrf52840_base.lib_deps} diff --git a/variants/xiao_ble/platformio.ini b/variants/xiao_ble/platformio.ini index 60e7cecbd5..156eba528c 100644 --- a/variants/xiao_ble/platformio.ini +++ b/variants/xiao_ble/platformio.ini @@ -3,9 +3,9 @@ extends = nrf52840_base board = xiao_ble_sense board_level = extra -build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Ivariants/xiao_ble/softdevice -Ivariants/xiao_ble/softdevice/nrf52 -D EBYTE_E22 -DPRIVATE_HW +build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -D EBYTE_E22 -DPRIVATE_HW -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -board_build.ldscript = variants/xiao_ble/nrf52840_s140_v7.ld +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/xiao_ble> lib_deps = ${nrf52840_base.lib_deps} From 9266a53f4ef3bdf787d0985a76e7f3969741bac1 Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 20 Jun 2024 09:47:07 -0700 Subject: [PATCH 074/211] Make serial port on wio-sdk-wm1110 board work By disabling the (inaccessible) adafruit USB --- boards/wio-sdk-wm1110.json | 7 ------- extra_scripts/README.md | 3 +++ extra_scripts/disable_adafruit_usb.py | 17 +++++++++++++++++ variants/wio-sdk-wm1110/platformio.ini | 6 +++++- variants/wio-sdk-wm1110/variant.h | 7 +++++++ 5 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 extra_scripts/README.md create mode 100644 extra_scripts/disable_adafruit_usb.py diff --git a/boards/wio-sdk-wm1110.json b/boards/wio-sdk-wm1110.json index 029c9c085e..882f4443ec 100644 --- a/boards/wio-sdk-wm1110.json +++ b/boards/wio-sdk-wm1110.json @@ -7,13 +7,6 @@ "cpu": "cortex-m4", "extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA", "f_cpu": "64000000L", - "hwids": [ - ["0x239A", "0x8029"], - ["0x239A", "0x0029"], - ["0x239A", "0x002A"], - ["0x239A", "0x802A"] - ], - "usb_product": "WIO-BOOT", "mcu": "nrf52840", "variant": "Seeed_WIO_WM1110", "bsp": { diff --git a/extra_scripts/README.md b/extra_scripts/README.md new file mode 100644 index 0000000000..4c797f49fe --- /dev/null +++ b/extra_scripts/README.md @@ -0,0 +1,3 @@ +# extra_scripts + +This directory contains special [scripts](https://docs.platformio.org/en/latest/scripting/index.html) that are used to modify the platformio environment in rare cases. diff --git a/extra_scripts/disable_adafruit_usb.py b/extra_scripts/disable_adafruit_usb.py new file mode 100644 index 0000000000..109d1f3d45 --- /dev/null +++ b/extra_scripts/disable_adafruit_usb.py @@ -0,0 +1,17 @@ +Import("env") + +# NOTE: This is not currently used, but can serve as an example on how to write extra_scripts + +print("Current CLI targets", COMMAND_LINE_TARGETS) +print("Current Build targets", BUILD_TARGETS) +print("CPP defs", env.get("CPPDEFINES")) + +# Adafruit.py in the platformio build tree is a bit naive and always enables their USB stack for building. We don't want this. +# So come in after that python script has run and disable it. This hack avoids us having to fork that big project and send in a PR +# which might not be accepted. -@geeksville + +env["CPPDEFINES"].remove("USBCON") +env["CPPDEFINES"].remove("USE_TINYUSB") + +# Custom actions when building program/firmware +# env.AddPreAction("buildprog", callback...) diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini index 8b1433dd1f..7ca82e4c68 100644 --- a/variants/wio-sdk-wm1110/platformio.ini +++ b/variants/wio-sdk-wm1110/platformio.ini @@ -2,6 +2,10 @@ [env:wio-sdk-wm1110] extends = nrf52840_base board = wio-sdk-wm1110 + +# Remove adafruit USB serial from the build (it is incompatible with using the ch340 serial chip on this board) +build_unflags = ${nrf52840_base:build_unflags} -DUSBCON -DUSE_TINYUSB + board_level = extra ; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -DWIO_WM1110 @@ -12,4 +16,4 @@ lib_deps = ${nrf52840_base.lib_deps} debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -upload_protocol = jlink \ No newline at end of file +upload_protocol = jlink diff --git a/variants/wio-sdk-wm1110/variant.h b/variants/wio-sdk-wm1110/variant.h index f027b469f3..8ad8c769af 100644 --- a/variants/wio-sdk-wm1110/variant.h +++ b/variants/wio-sdk-wm1110/variant.h @@ -31,6 +31,13 @@ #include "WVariant.h" +#ifdef USE_TINYUSB +#error TinyUSB must be disabled by platformio before using this variant +#endif + +// We use the hardware serial port for the serial console +#define Serial Serial1 + #ifdef __cplusplus extern "C" { #endif // __cplusplus From e050888b26e4c9327e0bb7bdb839958bc1915814 Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 20 Jun 2024 12:28:43 -0700 Subject: [PATCH 075/211] Don't complain about wierd platformio python --- extra_scripts/disable_adafruit_usb.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extra_scripts/disable_adafruit_usb.py b/extra_scripts/disable_adafruit_usb.py index 109d1f3d45..fb391715c5 100644 --- a/extra_scripts/disable_adafruit_usb.py +++ b/extra_scripts/disable_adafruit_usb.py @@ -1,3 +1,6 @@ +# trunk-ignore-all(flake8/F821) +# trunk-ignore-all(ruff/F821) + Import("env") # NOTE: This is not currently used, but can serve as an example on how to write extra_scripts From 2d39911f91f03dfc686fe542f6b34df828251973 Mon Sep 17 00:00:00 2001 From: Mike Date: Fri, 21 Jun 2024 00:14:34 +0300 Subject: [PATCH 076/211] Fix protobuf structs handling (#4140) * Fix protobuf structs handling * Log instead of assert --------- Co-authored-by: Ben Meadors --- src/main.cpp | 2 +- src/mesh/NodeDB.cpp | 5 ----- src/modules/AdminModule.cpp | 4 ++-- src/mqtt/MQTT.cpp | 7 ++++++- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ddb99568da..931c2a3fda 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -173,7 +173,7 @@ const char *getDeviceName() static char name[20]; snprintf(name, sizeof(name), "%02x%02x", dmac[4], dmac[5]); // if the shortname exists and is NOT the new default of ab3c, use it for BLE name. - if ((owner.short_name != NULL) && (strcmp(owner.short_name, name) != 0)) { + if (strcmp(owner.short_name, name) != 0) { snprintf(name, sizeof(name), "%s_%02x%02x", owner.short_name, dmac[4], dmac[5]); } else { snprintf(name, sizeof(name), "Meshtastic_%02x%02x", dmac[4], dmac[5]); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index cf576e94fe..209e0cbfae 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -141,11 +141,6 @@ NodeDB::NodeDB() if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile))) saveWhat |= SEGMENT_CHANNELS; - if (!devicestate.node_remote_hardware_pins) { - meshtastic_NodeRemoteHardwarePin empty[12] = {meshtastic_RemoteHardwarePin_init_default}; - memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty)); - } - if (config.position.gps_enabled) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED; config.position.gps_enabled = 0; diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 0915864623..8146866090 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -299,8 +299,8 @@ void AdminModule::handleGetModuleConfigResponse(const meshtastic_MeshPacket &mp, { // Skip if it's disabled or no pins are exposed if (!r->get_module_config_response.payload_variant.remote_hardware.enabled || - !r->get_module_config_response.payload_variant.remote_hardware.available_pins) { - LOG_DEBUG("Remote hardware module disabled or no vailable_pins. Skipping...\n"); + r->get_module_config_response.payload_variant.remote_hardware.available_pins_count == 0) { + LOG_DEBUG("Remote hardware module disabled or no available_pins. Skipping...\n"); return; } for (uint8_t i = 0; i < devicestate.node_remote_hardware_pins_count; i++) { diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 9f9ac5c243..74f3ca5a32 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -482,7 +482,12 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket & auto &ch = channels.getByIndex(chIndex); - if (&mp_decoded.decoded && strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0 && + if (mp_decoded.which_payload_variant != meshtastic_MeshPacket_decoded_tag) { + LOG_CRIT("MQTT::onSend(): mp_decoded isn't actually decoded\n"); + return; + } + + if (strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0 && (mp_decoded.decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP || mp_decoded.decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP)) { LOG_DEBUG("MQTT onSend - Ignoring range test or detection sensor message on public mqtt\n"); From 0bcc60d53561cb04b65deaada4f4483d1150c47c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 20 Jun 2024 16:14:55 -0500 Subject: [PATCH 077/211] BLE based logging (#4146) * WIP log characteristic * Bluetooth logging plumbing * Characteristic * Callback * Check for nullptr * Esp32 bluetooth impl * Formatting * Add thread name and log level * Add settings guard * Remove comments * Field name * Fixes esp32 * Open it up * Whoops * Move va_end past our logic --- src/BluetoothCommon.cpp | 4 +- src/BluetoothCommon.h | 4 +- src/RedirectablePrint.cpp | 39 +++++++++++++- src/main.cpp | 1 - src/nimble/NimbleBluetooth.cpp | 14 ++++- src/nimble/NimbleBluetooth.h | 1 + src/platform/nrf52/NRF52Bluetooth.cpp | 74 +++++++-------------------- src/platform/nrf52/NRF52Bluetooth.h | 2 +- 8 files changed, 76 insertions(+), 63 deletions(-) diff --git a/src/BluetoothCommon.cpp b/src/BluetoothCommon.cpp index 53faae997c..7ef1c39b45 100644 --- a/src/BluetoothCommon.cpp +++ b/src/BluetoothCommon.cpp @@ -10,4 +10,6 @@ const uint8_t TORADIO_UUID_16[16u] = {0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, const uint8_t FROMRADIO_UUID_16[16u] = {0x02, 0x00, 0x12, 0xac, 0x42, 0x02, 0x78, 0xb8, 0xed, 0x11, 0x93, 0x49, 0x9e, 0xe6, 0x55, 0x2c}; const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6, - 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed}; \ No newline at end of file + 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed}; +const uint8_t LOGRADIO_UUID_16[16u] = {0xe2, 0xf2, 0x1e, 0xbe, 0xc5, 0x15, 0xcf, 0xaa, + 0x6b, 0x43, 0xfa, 0x78, 0x38, 0xd2, 0x6f, 0x6c}; \ No newline at end of file diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h index 586ffaa3c1..5497e1d6db 100644 --- a/src/BluetoothCommon.h +++ b/src/BluetoothCommon.h @@ -11,10 +11,11 @@ #define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7" #define FROMRADIO_UUID "2c55e69e-4993-11ed-b878-0242ac120002" #define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453" +#define LOGRADIO_UUID "6c6fd238-78fa-436b-aacf-15c5be1ef2e2" // NRF52 wants these constants as byte arrays // Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER -extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[]; +extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[], LOGRADIO_UUID_16[]; /// Given a level between 0-100, update the BLE attribute void updateBatteryLevel(uint8_t level); @@ -27,4 +28,5 @@ class BluetoothApi virtual void clearBonds(); virtual bool isConnected(); virtual int getRssi() = 0; + virtual void sendLog(const char *logMessage); }; \ No newline at end of file diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index e09e5fe30a..2110761ffc 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -3,6 +3,7 @@ #include "RTC.h" #include "concurrency/OSThread.h" #include "configuration.h" +#include "main.h" #include #include #include @@ -166,9 +167,43 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) } #endif - va_end(arg); - isContinuationMessage = !hasNewline; + + if (config.bluetooth.device_logging_enabled) { + bool isBleConnected = false; +#ifdef ARCH_ESP32 + isBleConnected = nimbleBluetooth && nimbleBluetooth->isActive() && nimbleBluetooth->isConnected(); +#elif defined(ARCH_NRF52) + isBleConnected = nrf52Bluetooth != nullptr && nrf52Bluetooth->isConnected(); +#endif + if (isBleConnected) { + char *message; + size_t initialLen; + size_t len; + initialLen = strlen(format); + message = new char[initialLen + 1]; + len = vsnprintf(message, initialLen + 1, format, arg); + if (len > initialLen) { + delete[] message; + message = new char[len + 1]; + vsnprintf(message, len + 1, format, arg); + } + auto thread = concurrency::OSThread::currentThread; +#ifdef ARCH_ESP32 + if (thread) + nimbleBluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str()); + else + nimbleBluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str()); +#elif defined(ARCH_NRF52) + if (thread) + nrf52Bluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str()); + else + nrf52Bluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str()); +#endif + delete[] message; + } + } + va_end(arg); #ifdef HAS_FREE_RTOS xSemaphoreGive(inDebugPrint); #else diff --git a/src/main.cpp b/src/main.cpp index 931c2a3fda..725e3499db 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,7 +48,6 @@ NimbleBluetooth *nimbleBluetooth = nullptr; #ifdef ARCH_NRF52 #include "NRF52Bluetooth.h" NRF52Bluetooth *nrf52Bluetooth = nullptr; -; #endif #if HAS_WIFI diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 68aa9b4653..6ed4a49aed 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -12,6 +12,7 @@ NimBLECharacteristic *fromNumCharacteristic; NimBLECharacteristic *BatteryCharacteristic; +NimBLECharacteristic *logRadioCharacteristic; NimBLEServer *bleServer; static bool passkeyShowing; @@ -58,7 +59,6 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks { virtual void onRead(NimBLECharacteristic *pCharacteristic) { - LOG_INFO("From Radio onread\n"); uint8_t fromRadioBytes[meshtastic_FromRadio_size]; size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); @@ -180,6 +180,7 @@ void NimbleBluetooth::setupService() ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE); FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ); fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ); + logRadioCharacteristic = bleService->createCharacteristic(LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ); } else { ToRadioCharacteristic = bleService->createCharacteristic( TORADIO_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_AUTHEN | NIMBLE_PROPERTY::WRITE_ENC); @@ -188,6 +189,9 @@ void NimbleBluetooth::setupService() fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC); + logRadioCharacteristic = + bleService->createCharacteristic(LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | + NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC); } bluetoothPhoneAPI = new BluetoothPhoneAPI(); @@ -236,6 +240,14 @@ void NimbleBluetooth::clearBonds() NimBLEDevice::deleteAllBonds(); } +void NimbleBluetooth::sendLog(const char *logMessage) +{ + if (!bleServer || !isConnected() || strlen(logMessage) > 512) { + return; + } + logRadioCharacteristic->notify((uint8_t *)logMessage, strlen(logMessage)); +} + void clearNVS() { NimBLEDevice::deleteAllBonds(); diff --git a/src/nimble/NimbleBluetooth.h b/src/nimble/NimbleBluetooth.h index d1e347830a..39794779b2 100644 --- a/src/nimble/NimbleBluetooth.h +++ b/src/nimble/NimbleBluetooth.h @@ -11,6 +11,7 @@ class NimbleBluetooth : BluetoothApi bool isActive(); bool isConnected(); int getRssi(); + void sendLog(const char *logMessage); private: void setupService(); diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 4c25f38ea3..a14829285b 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -7,16 +7,16 @@ #include "mesh/mesh-pb-constants.h" #include #include - static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16)); static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16)); static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16)); static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16)); +static BLECharacteristic logRadio = BLECharacteristic(BLEUuid(LOGRADIO_UUID_16)); static BLEDis bledis; // DIS (Device Information Service) helper class instance static BLEBas blebas; // BAS (Battery Service) helper class instance -static BLEDfu bledfu; // DFU software update helper service +static BLEDfu bledfu; // DFU software update helper service // This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in // process at once // static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)]; @@ -50,16 +50,14 @@ static BluetoothPhoneAPI *bluetoothPhoneAPI; void onConnect(uint16_t conn_handle) { + // Get the reference to current connection BLEConnection *connection = Bluefruit.Connection(conn_handle); connectionHandle = conn_handle; - char central_name[32] = {0}; connection->getPeerName(central_name, sizeof(central_name)); - LOG_INFO("BLE Connected to %s\n", central_name); } - /** * Callback invoked when a connection is dropped * @param conn_handle connection where this event happens @@ -70,15 +68,13 @@ void onDisconnect(uint16_t conn_handle, uint8_t reason) // FIXME - we currently assume only one active connection LOG_INFO("BLE Disconnected, reason = 0x%x\n", reason); } - void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value) { // Display the raw request packet LOG_INFO("CCCD Updated: %u\n", cccd_value); - // Check the characteristic this CCCD update is associated with in case // this handler is used for multiple CCCD records. - if (chr->uuid == fromNum.uuid) { + if (chr->uuid == fromNum.uuid || chr->uuid == logRadio.uuid) { if (chr->notifyEnabled(conn_hdl)) { LOG_INFO("fromNum 'Notify' enabled\n"); } else { @@ -86,21 +82,17 @@ void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value) } } } - void startAdv(void) { // Advertising packet Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); - // IncludeService UUID // Bluefruit.ScanResponse.addService(meshBleService); Bluefruit.ScanResponse.addTxPower(); Bluefruit.ScanResponse.addName(); - // Include Name // Bluefruit.Advertising.addName(); Bluefruit.Advertising.addService(meshBleService); - /* Start Advertising * - Enable auto advertising if disconnected * - Interval: fast mode = 20 ms, slow mode = 152.5 ms @@ -115,7 +107,6 @@ void startAdv(void) Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X } - // Just ack that the caller is allowed to read static void authorizeRead(uint16_t conn_hdl) { @@ -123,7 +114,6 @@ static void authorizeRead(uint16_t conn_hdl) reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply); } - /** * client is starting read, pull the bytes from our API class */ @@ -132,7 +122,6 @@ void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e if (request->offset == 0) { // If the read is long, we will get multiple authorize invocations - we only populate data on the first size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); - // Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue // or make empty if the queue is empty fromRadio.write(fromRadioBytes, numBytes); @@ -141,37 +130,22 @@ void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e } authorizeRead(conn_hdl); } - void onToRadioWrite(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len) { LOG_INFO("toRadioWriteCb data %p, len %u\n", data, len); - bluetoothPhoneAPI->handleToRadio(data, len); } -/** - * client is starting read, pull the bytes from our API class - */ -void onFromNumAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) -{ - LOG_INFO("fromNumAuthorizeCb\n"); - - authorizeRead(conn_hdl); -} - void setupMeshService(void) { bluetoothPhoneAPI = new BluetoothPhoneAPI(); - meshBleService.begin(); - // Note: You must call .begin() on the BLEService before calling .begin() on // any characteristic(s) within that service definition.. Calling .begin() on // a BLECharacteristic will cause it to be added to the last BLEService that // was 'begin()'ed! auto secMode = config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN ? SECMODE_OPEN : SECMODE_ENC_NO_MITM; - fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ); fromNum.setPermission(secMode, SECMODE_NO_ACCESS); // FIXME, secure this!!! fromNum.setFixedLen( @@ -201,10 +175,15 @@ void setupMeshService(void) // We don't call this callback via the adafruit queue, because we can safely run in the BLE context toRadio.setWriteCallback(onToRadioWrite, false); toRadio.begin(); -} + logRadio.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ); + logRadio.setPermission(secMode, SECMODE_NO_ACCESS); + logRadio.setMaxLen(512); + logRadio.setCccdWriteCallback(onCccd); + logRadio.write32(0); + logRadio.begin(); +} static uint32_t configuredPasskey; - void NRF52Bluetooth::shutdown() { // Shutdown bluetooth for minimum power draw @@ -214,29 +193,23 @@ void NRF52Bluetooth::shutdown() } Bluefruit.Advertising.stop(); } - void NRF52Bluetooth::startDisabled() { // Setup Bluetooth nrf52Bluetooth->setup(); - // Shutdown bluetooth for minimum power draw Bluefruit.Advertising.stop(); Bluefruit.setTxPower(-40); // Minimum power - LOG_INFO("Disabling NRF52 Bluetooth. (Workaround: tx power min, advertising stopped)\n"); } - bool NRF52Bluetooth::isConnected() { return Bluefruit.connected(connectionHandle); } - int NRF52Bluetooth::getRssi() { return 0; // FIXME figure out where to source this } - void NRF52Bluetooth::setup() { // Initialise the Bluefruit module @@ -244,12 +217,10 @@ void NRF52Bluetooth::setup() Bluefruit.autoConnLed(false); Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); Bluefruit.begin(); - // Clear existing data. Bluefruit.Advertising.stop(); Bluefruit.Advertising.clearData(); Bluefruit.ScanResponse.clearData(); - if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) { configuredPasskey = config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN ? config.bluetooth.fixed_pin @@ -268,37 +239,29 @@ void NRF52Bluetooth::setup() } // Set the advertised device name (keep it short!) Bluefruit.setName(getDeviceName()); - // Set the connect/disconnect callback handlers Bluefruit.Periph.setConnectCallback(onConnect); Bluefruit.Periph.setDisconnectCallback(onDisconnect); - bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM); bledfu.begin(); // Install the DFU helper - // Configure and Start the Device Information Service LOG_INFO("Configuring the Device Information Service\n"); bledis.setModel(optstr(HW_VERSION)); bledis.setFirmwareRev(optstr(APP_VERSION)); bledis.begin(); - // Start the BLE Battery Service and set it to 100% LOG_INFO("Configuring the Battery Service\n"); blebas.begin(); blebas.write(0); // Unknown battery level for now - // Setup the Heart Rate Monitor service using // BLEService and BLECharacteristic classes LOG_INFO("Configuring the Mesh bluetooth service\n"); setupMeshService(); - // Setup the advertising packet(s) LOG_INFO("Setting up the advertising payload(s)\n"); startAdv(); - LOG_INFO("Advertising\n"); } - void NRF52Bluetooth::resumeAdvertising() { Bluefruit.Advertising.restartOnDisconnect(true); @@ -306,34 +269,28 @@ void NRF52Bluetooth::resumeAdvertising() Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.start(0); } - /// Given a level between 0-100, update the BLE attribute void updateBatteryLevel(uint8_t level) { blebas.write(level); } - void NRF52Bluetooth::clearBonds() { LOG_INFO("Clearing bluetooth bonds!\n"); bond_print_list(BLE_GAP_ROLE_PERIPH); bond_print_list(BLE_GAP_ROLE_CENTRAL); - Bluefruit.Periph.clearBonds(); Bluefruit.Central.clearBonds(); } - void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle) { LOG_INFO("BLE connection secured\n"); } - bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) { LOG_INFO("BLE pairing process started with passkey %.3s %.3s\n", passkey, passkey + 3); powerFSM.trigger(EVENT_BLUETOOTH_PAIR); screen->startBluetoothPinScreen(configuredPasskey); - if (match_request) { uint32_t start_time = millis(); while (millis() < start_time + 30000) { @@ -344,13 +301,18 @@ bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passke LOG_INFO("BLE passkey pairing: match_request=%i\n", match_request); return true; } - void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_status) { if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) LOG_INFO("BLE pairing success\n"); else LOG_INFO("BLE pairing failed\n"); - screen->stopBluetoothPinScreen(); +} + +void NRF52Bluetooth::sendLog(const char *logMessage) +{ + if (!isConnected() || strlen(logMessage) > 512) + return; + logRadio.notify(logMessage); } \ No newline at end of file diff --git a/src/platform/nrf52/NRF52Bluetooth.h b/src/platform/nrf52/NRF52Bluetooth.h index 450af47f91..0d621dda25 100644 --- a/src/platform/nrf52/NRF52Bluetooth.h +++ b/src/platform/nrf52/NRF52Bluetooth.h @@ -13,10 +13,10 @@ class NRF52Bluetooth : BluetoothApi void clearBonds(); bool isConnected(); int getRssi(); + void sendLog(const char *logMessage); private: static void onConnectionSecured(uint16_t conn_handle); - void convertToUint8(uint8_t target[4], uint32_t source); static bool onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request); static void onPairingCompleted(uint16_t conn_handle, uint8_t auth_status); }; \ No newline at end of file From 0dd363fa9842bdd00c703cd8edb1c9c2a7b66eea Mon Sep 17 00:00:00 2001 From: Mike G Date: Fri, 21 Jun 2024 04:01:36 +0300 Subject: [PATCH 078/211] Use `upload_protocol = esptool` as with the other heltec devices instead of `esp-builtin` (#4151) --- variants/heltec_wireless_tracker/platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/variants/heltec_wireless_tracker/platformio.ini b/variants/heltec_wireless_tracker/platformio.ini index 3259d563c3..c7ecce8eab 100644 --- a/variants/heltec_wireless_tracker/platformio.ini +++ b/variants/heltec_wireless_tracker/platformio.ini @@ -1,7 +1,7 @@ [env:heltec-wireless-tracker] extends = esp32s3_base board = heltec_wireless_tracker -upload_protocol = esp-builtin +upload_protocol = esptool build_flags = ${esp32s3_base.build_flags} -I variants/heltec_wireless_tracker @@ -11,4 +11,4 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} - lovyan03/LovyanGFX@^1.1.8 \ No newline at end of file + lovyan03/LovyanGFX@^1.1.8 From 02d8715ca0de6a468dce1dc3b03fe458540df291 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 21 Jun 2024 17:25:54 -0500 Subject: [PATCH 079/211] Standardize lat/lon position logs (#4156) * Standardize lat/lon position logs * Missed sone and condensed logs --- src/GPSStatus.h | 2 +- src/gps/GPS.cpp | 18 +++++++++++++++++- src/gps/GPS.h | 2 ++ src/mesh/FloodingRouter.cpp | 2 +- src/mesh/MeshService.cpp | 4 ++-- src/mesh/NodeDB.cpp | 6 +++--- src/mesh/NodeDB.h | 4 ++-- src/modules/PositionModule.cpp | 4 ++-- 8 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/GPSStatus.h b/src/GPSStatus.h index 1245d5e5dc..c2ab16c86f 100644 --- a/src/GPSStatus.h +++ b/src/GPSStatus.h @@ -124,7 +124,7 @@ class GPSStatus : public Status if (isDirty) { if (hasLock) { // In debug logs, identify position by @timestamp:stage (stage 3 = notify) - LOG_DEBUG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, speed=%.2f, sats=%d\n", p.timestamp, + LOG_DEBUG("New GPS pos@%x:3 lat=%f lon=%f alt=%d pdop=%.2f track=%.2f speed=%.2f sats=%d\n", p.timestamp, p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5, p.ground_speed * 1e-2, p.sats_in_view); } else { diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 8d46742baa..5efe962517 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -778,6 +778,22 @@ GPS::~GPS() notifyGPSSleepObserver.observe(¬ifyGPSSleep); } +const char *GPS::powerStateToString() +{ + switch (powerState) { + case GPS_OFF: + return "OFF"; + case GPS_IDLE: + return "IDLE"; + case GPS_STANDBY: + return "STANDBY"; + case GPS_ACTIVE: + return "ACTIVE"; + default: + return "UNKNOWN"; + } +} + void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) { // Record the current powerState @@ -792,7 +808,7 @@ void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) else powerState = GPS_OFF; - LOG_DEBUG("GPS::powerState=%d\n", powerState); + LOG_DEBUG("GPS::powerState=%s\n", powerStateToString()); // If the next update is due *really soon*, don't actually power off or enter standby. Just wait it out. if (!on && powerState == GPS_IDLE) diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 55bd42d0fb..6afbd4faba 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -289,6 +289,8 @@ class GPS : private concurrency::OSThread // delay counter to allow more sats before fixed position stops GPS thread uint8_t fixeddelayCtr = 0; + const char *powerStateToString(); + protected: GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN; }; diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index dd547a6f1a..7866fa444e 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -20,7 +20,7 @@ ErrorCode FloodingRouter::send(meshtastic_MeshPacket *p) bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { if (wasSeenRecently(p)) { // Note: this will also add a recent packet record - printPacket("Ignoring incoming msg, because we've already seen it", p); + printPacket("Ignoring incoming msg we've already seen", p); if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 2cfb4843cd..c92b89eb47 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -373,8 +373,8 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus) pos.time = getValidTime(RTCQualityFromNet); // In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB) - LOG_DEBUG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", pos.timestamp, pos.time, pos.latitude_i, - pos.longitude_i, pos.altitude); + LOG_DEBUG("onGPSChanged() pos@%x time=%u lat=%d lon=%d alt=%d\n", pos.timestamp, pos.time, pos.latitude_i, pos.longitude_i, + pos.altitude); // Update our current position in the local DB nodeDB->updatePosition(nodeDB->getNodeNum(), pos, RX_SRC_LOCAL); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 209e0cbfae..31fb983f4c 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -821,8 +821,8 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou if (src == RX_SRC_LOCAL) { // Local packet, fully authoritative - LOG_INFO("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.timestamp, p.time, p.latitude_i, - p.longitude_i, p.altitude); + LOG_INFO("updatePosition LOCAL pos@%x time=%u lat=%d lon=%d alt=%d\n", p.timestamp, p.time, p.latitude_i, p.longitude_i, + p.altitude); setLocalPosition(p); info->position = TypeConversions::ConvertToPositionLite(p); @@ -837,7 +837,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou // recorded based on the packet rxTime // // FIXME perhaps handle RX_SRC_USER separately? - LOG_INFO("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i); + LOG_INFO("updatePosition REMOTE node=0x%x time=%u lat=%d lon=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i); // First, back up fields that we want to protect from overwrite uint32_t tmp_time = info->position.time; diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index e9e36cc617..61bf90d4d3 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -155,8 +155,8 @@ class NodeDB localPosition.timestamp = position.timestamp > 0 ? position.timestamp : position.time; return; } - LOG_DEBUG("Setting local position: latitude=%i, longitude=%i, time=%u, timestamp=%u\n", position.latitude_i, - position.longitude_i, position.time, position.timestamp); + LOG_DEBUG("Setting local position: lat=%i lon=%i time=%u timestamp=%u\n", position.latitude_i, position.longitude_i, + position.time, position.timestamp); localPosition = position; } diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 49f2b808b9..61616841b3 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -73,7 +73,7 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes } // Log packet size and data fields - LOG_DEBUG("POSITION node=%08x l=%d latI=%d lonI=%d msl=%d hae=%d geo=%d pdop=%d hdop=%d vdop=%d siv=%d fxq=%d fxt=%d pts=%d " + LOG_DEBUG("POSITION node=%08x l=%d lat=%d lon=%d msl=%d hae=%d geo=%d pdop=%d hdop=%d vdop=%d siv=%d fxq=%d fxt=%d pts=%d " "time=%d\n", getFrom(&mp), mp.decoded.payload.size, p.latitude_i, p.longitude_i, p.altitude, p.altitude_hae, p.altitude_geoidal_separation, p.PDOP, p.HDOP, p.VDOP, p.sats_in_view, p.fix_quality, p.fix_type, p.timestamp, @@ -219,7 +219,7 @@ meshtastic_MeshPacket *PositionModule::allocReply() LOG_INFO("Providing time to mesh %u\n", p.time); } - LOG_INFO("Position reply: time=%i, latI=%i, lonI=%i\n", p.time, p.latitude_i, p.longitude_i); + LOG_INFO("Position reply: time=%i lat=%i lon=%i\n", p.time, p.latitude_i, p.longitude_i); // TAK Tracker devices should send their position in a TAK packet over the ATAK port if (config.device.role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER) From f8db38cf992efd2b44bcd2804a6f28684239b0ba Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2024 19:02:16 -0500 Subject: [PATCH 080/211] [create-pull-request] automated change (#4157) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/config.pb.h | 13 ++- src/mesh/generated/meshtastic/deviceonly.pb.h | 2 +- src/mesh/generated/meshtastic/localonly.pb.h | 2 +- src/mesh/generated/meshtastic/powermon.pb.cpp | 13 +++ src/mesh/generated/meshtastic/powermon.pb.h | 85 +++++++++++++++++++ 6 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 src/mesh/generated/meshtastic/powermon.pb.cpp create mode 100644 src/mesh/generated/meshtastic/powermon.pb.h diff --git a/protobufs b/protobufs index 1c3029f286..4da558d0f7 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 1c3029f2868e5fc49809fd378f6c0c66aee0eaf4 +Subproject commit 4da558d0f73c46ef91b74431facee73c09affbfc diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 5a78f13668..2da4b86e6a 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -372,6 +372,9 @@ typedef struct _meshtastic_Config_PowerConfig { uint32_t min_wake_secs; /* I2C address of INA_2XX to use for reading device battery voltage */ uint8_t device_battery_ina_address; + /* If non-zero, we want powermon log outputs. With the particular (bitfield) sources enabled. + Note: we picked an ID of 32 so that lower more efficient IDs can be used for more frequently used options. */ + uint64_t powermon_enables; } meshtastic_Config_PowerConfig; typedef struct _meshtastic_Config_NetworkConfig_IpV4Config { @@ -612,7 +615,7 @@ extern "C" { #define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}} #define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} #define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} -#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} @@ -621,7 +624,7 @@ extern "C" { #define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}} #define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} #define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} -#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} @@ -662,6 +665,7 @@ extern "C" { #define meshtastic_Config_PowerConfig_ls_secs_tag 7 #define meshtastic_Config_PowerConfig_min_wake_secs_tag 8 #define meshtastic_Config_PowerConfig_device_battery_ina_address_tag 9 +#define meshtastic_Config_PowerConfig_powermon_enables_tag 32 #define meshtastic_Config_NetworkConfig_IpV4Config_ip_tag 1 #define meshtastic_Config_NetworkConfig_IpV4Config_gateway_tag 2 #define meshtastic_Config_NetworkConfig_IpV4Config_subnet_tag 3 @@ -773,7 +777,8 @@ X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \ X(a, STATIC, SINGULAR, UINT32, sds_secs, 6) \ X(a, STATIC, SINGULAR, UINT32, ls_secs, 7) \ X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 8) \ -X(a, STATIC, SINGULAR, UINT32, device_battery_ina_address, 9) +X(a, STATIC, SINGULAR, UINT32, device_battery_ina_address, 9) \ +X(a, STATIC, SINGULAR, UINT64, powermon_enables, 32) #define meshtastic_Config_PowerConfig_CALLBACK NULL #define meshtastic_Config_PowerConfig_DEFAULT NULL @@ -871,7 +876,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 196 #define meshtastic_Config_PositionConfig_size 62 -#define meshtastic_Config_PowerConfig_size 40 +#define meshtastic_Config_PowerConfig_size 52 #define meshtastic_Config_size 199 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 5e291ee947..100972c1eb 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -308,7 +308,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size #define meshtastic_ChannelFile_size 718 #define meshtastic_NodeInfoLite_size 166 -#define meshtastic_OEMStore_size 3372 +#define meshtastic_OEMStore_size 3384 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 96a9976f03..c1d2a4ae3e 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -181,7 +181,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size -#define meshtastic_LocalConfig_size 541 +#define meshtastic_LocalConfig_size 553 #define meshtastic_LocalModuleConfig_size 685 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/powermon.pb.cpp b/src/mesh/generated/meshtastic/powermon.pb.cpp new file mode 100644 index 0000000000..4d798e9a39 --- /dev/null +++ b/src/mesh/generated/meshtastic/powermon.pb.cpp @@ -0,0 +1,13 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.8 */ + +#include "meshtastic/powermon.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(meshtastic_PowerMon, meshtastic_PowerMon, AUTO) + + + + diff --git a/src/mesh/generated/meshtastic/powermon.pb.h b/src/mesh/generated/meshtastic/powermon.pb.h new file mode 100644 index 0000000000..88e80bb559 --- /dev/null +++ b/src/mesh/generated/meshtastic/powermon.pb.h @@ -0,0 +1,85 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.8 */ + +#ifndef PB_MESHTASTIC_MESHTASTIC_POWERMON_PB_H_INCLUDED +#define PB_MESHTASTIC_MESHTASTIC_POWERMON_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +/* Any significant power changing event in meshtastic should be tagged with a powermon state transition. +If you are making new meshtastic features feel free to add new entries at the end of this definition. */ +typedef enum _meshtastic_PowerMon_State { + meshtastic_PowerMon_State_None = 0, + meshtastic_PowerMon_State_CPU_DeepSleep = 1, + meshtastic_PowerMon_State_CPU_LightSleep = 2, + /* The external Vext1 power is on. Many boards have auxillary power rails that the CPU turns on only +occasionally. In cases where that rail has multiple devices on it we usually want to have logging on +the state of that rail as an independent record. +For instance on the Heltec Tracker 1.1 board, this rail is the power source for the GPS and screen. + +The log messages will be short and complete (see PowerMon.Event in the protobufs for details). +something like "S:PM:C,0x00001234,REASON" where the hex number is the bitmask of all current states. +(We use a bitmask for states so that if a log message gets lost it won't be fatal) */ + meshtastic_PowerMon_State_Vext1_On = 4, + meshtastic_PowerMon_State_Lora_RXOn = 8, + meshtastic_PowerMon_State_Lora_TXOn = 16, + meshtastic_PowerMon_State_Lora_RXActive = 32, + meshtastic_PowerMon_State_BT_On = 64, + meshtastic_PowerMon_State_LED_On = 128, + meshtastic_PowerMon_State_Screen_On = 256, + meshtastic_PowerMon_State_Screen_Drawing = 512, + meshtastic_PowerMon_State_Wifi_On = 1024, + /* GPS is actively trying to find our location +See GPSPowerState for more details */ + meshtastic_PowerMon_State_GPS_Active = 2048 +} meshtastic_PowerMon_State; + +/* Struct definitions */ +/* Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs). +But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) */ +typedef struct _meshtastic_PowerMon { + char dummy_field; +} meshtastic_PowerMon; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Helper constants for enums */ +#define _meshtastic_PowerMon_State_MIN meshtastic_PowerMon_State_None +#define _meshtastic_PowerMon_State_MAX meshtastic_PowerMon_State_GPS_Active +#define _meshtastic_PowerMon_State_ARRAYSIZE ((meshtastic_PowerMon_State)(meshtastic_PowerMon_State_GPS_Active+1)) + + + +/* Initializer values for message structs */ +#define meshtastic_PowerMon_init_default {0} +#define meshtastic_PowerMon_init_zero {0} + +/* Field tags (for use in manual encoding/decoding) */ + +/* Struct field encoding specification for nanopb */ +#define meshtastic_PowerMon_FIELDLIST(X, a) \ + +#define meshtastic_PowerMon_CALLBACK NULL +#define meshtastic_PowerMon_DEFAULT NULL + +extern const pb_msgdesc_t meshtastic_PowerMon_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define meshtastic_PowerMon_fields &meshtastic_PowerMon_msg + +/* Maximum encoded size of messages (where known) */ +#define MESHTASTIC_MESHTASTIC_POWERMON_PB_H_MAX_SIZE meshtastic_PowerMon_size +#define meshtastic_PowerMon_size 0 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif From d32cdecc06b973d58f87eb34f75399774592a0ce Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 22 Jun 2024 07:00:48 -0500 Subject: [PATCH 081/211] Pause BLE logging during want_config flow (#4162) --- src/RedirectablePrint.cpp | 2 +- src/main.cpp | 1 + src/main.h | 2 ++ src/mesh/PhoneAPI.cpp | 4 ++++ src/mesh/PhoneAPI.h | 2 -- 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 2110761ffc..b77720d85d 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -169,7 +169,7 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) isContinuationMessage = !hasNewline; - if (config.bluetooth.device_logging_enabled) { + if (config.bluetooth.device_logging_enabled && !pauseBluetoothLogging) { bool isBleConnected = false; #ifdef ARCH_ESP32 isBleConnected = nimbleBluetooth && nimbleBluetooth->isActive() && nimbleBluetooth->isConnected(); diff --git a/src/main.cpp b/src/main.cpp index 725e3499db..9ec4fa82de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -154,6 +154,7 @@ bool isVibrating = false; bool eink_found = true; uint32_t serialSinceMsec; +bool pauseBluetoothLogging = false; bool pmu_found; diff --git a/src/main.h b/src/main.h index 2ef7edb3a9..ea2d80f94a 100644 --- a/src/main.h +++ b/src/main.h @@ -85,6 +85,8 @@ extern uint32_t serialSinceMsec; // This will suppress the current delay and instead try to run ASAP. extern bool runASAP; +extern bool pauseBluetoothLogging; + void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds(), enterDfuMode(); meshtastic_DeviceMetadata getDeviceMetadata(); diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 26d0d9525a..404666877c 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -46,6 +46,7 @@ void PhoneAPI::handleStartConfig() // even if we were already connected - restart our state machine state = STATE_SEND_MY_INFO; + pauseBluetoothLogging = true; LOG_INFO("Starting API client config\n"); nodeInfoForPhone.num = 0; // Don't keep returning old nodeinfos @@ -352,9 +353,11 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) fromRadioScratch.config_complete_id = config_nonce; config_nonce = 0; state = STATE_SEND_PACKETS; + pauseBluetoothLogging = false; break; case STATE_SEND_PACKETS: + pauseBluetoothLogging = false; // Do we have a message from the mesh or packet from the local device? LOG_INFO("getFromRadio=STATE_SEND_PACKETS\n"); if (queueStatusPacketForPhone) { @@ -398,6 +401,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) void PhoneAPI::handleDisconnect() { + pauseBluetoothLogging = false; LOG_INFO("PhoneAPI disconnect\n"); } diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 49bf0e292b..668f9c1f3c 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -98,8 +98,6 @@ class PhoneAPI bool isConnected() { return state != STATE_SEND_NOTHING; } - void setInitialState() { state = STATE_SEND_MY_INFO; } - protected: /// Our fromradio packet while it is being assembled meshtastic_FromRadio fromRadioScratch = {}; From eb6bd3a06fb74f47dd335e0812bd35ed76f837ae Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 22 Jun 2024 08:49:55 -0500 Subject: [PATCH 082/211] Update NimBLE to 1.4.2 (#4163) --- arch/esp32/esp32.ini | 2 +- src/nimble/NimbleBluetooth.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index f3eb0cbc03..58c1302da8 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -44,7 +44,7 @@ lib_deps = ${networking_base.lib_deps} ${environmental_base.lib_deps} https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2 - h2zero/NimBLE-Arduino@^1.4.1 + h2zero/NimBLE-Arduino@^1.4.2 https://github.com/dbSuS/libpax.git#7bcd3fcab75037505be9b122ab2b24cc5176b587 https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6 https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 6ed4a49aed..b70420c8a0 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -245,7 +245,7 @@ void NimbleBluetooth::sendLog(const char *logMessage) if (!bleServer || !isConnected() || strlen(logMessage) > 512) { return; } - logRadioCharacteristic->notify((uint8_t *)logMessage, strlen(logMessage)); + logRadioCharacteristic->notify(reinterpret_cast(logMessage), strlen(logMessage)); } void clearNVS() From 8078e03f5fea2af1e6dbc217c9fac5d3eb4d1029 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sun, 23 Jun 2024 14:13:59 +0200 Subject: [PATCH 083/211] Implement replies for all telemetry types based on variant tag (#4164) * Implement replies for all telemetry types based on variant tag * Remove check for `ignoreRequest`: modules can set this, don't need to check --------- Co-authored-by: Ben Meadors --- src/modules/Telemetry/AirQualityTelemetry.cpp | 107 ++++++++++++------ src/modules/Telemetry/AirQualityTelemetry.h | 5 + src/modules/Telemetry/DeviceTelemetry.cpp | 29 +++-- .../Telemetry/EnvironmentTelemetry.cpp | 84 +++++++++----- src/modules/Telemetry/EnvironmentTelemetry.h | 5 + src/modules/Telemetry/PowerTelemetry.cpp | 67 ++++++++--- src/modules/Telemetry/PowerTelemetry.h | 5 + src/modules/esp32/PaxcounterModule.cpp | 6 +- 8 files changed, 218 insertions(+), 90 deletions(-) diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index 4f5fbcd131..ba043feabf 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -85,53 +85,90 @@ bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPack return false; // Let others look at this message also if they want } -bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +bool AirQualityTelemetryModule::getAirQualityTelemetry(meshtastic_Telemetry *m) { if (!aqi.read(&data)) { LOG_WARN("Skipping send measurements. Could not read AQIn\n"); return false; } - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; - m.time = getTime(); - m.which_variant = meshtastic_Telemetry_air_quality_metrics_tag; - m.variant.air_quality_metrics.pm10_standard = data.pm10_standard; - m.variant.air_quality_metrics.pm25_standard = data.pm25_standard; - m.variant.air_quality_metrics.pm100_standard = data.pm100_standard; + m->time = getTime(); + m->which_variant = meshtastic_Telemetry_air_quality_metrics_tag; + m->variant.air_quality_metrics.pm10_standard = data.pm10_standard; + m->variant.air_quality_metrics.pm25_standard = data.pm25_standard; + m->variant.air_quality_metrics.pm100_standard = data.pm100_standard; - m.variant.air_quality_metrics.pm10_environmental = data.pm10_env; - m.variant.air_quality_metrics.pm25_environmental = data.pm25_env; - m.variant.air_quality_metrics.pm100_environmental = data.pm100_env; + m->variant.air_quality_metrics.pm10_environmental = data.pm10_env; + m->variant.air_quality_metrics.pm25_environmental = data.pm25_env; + m->variant.air_quality_metrics.pm100_environmental = data.pm100_env; LOG_INFO("(Sending): PM1.0(Standard)=%i, PM2.5(Standard)=%i, PM10.0(Standard)=%i\n", - m.variant.air_quality_metrics.pm10_standard, m.variant.air_quality_metrics.pm25_standard, - m.variant.air_quality_metrics.pm100_standard); + m->variant.air_quality_metrics.pm10_standard, m->variant.air_quality_metrics.pm25_standard, + m->variant.air_quality_metrics.pm100_standard); LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i\n", - m.variant.air_quality_metrics.pm10_environmental, m.variant.air_quality_metrics.pm25_environmental, - m.variant.air_quality_metrics.pm100_environmental); - - meshtastic_MeshPacket *p = allocDataProtobuf(m); - p->to = dest; - p->decoded.want_response = false; - if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) - p->priority = meshtastic_MeshPacket_Priority_RELIABLE; - else - p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; - - // release previous packet before occupying a new spot - if (lastMeasurementPacket != nullptr) - packetPool.release(lastMeasurementPacket); - - lastMeasurementPacket = packetPool.allocCopy(*p); - if (phoneOnly) { - LOG_INFO("Sending packet to phone\n"); - service.sendToPhone(p); - } else { - LOG_INFO("Sending packet to mesh\n"); - service.sendToMesh(p, RX_SRC_LOCAL, true); - } + m->variant.air_quality_metrics.pm10_environmental, m->variant.air_quality_metrics.pm25_environmental, + m->variant.air_quality_metrics.pm100_environmental); + return true; } +meshtastic_MeshPacket *AirQualityTelemetryModule::allocReply() +{ + if (currentRequest) { + auto req = *currentRequest; + const auto &p = req.decoded; + meshtastic_Telemetry scratch; + meshtastic_Telemetry *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { + decoded = &scratch; + } else { + LOG_ERROR("Error decoding AirQualityTelemetry module!\n"); + return NULL; + } + // Check for a request for air quality metrics + if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) { + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getAirQualityTelemetry(&m)) { + LOG_INFO("Air quality telemetry replying to request\n"); + return allocDataProtobuf(m); + } else { + return NULL; + } + } + } + return NULL; +} + +bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +{ + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getAirQualityTelemetry(&m)) { + meshtastic_MeshPacket *p = allocDataProtobuf(m); + p->to = dest; + p->decoded.want_response = false; + if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) + p->priority = meshtastic_MeshPacket_Priority_RELIABLE; + else + p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; + + // release previous packet before occupying a new spot + if (lastMeasurementPacket != nullptr) + packetPool.release(lastMeasurementPacket); + + lastMeasurementPacket = packetPool.allocCopy(*p); + if (phoneOnly) { + LOG_INFO("Sending packet to phone\n"); + service.sendToPhone(p); + } else { + LOG_INFO("Sending packet to mesh\n"); + service.sendToMesh(p, RX_SRC_LOCAL, true); + } + return true; + } + + return false; +} + #endif \ No newline at end of file diff --git a/src/modules/Telemetry/AirQualityTelemetry.h b/src/modules/Telemetry/AirQualityTelemetry.h index eb0355001e..9d09078b11 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.h +++ b/src/modules/Telemetry/AirQualityTelemetry.h @@ -26,6 +26,11 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override; virtual int32_t runOnce() override; + /** Called to get current Air Quality data + @return true if it contains valid data + */ + bool getAirQualityTelemetry(meshtastic_Telemetry *m); + virtual meshtastic_MeshPacket *allocReply() override; /** * Send our Telemetry into the mesh */ diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index b64e8d1130..9cc4bf6ea5 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -52,14 +52,27 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket & meshtastic_MeshPacket *DeviceTelemetryModule::allocReply() { - if (ignoreRequest) { - return NULL; - } - - LOG_INFO("Device telemetry replying to request\n"); + if (currentRequest) { + auto req = *currentRequest; + const auto &p = req.decoded; + meshtastic_Telemetry scratch; + meshtastic_Telemetry *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { + decoded = &scratch; + } else { + LOG_ERROR("Error decoding DeviceTelemetry module!\n"); + return NULL; + } + // Check for a request for device metrics + if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) { + LOG_INFO("Device telemetry replying to request\n"); - meshtastic_Telemetry telemetry = getDeviceTelemetry(); - return allocDataProtobuf(telemetry); + meshtastic_Telemetry telemetry = getDeviceTelemetry(); + return allocDataProtobuf(telemetry); + } + } + return NULL; } meshtastic_Telemetry DeviceTelemetryModule::getDeviceTelemetry() @@ -104,4 +117,4 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) service.sendToMesh(p, RX_SRC_LOCAL, true); } return true; -} +} \ No newline at end of file diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index ff32020675..8f899401b9 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -270,98 +270,129 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac return false; // Let others look at this message also if they want } -bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m) { - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; bool valid = true; bool hasSensor = false; - m.time = getTime(); - m.which_variant = meshtastic_Telemetry_environment_metrics_tag; + m->time = getTime(); + m->which_variant = meshtastic_Telemetry_environment_metrics_tag; if (dfRobotLarkSensor.hasSensor()) { - valid = valid && dfRobotLarkSensor.getMetrics(&m); + valid = valid && dfRobotLarkSensor.getMetrics(m); hasSensor = true; } if (sht31Sensor.hasSensor()) { - valid = valid && sht31Sensor.getMetrics(&m); + valid = valid && sht31Sensor.getMetrics(m); hasSensor = true; } if (lps22hbSensor.hasSensor()) { - valid = valid && lps22hbSensor.getMetrics(&m); + valid = valid && lps22hbSensor.getMetrics(m); hasSensor = true; } if (shtc3Sensor.hasSensor()) { - valid = valid && shtc3Sensor.getMetrics(&m); + valid = valid && shtc3Sensor.getMetrics(m); hasSensor = true; } if (bmp085Sensor.hasSensor()) { - valid = valid && bmp085Sensor.getMetrics(&m); + valid = valid && bmp085Sensor.getMetrics(m); hasSensor = true; } if (bmp280Sensor.hasSensor()) { - valid = valid && bmp280Sensor.getMetrics(&m); + valid = valid && bmp280Sensor.getMetrics(m); hasSensor = true; } if (bme280Sensor.hasSensor()) { - valid = valid && bme280Sensor.getMetrics(&m); + valid = valid && bme280Sensor.getMetrics(m); hasSensor = true; } if (bme680Sensor.hasSensor()) { - valid = valid && bme680Sensor.getMetrics(&m); + valid = valid && bme680Sensor.getMetrics(m); hasSensor = true; } if (mcp9808Sensor.hasSensor()) { - valid = valid && mcp9808Sensor.getMetrics(&m); + valid = valid && mcp9808Sensor.getMetrics(m); hasSensor = true; } if (ina219Sensor.hasSensor()) { - valid = valid && ina219Sensor.getMetrics(&m); + valid = valid && ina219Sensor.getMetrics(m); hasSensor = true; } if (ina260Sensor.hasSensor()) { - valid = valid && ina260Sensor.getMetrics(&m); + valid = valid && ina260Sensor.getMetrics(m); hasSensor = true; } if (veml7700Sensor.hasSensor()) { - valid = valid && veml7700Sensor.getMetrics(&m); + valid = valid && veml7700Sensor.getMetrics(m); hasSensor = true; } if (tsl2591Sensor.hasSensor()) { - valid = valid && tsl2591Sensor.getMetrics(&m); + valid = valid && tsl2591Sensor.getMetrics(m); hasSensor = true; } if (opt3001Sensor.hasSensor()) { - valid = valid && opt3001Sensor.getMetrics(&m); + valid = valid && opt3001Sensor.getMetrics(m); hasSensor = true; } if (mlx90632Sensor.hasSensor()) { - valid = valid && mlx90632Sensor.getMetrics(&m); + valid = valid && mlx90632Sensor.getMetrics(m); hasSensor = true; } if (rcwl9620Sensor.hasSensor()) { - valid = valid && rcwl9620Sensor.getMetrics(&m); + valid = valid && rcwl9620Sensor.getMetrics(m); hasSensor = true; } if (nau7802Sensor.hasSensor()) { - valid = valid && nau7802Sensor.getMetrics(&m); + valid = valid && nau7802Sensor.getMetrics(m); hasSensor = true; } if (aht10Sensor.hasSensor()) { if (!bmp280Sensor.hasSensor()) { - valid = valid && aht10Sensor.getMetrics(&m); + valid = valid && aht10Sensor.getMetrics(m); hasSensor = true; } else { // prefer bmp280 temp if both sensors are present, fetch only humidity meshtastic_Telemetry m_ahtx = meshtastic_Telemetry_init_zero; LOG_INFO("AHTX0+BMP280 module detected: using temp from BMP280 and humy from AHTX0\n"); aht10Sensor.getMetrics(&m_ahtx); - m.variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity; + m->variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity; } } - valid = valid && hasSensor; + return valid && hasSensor; +} + +meshtastic_MeshPacket *EnvironmentTelemetryModule::allocReply() +{ + if (currentRequest) { + auto req = *currentRequest; + const auto &p = req.decoded; + meshtastic_Telemetry scratch; + meshtastic_Telemetry *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { + decoded = &scratch; + } else { + LOG_ERROR("Error decoding EnvironmentTelemetry module!\n"); + return NULL; + } + // Check for a request for environment metrics + if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) { + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getEnvironmentTelemetry(&m)) { + LOG_INFO("Environment telemetry replying to request\n"); + return allocDataProtobuf(m); + } else { + return NULL; + } + } + } + return NULL; +} - if (valid) { +bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +{ + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getEnvironmentTelemetry(&m)) { LOG_INFO("(Sending): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f\n", m.variant.environment_metrics.barometric_pressure, m.variant.environment_metrics.current, m.variant.environment_metrics.gas_resistance, m.variant.environment_metrics.relative_humidity, @@ -399,8 +430,9 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) setIntervalFromNow(5000); } } + return true; } - return valid; + return false; } AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule(const meshtastic_MeshPacket &mp, diff --git a/src/modules/Telemetry/EnvironmentTelemetry.h b/src/modules/Telemetry/EnvironmentTelemetry.h index ca150347e7..ced617c2fc 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.h +++ b/src/modules/Telemetry/EnvironmentTelemetry.h @@ -32,6 +32,11 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override; virtual int32_t runOnce() override; + /** Called to get current Environment telemetry data + @return true if it contains valid data + */ + bool getEnvironmentTelemetry(meshtastic_Telemetry *m); + virtual meshtastic_MeshPacket *allocReply() override; /** * Send our Telemetry into the mesh */ diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index 826de8a4ab..cb864f4f3c 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -163,29 +163,63 @@ bool PowerTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &m return false; // Let others look at this message also if they want } -bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +bool PowerTelemetryModule::getPowerTelemetry(meshtastic_Telemetry *m) { - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; bool valid = false; - m.time = getTime(); - m.which_variant = meshtastic_Telemetry_power_metrics_tag; - - m.variant.power_metrics.ch1_voltage = 0; - m.variant.power_metrics.ch1_current = 0; - m.variant.power_metrics.ch2_voltage = 0; - m.variant.power_metrics.ch2_current = 0; - m.variant.power_metrics.ch3_voltage = 0; - m.variant.power_metrics.ch3_current = 0; + m->time = getTime(); + m->which_variant = meshtastic_Telemetry_power_metrics_tag; + + m->variant.power_metrics.ch1_voltage = 0; + m->variant.power_metrics.ch1_current = 0; + m->variant.power_metrics.ch2_voltage = 0; + m->variant.power_metrics.ch2_current = 0; + m->variant.power_metrics.ch3_voltage = 0; + m->variant.power_metrics.ch3_current = 0; #if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) if (ina219Sensor.hasSensor()) - valid = ina219Sensor.getMetrics(&m); + valid = ina219Sensor.getMetrics(m); if (ina260Sensor.hasSensor()) - valid = ina260Sensor.getMetrics(&m); + valid = ina260Sensor.getMetrics(m); if (ina3221Sensor.hasSensor()) - valid = ina3221Sensor.getMetrics(&m); + valid = ina3221Sensor.getMetrics(m); #endif - if (valid) { + return valid; +} + +meshtastic_MeshPacket *PowerTelemetryModule::allocReply() +{ + if (currentRequest) { + auto req = *currentRequest; + const auto &p = req.decoded; + meshtastic_Telemetry scratch; + meshtastic_Telemetry *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { + decoded = &scratch; + } else { + LOG_ERROR("Error decoding PowerTelemetry module!\n"); + return NULL; + } + // Check for a request for power metrics + if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) { + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getPowerTelemetry(&m)) { + LOG_INFO("Power telemetry replying to request\n"); + return allocDataProtobuf(m); + } else { + return NULL; + } + } + } + + return NULL; +} + +bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +{ + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getPowerTelemetry(&m)) { LOG_INFO("(Sending): ch1_voltage=%f, ch1_current=%f, ch2_voltage=%f, ch2_current=%f, " "ch3_voltage=%f, ch3_current=%f\n", m.variant.power_metrics.ch1_voltage, m.variant.power_metrics.ch1_current, m.variant.power_metrics.ch2_voltage, @@ -218,8 +252,9 @@ bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) setIntervalFromNow(5000); } } + return true; } - return valid; + return false; } #endif \ No newline at end of file diff --git a/src/modules/Telemetry/PowerTelemetry.h b/src/modules/Telemetry/PowerTelemetry.h index 3d6b686f22..1b68847dba 100644 --- a/src/modules/Telemetry/PowerTelemetry.h +++ b/src/modules/Telemetry/PowerTelemetry.h @@ -33,6 +33,11 @@ class PowerTelemetryModule : private concurrency::OSThread, public ProtobufModul */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override; virtual int32_t runOnce() override; + /** Called to get current Power telemetry data + @return true if it contains valid data + */ + bool getPowerTelemetry(meshtastic_Telemetry *m); + virtual meshtastic_MeshPacket *allocReply() override; /** * Send our Telemetry into the mesh */ diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index e6712871d0..0bae515dfa 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -66,10 +66,6 @@ bool PaxcounterModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, m meshtastic_MeshPacket *PaxcounterModule::allocReply() { - if (ignoreRequest) { - return NULL; - } - meshtastic_Paxcount pl = meshtastic_Paxcount_init_default; pl.wifi = count_from_libpax.wifi_count; pl.ble = count_from_libpax.ble_count; @@ -131,4 +127,4 @@ void PaxcounterModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state } #endif // HAS_SCREEN -#endif +#endif \ No newline at end of file From 2e0d96cecebc9b2aa09238ed6d26bb1a66c1c5bb Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 23 Jun 2024 07:54:13 -0500 Subject: [PATCH 084/211] Esptool is better --- variants/tlora_t3s3_v1/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/tlora_t3s3_v1/platformio.ini b/variants/tlora_t3s3_v1/platformio.ini index 002b2f224a..0a57972803 100644 --- a/variants/tlora_t3s3_v1/platformio.ini +++ b/variants/tlora_t3s3_v1/platformio.ini @@ -2,7 +2,7 @@ extends = esp32s3_base board = tlora-t3s3-v1 board_check = true -upload_protocol = esp-builtin +upload_protocol = esptool build_flags = ${esp32_base.build_flags} -D TLORA_T3S3_V1 -I variants/tlora_t3s3_v1 From f5098dc6d82e1a582a810e225d4f0aa1ddee8617 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 23 Jun 2024 14:47:25 -0500 Subject: [PATCH 085/211] Explicitly set characteristic --- src/nimble/NimbleBluetooth.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index b70420c8a0..48f945b0a8 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -180,7 +180,8 @@ void NimbleBluetooth::setupService() ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE); FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ); fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ); - logRadioCharacteristic = bleService->createCharacteristic(LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ); + logRadioCharacteristic = + bleService->createCharacteristic(LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ, 512U); } else { ToRadioCharacteristic = bleService->createCharacteristic( TORADIO_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_AUTHEN | NIMBLE_PROPERTY::WRITE_ENC); @@ -189,9 +190,10 @@ void NimbleBluetooth::setupService() fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC); - logRadioCharacteristic = - bleService->createCharacteristic(LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | - NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC); + logRadioCharacteristic = bleService->createCharacteristic( + LOGRADIO_UUID, + NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC, 512U); + logRadioCharacteristic->setValue("Init"); } bluetoothPhoneAPI = new BluetoothPhoneAPI(); @@ -245,7 +247,7 @@ void NimbleBluetooth::sendLog(const char *logMessage) if (!bleServer || !isConnected() || strlen(logMessage) > 512) { return; } - logRadioCharacteristic->notify(reinterpret_cast(logMessage), strlen(logMessage)); + logRadioCharacteristic->notify(reinterpret_cast(logMessage), strlen(logMessage), true); } void clearNVS() From 23ac6b65141914496ba108580cf0377f538db2e4 Mon Sep 17 00:00:00 2001 From: Warren Guy <5602790+warrenguy@users.noreply.github.com> Date: Sun, 23 Jun 2024 21:40:13 +0100 Subject: [PATCH 086/211] fix INA3221 sensor (#4168) - pass wire to begin() - remove redundant setAddr() (already set in header) --- src/modules/Telemetry/Sensor/INA3221Sensor.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp index ea2cb4ea8c..edd29682e0 100644 --- a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp +++ b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp @@ -16,8 +16,7 @@ int32_t INA3221Sensor::runOnce() return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; } if (!status) { - ina3221.setAddr(INA3221_ADDR42_SDA); // i2c address 0x42 - ina3221.begin(); + ina3221.begin(nodeTelemetrySensorsMap[sensorType].second); ina3221.setShuntRes(100, 100, 100); // 0.1 Ohm shunt resistors status = true; } else { From 64531fa1ae057f4128a65441766ad9eedaecb6b7 Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Mon, 24 Jun 2024 19:04:46 +1200 Subject: [PATCH 087/211] Show compass on waypoint frame; clear when waypoint deleted (#4116) * Clear expired or deleted waypoint frame * Return 0 to CallbackObserver * Add a missing comment * Draw compass for waypoint frame * Display our own waypoints --- src/graphics/Screen.cpp | 251 +++++++++++++++++++++++++++++----------- src/graphics/Screen.h | 3 + 2 files changed, 186 insertions(+), 68 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 60168cffcf..eb92d824e7 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -43,6 +43,7 @@ along with this program. If not, see . #include "meshUtils.h" #include "modules/ExternalNotificationModule.h" #include "modules/TextMessageModule.h" +#include "modules/WaypointModule.h" #include "sleep.h" #include "target_specific.h" @@ -59,6 +60,9 @@ along with this program. If not, see . #include "platform/portduino/PortduinoGlue.h" #endif +/// Convert an integer GPS coords to a floating point +#define DegD(i) (i * 1e-7) + using namespace meshtastic; /** @todo remove */ namespace graphics @@ -446,6 +450,37 @@ static bool shouldDrawMessage(const meshtastic_MeshPacket *packet) return packet->from != 0 && !moduleConfig.store_forward.enabled; } +// Determine whether the waypoint frame should be drawn (waypoint deleted? expired?) +static bool shouldDrawWaypoint(const meshtastic_MeshPacket *packet) +{ +#if !MESHTASTIC_EXCLUDE_WAYPOINT + // If no waypoint to show + if (!devicestate.has_rx_waypoint) + return false; + + // Decode the message, to find the expiration time (is waypoint still valid) + // This handles "deletion" as well as expiration + meshtastic_Waypoint wp; + memset(&wp, 0, sizeof(wp)); + if (pb_decode_from_bytes(packet->decoded.payload.bytes, packet->decoded.payload.size, &meshtastic_Waypoint_msg, &wp)) { + // Valid waypoint + if (wp.expire > getTime()) + return devicestate.has_rx_waypoint = true; + + // Expired, or deleted + else + return devicestate.has_rx_waypoint = false; + } + + // If decoding failed + LOG_ERROR("Failed to decode waypoint\n"); + devicestate.has_rx_waypoint = false; + return false; +#else + return false; +#endif +} + // Draw power bars or a charging indicator on an image of a battery, determined by battery charge voltage or percentage. static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, const PowerStatus *powerStatus) { @@ -1091,43 +1126,6 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state #endif } -/// Draw the last waypoint we received -static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -{ - static char tempBuf[237]; - - meshtastic_MeshPacket &mp = devicestate.rx_waypoint; - meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp)); - - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(FONT_SMALL); - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { - display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); - display->setColor(BLACK); - } - - uint32_t seconds = sinceReceived(&mp); - uint32_t minutes = seconds / 60; - uint32_t hours = minutes / 60; - uint32_t days = hours / 24; - - if (config.display.heading_bold) { - display->drawStringf(1 + x, 0 + y, tempBuf, "%s ago from %s", - screen->drawTimeDelta(days, hours, minutes, seconds).c_str(), - (node && node->has_user) ? node->user.short_name : "???"); - } - display->drawStringf(0 + x, 0 + y, tempBuf, "%s ago from %s", screen->drawTimeDelta(days, hours, minutes, seconds).c_str(), - (node && node->has_user) ? node->user.short_name : "???"); - - display->setColor(WHITE); - meshtastic_Waypoint scratch; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) { - snprintf(tempBuf, sizeof(tempBuf), "Received waypoint: %s", scratch.name); - display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf); - } -} - /// Draw a series of fields in a column, wrapping to multiple columns if needed static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields) { @@ -1453,8 +1451,35 @@ static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t com drawLine(display, N1, N4); } -/// Convert an integer GPS coords to a floating point -#define DegD(i) (i * 1e-7) +// Get a string representation of the time passed since something happened +static void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength) +{ + // Use an absolute timestamp in some cases. + // Particularly useful with E-Ink displays. Static UI, fewer refreshes. + uint8_t timestampHours, timestampMinutes; + int32_t daysAgo; + bool useTimestamp = deltaToTimestamp(agoSecs, ×tampHours, ×tampMinutes, &daysAgo); + + if (agoSecs < 120) // last 2 mins? + snprintf(timeStr, maxLength, "%u seconds ago", agoSecs); + // -- if suitable for timestamp -- + else if (useTimestamp && agoSecs < 15 * SECONDS_IN_MINUTE) // Last 15 minutes + snprintf(timeStr, maxLength, "%u minutes ago", agoSecs / SECONDS_IN_MINUTE); + else if (useTimestamp && daysAgo == 0) // Today + snprintf(timeStr, maxLength, "Last seen: %02u:%02u", (unsigned int)timestampHours, (unsigned int)timestampMinutes); + else if (useTimestamp && daysAgo == 1) // Yesterday + snprintf(timeStr, maxLength, "Seen yesterday"); + else if (useTimestamp && daysAgo > 1) // Last six months (capped by deltaToTimestamp method) + snprintf(timeStr, maxLength, "%li days ago", (long)daysAgo); + // -- if using time delta instead -- + else if (agoSecs < 120 * 60) // last 2 hrs + snprintf(timeStr, maxLength, "%u minutes ago", agoSecs / 60); + // Only show hours ago if it's been less than 6 months. Otherwise, we may have bad data. + else if ((agoSecs / 60 / 60) < (hours_in_month * 6)) + snprintf(timeStr, maxLength, "%u hours ago", agoSecs / 60 / 60); + else + snprintf(timeStr, maxLength, "unknown age"); +} static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { @@ -1494,34 +1519,8 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ snprintf(signalStr, sizeof(signalStr), "Signal: %d%%", clamp((int)((node->snr + 10) * 5), 0, 100)); } - uint32_t agoSecs = sinceLastSeen(node); static char lastStr[20]; - - // Use an absolute timestamp in some cases. - // Particularly useful with E-Ink displays. Static UI, fewer refreshes. - uint8_t timestampHours, timestampMinutes; - int32_t daysAgo; - bool useTimestamp = deltaToTimestamp(agoSecs, ×tampHours, ×tampMinutes, &daysAgo); - - if (agoSecs < 120) // last 2 mins? - snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs); - // -- if suitable for timestamp -- - else if (useTimestamp && agoSecs < 15 * SECONDS_IN_MINUTE) // Last 15 minutes - snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / SECONDS_IN_MINUTE); - else if (useTimestamp && daysAgo == 0) // Today - snprintf(lastStr, sizeof(lastStr), "Last seen: %02u:%02u", (unsigned int)timestampHours, (unsigned int)timestampMinutes); - else if (useTimestamp && daysAgo == 1) // Yesterday - snprintf(lastStr, sizeof(lastStr), "Seen yesterday"); - else if (useTimestamp && daysAgo > 1) // Last six months (capped by deltaToTimestamp method) - snprintf(lastStr, sizeof(lastStr), "%li days ago", (long)daysAgo); - // -- if using time delta instead -- - else if (agoSecs < 120 * 60) // last 2 hrs - snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60); - // Only show hours ago if it's been less than 6 months. Otherwise, we may have bad data. - else if ((agoSecs / 60 / 60) < (hours_in_month * 6)) - snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60); - else - snprintf(lastStr, sizeof(lastStr), "unknown age"); + getTimeAgoStr(sinceLastSeen(node), lastStr, sizeof(lastStr)); static char distStr[20]; if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) { @@ -1596,6 +1595,112 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ drawColumns(display, x, y, fields); } +/// Draw the last waypoint we received +static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + // Prepare to draw + display->setFont(FONT_SMALL); + display->setTextAlignment(TEXT_ALIGN_LEFT); + + // Handle inverted display + // Unsure of expected behavior: for now, copy drawNodeInfo + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) + display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); + + // Decode the waypoint + meshtastic_MeshPacket &mp = devicestate.rx_waypoint; + meshtastic_Waypoint wp; + memset(&wp, 0, sizeof(wp)); + if (!pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &wp)) { + // This *should* be caught by shouldDrawWaypoint, but we'll short-circuit here just in case + display->drawStringMaxWidth(0 + x, 0 + y, x + display->getWidth(), "Couldn't decode waypoint"); + devicestate.has_rx_waypoint = false; + return; + } + + // Get timestamp info. Will pass as a field to drawColumns + static char lastStr[20]; + getTimeAgoStr(sinceReceived(&mp), lastStr, sizeof(lastStr)); + + // Will contain distance information, passed as a field to drawColumns + static char distStr[20]; + + // Get our node, to use our own position + meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); + + // Text fields to draw (left of compass) + // Last element must be NULL. This signals the end of the char*[] to drawColumns + const char *fields[] = {"Waypoint", lastStr, wp.name, distStr, NULL}; + + // Co-ordinates for the center of the compass/circle + int16_t compassX = 0, compassY = 0; + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { + compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5; + compassY = y + SCREEN_HEIGHT / 2; + } else { + compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5; + compassY = y + FONT_HEIGHT_SMALL + (SCREEN_HEIGHT - FONT_HEIGHT_SMALL) / 2; + } + + // If our node has a position: + if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) { + const meshtastic_PositionLite &op = ourNode->position; + float myHeading; + if (screen->hasHeading()) + myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians + else + myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); + drawCompassNorth(display, compassX, compassY, myHeading); + + // Distance to Waypoint + float d = GeoCoord::latLongToMeter(DegD(wp.latitude_i), DegD(wp.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i)); + if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) { + if (d < (2 * MILES_TO_FEET)) + snprintf(distStr, sizeof(distStr), "%.0f ft", d * METERS_TO_FEET); + else + snprintf(distStr, sizeof(distStr), "%.1f mi", d * METERS_TO_FEET / MILES_TO_FEET); + } else { + if (d < 2000) + snprintf(distStr, sizeof(distStr), "%.0f m", d); + else + snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000); + } + + // Compass bearing to waypoint + float bearingToOther = + GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(wp.latitude_i), DegD(wp.longitude_i)); + // If the top of the compass is a static north then bearingToOther can be drawn on the compass directly + // If the top of the compass is not a static north we need adjust bearingToOther based on heading + if (!config.display.compass_north_top) + bearingToOther -= myHeading; + drawNodeHeading(display, compassX, compassY, bearingToOther); + } + + // If our node doesn't have position + else { + // ? in the compass + display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?"); + + // ? in the distance field + if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) + strncpy(distStr, "? mi", sizeof(distStr)); + else + strncpy(distStr, "? km", sizeof(distStr)); + } + + // Undo color-inversion, if set prior to drawing header + // Unsure of expected behavior? For now: copy drawNodeInfo + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { + display->setColor(BLACK); + } + + // Draw compass circle + display->drawCircle(compassX, compassY, getCompassDiam(display) / 2); + + // Must be after distStr is populated + drawColumns(display, x, y, fields); +} + Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry) : concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32) { @@ -1806,6 +1911,8 @@ void Screen::setup() textMessageObserver.observe(textMessageModule); if (inputBroker) inputObserver.observe(inputBroker); + if (waypointModule) + waypointObserver.observe(waypointModule); // Modules can notify screen about refresh MeshModule::observeUIEvents(&uiFrameEventObserver); @@ -2133,8 +2240,9 @@ void Screen::setFrames() if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) { normalFrames[numframes++] = drawTextMessageFrame; } - // If we have a waypoint - show it next, unless it's a phone message and we aren't using any special modules - if (devicestate.has_rx_waypoint && shouldDrawMessage(&devicestate.rx_waypoint)) { + + // If we have a waypoint (not expired, not deleted) + if (devicestate.has_rx_waypoint && shouldDrawWaypoint(&devicestate.rx_waypoint)) { normalFrames[numframes++] = drawWaypointFrame; } @@ -2736,6 +2844,13 @@ int Screen::handleInputEvent(const InputEvent *event) return 0; } +int Screen::handleWaypoint(const meshtastic_MeshPacket *arg) +{ + // TODO: move to appropriate frame when redrawing + setFrames(); + return 0; +} + } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index f4d7197152..b1bbffc3b2 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -126,6 +126,8 @@ class Screen : public concurrency::OSThread CallbackObserver(this, &Screen::handleStatusUpdate); CallbackObserver textMessageObserver = CallbackObserver(this, &Screen::handleTextMessage); + CallbackObserver waypointObserver = + CallbackObserver(this, &Screen::handleWaypoint); CallbackObserver uiFrameEventObserver = CallbackObserver(this, &Screen::handleUIFrameEvent); CallbackObserver inputObserver = @@ -336,6 +338,7 @@ class Screen : public concurrency::OSThread int handleTextMessage(const meshtastic_MeshPacket *arg); int handleUIFrameEvent(const UIFrameEvent *arg); int handleInputEvent(const InputEvent *arg); + int handleWaypoint(const meshtastic_MeshPacket *arg); /// Used to force (super slow) eink displays to draw critical frames void forceDisplay(bool forceUiUpdate = false); From 58c00d044776d0d9fd5b71a78ce7b2dfbec68cd1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 08:01:40 -0500 Subject: [PATCH 088/211] [create-pull-request] automated change (#4171) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 268987418b..1cb93ac2bf 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 14 +build = 15 From aa12e28568b28d471acb5b594c084eebaf0d6037 Mon Sep 17 00:00:00 2001 From: geeksville Date: Mon, 24 Jun 2024 08:27:37 -0700 Subject: [PATCH 089/211] Add semihosting support for nrf52 devices (#4137) * Turn off vscode cmake prompt - we don't use cmake on meshtastic * Add rak4631_dap variant for debugging with NanoDAP debug probe device. * The rak device can also run freertos (which is underneath nrf52 arduino) * Add semihosting support for nrf52840 devices Initial platformio.ini file only supports rak4630 Default to non TCP for the semihosting log output for now... Fixes https://github.com/meshtastic/firmware/issues/4135 * fix my botched merge - keep board_level = extra flag for rak3631_dbg --------- Co-authored-by: Ben Meadors --- boards/wiscore_rak4631.json | 2 +- pyocd.yaml | 7 +++ src/DebugConfiguration.h | 8 +++ src/platform/nrf52/main-nrf52.cpp | 32 ++++++++++- variants/rak4631/platformio.ini | 91 +++++++++++++++++++++++++++---- 5 files changed, 126 insertions(+), 14 deletions(-) create mode 100644 pyocd.yaml diff --git a/boards/wiscore_rak4631.json b/boards/wiscore_rak4631.json index 6dec3f7cb4..c783f33a69 100644 --- a/boards/wiscore_rak4631.json +++ b/boards/wiscore_rak4631.json @@ -35,7 +35,7 @@ "svd_path": "nrf52840.svd", "openocd_target": "nrf52840-mdk-rs" }, - "frameworks": ["arduino"], + "frameworks": ["arduino", "freertos"], "name": "WisCore RAK4631 Board", "upload": { "maximum_ram_size": 248832, diff --git a/pyocd.yaml b/pyocd.yaml new file mode 100644 index 0000000000..84bd9336b9 --- /dev/null +++ b/pyocd.yaml @@ -0,0 +1,7 @@ +# This is a config file to control pyocd ICE debugger probe options (only used for NRF52 targets with hardware debugging connections) +# for more info see FIXMEURL + +# console or telnet +semihost_console_type: telnet +enable_semihosting: True +telnet_port: 4444 diff --git a/src/DebugConfiguration.h b/src/DebugConfiguration.h index ca908197ed..874d63bca1 100644 --- a/src/DebugConfiguration.h +++ b/src/DebugConfiguration.h @@ -25,6 +25,14 @@ #include "SerialConsole.h" +// If defined we will include support for ARM ICE "semihosting" for a virtual +// console over the JTAG port (to replace the normal serial port) +// Note: Normally this flag is passed into the gcc commandline by platformio.ini. +// for an example see env:rak4631_dap. +// #ifndef USE_SEMIHOSTING +// #define USE_SEMIHOSTING +// #endif + #define DEBUG_PORT (*console) // Serial debug port #ifdef USE_SEGGER diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 1f2c6867d5..86575bda6f 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -149,13 +149,43 @@ void nrf52Loop() checkSDEvents(); } +#ifdef USE_SEMIHOSTING +#include + +/** + * Note: this variable is in BSS and therfore false by default. But the gdbinit + * file will be installing a temporary breakpoint that changes wantSemihost to true. + */ +bool wantSemihost; + +/** + * Turn on semihosting if the ICE debugger wants it. + */ +void nrf52InitSemiHosting() +{ + if (wantSemihost) { + static SemihostingStream semiStream; + // We must dynamically alloc because the constructor does semihost operations which + // would crash any load not talking to a debugger + semiStream.open(); + semiStream.println("Semihosting starts!"); + // Redirect our serial output to instead go via the ICE port + console->setDestination(&semiStream); + } +} +#endif + void nrf52Setup() { - auto why = NRF_POWER->RESETREAS; + uint32_t why = NRF_POWER->RESETREAS; // per // https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpower.html LOG_DEBUG("Reset reason: 0x%x\n", why); +#ifdef USE_SEMIHOSTING + nrf52InitSemiHosting(); +#endif + // Per // https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/monitor-mode-debugging-with-j-link-and-gdbeclipse // This is the recommended setting for Monitor Mode Debugging diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index ef3e5a6458..beffa7d3df 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -20,6 +20,7 @@ lib_deps = debug_tool = jlink + ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds ;upload_protocol = jlink @@ -27,26 +28,92 @@ debug_tool = jlink ; Allows programming and debug via the RAK NanoDAP as the default debugger tool for the RAK4631 (it is only $10!) ; programming time is about the same as the bootloader version. ; For information on this see the meshtastic developers documentation for "Development on the NRF52" -[env:rak4631_dap] +[env:rak4631_dbg] extends = env:rak4631 board_level = extra -; pyocd pack --i nrf52840 + +; if the builtin version of openocd has a buggy version of semihosting, so use the external version +; platform_packages = platformio/tool-openocd@^3.1200.0 + +build_flags = + ${env:rak4631.build_flags} + -D USE_SEMIHOSTING + +lib_deps = + ${env:rak4631.lib_deps} + https://github.com/geeksville/Armduino-Semihosting.git#35b538fdf208c3530c1434cd099a08e486672ee4 + +; NOTE: the pyocd support for semihosting is buggy. So I switched to using the builtin platformio support for the stlink adapter which worked much better. +; However the built in openocd version in platformio has buggy support for TCP to semihosting. +; +; So I'm now trying the external openocd - but the openocd scripts for nrf52.cfg assume you are using a DAP adapter not an STLINK adapter. +; In theory I could change those scripts. But for now I'm trying going back to a DAP adapter but with the external openocd. + +upload_protocol = stlink ; eventually use platformio/tool-pyocd@^2.3600.0 instad -upload_protocol = custom -upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE +;upload_protocol = custom +;upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE + +; We want the initial breakpoint at setup() instead of main(). Also we want to enable semihosting at that point so instead of +; debug_init_break = tbreak setup +; we just turn off the platformio tbreak and do it in .gdbinit (where we have more flexibility for scripting) +; also we use a permanent breakpoint so it gets reused each time we restart the debugging session? +debug_init_break = tbreak setup + +; Note: add "monitor arm semihosting_redirect tcp 4444 all" if you want the stdout from the device to go to that port number instead +; (for use by meshtastic command line) +; monitor arm semihosting disable +; monitor debug_level 3 +; +; IMPORTANT: fileio must be disabled before using port 5555 - openocd ver 0.12 has a bug where if enabled it never properly parses the special :tt name +; for stdio access. +; monitor arm semihosting_redirect tcp 5555 stdio + +; Also note: it is _impossible_ to do non blocking reads on the semihost console port (an oversight when ARM specified the semihost API). +; So we'll neve be able to general purpose bi-directional communication with the device over semihosting. +debug_extra_cmds = + echo Running .gdbinit script + monitor arm semihosting enable + monitor arm semihosting_fileio enable + monitor arm semihosting_redirect disable + commands 1 + echo Breakpoint at setup() has semihosting console, connect to it with "telnet localhost 5555" + set wantSemihost = true + end + ; Only reprogram the board if the code has changed debug_load_mode = modified ;debug_load_mode = manual -debug_tool = custom +debug_tool = stlink +;debug_tool = custom +; debug_server = +; openocd +; -f +; /usr/local/share/openocd/scripts/interface/stlink.cfg +; -f +; /usr/local/share/openocd/scripts/target/nrf52.cfg +; $PLATFORMIO_CORE_DIR/packages/tool-openocd/openocd/scripts/interface/cmsis-dap.cfg + +; Allows programming and debug via the RAK NanoDAP as the default debugger tool for the RAK4631 (it is only $10!) +; programming time is about the same as the bootloader version. +; For information on this see the meshtastic developers documentation for "Development on the NRF52" ; We manually pass in the elf file so that pyocd can reverse engineer FreeRTOS data (running threads, etc...) -debug_server = - pyocd - gdbserver - -t - nrf52840 - --elf - ${platformio.build_dir}/${this.__env__}/firmware.elf +;debug_server = +; pyocd +; gdbserver +; -j +; ${platformio.workspace_dir}/.. +; -t +; nrf52840 +; --semihosting +; --elf +; ${platformio.build_dir}/${this.__env__}/firmware.elf + +; If you want to debug the semihosting support you can turn on extra logging in pyocd with +; -L +; pyocd.debug.semihost.trace=debug + ; The following is not needed because it automatically tries do this ;debug_server_ready_pattern = -.*GDB server started on port \d+.* ;debug_port = localhost:3333 \ No newline at end of file From 626aa762df18ea2deab5a1a8a350a65e5c5977b8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 20:27:00 -0500 Subject: [PATCH 090/211] [create-pull-request] automated change (#4174) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.cpp | 3 +++ src/mesh/generated/meshtastic/mesh.pb.h | 29 ++++++++++++++++++++++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/protobufs b/protobufs index 4da558d0f7..a3030d5ff1 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 4da558d0f73c46ef91b74431facee73c09affbfc +Subproject commit a3030d5ff187091c9fbbd08dd797cca5085736fe diff --git a/src/mesh/generated/meshtastic/mesh.pb.cpp b/src/mesh/generated/meshtastic/mesh.pb.cpp index 46d59d6094..d4ad9186aa 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.cpp +++ b/src/mesh/generated/meshtastic/mesh.pb.cpp @@ -45,6 +45,9 @@ PB_BIND(meshtastic_QueueStatus, meshtastic_QueueStatus, AUTO) PB_BIND(meshtastic_FromRadio, meshtastic_FromRadio, 2) +PB_BIND(meshtastic_FileInfo, meshtastic_FileInfo, AUTO) + + PB_BIND(meshtastic_ToRadio, meshtastic_ToRadio, 2) diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 0641158155..e4e034cbdd 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -711,6 +711,14 @@ typedef struct _meshtastic_QueueStatus { uint32_t mesh_packet_id; } meshtastic_QueueStatus; +/* Individual File info for the device */ +typedef struct _meshtastic_FileInfo { + /* The fully qualified path of the file */ + char file_name[228]; + /* The size of the file in bytes */ + uint32_t size_bytes; +} meshtastic_FileInfo; + typedef PB_BYTES_ARRAY_T(237) meshtastic_Compressed_data_t; /* Compressed message payload */ typedef struct _meshtastic_Compressed { @@ -815,6 +823,8 @@ typedef struct _meshtastic_FromRadio { meshtastic_DeviceMetadata metadata; /* MQTT Client Proxy Message (device sending to client / phone for publishing to MQTT) */ meshtastic_MqttClientProxyMessage mqttClientProxyMessage; + /* File system manifest messages */ + meshtastic_FileInfo fileInfo; }; } meshtastic_FromRadio; @@ -958,6 +968,7 @@ extern "C" { + #define meshtastic_Compressed_portnum_ENUMTYPE meshtastic_PortNum @@ -985,6 +996,7 @@ extern "C" { #define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_default {0, 0, 0, 0} #define meshtastic_FromRadio_init_default {0, 0, {meshtastic_MeshPacket_init_default}} +#define meshtastic_FileInfo_init_default {"", 0} #define meshtastic_ToRadio_init_default {0, {meshtastic_MeshPacket_init_default}} #define meshtastic_Compressed_init_default {_meshtastic_PortNum_MIN, {0, {0}}} #define meshtastic_NeighborInfo_init_default {0, 0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}} @@ -1008,6 +1020,7 @@ extern "C" { #define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_zero {0, 0, 0, 0} #define meshtastic_FromRadio_init_zero {0, 0, {meshtastic_MeshPacket_init_zero}} +#define meshtastic_FileInfo_init_zero {"", 0} #define meshtastic_ToRadio_init_zero {0, {meshtastic_MeshPacket_init_zero}} #define meshtastic_Compressed_init_zero {_meshtastic_PortNum_MIN, {0, {0}}} #define meshtastic_NeighborInfo_init_zero {0, 0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}} @@ -1110,6 +1123,8 @@ extern "C" { #define meshtastic_QueueStatus_free_tag 2 #define meshtastic_QueueStatus_maxlen_tag 3 #define meshtastic_QueueStatus_mesh_packet_id_tag 4 +#define meshtastic_FileInfo_file_name_tag 1 +#define meshtastic_FileInfo_size_bytes_tag 2 #define meshtastic_Compressed_portnum_tag 1 #define meshtastic_Compressed_data_tag 2 #define meshtastic_Neighbor_node_id_tag 1 @@ -1144,6 +1159,7 @@ extern "C" { #define meshtastic_FromRadio_xmodemPacket_tag 12 #define meshtastic_FromRadio_metadata_tag 13 #define meshtastic_FromRadio_mqttClientProxyMessage_tag 14 +#define meshtastic_FromRadio_fileInfo_tag 15 #define meshtastic_ToRadio_packet_tag 1 #define meshtastic_ToRadio_want_config_id_tag 3 #define meshtastic_ToRadio_disconnect_tag 4 @@ -1321,7 +1337,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,queueStatus,queueStatus), 11) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 12) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,metadata,metadata), 13) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 14) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 14) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,fileInfo,fileInfo), 15) #define meshtastic_FromRadio_CALLBACK NULL #define meshtastic_FromRadio_DEFAULT NULL #define meshtastic_FromRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket @@ -1335,6 +1352,13 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttC #define meshtastic_FromRadio_payload_variant_xmodemPacket_MSGTYPE meshtastic_XModem #define meshtastic_FromRadio_payload_variant_metadata_MSGTYPE meshtastic_DeviceMetadata #define meshtastic_FromRadio_payload_variant_mqttClientProxyMessage_MSGTYPE meshtastic_MqttClientProxyMessage +#define meshtastic_FromRadio_payload_variant_fileInfo_MSGTYPE meshtastic_FileInfo + +#define meshtastic_FileInfo_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, file_name, 1) \ +X(a, STATIC, SINGULAR, UINT32, size_bytes, 2) +#define meshtastic_FileInfo_CALLBACK NULL +#define meshtastic_FileInfo_DEFAULT NULL #define meshtastic_ToRadio_FIELDLIST(X, a) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \ @@ -1434,6 +1458,7 @@ extern const pb_msgdesc_t meshtastic_MyNodeInfo_msg; extern const pb_msgdesc_t meshtastic_LogRecord_msg; extern const pb_msgdesc_t meshtastic_QueueStatus_msg; extern const pb_msgdesc_t meshtastic_FromRadio_msg; +extern const pb_msgdesc_t meshtastic_FileInfo_msg; extern const pb_msgdesc_t meshtastic_ToRadio_msg; extern const pb_msgdesc_t meshtastic_Compressed_msg; extern const pb_msgdesc_t meshtastic_NeighborInfo_msg; @@ -1459,6 +1484,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_LogRecord_fields &meshtastic_LogRecord_msg #define meshtastic_QueueStatus_fields &meshtastic_QueueStatus_msg #define meshtastic_FromRadio_fields &meshtastic_FromRadio_msg +#define meshtastic_FileInfo_fields &meshtastic_FileInfo_msg #define meshtastic_ToRadio_fields &meshtastic_ToRadio_msg #define meshtastic_Compressed_fields &meshtastic_Compressed_msg #define meshtastic_NeighborInfo_fields &meshtastic_NeighborInfo_msg @@ -1478,6 +1504,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_Compressed_size 243 #define meshtastic_Data_size 270 #define meshtastic_DeviceMetadata_size 46 +#define meshtastic_FileInfo_size 236 #define meshtastic_FromRadio_size 510 #define meshtastic_Heartbeat_size 0 #define meshtastic_LogRecord_size 81 From 042555134185b522c00c85f8590a7b1c280601fd Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 25 Jun 2024 11:26:02 -0500 Subject: [PATCH 091/211] Display alerts (#4170) * Move static functions into Screen.h, show compass during calibration * Move to _fontHeight macro to avoid collision * Move some alert functions to new alert handler * Catch missed reboot code * ESP32 fixes * Bump esp8266-oled-ssd1306 * Fixes for when a device has no screen * Use new startAlert(char*) helper class * Add EINK bits back to alert handling * Add noop class for no-display devices --------- Co-authored-by: Ben Meadors --- platformio.ini | 5 +- src/AccelerometerThread.h | 35 +++- src/ButtonThread.cpp | 7 +- src/commands.h | 6 +- src/graphics/Screen.cpp | 166 ++---------------- src/graphics/Screen.h | 136 +++++++++++--- src/graphics/ScreenFonts.h | 8 +- src/main.cpp | 2 +- src/mesh/NodeDB.cpp | 2 +- src/modules/AdminModule.cpp | 6 +- src/modules/CannedMessageModule.cpp | 4 +- .../Telemetry/EnvironmentTelemetry.cpp | 14 +- src/modules/Telemetry/PowerTelemetry.cpp | 12 +- src/nimble/NimbleBluetooth.cpp | 30 +++- src/platform/nrf52/NRF52Bluetooth.cpp | 28 ++- src/shutdown.h | 2 +- 16 files changed, 246 insertions(+), 217 deletions(-) diff --git a/platformio.ini b/platformio.ini index 23ff53a102..720525f095 100644 --- a/platformio.ini +++ b/platformio.ini @@ -80,7 +80,7 @@ monitor_speed = 115200 lib_deps = jgromes/RadioLib@~6.6.0 - https://github.com/meshtastic/esp8266-oled-ssd1306.git#2b40affbe7f7dc63b6c00fa88e7e12ed1f8e1719 ; ESP8266_SSD1306 + https://github.com/meshtastic/esp8266-oled-ssd1306.git#e16cee124fe26490cb14880c679321ad8ac89c95 ; ESP8266_SSD1306 mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4 @@ -150,5 +150,4 @@ lib_deps = mprograms/QMC5883LCompass@^1.2.0 - https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee - + https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee \ No newline at end of file diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h index f45511cca3..0f04de057c 100644 --- a/src/AccelerometerThread.h +++ b/src/AccelerometerThread.h @@ -16,6 +16,8 @@ #include #ifdef RAK_4631 #include "Fusion/Fusion.h" +#include "graphics/Screen.h" +#include "graphics/ScreenFonts.h" #include #endif @@ -101,7 +103,11 @@ class AccelerometerThread : public concurrency::OSThread bmx160.getAllData(&magAccel, NULL, &gAccel); // expirimental calibrate routine. Limited to between 10 and 30 seconds after boot - if (millis() > 10 * 1000 && millis() < 30 * 1000) { + if (millis() > 12 * 1000 && millis() < 30 * 1000) { + if (!showingScreen) { + showingScreen = true; + screen->startAlert((FrameCallback)drawFrameCalibration); + } if (magAccel.x > highestX) highestX = magAccel.x; if (magAccel.x < lowestX) @@ -114,6 +120,9 @@ class AccelerometerThread : public concurrency::OSThread highestZ = magAccel.z; if (magAccel.z < lowestZ) lowestZ = magAccel.z; + } else if (showingScreen && millis() >= 30 * 1000) { + showingScreen = false; + screen->endAlert(); } int highestRealX = highestX - (highestX + lowestX) / 2; @@ -255,11 +264,33 @@ class AccelerometerThread : public concurrency::OSThread Adafruit_LIS3DH lis; Adafruit_LSM6DS3TRC lsm; SensorBMA423 bmaSensor; + bool BMA_IRQ = false; #ifdef RAK_4631 + bool showingScreen = false; RAK_BMX160 bmx160; float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0; + + static void drawFrameCalibration(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) + { + int x_offset = display->width() / 2; + int y_offset = display->height() <= 80 ? 0 : 32; + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(FONT_MEDIUM); + display->drawString(x, y, "Calibrating\nCompass"); + int16_t compassX = 0, compassY = 0; + + // coordinates for the center of the compass/circle + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { + compassX = x + display->getWidth() - getCompassDiam(display) / 2 - 5; + compassY = y + display->getHeight() / 2; + } else { + compassX = x + display->getWidth() - getCompassDiam(display) / 2 - 5; + compassY = y + FONT_HEIGHT_SMALL + (display->getHeight() - FONT_HEIGHT_SMALL) / 2; + } + display->drawCircle(compassX, compassY, getCompassDiam(display) / 2); + drawCompassNorth(display, compassX, compassY, screen->getHeading() * PI / 180); + } #endif - bool BMA_IRQ = false; }; #endif \ No newline at end of file diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index 4b3bb3fbc5..1b85166d21 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -181,8 +181,9 @@ int32_t ButtonThread::runOnce() case BUTTON_EVENT_LONG_PRESSED: { LOG_BUTTON("Long press!\n"); powerFSM.trigger(EVENT_PRESS); - if (screen) - screen->startShutdownScreen(); + if (screen) { + screen->startAlert("Shutting down..."); + } playBeep(); break; } @@ -322,4 +323,4 @@ void ButtonThread::userButtonPressedLongStop() if (millis() > c_holdOffTime) { btnEvent = BUTTON_EVENT_LONG_RELEASED; } -} +} \ No newline at end of file diff --git a/src/commands.h b/src/commands.h index 03ede5982e..f2b7830105 100644 --- a/src/commands.h +++ b/src/commands.h @@ -8,13 +8,11 @@ enum class Cmd { SET_ON, SET_OFF, ON_PRESS, - START_BLUETOOTH_PIN_SCREEN, + START_ALERT_FRAME, + STOP_ALERT_FRAME, START_FIRMWARE_UPDATE_SCREEN, - STOP_BLUETOOTH_PIN_SCREEN, STOP_BOOT_SCREEN, PRINT, - START_SHUTDOWN_SCREEN, - START_REBOOT_SCREEN, SHOW_PREV_FRAME, SHOW_NEXT_FRAME }; \ No newline at end of file diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index eb92d824e7..234381aa5a 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -379,7 +379,7 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int // in the array of "drawScreen" functions; however, // the passed-state doesn't quite reflect the "current" // screen, so we have to detect it. - if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == INCOMING) { + if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == TransitionRelationship_INCOMING) { // if we're transitioning from the end of the frame list back around to the first // frame, then we want this to be `0` module_frame = state->transitionFrameTarget; @@ -393,31 +393,6 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int pi.drawFrame(display, state, x, y); } -static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -{ - int x_offset = display->width() / 2; - int y_offset = display->height() <= 80 ? 0 : 32; - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->setFont(FONT_MEDIUM); - display->drawString(x_offset + x, y_offset + y, "Bluetooth"); - - display->setFont(FONT_SMALL); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5; - display->drawString(x_offset + x, y_offset + y, "Enter this code"); - - display->setFont(FONT_LARGE); - String displayPin(btPIN); - String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5; - display->drawString(x_offset + x, y_offset + y, pin); - - display->setFont(FONT_SMALL); - String deviceName = "Name: "; - deviceName.concat(getDeviceName()); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; - display->drawString(x_offset + x, y_offset + y, deviceName); -} - static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { display->setTextAlignment(TEXT_ALIGN_CENTER); @@ -1307,49 +1282,6 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const } } #endif -namespace -{ - -/// A basic 2D point class for drawing -class Point -{ - public: - float x, y; - - Point(float _x, float _y) : x(_x), y(_y) {} - - /// Apply a rotation around zero (standard rotation matrix math) - void rotate(float radian) - { - float cos = cosf(radian), sin = sinf(radian); - float rx = x * cos + y * sin, ry = -x * sin + y * cos; - - x = rx; - y = ry; - } - - void translate(int16_t dx, int dy) - { - x += dx; - y += dy; - } - - void scale(float f) - { - // We use -f here to counter the flip that happens - // on the y axis when drawing and rotating on screen - x *= f; - y *= -f; - } -}; - -} // namespace - -static void drawLine(OLEDDisplay *d, const Point &p1, const Point &p2) -{ - d->drawLine(p1.x, p1.y, p2.x, p2.y); -} - /** * Given a recent lat/lon return a guess of the heading the user is walking on. * @@ -1380,31 +1312,6 @@ static float estimatedHeading(double lat, double lon) return b; } -static uint16_t getCompassDiam(OLEDDisplay *display) -{ - uint16_t diam = 0; - uint16_t offset = 0; - - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) - offset = FONT_HEIGHT_SMALL; - - // get the smaller of the 2 dimensions and subtract 20 - if (display->getWidth() > (display->getHeight() - offset)) { - diam = display->getHeight() - offset; - // if 2/3 of the other size would be smaller, use that - if (diam > (display->getWidth() * 2 / 3)) { - diam = display->getWidth() * 2 / 3; - } - } else { - diam = display->getWidth(); - if (diam > ((display->getHeight() - offset) * 2 / 3)) { - diam = (display->getHeight() - offset) * 2 / 3; - } - } - - return diam - 20; -}; - /// We will skip one node - the one for us, so we just blindly loop over all /// nodes static size_t nodeIndex; @@ -1428,7 +1335,7 @@ static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t comp drawLine(display, leftArrow, tip); drawLine(display, rightArrow, tip); } - +/* // Draw north static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading) { @@ -1449,7 +1356,7 @@ static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t com drawLine(display, N1, N3); drawLine(display, N2, N4); drawLine(display, N1, N4); -} +}*/ // Get a string representation of the time passed since something happened static void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength) @@ -2023,13 +1930,22 @@ int32_t Screen::runOnce() case Cmd::SHOW_NEXT_FRAME: handleShowNextFrame(); break; - case Cmd::START_BLUETOOTH_PIN_SCREEN: - handleStartBluetoothPinScreen(cmd.bluetooth_pin); + case Cmd::START_ALERT_FRAME: { + showingBootScreen = false; // this should avoid the edge case where an alert triggers before the boot screen goes away + showingNormalScreen = false; + alertFrames[0] = alertFrame; +#ifdef USE_EINK + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Use fast-refresh for next frame, no skip please + EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update + handleSetOn(true); // Ensure power-on to receive deep-sleep screensaver (PowerFSM should handle?) +#endif + setFrameImmediateDraw(alertFrames); break; + } case Cmd::START_FIRMWARE_UPDATE_SCREEN: handleStartFirmwareUpdateScreen(); break; - case Cmd::STOP_BLUETOOTH_PIN_SCREEN: + case Cmd::STOP_ALERT_FRAME: case Cmd::STOP_BOOT_SCREEN: EINK_ADD_FRAMEFLAG(dispdev, COSMETIC); // E-Ink: Explicitly use full-refresh for next frame setFrames(); @@ -2038,12 +1954,6 @@ int32_t Screen::runOnce() handlePrint(cmd.print_text); free(cmd.print_text); break; - case Cmd::START_SHUTDOWN_SCREEN: - handleShutdownScreen(); - break; - case Cmd::START_REBOOT_SCREEN: - handleRebootScreen(); - break; default: LOG_ERROR("Invalid screen cmd\n"); } @@ -2284,17 +2194,6 @@ void Screen::setFrames() setFastFramerate(); // Draw ASAP } -void Screen::handleStartBluetoothPinScreen(uint32_t pin) -{ - LOG_DEBUG("showing bluetooth screen\n"); - showingNormalScreen = false; - EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame - - static FrameCallback frames[] = {drawFrameBluetooth}; - snprintf(btPIN, sizeof(btPIN), "%06u", pin); - setFrameImmediateDraw(frames); -} - void Screen::setFrameImmediateDraw(FrameCallback *drawFrames) { ui->disableAllIndicators(); @@ -2302,41 +2201,6 @@ void Screen::setFrameImmediateDraw(FrameCallback *drawFrames) setFastFramerate(); } -void Screen::handleShutdownScreen() -{ - LOG_DEBUG("showing shutdown screen\n"); - showingNormalScreen = false; -#ifdef USE_EINK - EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Use fast-refresh for next frame, no skip please - EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update - handleSetOn(true); // Ensure power-on to receive deep-sleep screensaver (PowerFSM should handle?) -#endif - - auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { - drawFrameText(display, state, x, y, "Shutting down..."); - }; - static FrameCallback frames[] = {frame}; - - setFrameImmediateDraw(frames); -} - -void Screen::handleRebootScreen() -{ - LOG_DEBUG("showing reboot screen\n"); - showingNormalScreen = false; -#ifdef USE_EINK - EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Use fast-refresh for next frame, no skip please - EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update - handleSetOn(true); // Power-on to show rebooting screen (PowerFSM should handle?) -#endif - - auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { - drawFrameText(display, state, x, y, "Rebooting..."); - }; - static FrameCallback frames[] = {frame}; - setFrameImmediateDraw(frames); -} - void Screen::handleStartFirmwareUpdateScreen() { LOG_DEBUG("showing firmware screen\n"); diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index b1bbffc3b2..a8aca36576 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -21,11 +21,9 @@ class Screen void print(const char *) {} void doDeepSleep() {} void forceDisplay(bool forceUiUpdate = false) {} - void startBluetoothPinScreen(uint32_t pin) {} - void stopBluetoothPinScreen() {} - void startRebootScreen() {} - void startShutdownScreen() {} void startFirmwareUpdateScreen() {} + void startAlert(const char *) {} + void endAlert() {} }; } // namespace graphics #else @@ -34,6 +32,8 @@ class Screen #include #include "../configuration.h" +#include "gps/GeoCoord.h" +#include "graphics/ScreenFonts.h" #ifdef USE_ST7567 #include @@ -173,36 +173,36 @@ class Screen : public concurrency::OSThread void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); } void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); } - /// Starts showing the Bluetooth PIN screen. - // - // Switches over to a static frame showing the Bluetooth pairing screen - // with the PIN. - void startBluetoothPinScreen(uint32_t pin) + // generic alert start + void startAlert(FrameCallback _alertFrame) { + alertFrame = _alertFrame; ScreenCmd cmd; - cmd.cmd = Cmd::START_BLUETOOTH_PIN_SCREEN; - cmd.bluetooth_pin = pin; + cmd.cmd = Cmd::START_ALERT_FRAME; enqueueCmd(cmd); } - void startFirmwareUpdateScreen() + void startAlert(const char *_alertMessage) { - ScreenCmd cmd; - cmd.cmd = Cmd::START_FIRMWARE_UPDATE_SCREEN; - enqueueCmd(cmd); + startAlert([_alertMessage](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { + uint16_t x_offset = display->width() / 2; + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(x_offset + x, 26 + y, _alertMessage); + }); } - void startShutdownScreen() + void endAlert() { ScreenCmd cmd; - cmd.cmd = Cmd::START_SHUTDOWN_SCREEN; + cmd.cmd = Cmd::STOP_ALERT_FRAME; enqueueCmd(cmd); } - void startRebootScreen() + void startFirmwareUpdateScreen() { ScreenCmd cmd; - cmd.cmd = Cmd::START_REBOOT_SCREEN; + cmd.cmd = Cmd::START_FIRMWARE_UPDATE_SCREEN; enqueueCmd(cmd); } @@ -224,9 +224,6 @@ class Screen : public concurrency::OSThread void setFunctionSymbal(std::string sym); void removeFunctionSymbal(std::string sym); - /// Stops showing the bluetooth PIN screen. - void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); } - /// Stops showing the boot screen. void stopBootScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BOOT_SCREEN}); } @@ -362,6 +359,7 @@ class Screen : public concurrency::OSThread bool isAUTOOled = false; private: + FrameCallback alertFrames[1]; struct ScreenCmd { Cmd cmd; union { @@ -387,11 +385,8 @@ class Screen : public concurrency::OSThread void handleOnPress(); void handleShowNextFrame(); void handleShowPrevFrame(); - void handleStartBluetoothPinScreen(uint32_t pin); void handlePrint(const char *text); void handleStartFirmwareUpdateScreen(); - void handleShutdownScreen(); - void handleRebootScreen(); /// Rebuilds our list of frames (screens) to default ones. void setFrames(); @@ -429,6 +424,9 @@ class Screen : public concurrency::OSThread bool digitalWatchFace = true; #endif + /// callback for current alert frame + FrameCallback alertFrame; + /// Queue of commands to execute in doTask. TypedQueue cmdQueue; /// Whether we are using a display @@ -455,4 +453,92 @@ class Screen : public concurrency::OSThread }; } // namespace graphics +namespace +{ +/// A basic 2D point class for drawing +class Point +{ + public: + float x, y; + + Point(float _x, float _y) : x(_x), y(_y) {} + + /// Apply a rotation around zero (standard rotation matrix math) + void rotate(float radian) + { + float cos = cosf(radian), sin = sinf(radian); + float rx = x * cos + y * sin, ry = -x * sin + y * cos; + + x = rx; + y = ry; + } + + void translate(int16_t dx, int dy) + { + x += dx; + y += dy; + } + + void scale(float f) + { + // We use -f here to counter the flip that happens + // on the y axis when drawing and rotating on screen + x *= f; + y *= -f; + } +}; + +} // namespace + +static void drawLine(OLEDDisplay *d, const Point &p1, const Point &p2) +{ + d->drawLine(p1.x, p1.y, p2.x, p2.y); +} + +static uint16_t getCompassDiam(OLEDDisplay *display) +{ + uint16_t diam = 0; + uint16_t offset = 0; + + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) + offset = FONT_HEIGHT_SMALL; + + // get the smaller of the 2 dimensions and subtract 20 + if (display->getWidth() > (display->getHeight() - offset)) { + diam = display->getHeight() - offset; + // if 2/3 of the other size would be smaller, use that + if (diam > (display->getWidth() * 2 / 3)) { + diam = display->getWidth() * 2 / 3; + } + } else { + diam = display->getWidth(); + if (diam > ((display->getHeight() - offset) * 2 / 3)) { + diam = (display->getHeight() - offset) * 2 / 3; + } + } + + return diam - 20; +}; + +// Draw north +static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading) +{ + // If north is supposed to be at the top of the compass we want rotation to be +0 + if (config.display.compass_north_top) + myHeading = -0; + + Point N1(-0.04f, 0.65f), N2(0.04f, 0.65f); + Point N3(-0.04f, 0.55f), N4(0.04f, 0.55f); + Point *rosePoints[] = {&N1, &N2, &N3, &N4}; + + for (int i = 0; i < 4; i++) { + // North on compass will be negative of heading + rosePoints[i]->rotate(-myHeading); + rosePoints[i]->scale(getCompassDiam(display)); + rosePoints[i]->translate(compassX, compassY); + } + drawLine(display, N1, N3); + drawLine(display, N2, N4); + drawLine(display, N1, N4); +} #endif \ No newline at end of file diff --git a/src/graphics/ScreenFonts.h b/src/graphics/ScreenFonts.h index 4b34563f70..8a48d053e9 100644 --- a/src/graphics/ScreenFonts.h +++ b/src/graphics/ScreenFonts.h @@ -28,8 +28,8 @@ #define FONT_LARGE ArialMT_Plain_24 // Height: 28 #endif -#define fontHeight(font) ((font)[1] + 1) // height is position 1 +#define _fontHeight(font) ((font)[1] + 1) // height is position 1 -#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL) -#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM) -#define FONT_HEIGHT_LARGE fontHeight(FONT_LARGE) +#define FONT_HEIGHT_SMALL _fontHeight(FONT_SMALL) +#define FONT_HEIGHT_MEDIUM _fontHeight(FONT_MEDIUM) +#define FONT_HEIGHT_LARGE _fontHeight(FONT_LARGE) \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 9ec4fa82de..462eaa0f4e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -930,7 +930,7 @@ void setup() nodeDB->saveToDisk(SEGMENT_CONFIG); if (!rIf->reconfigure()) { LOG_WARN("Reconfigure failed, rebooting\n"); - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); rebootAtMsec = millis() + 5000; } } diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 31fb983f4c..1dc6d7883e 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -180,7 +180,7 @@ bool NodeDB::resetRadioConfig(bool factory_reset) if (didFactoryReset) { LOG_INFO("Rebooting due to factory reset"); - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); rebootAtMsec = millis() + (5 * 1000); } diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 8146866090..3a3901433d 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -137,7 +137,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta #if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH if (BleOta::getOtaAppVersion().isEmpty()) { LOG_INFO("No OTA firmware available, scheduling regular reboot in %d seconds\n", s); - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); } else { screen->startFirmwareUpdateScreen(); BleOta::switchToOtaApp(); @@ -145,7 +145,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta } #else LOG_INFO("Not on ESP32, scheduling regular reboot in %d seconds\n", s); - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); #endif rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000); break; @@ -811,7 +811,7 @@ void AdminModule::handleGetChannel(const meshtastic_MeshPacket &req, uint32_t ch void AdminModule::reboot(int32_t seconds) { LOG_INFO("Rebooting in %d seconds\n", seconds); - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); rebootAtMsec = (seconds < 0) ? 0 : (millis() + seconds * 1000); } diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index f513e045f4..be414dce13 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -597,14 +597,14 @@ int32_t CannedMessageModule::runOnce() // handle fn+s for shutdown case 0x9b: if (screen) - screen->startShutdownScreen(); + screen->startAlert("Shutting down..."); shutdownAtMsec = millis() + DEFAULT_SHUTDOWN_SECONDS * 1000; runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; break; // and fn+r for reboot case 0x90: if (screen) - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000; runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; break; diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 8f899401b9..b69b2bfae1 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -188,7 +188,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt if (lastMeasurementPacket == nullptr) { // If there's no valid packet, display "Environment" display->drawString(x, y, "Environment"); - display->drawString(x, y += fontHeight(FONT_SMALL), "No measurement"); + display->drawString(x, y += _fontHeight(FONT_SMALL), "No measurement"); return; } @@ -213,31 +213,31 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt } // Continue with the remaining details - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Temp/Hum: " + last_temp + " / " + String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%"); if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0) { - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA"); } if (lastMeasurement.variant.environment_metrics.voltage != 0) { - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Volt/Cur: " + String(lastMeasurement.variant.environment_metrics.voltage, 0) + "V / " + String(lastMeasurement.variant.environment_metrics.current, 0) + "mA"); } if (lastMeasurement.variant.environment_metrics.iaq != 0) { - display->drawString(x, y += fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq)); + display->drawString(x, y += _fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq)); } if (lastMeasurement.variant.environment_metrics.distance != 0) - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Water Level: " + String(lastMeasurement.variant.environment_metrics.distance, 0) + "mm"); if (lastMeasurement.variant.environment_metrics.weight != 0) - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg"); } diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index cb864f4f3c..fb5aee375b 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -108,7 +108,7 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s display->drawString(x, y, "Power Telemetry"); if (lastMeasurementPacket == nullptr) { display->setFont(FONT_SMALL); - display->drawString(x, y += fontHeight(FONT_MEDIUM), "No measurement"); + display->drawString(x, y += _fontHeight(FONT_MEDIUM), "No measurement"); return; } @@ -120,22 +120,22 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s auto &p = lastMeasurementPacket->decoded; if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &lastMeasurement)) { display->setFont(FONT_SMALL); - display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error"); + display->drawString(x, y += _fontHeight(FONT_MEDIUM), "Measurement Error"); LOG_ERROR("Unable to decode last packet"); return; } display->setFont(FONT_SMALL); String last_temp = String(lastMeasurement.variant.environment_metrics.temperature, 0) + "°C"; - display->drawString(x, y += fontHeight(FONT_MEDIUM) - 2, "From: " + String(lastSender) + "(" + String(agoSecs) + "s)"); + display->drawString(x, y += _fontHeight(FONT_MEDIUM) - 2, "From: " + String(lastSender) + "(" + String(agoSecs) + "s)"); if (lastMeasurement.variant.power_metrics.ch1_voltage != 0) { - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Ch 1 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch1_voltage, 0) + "V / " + String(lastMeasurement.variant.power_metrics.ch1_current, 0) + "mA"); - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Ch 2 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch2_voltage, 0) + "V / " + String(lastMeasurement.variant.power_metrics.ch2_current, 0) + "mA"); - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Ch 3 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch3_voltage, 0) + "V / " + String(lastMeasurement.variant.power_metrics.ch3_current, 0) + "mA"); } diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 48f945b0a8..78ef5a1d3e 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -82,7 +82,33 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks LOG_INFO("*** Enter passkey %d on the peer side ***\n", passkey); powerFSM.trigger(EVENT_BLUETOOTH_PAIR); - screen->startBluetoothPinScreen(passkey); +#if HAS_SCREEN + screen->startAlert([passkey](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { + char btPIN[16] = "888888"; + snprintf(btPIN, sizeof(btPIN), "%06u", passkey); + int x_offset = display->width() / 2; + int y_offset = display->height() <= 80 ? 0 : 32; + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(x_offset + x, y_offset + y, "Bluetooth"); + + display->setFont(FONT_SMALL); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5; + display->drawString(x_offset + x, y_offset + y, "Enter this code"); + + display->setFont(FONT_LARGE); + String displayPin(btPIN); + String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5; + display->drawString(x_offset + x, y_offset + y, pin); + + display->setFont(FONT_SMALL); + String deviceName = "Name: "; + deviceName.concat(getDeviceName()); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; + display->drawString(x_offset + x, y_offset + y, deviceName); + }); +#endif passkeyShowing = true; return passkey; @@ -94,7 +120,7 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks if (passkeyShowing) { passkeyShowing = false; - screen->stopBluetoothPinScreen(); + screen->endAlert(); } } diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index a14829285b..56d7ed167d 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -290,7 +290,31 @@ bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passke { LOG_INFO("BLE pairing process started with passkey %.3s %.3s\n", passkey, passkey + 3); powerFSM.trigger(EVENT_BLUETOOTH_PAIR); - screen->startBluetoothPinScreen(configuredPasskey); + screen->startAlert([](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { + char btPIN[16] = "888888"; + snprintf(btPIN, sizeof(btPIN), "%06u", configuredPasskey); + int x_offset = display->width() / 2; + int y_offset = display->height() <= 80 ? 0 : 32; + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(x_offset + x, y_offset + y, "Bluetooth"); + + display->setFont(FONT_SMALL); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5; + display->drawString(x_offset + x, y_offset + y, "Enter this code"); + + display->setFont(FONT_LARGE); + String displayPin(btPIN); + String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5; + display->drawString(x_offset + x, y_offset + y, pin); + + display->setFont(FONT_SMALL); + String deviceName = "Name: "; + deviceName.concat(getDeviceName()); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; + display->drawString(x_offset + x, y_offset + y, deviceName); + }); if (match_request) { uint32_t start_time = millis(); while (millis() < start_time + 30000) { @@ -307,7 +331,7 @@ void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_statu LOG_INFO("BLE pairing success\n"); else LOG_INFO("BLE pairing failed\n"); - screen->stopBluetoothPinScreen(); + screen->endAlert(); } void NRF52Bluetooth::sendLog(const char *logMessage) diff --git a/src/shutdown.h b/src/shutdown.h index 54fb3071b7..3f191eea88 100644 --- a/src/shutdown.h +++ b/src/shutdown.h @@ -38,7 +38,7 @@ void powerCommandsCheck() #if defined(ARCH_ESP32) || defined(ARCH_NRF52) if (shutdownAtMsec) { - screen->startShutdownScreen(); + screen->startAlert("Shutting down..."); } #endif From a966d84e3d2409779c13894e68676680c9f2453f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 27 Jun 2024 07:07:27 -0500 Subject: [PATCH 092/211] Send file system manifest up on want_config (#4176) * Send file system manifest up on want_config * Platform specific methods * Helps to actually make the change * Clear --- src/FSCommon.cpp | 50 +++++++++++++++++++++++++++++++++++++++++++ src/FSCommon.h | 2 ++ src/mesh/PhoneAPI.cpp | 27 ++++++++++++++++++++--- src/mesh/PhoneAPI.h | 5 +++++ 4 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index 96aad1a9a4..f9e9f1a826 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -84,6 +84,56 @@ bool renameFile(const char *pathFrom, const char *pathTo) #endif } +#include + +/** + * @brief Get the list of files in a directory. + * + * This function returns a list of files in a directory. The list includes the full path of each file. + * + * @param dirname The name of the directory. + * @param levels The number of levels of subdirectories to list. + * @return A vector of strings containing the full path of each file in the directory. + */ +std::vector getFiles(const char *dirname, uint8_t levels) +{ + std::vector filenames = {}; +#ifdef FSCom + File root = FSCom.open(dirname, FILE_O_READ); + if (!root) + return filenames; + if (!root.isDirectory()) + return filenames; + + File file = root.openNextFile(); + while (file) { + if (file.isDirectory() && !String(file.name()).endsWith(".")) { + if (levels) { +#ifdef ARCH_ESP32 + std::vector subDirFilenames = getFiles(file.path(), levels - 1); +#else + std::vector subDirFilenames = getFiles(file.name(), levels - 1); +#endif + filenames.insert(filenames.end(), subDirFilenames.begin(), subDirFilenames.end()); + file.close(); + } + } else { + meshtastic_FileInfo fileInfo = {"", file.size()}; +#ifdef ARCH_ESP32 + strcpy(fileInfo.file_name, file.path()); +#else + strcpy(fileInfo.file_name, file.name()); +#endif + filenames.push_back(fileInfo); + file.close(); + } + file = root.openNextFile(); + } + root.close(); +#endif + return filenames; +} + /** * Lists the contents of a directory. * diff --git a/src/FSCommon.h b/src/FSCommon.h index ef1d3e4c17..8fbabd9526 100644 --- a/src/FSCommon.h +++ b/src/FSCommon.h @@ -1,6 +1,7 @@ #pragma once #include "configuration.h" +#include // Cross platform filesystem API @@ -49,6 +50,7 @@ using namespace Adafruit_LittleFS_Namespace; void fsInit(); bool copyFile(const char *from, const char *to); bool renameFile(const char *pathFrom, const char *pathTo); +std::vector getFiles(const char *dirname, uint8_t levels); void listDir(const char *dirname, uint8_t levels, bool del); void rmDir(const char *dirname); void setupSDCard(); \ No newline at end of file diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 404666877c..57a42651ac 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -5,6 +5,7 @@ #include "Channels.h" #include "Default.h" +#include "FSCommon.h" #include "MeshService.h" #include "NodeDB.h" #include "PhoneAPI.h" @@ -47,6 +48,8 @@ void PhoneAPI::handleStartConfig() // even if we were already connected - restart our state machine state = STATE_SEND_MY_INFO; pauseBluetoothLogging = true; + filesManifest = getFiles("/", 10); + LOG_DEBUG("Got %d files in manifest\n", filesManifest.size()); LOG_INFO("Starting API client config\n"); nodeInfoForPhone.num = 0; // Don't keep returning old nodeinfos @@ -149,6 +152,7 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) STATE_SEND_CONFIG, STATE_SEND_MODULE_CONFIG, STATE_SEND_OTHER_NODEINFOS, // states progress in this order as the device sends to the client + STATE_SEND_FILEMANIFEST, STATE_SEND_COMPLETE_ID, STATE_SEND_PACKETS // send packets or debug strings */ @@ -324,8 +328,9 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Advance when we have sent all of our ModuleConfig objects if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1)) { // Clients sending special nonce don't want to see other nodeinfos - state = config_nonce == SPECIAL_NONCE ? STATE_SEND_COMPLETE_ID : STATE_SEND_OTHER_NODEINFOS; + state = config_nonce == SPECIAL_NONCE ? STATE_SEND_FILEMANIFEST : STATE_SEND_OTHER_NODEINFOS; config_state = 0; + filesManifest.clear(); } break; @@ -340,13 +345,28 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) nodeInfoForPhone.num = 0; // We just consumed a nodeinfo, will need a new one next time } else { LOG_INFO("Done sending nodeinfos\n"); - state = STATE_SEND_COMPLETE_ID; + state = STATE_SEND_FILEMANIFEST; // Go ahead and send that ID right now return getFromRadio(buf); } break; } + case STATE_SEND_FILEMANIFEST: { + LOG_INFO("getFromRadio=STATE_SEND_FILEMANIFEST\n"); + fromRadioScratch.which_payload_variant = meshtastic_FromRadio_fileInfo_tag; + if (config_state < filesManifest.size()) { + fromRadioScratch.fileInfo = filesManifest.at(config_state); + config_state++; + // last element + if (config_state == filesManifest.size()) { + state = STATE_SEND_COMPLETE_ID; + config_state = 0; + } + } + break; + } + case STATE_SEND_COMPLETE_ID: LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n"); fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag; @@ -401,6 +421,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) void PhoneAPI::handleDisconnect() { + filesManifest.clear(); pauseBluetoothLogging = false; LOG_INFO("PhoneAPI disconnect\n"); } @@ -443,6 +464,7 @@ bool PhoneAPI::available() case STATE_SEND_MODULECONFIG: case STATE_SEND_METADATA: case STATE_SEND_OWN_NODEINFO: + case STATE_SEND_FILEMANIFEST: case STATE_SEND_COMPLETE_ID: return true; @@ -457,7 +479,6 @@ bool PhoneAPI::available() } } return true; // Always say we have something, because we might need to advance our state machine - case STATE_SEND_PACKETS: { if (!queueStatusPacketForPhone) queueStatusPacketForPhone = service.getQueueStatusForPhone(); diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 668f9c1f3c..3d7bfbadeb 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -2,7 +2,9 @@ #include "Observer.h" #include "mesh-pb-constants.h" +#include #include +#include // Make sure that we never let our packets grow too large for one BLE packet #define MAX_TO_FROM_RADIO_SIZE 512 @@ -29,6 +31,7 @@ class PhoneAPI STATE_SEND_CONFIG, // Replacement for the old Radioconfig STATE_SEND_MODULECONFIG, // Send Module specific config STATE_SEND_OTHER_NODEINFOS, // states progress in this order as the device sends to to the client + STATE_SEND_FILEMANIFEST, // Send file manifest STATE_SEND_COMPLETE_ID, STATE_SEND_PACKETS // send packets or debug strings }; @@ -65,6 +68,8 @@ class PhoneAPI uint32_t config_nonce = 0; uint32_t readIndex = 0; + std::vector filesManifest = {}; + void resetReadIndex() { readIndex = 0; } public: From 2cb6e7bd37f0ff705fc73ba042832237ed143f62 Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 27 Jun 2024 11:14:16 -0700 Subject: [PATCH 093/211] tell vscode, if formatting, use whatever our trunk formatter wants (#4186) without this flag if the user has set some other formatter (clang) in their user level settings, it will be looking in the wrong directory for the clang options (we want the options in .trunk/clang) Note: formatOnSave is true in master, which means a bunch of our older files are non compliant and if you edit them it will generate lots of formatting related diffs. I guess I'll start letting that happen with my future commits ;-). --- .vscode/settings.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 07e198f0a7..bf9b82111d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,8 @@ "trunk.enableWindows": true, "files.insertFinalNewline": false, "files.trimFinalNewlines": false, - "cmake.configureOnOpen": false + "cmake.configureOnOpen": false, + "[cpp]": { + "editor.defaultFormatter": "trunk.io" + } } From 41d633bfd84aec023922a7f34611a3715a6dd1cd Mon Sep 17 00:00:00 2001 From: geeksville Date: Thu, 27 Jun 2024 18:43:08 -0700 Subject: [PATCH 094/211] fix the build - would loop forever if there were no files to send (#4188) --- src/mesh/PhoneAPI.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 57a42651ac..399715f614 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -354,15 +354,14 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) case STATE_SEND_FILEMANIFEST: { LOG_INFO("getFromRadio=STATE_SEND_FILEMANIFEST\n"); - fromRadioScratch.which_payload_variant = meshtastic_FromRadio_fileInfo_tag; - if (config_state < filesManifest.size()) { + // last element + if (config_state == filesManifest.size()) { // also handles an empty filesManifest + state = STATE_SEND_COMPLETE_ID; + config_state = 0; + } else { + fromRadioScratch.which_payload_variant = meshtastic_FromRadio_fileInfo_tag; fromRadioScratch.fileInfo = filesManifest.at(config_state); config_state++; - // last element - if (config_state == filesManifest.size()) { - state = STATE_SEND_COMPLETE_ID; - config_state = 0; - } } break; } From 51f3ce5e600b08dd96ce9a9aa3e37384456ba347 Mon Sep 17 00:00:00 2001 From: Alexander <156134901+Dorn8010@users.noreply.github.com> Date: Fri, 28 Jun 2024 08:55:54 +0200 Subject: [PATCH 095/211] Show owner.short_name on boot (and E-Ink sleep screen) (#4134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Show owner.short_name on boot and sleep screen (on e-ink) * Update Screen.cpp - new line for short_name Boot screen short_name now below the region setting. Looks better on small screens. * Draw short_name on right --------- Co-authored-by: Thomas Göttgens Co-authored-by: todd-herbert Co-authored-by: Ben Meadors --- src/graphics/Screen.cpp | 83 ++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 234381aa5a..924ca97c67 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -121,6 +121,30 @@ static uint16_t displayWidth, displayHeight; #define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2) +/// Check if the display can render a string (detect special chars; emoji) +static bool haveGlyphs(const char *str) +{ +#if defined(OLED_UA) || defined(OLED_RU) + // Don't want to make any assumptions about custom language support + return true; +#endif + + // Check each character with the lookup function for the OLED library + // We're not really meant to use this directly.. + bool have = true; + for (uint16_t i = 0; i < strlen(str); i++) { + uint8_t result = Screen::customFontTableLookup((uint8_t)str[i]); + // If font doesn't support a character, it is substituted for ¿ + if (result == 191 && (uint8_t)str[i] != 191) { + have = false; + break; + } + } + + LOG_DEBUG("haveGlyphs=%d\n", have); + return have; +} + /** * Draw the icon with extra info printed around the corners */ @@ -144,13 +168,15 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl if (upperMsg) display->drawString(x + 0, y + 0, upperMsg); - // Draw version in upper right - char buf[16]; - snprintf(buf, sizeof(buf), "%s", - xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long - display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf); + // Draw version and short name in upper right + char buf[25]; + snprintf(buf, sizeof(buf), "%s\n%s", xstr(APP_VERSION_SHORT), haveGlyphs(owner.short_name) ? owner.short_name : ""); + + display->setTextAlignment(TEXT_ALIGN_RIGHT); + display->drawString(x + SCREEN_WIDTH, y + 0, buf); screen->forceDisplay(); - // FIXME - draw serial # somewhere? + + display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code } static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) @@ -185,14 +211,15 @@ static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDi if (upperMsg) display->drawString(x + 0, y + 0, upperMsg); - // Draw version in upper right - char buf[16]; - snprintf(buf, sizeof(buf), "%s", - xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long - display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf); + // Draw version and shortname in upper right + char buf[25]; + snprintf(buf, sizeof(buf), "%s\n%s", xstr(APP_VERSION_SHORT), haveGlyphs(owner.short_name) ? owner.short_name : ""); + + display->setTextAlignment(TEXT_ALIGN_RIGHT); + display->drawString(x + SCREEN_WIDTH, y + 0, buf); screen->forceDisplay(); - // FIXME - draw serial # somewhere? + display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code } static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) @@ -218,7 +245,6 @@ static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int1 } else #endif { - // Draw region in upper left const char *region = myRegion ? myRegion->name : NULL; drawIconScreen(region, display, state, x, y); } @@ -281,40 +307,19 @@ static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state) } } -/// Check if the display can render a string (detect special chars; emoji) -static bool haveGlyphs(const char *str) -{ -#if defined(OLED_UA) || defined(OLED_RU) - // Don't want to make any assumptions about custom language support - return true; -#endif - - // Check each character with the lookup function for the OLED library - // We're not really meant to use this directly.. - bool have = true; - for (uint16_t i = 0; i < strlen(str); i++) { - uint8_t result = Screen::customFontTableLookup((uint8_t)str[i]); - // If font doesn't support a character, it is substituted for ¿ - if (result == 191 && (uint8_t)str[i] != 191) { - have = false; - break; - } - } - - LOG_DEBUG("haveGlyphs=%d\n", have); - return have; -} - #ifdef USE_EINK /// Used on eink displays while in deep sleep static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { + // Next frame should use full-refresh, and block while running, else device will sleep before async callback EINK_ADD_FRAMEFLAG(display, COSMETIC); EINK_ADD_FRAMEFLAG(display, BLOCKING); LOG_DEBUG("Drawing deep sleep screen\n"); - drawIconScreen("Sleeping...", display, state, x, y); + + // Display displayStr on the screen + drawIconScreen("Sleeping", display, state, x, y); } /// Used on eink displays when screen updates are paused @@ -2718,4 +2723,4 @@ int Screen::handleWaypoint(const meshtastic_MeshPacket *arg) } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} -#endif // HAS_SCREEN \ No newline at end of file +#endif // HAS_SCREEN From f86a0e522853a90377e8e4fc9533f7212df11bcf Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 28 Jun 2024 04:48:55 -0700 Subject: [PATCH 096/211] nrf52 soft device will watchdog if you use ICE while BT on... (#4189) so have debugger disable bluetooth. --- src/platform/nrf52/main-nrf52.cpp | 3 ++- variants/rak4631/platformio.ini | 1 + variants/wio-sdk-wm1110/platformio.ini | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 86575bda6f..b79f28f139 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -63,7 +63,8 @@ static void initBrownout() // We don't bother with setting up brownout if soft device is disabled - because during production we always use softdevice } -static const bool useSoftDevice = true; // Set to false for easier debugging +// This is a public global so that the debugger can set it to false automatically from our gdbinit +bool useSoftDevice = true; // Set to false for easier debugging #if !MESHTASTIC_EXCLUDE_BLUETOOTH void setBluetoothEnable(bool enable) diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index beffa7d3df..6a67b00835 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -79,6 +79,7 @@ debug_extra_cmds = commands 1 echo Breakpoint at setup() has semihosting console, connect to it with "telnet localhost 5555" set wantSemihost = true + set useSoftDevice = false end diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini index 7ca82e4c68..4a23e7a119 100644 --- a/variants/wio-sdk-wm1110/platformio.ini +++ b/variants/wio-sdk-wm1110/platformio.ini @@ -15,5 +15,19 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-sdk-wm1110> lib_deps = ${nrf52840_base.lib_deps} debug_tool = jlink +;debug_tool = stlink +;debug_speed = 4000 +; No need to reflash if the binary hasn't changed +debug_load_mode = modified ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) upload_protocol = jlink +;upload_protocol = stlink +; we prefer to stop in setup() because we are an 'ardiuno' app +debug_init_break = tbreak setup + +; we need to turn off BLE/soft device if we are debugging otherwise it will watchdog reset us. +debug_extra_cmds = + echo Running .gdbinit script + commands 1 + set useSoftDevice = false + end \ No newline at end of file From c95b2c2d3c4312c8a925c68f066ec05b6ea5636b Mon Sep 17 00:00:00 2001 From: quimnut Date: Fri, 28 Jun 2024 21:49:38 +1000 Subject: [PATCH 097/211] correct xiao_ble build preventing sx1262 init (#4191) --- variants/xiao_ble/platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/variants/xiao_ble/platformio.ini b/variants/xiao_ble/platformio.ini index 9d533c0ada..76e91e8444 100644 --- a/variants/xiao_ble/platformio.ini +++ b/variants/xiao_ble/platformio.ini @@ -3,7 +3,7 @@ extends = nrf52840_base board = xiao_ble_sense board_level = extra -build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Ivariants/xiao_ble/softdevice -Ivariants/xiao_ble/softdevice/nrf52 -D EBYTE_E22 -DEBYTE_E22_900M30S -DPRIVATE_HW +build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Ivariants/xiao_ble/softdevice -Ivariants/xiao_ble/softdevice/nrf52 -DEBYTE_E22 -DEBYTE_E22_900M30S -DPRIVATE_HW -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" board_build.ldscript = variants/xiao_ble/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/xiao_ble> @@ -11,4 +11,4 @@ lib_deps = ${nrf52840_base.lib_deps} debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink \ No newline at end of file +;upload_protocol = jlink From ce58a23f9baab06e5084fe81e32242f9d2e3d1f0 Mon Sep 17 00:00:00 2001 From: geeksville Date: Fri, 28 Jun 2024 04:51:04 -0700 Subject: [PATCH 098/211] Force a compile time failur if FromRadio or ToRadio get larger than (#4190) a BLE packet size. We are actually very close to this threshold so important to make sure we don't accidentally pass it. --- src/mesh/PhoneAPI.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 3d7bfbadeb..1a2a065d35 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -8,6 +8,14 @@ // Make sure that we never let our packets grow too large for one BLE packet #define MAX_TO_FROM_RADIO_SIZE 512 + +#if meshtastic_FromRadio_size > MAX_TO_FROM_RADIO_SIZE +#error "meshtastic_FromRadio_size is too large for our BLE packets" +#endif +#if meshtastic_ToRadio_size > MAX_TO_FROM_RADIO_SIZE +#error "meshtastic_ToRadio_size is too large for our BLE packets" +#endif + #define SPECIAL_NONCE 69420 /** From 0016e747e912e2583a36ac7be6a6b9ed23073b3b Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 28 Jun 2024 09:50:22 -0500 Subject: [PATCH 099/211] Clear vector after complete config state (#4194) * Clear after complete config * Don't collect . entries * Log file name and size --- src/FSCommon.cpp | 4 +++- src/mesh/PhoneAPI.cpp | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index f9e9f1a826..7d3788c4d9 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -124,7 +124,9 @@ std::vector getFiles(const char *dirname, uint8_t levels) #else strcpy(fileInfo.file_name, file.name()); #endif - filenames.push_back(fileInfo); + if (!String(fileInfo.file_name).endsWith(".")) { + filenames.push_back(fileInfo); + } file.close(); } file = root.openNextFile(); diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 399715f614..d6721b018e 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -330,7 +330,6 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Clients sending special nonce don't want to see other nodeinfos state = config_nonce == SPECIAL_NONCE ? STATE_SEND_FILEMANIFEST : STATE_SEND_OTHER_NODEINFOS; config_state = 0; - filesManifest.clear(); } break; @@ -358,9 +357,11 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) if (config_state == filesManifest.size()) { // also handles an empty filesManifest state = STATE_SEND_COMPLETE_ID; config_state = 0; + filesManifest.clear(); } else { fromRadioScratch.which_payload_variant = meshtastic_FromRadio_fileInfo_tag; fromRadioScratch.fileInfo = filesManifest.at(config_state); + LOG_DEBUG("File: %s (%d) bytes\n", fromRadioScratch.fileInfo.file_name, fromRadioScratch.fileInfo.size_bytes); config_state++; } break; From 9c232da00f73b3c8e97f6d6ede0993cb553e4bf8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Jun 2024 18:46:44 -0500 Subject: [PATCH 100/211] [create-pull-request] automated change (#4200) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/config.pb.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/protobufs b/protobufs index a3030d5ff1..57ddb288e8 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit a3030d5ff187091c9fbbd08dd797cca5085736fe +Subproject commit 57ddb288e87438db3b5b99aa61f66a354c47bffb diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 2da4b86e6a..e3037c910d 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -22,7 +22,6 @@ typedef enum _meshtastic_Config_DeviceConfig_Role { The wifi radio and the oled screen will be put to sleep. This mode may still potentially have higher power usage due to it's preference in message rebroadcasting on the mesh. */ meshtastic_Config_DeviceConfig_Role_ROUTER = 2, - /* Description: Combination of both ROUTER and CLIENT. Not for mobile devices. */ meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT = 3, /* Description: Infrastructure node for extending network coverage by relaying messages with minimal overhead. Not visible in Nodes list. Technical Details: Mesh packets will simply be rebroadcasted over this node. Nodes configured with this role will not originate NodeInfo, Position, Telemetry From 5263c738f3af11c8284587623a16ac130c1ead98 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Fri, 28 Jun 2024 20:10:41 -0500 Subject: [PATCH 101/211] Make the logs Colorful! (#4199) --- src/RedirectablePrint.cpp | 61 +++++++++++++++++++++++++++++++-------- src/RedirectablePrint.h | 3 +- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index b77720d85d..ee819643e8 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -71,20 +71,49 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg) return len; } -size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) +size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_list arg) +{ + va_list copy; + static char printBuf[160]; + + va_copy(copy, arg); + size_t len = vsnprintf(printBuf, sizeof(printBuf), format, copy); + va_end(copy); + + // If the resulting string is longer than sizeof(printBuf)-1 characters, the remaining characters are still counted for the + // return value + + if (len > sizeof(printBuf) - 1) { + len = sizeof(printBuf) - 1; + printBuf[sizeof(printBuf) - 2] = '\n'; + } + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) + Print::write("\u001b[34m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) + Print::write("\u001b[32m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) + Print::write("\u001b[33m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) + Print::write("\u001b[31m", 6); + len = Print::write(printBuf, len); + Print::write("\u001b[0m", 5); + return len; +} + +void RedirectablePrint::log(const char *logLevel, const char *format, ...) { #ifdef ARCH_PORTDUINO if (settingsMap[logoutputlevel] < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) - return 0; + return; else if (settingsMap[logoutputlevel] < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) - return 0; + return; else if (settingsMap[logoutputlevel] < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) - return 0; + return; #endif if (moduleConfig.serial.override_console_serial_port && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) { - return 0; + return; } - size_t r = 0; + #ifdef HAS_FREE_RTOS if (inDebugPrint != nullptr && xSemaphoreTake(inDebugPrint, portMAX_DELAY) == pdTRUE) { #else @@ -100,6 +129,14 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) // If we are the first message on a report, include the header if (!isContinuationMessage) { + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) + Print::write("\u001b[34m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) + Print::write("\u001b[32m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) + Print::write("\u001b[33m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) + Print::write("\u001b[31m", 6); uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile if (rtc_sec > 0) { long hms = rtc_sec % SEC_PER_DAY; @@ -113,15 +150,15 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN #ifdef ARCH_PORTDUINO - r += ::printf("%s | %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); + ::printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); #else - r += printf("%s | %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); + printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); #endif } else #ifdef ARCH_PORTDUINO - r += ::printf("%s | ??:??:?? %u ", logLevel, millis() / 1000); + ::printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); #else - r += printf("%s | ??:??:?? %u ", logLevel, millis() / 1000); + printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); #endif auto thread = concurrency::OSThread::currentThread; @@ -133,7 +170,7 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) print("] "); } } - r += vprintf(format, arg); + vprintf(logLevel, format, arg); #if (HAS_WIFI || HAS_ETHERNET) && !defined(ARCH_PORTDUINO) // if syslog is in use, collect the log messages and send them to syslog @@ -211,7 +248,7 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) #endif } - return r; + return; } void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len) diff --git a/src/RedirectablePrint.h b/src/RedirectablePrint.h index 31cc1b6ef7..c997d3d4e3 100644 --- a/src/RedirectablePrint.h +++ b/src/RedirectablePrint.h @@ -41,10 +41,11 @@ class RedirectablePrint : public Print * log message. Otherwise we assume more prints will come before the log message ends. This * allows you to call logDebug a few times to build up a single log message line if you wish. */ - size_t log(const char *logLevel, const char *format, ...) __attribute__((format(printf, 3, 4))); + void log(const char *logLevel, const char *format, ...) __attribute__((format(printf, 3, 4))); /** like printf but va_list based */ size_t vprintf(const char *format, va_list arg); + size_t vprintf(const char *logLevel, const char *format, va_list arg); void hexDump(const char *logLevel, unsigned char *buf, uint16_t len); From ca969e26a5c831b16881615c55524fd597e57355 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Fri, 28 Jun 2024 21:28:18 -0500 Subject: [PATCH 102/211] Squash needlessly static functions (#4183) --- src/AccelerometerThread.h | 2 +- src/graphics/Screen.cpp | 66 +++++---------- src/graphics/Screen.h | 173 +++++++++++++++++++------------------- 3 files changed, 107 insertions(+), 134 deletions(-) diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h index 0f04de057c..39ae903855 100644 --- a/src/AccelerometerThread.h +++ b/src/AccelerometerThread.h @@ -288,7 +288,7 @@ class AccelerometerThread : public concurrency::OSThread compassY = y + FONT_HEIGHT_SMALL + (display->getHeight() - FONT_HEIGHT_SMALL) / 2; } display->drawCircle(compassX, compassY, getCompassDiam(display) / 2); - drawCompassNorth(display, compassX, compassY, screen->getHeading() * PI / 180); + screen->drawCompassNorth(display, compassX, compassY, screen->getHeading() * PI / 180); } #endif }; diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 924ca97c67..7c8bf40bb8 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -79,7 +79,6 @@ namespace graphics // A text message frame + debug frame + all the node infos FrameCallback *normalFrames; static uint32_t targetFramerate = IDLE_FRAMERATE; -static char btPIN[16] = "888888"; uint32_t logo_timeout = 5000; // 4 seconds for EACH logo @@ -229,7 +228,7 @@ static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i drawOEMIconScreen(region, display, state, x, y); } -static void drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *message) +void Screen::drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *message) { uint16_t x_offset = display->width() / 2; display->setTextAlignment(TEXT_ALIGN_CENTER); @@ -237,19 +236,6 @@ static void drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16 display->drawString(x_offset + x, 26 + y, message); } -static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -{ -#ifdef ARCH_ESP32 - if (wakeCause == ESP_SLEEP_WAKEUP_TIMER || wakeCause == ESP_SLEEP_WAKEUP_EXT1) { - drawFrameText(display, state, x, y, "Resuming..."); - } else -#endif - { - const char *region = myRegion ? myRegion->name : NULL; - drawIconScreen(region, display, state, x, y); - } -} - // Used on boot when a certificate is being created static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { @@ -1336,32 +1322,10 @@ static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t comp arrowPoints[i]->scale(getCompassDiam(display) * 0.6); arrowPoints[i]->translate(compassX, compassY); } - drawLine(display, tip, tail); - drawLine(display, leftArrow, tip); - drawLine(display, rightArrow, tip); + display->drawLine(tip.x, tip.y, tail.x, tail.y); + display->drawLine(leftArrow.x, leftArrow.y, tip.x, tip.y); + display->drawLine(rightArrow.x, rightArrow.y, tip.x, tip.y); } -/* -// Draw north -static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading) -{ - // If north is supposed to be at the top of the compass we want rotation to be +0 - if (config.display.compass_north_top) - myHeading = -0; - - Point N1(-0.04f, 0.65f), N2(0.04f, 0.65f); - Point N3(-0.04f, 0.55f), N4(0.04f, 0.55f); - Point *rosePoints[] = {&N1, &N2, &N3, &N4}; - - for (int i = 0; i < 4; i++) { - // North on compass will be negative of heading - rosePoints[i]->rotate(-myHeading); - rosePoints[i]->scale(getCompassDiam(display)); - rosePoints[i]->translate(compassX, compassY); - } - drawLine(display, N1, N3); - drawLine(display, N2, N4); - drawLine(display, N1, N4); -}*/ // Get a string representation of the time passed since something happened static void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength) @@ -1461,7 +1425,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians else myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); - drawCompassNorth(display, compassX, compassY, myHeading); + screen->drawCompassNorth(display, compassX, compassY, myHeading); if (hasValidPosition(node)) { // display direction toward node @@ -1562,7 +1526,7 @@ static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, i myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians else myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); - drawCompassNorth(display, compassX, compassY, myHeading); + screen->drawCompassNorth(display, compassX, compassY, myHeading); // Distance to Waypoint float d = GeoCoord::latLongToMeter(DegD(wp.latitude_i), DegD(wp.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i)); @@ -1758,9 +1722,19 @@ void Screen::setup() // Add frames. EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); - static FrameCallback bootFrames[] = {drawBootScreen}; - static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]); - ui->setFrames(bootFrames, bootFrameCount); + alertFrames[0] = [this](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { +#ifdef ARCH_ESP32 + if (wakeCause == ESP_SLEEP_WAKEUP_TIMER || wakeCause == ESP_SLEEP_WAKEUP_EXT1) { + drawFrameText(display, state, x, y, "Resuming..."); + } else +#endif + { + // Draw region in upper left + const char *region = myRegion ? myRegion->name : NULL; + drawIconScreen(region, display, state, x, y); + } + }; + ui->setFrames(alertFrames, 1); // No overlays. ui->setOverlays(nullptr, 0); @@ -2723,4 +2697,4 @@ int Screen::handleWaypoint(const meshtastic_MeshPacket *arg) } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} -#endif // HAS_SCREEN +#endif // HAS_SCREEN \ No newline at end of file diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index a8aca36576..aa6e428937 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -82,6 +82,68 @@ class Screen #define SEGMENT_WIDTH 16 #define SEGMENT_HEIGHT 4 +namespace +{ +/// A basic 2D point class for drawing +class Point +{ + public: + float x, y; + + Point(float _x, float _y) : x(_x), y(_y) {} + + /// Apply a rotation around zero (standard rotation matrix math) + void rotate(float radian) + { + float cos = cosf(radian), sin = sinf(radian); + float rx = x * cos + y * sin, ry = -x * sin + y * cos; + + x = rx; + y = ry; + } + + void translate(int16_t dx, int dy) + { + x += dx; + y += dy; + } + + void scale(float f) + { + // We use -f here to counter the flip that happens + // on the y axis when drawing and rotating on screen + x *= f; + y *= -f; + } +}; + +} // namespace + +static uint16_t getCompassDiam(OLEDDisplay *display) +{ + uint16_t diam = 0; + uint16_t offset = 0; + + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) + offset = FONT_HEIGHT_SMALL; + + // get the smaller of the 2 dimensions and subtract 20 + if (display->getWidth() > (display->getHeight() - offset)) { + diam = display->getHeight() - offset; + // if 2/3 of the other size would be smaller, use that + if (diam > (display->getWidth() * 2 / 3)) { + diam = display->getWidth() * 2 / 3; + } + } else { + diam = display->getWidth(); + if (diam > ((display->getHeight() - offset) * 2 / 3)) { + diam = (display->getHeight() - offset) * 2 / 3; + } + } + + return diam - 20; +}; + namespace graphics { @@ -168,6 +230,30 @@ class Screen : public concurrency::OSThread void blink(); + void drawFrameText(OLEDDisplay *, OLEDDisplayUiState *, int16_t, int16_t, const char *); + + // Draw north + void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading) + { + // If north is supposed to be at the top of the compass we want rotation to be +0 + if (config.display.compass_north_top) + myHeading = -0; + + Point N1(-0.04f, 0.65f), N2(0.04f, 0.65f); + Point N3(-0.04f, 0.55f), N4(0.04f, 0.55f); + Point *rosePoints[] = {&N1, &N2, &N3, &N4}; + + for (int i = 0; i < 4; i++) { + // North on compass will be negative of heading + rosePoints[i]->rotate(-myHeading); + rosePoints[i]->scale(getCompassDiam(display)); + rosePoints[i]->translate(compassX, compassY); + } + display->drawLine(N1.x, N1.y, N3.x, N3.y); + display->drawLine(N2.x, N2.y, N4.x, N4.y); + display->drawLine(N1.x, N1.y, N4.x, N4.y); + } + /// Handle button press, trackball or swipe action) void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); } void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); } @@ -453,92 +539,5 @@ class Screen : public concurrency::OSThread }; } // namespace graphics -namespace -{ -/// A basic 2D point class for drawing -class Point -{ - public: - float x, y; - - Point(float _x, float _y) : x(_x), y(_y) {} - - /// Apply a rotation around zero (standard rotation matrix math) - void rotate(float radian) - { - float cos = cosf(radian), sin = sinf(radian); - float rx = x * cos + y * sin, ry = -x * sin + y * cos; - - x = rx; - y = ry; - } - - void translate(int16_t dx, int dy) - { - x += dx; - y += dy; - } - - void scale(float f) - { - // We use -f here to counter the flip that happens - // on the y axis when drawing and rotating on screen - x *= f; - y *= -f; - } -}; -} // namespace - -static void drawLine(OLEDDisplay *d, const Point &p1, const Point &p2) -{ - d->drawLine(p1.x, p1.y, p2.x, p2.y); -} - -static uint16_t getCompassDiam(OLEDDisplay *display) -{ - uint16_t diam = 0; - uint16_t offset = 0; - - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) - offset = FONT_HEIGHT_SMALL; - - // get the smaller of the 2 dimensions and subtract 20 - if (display->getWidth() > (display->getHeight() - offset)) { - diam = display->getHeight() - offset; - // if 2/3 of the other size would be smaller, use that - if (diam > (display->getWidth() * 2 / 3)) { - diam = display->getWidth() * 2 / 3; - } - } else { - diam = display->getWidth(); - if (diam > ((display->getHeight() - offset) * 2 / 3)) { - diam = (display->getHeight() - offset) * 2 / 3; - } - } - - return diam - 20; -}; - -// Draw north -static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading) -{ - // If north is supposed to be at the top of the compass we want rotation to be +0 - if (config.display.compass_north_top) - myHeading = -0; - - Point N1(-0.04f, 0.65f), N2(0.04f, 0.65f); - Point N3(-0.04f, 0.55f), N4(0.04f, 0.55f); - Point *rosePoints[] = {&N1, &N2, &N3, &N4}; - - for (int i = 0; i < 4; i++) { - // North on compass will be negative of heading - rosePoints[i]->rotate(-myHeading); - rosePoints[i]->scale(getCompassDiam(display)); - rosePoints[i]->translate(compassX, compassY); - } - drawLine(display, N1, N3); - drawLine(display, N2, N4); - drawLine(display, N1, N4); -} #endif \ No newline at end of file From 6f3d7ca4d21c1bd1f05751c1e2777910f20424c3 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Fri, 28 Jun 2024 23:30:39 -0500 Subject: [PATCH 103/211] Trim extra vprintf and filter for unprintable characters --- src/RedirectablePrint.cpp | 43 +++++++++++++-------------------------- src/RedirectablePrint.h | 1 - src/SerialConsole.cpp | 2 +- 3 files changed, 15 insertions(+), 31 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index ee819643e8..265bb42d66 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -50,27 +50,6 @@ size_t RedirectablePrint::write(uint8_t c) // serial port said (which could be zero) } -size_t RedirectablePrint::vprintf(const char *format, va_list arg) -{ - va_list copy; - static char printBuf[160]; - - va_copy(copy, arg); - size_t len = vsnprintf(printBuf, sizeof(printBuf), format, copy); - va_end(copy); - - // If the resulting string is longer than sizeof(printBuf)-1 characters, the remaining characters are still counted for the - // return value - - if (len > sizeof(printBuf) - 1) { - len = sizeof(printBuf) - 1; - printBuf[sizeof(printBuf) - 2] = '\n'; - } - - len = Print::write(printBuf, len); - return len; -} - size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_list arg) { va_list copy; @@ -87,14 +66,20 @@ size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_l len = sizeof(printBuf) - 1; printBuf[sizeof(printBuf) - 2] = '\n'; } - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) - Print::write("\u001b[34m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) - Print::write("\u001b[32m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) - Print::write("\u001b[33m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) - Print::write("\u001b[31m", 6); + for (size_t f = 0; f < len; f++) { + if (!std::isprint(static_cast(printBuf[f])) && printBuf[f] != '\n') + printBuf[f] = '#'; + } + if (logLevel != nullptr) { + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) + Print::write("\u001b[34m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) + Print::write("\u001b[32m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) + Print::write("\u001b[33m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) + Print::write("\u001b[31m", 6); + } len = Print::write(printBuf, len); Print::write("\u001b[0m", 5); return len; diff --git a/src/RedirectablePrint.h b/src/RedirectablePrint.h index c997d3d4e3..a29ad9c749 100644 --- a/src/RedirectablePrint.h +++ b/src/RedirectablePrint.h @@ -44,7 +44,6 @@ class RedirectablePrint : public Print void log(const char *logLevel, const char *format, ...) __attribute__((format(printf, 3, 4))); /** like printf but va_list based */ - size_t vprintf(const char *format, va_list arg); size_t vprintf(const char *logLevel, const char *format, va_list arg); void hexDump(const char *logLevel, unsigned char *buf, uint16_t len); diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index 53ece0fa3d..41064f2882 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -24,7 +24,7 @@ void consolePrintf(const char *format, ...) { va_list arg; va_start(arg, format); - console->vprintf(format, arg); + console->vprintf(nullptr, format, arg); va_end(arg); console->flush(); } From 20c1d71214aff27b6a63602fcd1f8ac922c15c87 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 29 Jun 2024 19:03:00 -0500 Subject: [PATCH 104/211] Deprecate Router Client role (and make it Client) (#4201) --- src/mesh/FloodingRouter.cpp | 1 - src/mesh/RadioInterface.cpp | 1 - src/modules/AdminModule.cpp | 4 ++++ src/modules/esp32/StoreForwardModule.cpp | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 7866fa444e..0fdde52772 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -22,7 +22,6 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) if (wasSeenRecently(p)) { // Note: this will also add a recent packet record printPacket("Ignoring incoming msg we've already seen", p); if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && - config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! Router::cancelSending(p->from, p->id); diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 78228c077c..cdea337172 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -261,7 +261,6 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr) uint8_t CWsize = map(snr, SNR_MIN, SNR_MAX, CWmin, CWmax); // LOG_DEBUG("rx_snr of %f so setting CWsize to:%d\n", snr, CWsize); if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || - config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT || config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { delay = random(0, 2 * CWsize) * slotTimeMsec; LOG_DEBUG("rx_snr found in packet. As a router, setting tx delay:%d\n", delay); diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 3a3901433d..11821a0a3e 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -388,6 +388,10 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) LOG_DEBUG("Tried to set node_info_broadcast_secs too low, setting to %d\n", min_node_info_broadcast_secs); config.device.node_info_broadcast_secs = min_node_info_broadcast_secs; } + // Router Client is deprecated; Set it to client + if (c.payload_variant.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT) { + config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT; + } break; case meshtastic_Config_position_tag: LOG_INFO("Setting config: Position\n"); diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp index 12cddc5202..dc8650ad0b 100644 --- a/src/modules/esp32/StoreForwardModule.cpp +++ b/src/modules/esp32/StoreForwardModule.cpp @@ -319,8 +319,8 @@ ProcessMessage StoreForwardModule::handleReceived(const meshtastic_MeshPacket &m #ifdef ARCH_ESP32 if (moduleConfig.store_forward.enabled) { - // The router node should not be sending messages as a client. Unless he is a ROUTER_CLIENT - if ((getFrom(&mp) != nodeDB->getNodeNum()) || (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT)) { + // The router node should not be sending messages as a client + if ((getFrom(&mp) != nodeDB->getNodeNum())) { if ((mp.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) && is_server) { auto &p = mp.decoded; From 47a94d7a076e2cd9ba0e3260ca51a74a7c101f01 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 29 Jun 2024 19:04:08 -0500 Subject: [PATCH 105/211] [create-pull-request] automated change (#4205) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/deviceonly.pb.h | 1 - src/mesh/generated/meshtastic/mesh.pb.cpp | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 6 +- src/mesh/generated/meshtastic/portnums.pb.h | 2 + src/mesh/generated/meshtastic/powermon.pb.cpp | 4 ++ src/mesh/generated/meshtastic/powermon.pb.h | 55 ++++++++++++++++++- 7 files changed, 65 insertions(+), 7 deletions(-) diff --git a/protobufs b/protobufs index 57ddb288e8..e7327e76bd 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 57ddb288e87438db3b5b99aa61f66a354c47bffb +Subproject commit e7327e76bdc0b3b77c50e214fae5beb1cb303e9c diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 100972c1eb..fc7bea53a4 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -8,7 +8,6 @@ #include "meshtastic/channel.pb.h" #include "meshtastic/localonly.pb.h" #include "meshtastic/mesh.pb.h" -#include "meshtastic/module_config.pb.h" #include "meshtastic/telemetry.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/mesh/generated/meshtastic/mesh.pb.cpp b/src/mesh/generated/meshtastic/mesh.pb.cpp index d4ad9186aa..3fa81e1312 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.cpp +++ b/src/mesh/generated/meshtastic/mesh.pb.cpp @@ -36,7 +36,7 @@ PB_BIND(meshtastic_NodeInfo, meshtastic_NodeInfo, AUTO) PB_BIND(meshtastic_MyNodeInfo, meshtastic_MyNodeInfo, AUTO) -PB_BIND(meshtastic_LogRecord, meshtastic_LogRecord, AUTO) +PB_BIND(meshtastic_LogRecord, meshtastic_LogRecord, 2) PB_BIND(meshtastic_QueueStatus, meshtastic_QueueStatus, AUTO) diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index e4e034cbdd..5e245a2b58 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -691,11 +691,11 @@ typedef struct _meshtastic_MyNodeInfo { and then extend as needed by emitting multiple records. */ typedef struct _meshtastic_LogRecord { /* Log levels, chosen to match python logging conventions. */ - char message[64]; + char message[384]; /* Seconds since 1970 - or 0 for unknown/unset */ uint32_t time; /* Usually based on thread name - if known */ - char source[8]; + char source[32]; /* Not yet set */ meshtastic_LogRecord_Level level; } meshtastic_LogRecord; @@ -1507,7 +1507,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_FileInfo_size 236 #define meshtastic_FromRadio_size 510 #define meshtastic_Heartbeat_size 0 -#define meshtastic_LogRecord_size 81 +#define meshtastic_LogRecord_size 426 #define meshtastic_MeshPacket_size 326 #define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 18 diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index 233e8d6534..6cc82352ab 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -124,6 +124,8 @@ typedef enum _meshtastic_PortNum { meshtastic_PortNum_ATAK_PLUGIN = 72, /* Provides unencrypted information about a node for consumption by a map via MQTT */ meshtastic_PortNum_MAP_REPORT_APP = 73, + /* PowerStress based monitoring support (for automated power consumption testing) */ + meshtastic_PortNum_POWERSTRESS_APP = 74, /* Private applications should use portnums >= 256. To simplify initial development and testing you can use "PRIVATE_APP" in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */ diff --git a/src/mesh/generated/meshtastic/powermon.pb.cpp b/src/mesh/generated/meshtastic/powermon.pb.cpp index 4d798e9a39..ce41ea0217 100644 --- a/src/mesh/generated/meshtastic/powermon.pb.cpp +++ b/src/mesh/generated/meshtastic/powermon.pb.cpp @@ -9,5 +9,9 @@ PB_BIND(meshtastic_PowerMon, meshtastic_PowerMon, AUTO) +PB_BIND(meshtastic_PowerStressMessage, meshtastic_PowerStressMessage, AUTO) + + + diff --git a/src/mesh/generated/meshtastic/powermon.pb.h b/src/mesh/generated/meshtastic/powermon.pb.h index 88e80bb559..7de0618e9b 100644 --- a/src/mesh/generated/meshtastic/powermon.pb.h +++ b/src/mesh/generated/meshtastic/powermon.pb.h @@ -38,6 +38,33 @@ See GPSPowerState for more details */ meshtastic_PowerMon_State_GPS_Active = 2048 } meshtastic_PowerMon_State; +/* What operation would we like the UUT to perform. +note: senders should probably set want_response in their request packets, so that they can know when the state +machine has started processing their request */ +typedef enum _meshtastic_PowerStressMessage_Opcode { + /* Unset/unused */ + meshtastic_PowerStressMessage_Opcode_UNSET = 0, + meshtastic_PowerStressMessage_Opcode_PRINT_INFO = 1, /* Print board version slog and send an ack that we are alive and ready to process commands */ + meshtastic_PowerStressMessage_Opcode_FORCE_QUIET = 2, /* Try to turn off all automatic processing of packets, screen, sleeping, etc (to make it easier to measure in isolation) */ + meshtastic_PowerStressMessage_Opcode_END_QUIET = 3, /* Stop powerstress processing - probably by just rebooting the board */ + meshtastic_PowerStressMessage_Opcode_SCREEN_ON = 16, /* Turn the screen on */ + meshtastic_PowerStressMessage_Opcode_SCREEN_OFF = 17, /* Turn the screen off */ + meshtastic_PowerStressMessage_Opcode_CPU_IDLE = 32, /* Let the CPU run but we assume mostly idling for num_seconds */ + meshtastic_PowerStressMessage_Opcode_CPU_DEEPSLEEP = 33, /* Force deep sleep for FIXME seconds */ + meshtastic_PowerStressMessage_Opcode_CPU_FULLON = 34, /* Spin the CPU as fast as possible for num_seconds */ + meshtastic_PowerStressMessage_Opcode_LED_ON = 48, /* Turn the LED on for num_seconds (and leave it on - for baseline power measurement purposes) */ + meshtastic_PowerStressMessage_Opcode_LED_OFF = 49, /* Force the LED off for num_seconds */ + meshtastic_PowerStressMessage_Opcode_LORA_OFF = 64, /* Completely turn off the LORA radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_LORA_TX = 65, /* Send Lora packets for num_seconds */ + meshtastic_PowerStressMessage_Opcode_LORA_RX = 66, /* Receive Lora packets for num_seconds (node will be mostly just listening, unless an external agent is helping stress this by sending packets on the current channel) */ + meshtastic_PowerStressMessage_Opcode_BT_OFF = 80, /* Turn off the BT radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_BT_ON = 81, /* Turn on the BT radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_WIFI_OFF = 96, /* Turn off the WIFI radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_WIFI_ON = 97, /* Turn on the WIFI radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_GPS_OFF = 112, /* Turn off the GPS radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_GPS_ON = 113 /* Turn on the GPS radio for num_seconds */ +} meshtastic_PowerStressMessage_Opcode; + /* Struct definitions */ /* Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs). But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) */ @@ -45,6 +72,13 @@ typedef struct _meshtastic_PowerMon { char dummy_field; } meshtastic_PowerMon; +/* PowerStress testing support via the C++ PowerStress module */ +typedef struct _meshtastic_PowerStressMessage { + /* What type of HardwareMessage is this? */ + meshtastic_PowerStressMessage_Opcode cmd; + float num_seconds; +} meshtastic_PowerStressMessage; + #ifdef __cplusplus extern "C" { @@ -55,13 +89,23 @@ extern "C" { #define _meshtastic_PowerMon_State_MAX meshtastic_PowerMon_State_GPS_Active #define _meshtastic_PowerMon_State_ARRAYSIZE ((meshtastic_PowerMon_State)(meshtastic_PowerMon_State_GPS_Active+1)) +#define _meshtastic_PowerStressMessage_Opcode_MIN meshtastic_PowerStressMessage_Opcode_UNSET +#define _meshtastic_PowerStressMessage_Opcode_MAX meshtastic_PowerStressMessage_Opcode_GPS_ON +#define _meshtastic_PowerStressMessage_Opcode_ARRAYSIZE ((meshtastic_PowerStressMessage_Opcode)(meshtastic_PowerStressMessage_Opcode_GPS_ON+1)) + + +#define meshtastic_PowerStressMessage_cmd_ENUMTYPE meshtastic_PowerStressMessage_Opcode /* Initializer values for message structs */ #define meshtastic_PowerMon_init_default {0} +#define meshtastic_PowerStressMessage_init_default {_meshtastic_PowerStressMessage_Opcode_MIN, 0} #define meshtastic_PowerMon_init_zero {0} +#define meshtastic_PowerStressMessage_init_zero {_meshtastic_PowerStressMessage_Opcode_MIN, 0} /* Field tags (for use in manual encoding/decoding) */ +#define meshtastic_PowerStressMessage_cmd_tag 1 +#define meshtastic_PowerStressMessage_num_seconds_tag 2 /* Struct field encoding specification for nanopb */ #define meshtastic_PowerMon_FIELDLIST(X, a) \ @@ -69,14 +113,23 @@ extern "C" { #define meshtastic_PowerMon_CALLBACK NULL #define meshtastic_PowerMon_DEFAULT NULL +#define meshtastic_PowerStressMessage_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, cmd, 1) \ +X(a, STATIC, SINGULAR, FLOAT, num_seconds, 2) +#define meshtastic_PowerStressMessage_CALLBACK NULL +#define meshtastic_PowerStressMessage_DEFAULT NULL + extern const pb_msgdesc_t meshtastic_PowerMon_msg; +extern const pb_msgdesc_t meshtastic_PowerStressMessage_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define meshtastic_PowerMon_fields &meshtastic_PowerMon_msg +#define meshtastic_PowerStressMessage_fields &meshtastic_PowerStressMessage_msg /* Maximum encoded size of messages (where known) */ -#define MESHTASTIC_MESHTASTIC_POWERMON_PB_H_MAX_SIZE meshtastic_PowerMon_size +#define MESHTASTIC_MESHTASTIC_POWERMON_PB_H_MAX_SIZE meshtastic_PowerStressMessage_size #define meshtastic_PowerMon_size 0 +#define meshtastic_PowerStressMessage_size 7 #ifdef __cplusplus } /* extern "C" */ From b5d771831921bee1b59c969a04c246fd3fdae630 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sat, 29 Jun 2024 21:16:07 -0500 Subject: [PATCH 106/211] Move waypoint (#4202) * Move waypoint screen draw into the waypoint module * Get the observer set up for the waypoint screen draw * Static squashing: screen dimensions Macros moved back to Screen.cpp, as a band-aid until we eventually move all those static functions into the Screen class. * Move getCompassDiam into Screen class (supress compiler warnings) At this stage, the method is still static, because it's used by drawNodeInfo, which has no tidy reference to our screen instance. This is probably just another band-aid until these static functions all move. * Use new getCompassDiam function in AccelerometerThread * Properly gate display code in WaypointModule --------- Co-authored-by: Todd Herbert --- src/AccelerometerThread.h | 7 +- src/graphics/Screen.cpp | 238 +++++++++------------------------ src/graphics/Screen.h | 67 +++------- src/modules/WaypointModule.cpp | 150 ++++++++++++++++++++- src/modules/WaypointModule.h | 14 +- 5 files changed, 248 insertions(+), 228 deletions(-) diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h index 39ae903855..c2910007e3 100644 --- a/src/AccelerometerThread.h +++ b/src/AccelerometerThread.h @@ -278,16 +278,17 @@ class AccelerometerThread : public concurrency::OSThread display->setFont(FONT_MEDIUM); display->drawString(x, y, "Calibrating\nCompass"); int16_t compassX = 0, compassY = 0; + uint16_t compassDiam = graphics::Screen::getCompassDiam(display->getWidth(), display->getHeight()); // coordinates for the center of the compass/circle if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { - compassX = x + display->getWidth() - getCompassDiam(display) / 2 - 5; + compassX = x + display->getWidth() - compassDiam / 2 - 5; compassY = y + display->getHeight() / 2; } else { - compassX = x + display->getWidth() - getCompassDiam(display) / 2 - 5; + compassX = x + display->getWidth() - compassDiam / 2 - 5; compassY = y + FONT_HEIGHT_SMALL + (display->getHeight() - FONT_HEIGHT_SMALL) / 2; } - display->drawCircle(compassX, compassY, getCompassDiam(display) / 2); + display->drawCircle(compassX, compassY, compassDiam / 2); screen->drawCompassNorth(display, compassX, compassY, screen->getHeading() * PI / 180); } #endif diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 7c8bf40bb8..f724ddd3d4 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -43,7 +43,6 @@ along with this program. If not, see . #include "meshUtils.h" #include "modules/ExternalNotificationModule.h" #include "modules/TextMessageModule.h" -#include "modules/WaypointModule.h" #include "sleep.h" #include "target_specific.h" @@ -60,9 +59,6 @@ along with this program. If not, see . #include "platform/portduino/PortduinoGlue.h" #endif -/// Convert an integer GPS coords to a floating point -#define DegD(i) (i * 1e-7) - using namespace meshtastic; /** @todo remove */ namespace graphics @@ -111,10 +107,10 @@ GeoCoord geoCoord; static bool heartbeat = false; #endif -static uint16_t displayWidth, displayHeight; - -#define SCREEN_WIDTH displayWidth -#define SCREEN_HEIGHT displayHeight +// Quick access to screen dimensions from static drawing functions +// DEPRECATED. To-do: move static functions inside Screen class +#define SCREEN_WIDTH display->getWidth() +#define SCREEN_HEIGHT display->getHeight() #include "graphics/ScreenFonts.h" @@ -416,37 +412,6 @@ static bool shouldDrawMessage(const meshtastic_MeshPacket *packet) return packet->from != 0 && !moduleConfig.store_forward.enabled; } -// Determine whether the waypoint frame should be drawn (waypoint deleted? expired?) -static bool shouldDrawWaypoint(const meshtastic_MeshPacket *packet) -{ -#if !MESHTASTIC_EXCLUDE_WAYPOINT - // If no waypoint to show - if (!devicestate.has_rx_waypoint) - return false; - - // Decode the message, to find the expiration time (is waypoint still valid) - // This handles "deletion" as well as expiration - meshtastic_Waypoint wp; - memset(&wp, 0, sizeof(wp)); - if (pb_decode_from_bytes(packet->decoded.payload.bytes, packet->decoded.payload.size, &meshtastic_Waypoint_msg, &wp)) { - // Valid waypoint - if (wp.expire > getTime()) - return devicestate.has_rx_waypoint = true; - - // Expired, or deleted - else - return devicestate.has_rx_waypoint = false; - } - - // If decoding failed - LOG_ERROR("Failed to decode waypoint\n"); - devicestate.has_rx_waypoint = false; - return false; -#else - return false; -#endif -} - // Draw power bars or a charging indicator on an image of a battery, determined by battery charge voltage or percentage. static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *imgBuffer, const PowerStatus *powerStatus) { @@ -1093,7 +1058,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state } /// Draw a series of fields in a column, wrapping to multiple columns if needed -static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields) +void Screen::drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields) { // The coordinates define the left starting point of the text display->setTextAlignment(TEXT_ALIGN_LEFT); @@ -1279,7 +1244,7 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const * We keep a series of "after you've gone 10 meters, what is your heading since * the last reference point?" */ -static float estimatedHeading(double lat, double lon) +float Screen::estimatedHeading(double lat, double lon) { static double oldLat, oldLon; static float b; @@ -1309,7 +1274,7 @@ static size_t nodeIndex; static int8_t prevFrame = -1; // Draw the arrow pointing to a node's location -static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, float headingRadian) +void Screen::drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, uint16_t compassDiam, float headingRadian) { Point tip(0.0f, 0.5f), tail(0.0f, -0.5f); // pointing up initially float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f; @@ -1319,7 +1284,7 @@ static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t comp for (int i = 0; i < 4; i++) { arrowPoints[i]->rotate(headingRadian); - arrowPoints[i]->scale(getCompassDiam(display) * 0.6); + arrowPoints[i]->scale(compassDiam * 0.6); arrowPoints[i]->translate(compassX, compassY); } display->drawLine(tip.x, tip.y, tail.x, tail.y); @@ -1328,7 +1293,7 @@ static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t comp } // Get a string representation of the time passed since something happened -static void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength) +void Screen::getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength) { // Use an absolute timestamp in some cases. // Particularly useful with E-Ink displays. Static UI, fewer refreshes. @@ -1357,6 +1322,54 @@ static void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength) snprintf(timeStr, maxLength, "unknown age"); } +void Screen::drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading) +{ + // If north is supposed to be at the top of the compass we want rotation to be +0 + if (config.display.compass_north_top) + myHeading = -0; + + Point N1(-0.04f, 0.65f), N2(0.04f, 0.65f); + Point N3(-0.04f, 0.55f), N4(0.04f, 0.55f); + Point *rosePoints[] = {&N1, &N2, &N3, &N4}; + + uint16_t compassDiam = Screen::getCompassDiam(SCREEN_WIDTH, SCREEN_HEIGHT); + + for (int i = 0; i < 4; i++) { + // North on compass will be negative of heading + rosePoints[i]->rotate(-myHeading); + rosePoints[i]->scale(compassDiam); + rosePoints[i]->translate(compassX, compassY); + } + display->drawLine(N1.x, N1.y, N3.x, N3.y); + display->drawLine(N2.x, N2.y, N4.x, N4.y); + display->drawLine(N1.x, N1.y, N4.x, N4.y); +} + +uint16_t Screen::getCompassDiam(uint32_t displayWidth, uint32_t displayHeight) +{ + uint16_t diam = 0; + uint16_t offset = 0; + + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) + offset = FONT_HEIGHT_SMALL; + + // get the smaller of the 2 dimensions and subtract 20 + if (displayWidth > (displayHeight - offset)) { + diam = displayHeight - offset; + // if 2/3 of the other size would be smaller, use that + if (diam > (displayWidth * 2 / 3)) { + diam = displayWidth * 2 / 3; + } + } else { + diam = displayWidth; + if (diam > ((displayHeight - offset) * 2 / 3)) { + diam = (displayHeight - offset) * 2 / 3; + } + } + + return diam - 20; +}; + static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { // We only advance our nodeIndex if the frame # has changed - because @@ -1396,7 +1409,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ } static char lastStr[20]; - getTimeAgoStr(sinceLastSeen(node), lastStr, sizeof(lastStr)); + screen->getTimeAgoStr(sinceLastSeen(node), lastStr, sizeof(lastStr)); static char distStr[20]; if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) { @@ -1407,13 +1420,14 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); const char *fields[] = {username, lastStr, signalStr, distStr, NULL}; int16_t compassX = 0, compassY = 0; + uint16_t compassDiam = Screen::getCompassDiam(SCREEN_WIDTH, SCREEN_HEIGHT); // coordinates for the center of the compass/circle if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { - compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5; + compassX = x + SCREEN_WIDTH - compassDiam / 2 - 5; compassY = y + SCREEN_HEIGHT / 2; } else { - compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5; + compassX = x + SCREEN_WIDTH - compassDiam / 2 - 5; compassY = y + FONT_HEIGHT_SMALL + (SCREEN_HEIGHT - FONT_HEIGHT_SMALL) / 2; } bool hasNodeHeading = false; @@ -1424,7 +1438,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ if (screen->hasHeading()) myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians else - myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); + myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); screen->drawCompassNorth(display, compassX, compassY, myHeading); if (hasValidPosition(node)) { @@ -1452,7 +1466,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ // If the top of the compass is not a static north we need adjust bearingToOther based on heading if (!config.display.compass_north_top) bearingToOther -= myHeading; - drawNodeHeading(display, compassX, compassY, bearingToOther); + screen->drawNodeHeading(display, compassX, compassY, compassDiam, bearingToOther); } } if (!hasNodeHeading) { @@ -1462,119 +1476,13 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ // hasValidPosition(node)); display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?"); } - display->drawCircle(compassX, compassY, getCompassDiam(display) / 2); - - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { - display->setColor(BLACK); - } - // Must be after distStr is populated - drawColumns(display, x, y, fields); -} - -/// Draw the last waypoint we received -static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -{ - // Prepare to draw - display->setFont(FONT_SMALL); - display->setTextAlignment(TEXT_ALIGN_LEFT); - - // Handle inverted display - // Unsure of expected behavior: for now, copy drawNodeInfo - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) - display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); - - // Decode the waypoint - meshtastic_MeshPacket &mp = devicestate.rx_waypoint; - meshtastic_Waypoint wp; - memset(&wp, 0, sizeof(wp)); - if (!pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &wp)) { - // This *should* be caught by shouldDrawWaypoint, but we'll short-circuit here just in case - display->drawStringMaxWidth(0 + x, 0 + y, x + display->getWidth(), "Couldn't decode waypoint"); - devicestate.has_rx_waypoint = false; - return; - } - - // Get timestamp info. Will pass as a field to drawColumns - static char lastStr[20]; - getTimeAgoStr(sinceReceived(&mp), lastStr, sizeof(lastStr)); - - // Will contain distance information, passed as a field to drawColumns - static char distStr[20]; - - // Get our node, to use our own position - meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); - - // Text fields to draw (left of compass) - // Last element must be NULL. This signals the end of the char*[] to drawColumns - const char *fields[] = {"Waypoint", lastStr, wp.name, distStr, NULL}; - - // Co-ordinates for the center of the compass/circle - int16_t compassX = 0, compassY = 0; - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { - compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5; - compassY = y + SCREEN_HEIGHT / 2; - } else { - compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5; - compassY = y + FONT_HEIGHT_SMALL + (SCREEN_HEIGHT - FONT_HEIGHT_SMALL) / 2; - } - - // If our node has a position: - if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) { - const meshtastic_PositionLite &op = ourNode->position; - float myHeading; - if (screen->hasHeading()) - myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians - else - myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); - screen->drawCompassNorth(display, compassX, compassY, myHeading); - - // Distance to Waypoint - float d = GeoCoord::latLongToMeter(DegD(wp.latitude_i), DegD(wp.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i)); - if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) { - if (d < (2 * MILES_TO_FEET)) - snprintf(distStr, sizeof(distStr), "%.0f ft", d * METERS_TO_FEET); - else - snprintf(distStr, sizeof(distStr), "%.1f mi", d * METERS_TO_FEET / MILES_TO_FEET); - } else { - if (d < 2000) - snprintf(distStr, sizeof(distStr), "%.0f m", d); - else - snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000); - } - - // Compass bearing to waypoint - float bearingToOther = - GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(wp.latitude_i), DegD(wp.longitude_i)); - // If the top of the compass is a static north then bearingToOther can be drawn on the compass directly - // If the top of the compass is not a static north we need adjust bearingToOther based on heading - if (!config.display.compass_north_top) - bearingToOther -= myHeading; - drawNodeHeading(display, compassX, compassY, bearingToOther); - } - - // If our node doesn't have position - else { - // ? in the compass - display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?"); - - // ? in the distance field - if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) - strncpy(distStr, "? mi", sizeof(distStr)); - else - strncpy(distStr, "? km", sizeof(distStr)); - } + display->drawCircle(compassX, compassY, compassDiam / 2); - // Undo color-inversion, if set prior to drawing header - // Unsure of expected behavior? For now: copy drawNodeInfo if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { display->setColor(BLACK); } - - // Draw compass circle - display->drawCircle(compassX, compassY, getCompassDiam(display) / 2); - // Must be after distStr is populated - drawColumns(display, x, y, fields); + screen->drawColumns(display, x, y, fields); } Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry) @@ -1797,8 +1705,6 @@ void Screen::setup() textMessageObserver.observe(textMessageModule); if (inputBroker) inputObserver.observe(inputBroker); - if (waypointModule) - waypointObserver.observe(waypointModule); // Modules can notify screen about refresh MeshModule::observeUIEvents(&uiFrameEventObserver); @@ -2130,11 +2036,6 @@ void Screen::setFrames() normalFrames[numframes++] = drawTextMessageFrame; } - // If we have a waypoint (not expired, not deleted) - if (devicestate.has_rx_waypoint && shouldDrawWaypoint(&devicestate.rx_waypoint)) { - normalFrames[numframes++] = drawWaypointFrame; - } - // then all the nodes // We only show a few nodes in our scrolling list - because meshes with many nodes would have too many screens size_t numToShow = min(numMeshNodes, 4U); @@ -2196,7 +2097,7 @@ void Screen::blink() uint8_t count = 10; dispdev->setBrightness(254); while (count > 0) { - dispdev->fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + dispdev->fillRect(0, 0, dispdev->getWidth(), dispdev->getHeight()); dispdev->display(); delay(50); dispdev->clear(); @@ -2687,13 +2588,6 @@ int Screen::handleInputEvent(const InputEvent *event) return 0; } -int Screen::handleWaypoint(const meshtastic_MeshPacket *arg) -{ - // TODO: move to appropriate frame when redrawing - setFrames(); - return 0; -} - } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index aa6e428937..e80581d6d9 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -82,6 +82,9 @@ class Screen #define SEGMENT_WIDTH 16 #define SEGMENT_HEIGHT 4 +/// Convert an integer GPS coords to a floating point +#define DegD(i) (i * 1e-7) + namespace { /// A basic 2D point class for drawing @@ -119,31 +122,6 @@ class Point } // namespace -static uint16_t getCompassDiam(OLEDDisplay *display) -{ - uint16_t diam = 0; - uint16_t offset = 0; - - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) - offset = FONT_HEIGHT_SMALL; - - // get the smaller of the 2 dimensions and subtract 20 - if (display->getWidth() > (display->getHeight() - offset)) { - diam = display->getHeight() - offset; - // if 2/3 of the other size would be smaller, use that - if (diam > (display->getWidth() * 2 / 3)) { - diam = display->getWidth() * 2 / 3; - } - } else { - diam = display->getWidth(); - if (diam > ((display->getHeight() - offset) * 2 / 3)) { - diam = (display->getHeight() - offset) * 2 / 3; - } - } - - return diam - 20; -}; - namespace graphics { @@ -188,8 +166,6 @@ class Screen : public concurrency::OSThread CallbackObserver(this, &Screen::handleStatusUpdate); CallbackObserver textMessageObserver = CallbackObserver(this, &Screen::handleTextMessage); - CallbackObserver waypointObserver = - CallbackObserver(this, &Screen::handleWaypoint); CallbackObserver uiFrameEventObserver = CallbackObserver(this, &Screen::handleUIFrameEvent); CallbackObserver inputObserver = @@ -232,27 +208,18 @@ class Screen : public concurrency::OSThread void drawFrameText(OLEDDisplay *, OLEDDisplayUiState *, int16_t, int16_t, const char *); + void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength); + // Draw north - void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading) - { - // If north is supposed to be at the top of the compass we want rotation to be +0 - if (config.display.compass_north_top) - myHeading = -0; - - Point N1(-0.04f, 0.65f), N2(0.04f, 0.65f); - Point N3(-0.04f, 0.55f), N4(0.04f, 0.55f); - Point *rosePoints[] = {&N1, &N2, &N3, &N4}; - - for (int i = 0; i < 4; i++) { - // North on compass will be negative of heading - rosePoints[i]->rotate(-myHeading); - rosePoints[i]->scale(getCompassDiam(display)); - rosePoints[i]->translate(compassX, compassY); - } - display->drawLine(N1.x, N1.y, N3.x, N3.y); - display->drawLine(N2.x, N2.y, N4.x, N4.y); - display->drawLine(N1.x, N1.y, N4.x, N4.y); - } + void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading); + + static uint16_t getCompassDiam(uint32_t displayWidth, uint32_t displayHeight); + + float estimatedHeading(double lat, double lon); + + void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, uint16_t compassDiam, float headingRadian); + + void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields); /// Handle button press, trackball or swipe action) void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); } @@ -421,7 +388,6 @@ class Screen : public concurrency::OSThread int handleTextMessage(const meshtastic_MeshPacket *arg); int handleUIFrameEvent(const UIFrameEvent *arg); int handleInputEvent(const InputEvent *arg); - int handleWaypoint(const meshtastic_MeshPacket *arg); /// Used to force (super slow) eink displays to draw critical frames void forceDisplay(bool forceUiUpdate = false); @@ -444,6 +410,11 @@ class Screen : public concurrency::OSThread bool isAUTOOled = false; + // Screen dimensions (for convenience) + // Defined during Screen::setup + uint16_t displayWidth = 0; + uint16_t displayHeight = 0; + private: FrameCallback alertFrames[1]; struct ScreenCmd { diff --git a/src/modules/WaypointModule.cpp b/src/modules/WaypointModule.cpp index 83485c8eee..d5b7d29ee5 100644 --- a/src/modules/WaypointModule.cpp +++ b/src/modules/WaypointModule.cpp @@ -2,6 +2,11 @@ #include "NodeDB.h" #include "PowerFSM.h" #include "configuration.h" +#if HAS_SCREEN +#include "gps/RTC.h" +#include "graphics/Screen.h" +#include "main.h" +#endif WaypointModule *waypointModule; @@ -11,14 +16,155 @@ ProcessMessage WaypointModule::handleReceived(const meshtastic_MeshPacket &mp) auto &p = mp.decoded; LOG_INFO("Received waypoint msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes); #endif - + UIFrameEvent e = {true, true}; // We only store/display messages destined for us. // Keep a copy of the most recent text message. devicestate.rx_waypoint = mp; devicestate.has_rx_waypoint = true; powerFSM.trigger(EVENT_RECEIVED_MSG); - notifyObservers(&mp); + notifyObservers(&e); return ProcessMessage::CONTINUE; // Let others look at this message also if they want } + +#if HAS_SCREEN +bool WaypointModule::shouldDraw() +{ +#if !MESHTASTIC_EXCLUDE_WAYPOINT + // If no waypoint to show + if (!devicestate.has_rx_waypoint) + return false; + + // Decode the message, to find the expiration time (is waypoint still valid) + // This handles "deletion" as well as expiration + meshtastic_Waypoint wp; + memset(&wp, 0, sizeof(wp)); + if (pb_decode_from_bytes(devicestate.rx_waypoint.decoded.payload.bytes, devicestate.rx_waypoint.decoded.payload.size, + &meshtastic_Waypoint_msg, &wp)) { + // Valid waypoint + if (wp.expire > getTime()) + return devicestate.has_rx_waypoint = true; + + // Expired, or deleted + else + return devicestate.has_rx_waypoint = false; + } + + // If decoding failed + LOG_ERROR("Failed to decode waypoint\n"); + devicestate.has_rx_waypoint = false; + return false; +#else + return false; +#endif +} + +/// Draw the last waypoint we received +void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + // Prepare to draw + display->setFont(FONT_SMALL); + display->setTextAlignment(TEXT_ALIGN_LEFT); + + // Handle inverted display + // Unsure of expected behavior: for now, copy drawNodeInfo + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) + display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); + + // Decode the waypoint + meshtastic_MeshPacket &mp = devicestate.rx_waypoint; + meshtastic_Waypoint wp; + memset(&wp, 0, sizeof(wp)); + if (!pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &wp)) { + // This *should* be caught by shouldDrawWaypoint, but we'll short-circuit here just in case + display->drawStringMaxWidth(0 + x, 0 + y, x + display->getWidth(), "Couldn't decode waypoint"); + devicestate.has_rx_waypoint = false; + return; + } + + // Get timestamp info. Will pass as a field to drawColumns + static char lastStr[20]; + screen->getTimeAgoStr(sinceReceived(&mp), lastStr, sizeof(lastStr)); + + // Will contain distance information, passed as a field to drawColumns + static char distStr[20]; + + // Get our node, to use our own position + meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); + + // Text fields to draw (left of compass) + // Last element must be NULL. This signals the end of the char*[] to drawColumns + const char *fields[] = {"Waypoint", lastStr, wp.name, distStr, NULL}; + + // Dimensions / co-ordinates for the compass/circle + int16_t compassX = 0, compassY = 0; + uint16_t compassDiam = graphics::Screen::getCompassDiam(display->getWidth(), display->getHeight()); + + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { + compassX = x + display->getWidth() - compassDiam / 2 - 5; + compassY = y + display->getHeight() / 2; + } else { + compassX = x + display->getWidth() - compassDiam / 2 - 5; + compassY = y + FONT_HEIGHT_SMALL + (display->getHeight() - FONT_HEIGHT_SMALL) / 2; + } + + // If our node has a position: + if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) { + const meshtastic_PositionLite &op = ourNode->position; + float myHeading; + if (screen->hasHeading()) + myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians + else + myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); + screen->drawCompassNorth(display, compassX, compassY, myHeading); + + // Distance to Waypoint + float d = GeoCoord::latLongToMeter(DegD(wp.latitude_i), DegD(wp.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i)); + if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) { + if (d < (2 * MILES_TO_FEET)) + snprintf(distStr, sizeof(distStr), "%.0f ft", d * METERS_TO_FEET); + else + snprintf(distStr, sizeof(distStr), "%.1f mi", d * METERS_TO_FEET / MILES_TO_FEET); + } else { + if (d < 2000) + snprintf(distStr, sizeof(distStr), "%.0f m", d); + else + snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000); + } + + // Compass bearing to waypoint + float bearingToOther = + GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(wp.latitude_i), DegD(wp.longitude_i)); + // If the top of the compass is a static north then bearingToOther can be drawn on the compass directly + // If the top of the compass is not a static north we need adjust bearingToOther based on heading + if (!config.display.compass_north_top) + bearingToOther -= myHeading; + screen->drawNodeHeading(display, compassX, compassY, compassDiam, bearingToOther); + } + + // If our node doesn't have position + else { + // ? in the compass + display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?"); + + // ? in the distance field + if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) + strncpy(distStr, "? mi", sizeof(distStr)); + else + strncpy(distStr, "? km", sizeof(distStr)); + } + + // Undo color-inversion, if set prior to drawing header + // Unsure of expected behavior? For now: copy drawNodeInfo + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { + display->setColor(BLACK); + } + + // Draw compass circle + display->drawCircle(compassX, compassY, compassDiam / 2); + + // Must be after distStr is populated + screen->drawColumns(display, x, y, fields); +} +#endif \ No newline at end of file diff --git a/src/modules/WaypointModule.h b/src/modules/WaypointModule.h index ddbabf4deb..4c9c7b86b0 100644 --- a/src/modules/WaypointModule.h +++ b/src/modules/WaypointModule.h @@ -5,21 +5,29 @@ /** * Waypoint message handling for meshtastic */ -class WaypointModule : public SinglePortModule, public Observable +class WaypointModule : public SinglePortModule, public Observable { public: /** Constructor * name is for debugging output */ WaypointModule() : SinglePortModule("waypoint", meshtastic_PortNum_WAYPOINT_APP) {} - +#if HAS_SCREEN + bool shouldDraw(); +#endif protected: /** Called to handle a particular incoming message @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it */ + + virtual Observable *getUIFrameObservable() override { return this; } +#if HAS_SCREEN + virtual bool wantUIFrame() override { return this->shouldDraw(); } + virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override; +#endif virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override; }; -extern WaypointModule *waypointModule; +extern WaypointModule *waypointModule; \ No newline at end of file From 469ae0ff846944be12f293023954aad917e4ffcf Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 30 Jun 2024 08:22:24 -0500 Subject: [PATCH 107/211] Fix flakey phone api transition from file manifest to complete (#4209) * Try fix flakey phone api transition from file manifest to complete * Skip --- src/mesh/PhoneAPI.cpp | 20 +++++++++++++------- src/mesh/PhoneAPI.h | 2 ++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index d6721b018e..322b0cf5eb 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -355,9 +355,10 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) LOG_INFO("getFromRadio=STATE_SEND_FILEMANIFEST\n"); // last element if (config_state == filesManifest.size()) { // also handles an empty filesManifest - state = STATE_SEND_COMPLETE_ID; config_state = 0; filesManifest.clear(); + // Skip to complete packet + sendConfigComplete(); } else { fromRadioScratch.which_payload_variant = meshtastic_FromRadio_fileInfo_tag; fromRadioScratch.fileInfo = filesManifest.at(config_state); @@ -368,12 +369,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) } case STATE_SEND_COMPLETE_ID: - LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n"); - fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag; - fromRadioScratch.config_complete_id = config_nonce; - config_nonce = 0; - state = STATE_SEND_PACKETS; - pauseBluetoothLogging = false; + sendConfigComplete(); break; case STATE_SEND_PACKETS: @@ -419,6 +415,16 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) return 0; } +void PhoneAPI::sendConfigComplete() +{ + LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n"); + fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag; + fromRadioScratch.config_complete_id = config_nonce; + config_nonce = 0; + state = STATE_SEND_PACKETS; + pauseBluetoothLogging = false; +} + void PhoneAPI::handleDisconnect() { filesManifest.clear(); diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 1a2a065d35..3c3668300a 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -104,6 +104,8 @@ class PhoneAPI */ size_t getFromRadio(uint8_t *buf); + void sendConfigComplete(); + /** * Return true if we have data available to send to the phone */ From 8177329eac557c0bc366428fc8fc500014b5185c Mon Sep 17 00:00:00 2001 From: Manuel <71137295+mverch67@users.noreply.github.com> Date: Sun, 30 Jun 2024 23:01:28 +0200 Subject: [PATCH 108/211] enable colors in platformio serial monitor (#4217) --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index 720525f095..bcdcc0034b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -77,6 +77,7 @@ build_flags = -Wno-missing-field-initializers -DMESHTASTIC_EXCLUDE_DROPZONE=1 monitor_speed = 115200 +monitor_filters = direct lib_deps = jgromes/RadioLib@~6.6.0 From 3219d65387876e9582a5bd8c99bb5c15843d4344 Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 30 Jun 2024 16:41:27 -0700 Subject: [PATCH 109/211] When talking via serial, encapsulate log messages in protobufs if necessary (#4187) * clean up RedirectablePrint::log so it doesn't have three very different implementations inline. * remove NoopPrint - it is no longer needed * when talking to API clients via serial, don't turn off log msgs instead encapsuate them * fix the build - would loop forever if there were no files to send * don't use Segger code if not talking to a Segger debugger * when encapsulating logs, make sure the strings always has nul terminators * nrf52 soft device will watchdog if you use ICE while BT on... so have debugger disable bluetooth. * Important to not print debug messages while writing to the toPhone scratch buffer * don't include newlines if encapsulating log records as protobufs --------- Co-authored-by: Ben Meadors --- src/RedirectablePrint.cpp | 253 ++++++++++++++++++++------------------ src/RedirectablePrint.h | 17 ++- src/SerialConsole.cpp | 34 ++++- src/SerialConsole.h | 10 +- src/main.cpp | 2 +- src/mesh/PhoneAPI.cpp | 4 +- src/mesh/StreamAPI.cpp | 23 +++- src/mesh/StreamAPI.h | 5 +- 8 files changed, 207 insertions(+), 141 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 265bb42d66..782febd759 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -15,11 +15,6 @@ #include "platform/portduino/PortduinoGlue.h" #endif -/** - * A printer that doesn't go anywhere - */ -NoopPrint noopPrint; - #if HAS_WIFI || HAS_ETHERNET extern Syslog syslog; #endif @@ -39,7 +34,7 @@ void RedirectablePrint::setDestination(Print *_dest) size_t RedirectablePrint::write(uint8_t c) { // Always send the characters to our segger JTAG debugger -#ifdef SEGGER_STDOUT_CH +#ifdef USE_SEGGER SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c); #endif @@ -85,6 +80,134 @@ size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_l return len; } +void RedirectablePrint::log_to_serial(const char *logLevel, const char *format, va_list arg) +{ + size_t r = 0; + + // Cope with 0 len format strings, but look for new line terminator + bool hasNewline = *format && format[strlen(format) - 1] == '\n'; + + // If we are the first message on a report, include the header + if (!isContinuationMessage) { + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) + Print::write("\u001b[34m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) + Print::write("\u001b[32m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) + Print::write("\u001b[33m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) + Print::write("\u001b[31m", 6); + uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile + if (rtc_sec > 0) { + long hms = rtc_sec % SEC_PER_DAY; + // hms += tz.tz_dsttime * SEC_PER_HOUR; + // hms -= tz.tz_minuteswest * SEC_PER_MIN; + // mod `hms` to ensure in positive range of [0...SEC_PER_DAY) + hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; + + // Tear apart hms into h:m:s + int hour = hms / SEC_PER_HOUR; + int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; + int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN +#ifdef ARCH_PORTDUINO + ::printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); +#else + printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); +#endif + } else +#ifdef ARCH_PORTDUINO + ::printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); +#else + printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); +#endif + + auto thread = concurrency::OSThread::currentThread; + if (thread) { + print("["); + // printf("%p ", thread); + // assert(thread->ThreadName.length()); + print(thread->ThreadName); + print("] "); + } + } + r += vprintf(logLevel, format, arg); + + isContinuationMessage = !hasNewline; +} + +void RedirectablePrint::log_to_syslog(const char *logLevel, const char *format, va_list arg) +{ +#if (HAS_WIFI || HAS_ETHERNET) && !defined(ARCH_PORTDUINO) + // if syslog is in use, collect the log messages and send them to syslog + if (syslog.isEnabled()) { + int ll = 0; + switch (logLevel[0]) { + case 'D': + ll = SYSLOG_DEBUG; + break; + case 'I': + ll = SYSLOG_INFO; + break; + case 'W': + ll = SYSLOG_WARN; + break; + case 'E': + ll = SYSLOG_ERR; + break; + case 'C': + ll = SYSLOG_CRIT; + break; + default: + ll = 0; + } + auto thread = concurrency::OSThread::currentThread; + if (thread) { + syslog.vlogf(ll, thread->ThreadName.c_str(), format, arg); + } else { + syslog.vlogf(ll, format, arg); + } + } +#endif +} + +void RedirectablePrint::log_to_ble(const char *logLevel, const char *format, va_list arg) +{ + if (config.bluetooth.device_logging_enabled && !pauseBluetoothLogging) { + bool isBleConnected = false; +#ifdef ARCH_ESP32 + isBleConnected = nimbleBluetooth && nimbleBluetooth->isActive() && nimbleBluetooth->isConnected(); +#elif defined(ARCH_NRF52) + isBleConnected = nrf52Bluetooth != nullptr && nrf52Bluetooth->isConnected(); +#endif + if (isBleConnected) { + char *message; + size_t initialLen; + size_t len; + initialLen = strlen(format); + message = new char[initialLen + 1]; + len = vsnprintf(message, initialLen + 1, format, arg); + if (len > initialLen) { + delete[] message; + message = new char[len + 1]; + vsnprintf(message, len + 1, format, arg); + } + auto thread = concurrency::OSThread::currentThread; +#ifdef ARCH_ESP32 + if (thread) + nimbleBluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str()); + else + nimbleBluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str()); +#elif defined(ARCH_NRF52) + if (thread) + nrf52Bluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str()); + else + nrf52Bluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str()); +#endif + delete[] message; + } + } +} + void RedirectablePrint::log(const char *logLevel, const char *format, ...) { #ifdef ARCH_PORTDUINO @@ -109,122 +232,10 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...) va_list arg; va_start(arg, format); - // Cope with 0 len format strings, but look for new line terminator - bool hasNewline = *format && format[strlen(format) - 1] == '\n'; - - // If we are the first message on a report, include the header - if (!isContinuationMessage) { - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) - Print::write("\u001b[34m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) - Print::write("\u001b[32m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) - Print::write("\u001b[33m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) - Print::write("\u001b[31m", 6); - uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile - if (rtc_sec > 0) { - long hms = rtc_sec % SEC_PER_DAY; - // hms += tz.tz_dsttime * SEC_PER_HOUR; - // hms -= tz.tz_minuteswest * SEC_PER_MIN; - // mod `hms` to ensure in positive range of [0...SEC_PER_DAY) - hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; + log_to_serial(logLevel, format, arg); + log_to_syslog(logLevel, format, arg); + log_to_ble(logLevel, format, arg); - // Tear apart hms into h:m:s - int hour = hms / SEC_PER_HOUR; - int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; - int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN -#ifdef ARCH_PORTDUINO - ::printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); -#else - printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); -#endif - } else -#ifdef ARCH_PORTDUINO - ::printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); -#else - printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); -#endif - - auto thread = concurrency::OSThread::currentThread; - if (thread) { - print("["); - // printf("%p ", thread); - // assert(thread->ThreadName.length()); - print(thread->ThreadName); - print("] "); - } - } - vprintf(logLevel, format, arg); - -#if (HAS_WIFI || HAS_ETHERNET) && !defined(ARCH_PORTDUINO) - // if syslog is in use, collect the log messages and send them to syslog - if (syslog.isEnabled()) { - int ll = 0; - switch (logLevel[0]) { - case 'D': - ll = SYSLOG_DEBUG; - break; - case 'I': - ll = SYSLOG_INFO; - break; - case 'W': - ll = SYSLOG_WARN; - break; - case 'E': - ll = SYSLOG_ERR; - break; - case 'C': - ll = SYSLOG_CRIT; - break; - default: - ll = 0; - } - auto thread = concurrency::OSThread::currentThread; - if (thread) { - syslog.vlogf(ll, thread->ThreadName.c_str(), format, arg); - } else { - syslog.vlogf(ll, format, arg); - } - } -#endif - - isContinuationMessage = !hasNewline; - - if (config.bluetooth.device_logging_enabled && !pauseBluetoothLogging) { - bool isBleConnected = false; -#ifdef ARCH_ESP32 - isBleConnected = nimbleBluetooth && nimbleBluetooth->isActive() && nimbleBluetooth->isConnected(); -#elif defined(ARCH_NRF52) - isBleConnected = nrf52Bluetooth != nullptr && nrf52Bluetooth->isConnected(); -#endif - if (isBleConnected) { - char *message; - size_t initialLen; - size_t len; - initialLen = strlen(format); - message = new char[initialLen + 1]; - len = vsnprintf(message, initialLen + 1, format, arg); - if (len > initialLen) { - delete[] message; - message = new char[len + 1]; - vsnprintf(message, len + 1, format, arg); - } - auto thread = concurrency::OSThread::currentThread; -#ifdef ARCH_ESP32 - if (thread) - nimbleBluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str()); - else - nimbleBluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str()); -#elif defined(ARCH_NRF52) - if (thread) - nrf52Bluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str()); - else - nrf52Bluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str()); -#endif - delete[] message; - } - } va_end(arg); #ifdef HAS_FREE_RTOS xSemaphoreGive(inDebugPrint); diff --git a/src/RedirectablePrint.h b/src/RedirectablePrint.h index a29ad9c749..3f20c894cc 100644 --- a/src/RedirectablePrint.h +++ b/src/RedirectablePrint.h @@ -49,15 +49,12 @@ class RedirectablePrint : public Print void hexDump(const char *logLevel, unsigned char *buf, uint16_t len); std::string mt_sprintf(const std::string fmt_str, ...); -}; -class NoopPrint : public Print -{ - public: - virtual size_t write(uint8_t c) { return 1; } -}; + protected: + /// Subclasses can override if they need to change how we format over the serial port + virtual void log_to_serial(const char *logLevel, const char *format, va_list arg); -/** - * A printer that doesn't go anywhere - */ -extern NoopPrint noopPrint; \ No newline at end of file + private: + void log_to_syslog(const char *logLevel, const char *format, va_list arg); + void log_to_ble(const char *logLevel, const char *format, va_list arg); +}; \ No newline at end of file diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index 41064f2882..12b9d2bd06 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -34,7 +34,6 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con assert(!console); console = this; canWrite = false; // We don't send packets to our port until it has talked to us first - // setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks #ifdef RP2040_SLOW_CLOCK Port.setTX(SERIAL2_TX); @@ -81,13 +80,40 @@ bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len) { // only talk to the API once the configuration has been loaded and we're sure the serial port is not disabled. if (config.has_lora && config.device.serial_enabled) { - // Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets - if (!config.device.debug_log_enabled) - setDestination(&noopPrint); + // Switch to protobufs for log messages + usingProtobufs = true; canWrite = true; return StreamAPI::handleToRadio(buf, len); } else { return false; } +} + +void SerialConsole::log_to_serial(const char *logLevel, const char *format, va_list arg) +{ + if (usingProtobufs) { + meshtastic_LogRecord_Level ll = meshtastic_LogRecord_Level_UNSET; // default to unset + switch (logLevel[0]) { + case 'D': + ll = meshtastic_LogRecord_Level_DEBUG; + break; + case 'I': + ll = meshtastic_LogRecord_Level_INFO; + break; + case 'W': + ll = meshtastic_LogRecord_Level_WARNING; + break; + case 'E': + ll = meshtastic_LogRecord_Level_ERROR; + break; + case 'C': + ll = meshtastic_LogRecord_Level_CRITICAL; + break; + } + + auto thread = concurrency::OSThread::currentThread; + emitLogRecord(ll, thread ? thread->ThreadName.c_str() : "", format, arg); + } else + RedirectablePrint::log_to_serial(logLevel, format, arg); } \ No newline at end of file diff --git a/src/SerialConsole.h b/src/SerialConsole.h index f8891ba14f..f1e636c9de 100644 --- a/src/SerialConsole.h +++ b/src/SerialConsole.h @@ -8,6 +8,11 @@ */ class SerialConsole : public StreamAPI, public RedirectablePrint, private concurrency::OSThread { + /** + * If true we are talking to a smart host and all messages (including log messages) must be framed as protobufs. + */ + bool usingProtobufs = false; + public: SerialConsole(); @@ -31,10 +36,13 @@ class SerialConsole : public StreamAPI, public RedirectablePrint, private concur protected: /// Check the current underlying physical link to see if the client is currently connected virtual bool checkIsConnected() override; + + /// Possibly switch to protobufs if we see a valid protobuf message + virtual void log_to_serial(const char *logLevel, const char *format, va_list arg); }; // A simple wrapper to allow non class aware code write to the console void consolePrintf(const char *format, ...); void consoleInit(); -extern SerialConsole *console; +extern SerialConsole *console; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 462eaa0f4e..196eae525b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -221,7 +221,7 @@ void setup() meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO; OLEDDISPLAY_GEOMETRY screen_geometry = GEOMETRY_128_64; -#ifdef SEGGER_STDOUT_CH +#ifdef USE_SEGGER auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM; #ifdef NRF52840_XXAA auto buflen = 4096; // this board has a fair amount of ram diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 322b0cf5eb..0f69b21f9c 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -407,7 +407,9 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Encapsulate as a FromRadio packet size_t numbytes = pb_encode_to_bytes(buf, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch); - LOG_DEBUG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes); + // VERY IMPORTANT to not print debug messages while writing to fromRadioScratch - because we use that same buffer + // for logging (when we are encapsulating with protobufs) + // LOG_DEBUG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes); return numbytes; } diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp index 4d04dffe48..9f59aa971c 100644 --- a/src/mesh/StreamAPI.cpp +++ b/src/mesh/StreamAPI.cpp @@ -1,5 +1,6 @@ #include "StreamAPI.h" #include "PowerFSM.h" +#include "RTC.h" #include "configuration.h" #define START1 0x94 @@ -96,7 +97,6 @@ void StreamAPI::writeStream() void StreamAPI::emitTxBuffer(size_t len) { if (len != 0) { - // LOG_DEBUG("emit tx %d\n", len); txBuf[0] = START1; txBuf[1] = START2; txBuf[2] = (len >> 8) & 0xff; @@ -119,6 +119,25 @@ void StreamAPI::emitRebooted() emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch)); } +void StreamAPI::emitLogRecord(meshtastic_LogRecord_Level level, const char *src, const char *format, va_list arg) +{ + // In case we send a FromRadio packet + memset(&fromRadioScratch, 0, sizeof(fromRadioScratch)); + fromRadioScratch.which_payload_variant = meshtastic_FromRadio_log_record_tag; + fromRadioScratch.log_record.level = level; + + uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); + fromRadioScratch.log_record.time = rtc_sec; + strncpy(fromRadioScratch.log_record.source, src, sizeof(fromRadioScratch.log_record.source) - 1); + + auto num_printed = + vsnprintf(fromRadioScratch.log_record.message, sizeof(fromRadioScratch.log_record.message) - 1, format, arg); + if (num_printed > 0 && fromRadioScratch.log_record.message[num_printed - 1] == + '\n') // Strip any ending newline, because we have records for framing instead. + fromRadioScratch.log_record.message[num_printed - 1] = '\0'; + emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch)); +} + /// Hookable to find out when connection changes void StreamAPI::onConnectionChanged(bool connected) { @@ -131,4 +150,4 @@ void StreamAPI::onConnectionChanged(bool connected) // received a packet in a while powerFSM.trigger(EVENT_SERIAL_DISCONNECTED); } -} +} \ No newline at end of file diff --git a/src/mesh/StreamAPI.h b/src/mesh/StreamAPI.h index 3196e96f8b..45cbb231c7 100644 --- a/src/mesh/StreamAPI.h +++ b/src/mesh/StreamAPI.h @@ -82,4 +82,7 @@ class StreamAPI : public PhoneAPI /// Subclasses can use this scratch buffer if they wish uint8_t txBuf[MAX_STREAM_BUF_SIZE] = {0}; -}; + + /// Low level function to emit a protobuf encapsulated log record + void emitLogRecord(meshtastic_LogRecord_Level level, const char *src, const char *format, va_list arg); +}; \ No newline at end of file From 9701f35a83fc9d57a91626b97dc8113f5e106375 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 06:29:44 -0500 Subject: [PATCH 110/211] [create-pull-request] automated change (#4218) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index e7327e76bd..1198b7dbab 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit e7327e76bdc0b3b77c50e214fae5beb1cb303e9c +Subproject commit 1198b7dbabf9768cb0143d2897707b4c7a51a5da diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 5e245a2b58..dbe9281ec0 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -167,6 +167,15 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO = 64, /* Heltec Capsule Sensor V3 with ESP32-S3 CPU, Portable LoRa device that can replace GNSS modules or sensors */ meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3 = 65, + /* Heltec Vision Master T190 with ESP32-S3 CPU, and a 1.90 inch TFT display */ + meshtastic_HardwareModel_HELTEC_VISION_MASTER_T190 = 66, + /* Heltec Vision Master E213 with ESP32-S3 CPU, and a 2.13 inch E-Ink display */ + meshtastic_HardwareModel_HELTEC_VISION_MASTER_E213 = 67, + /* Heltec Vision Master E290 with ESP32-S3 CPU, and a 2.9 inch E-Ink display */ + meshtastic_HardwareModel_HELTEC_VISION_MASTER_E290 = 68, + /* Heltec Mesh Node T114 board with nRF52840 CPU, and a 1.14 inch TFT display, Ultimate low-power design, + specifically adapted for the Meshtatic project */ + meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 = 69, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ From e65c309af60bd897c72ac9d49bd9ed52e13c327f Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 2 Jul 2024 20:03:51 +0800 Subject: [PATCH 111/211] Fix SHT41 support (#4222) * Add SHT41 Serial to I2c Detection Code On the Seeed Wio-WM1110 Dev Kit board, the SHT41 chip was being incorrectly detected as SHT31. This patch adds the necessary serial number for the SHT41 chip to be correctly detected. fixes meshtastic/firmware#4221 * Add missing sensor read for SHT41 --- src/detect/ScanI2CTwoWire.cpp | 4 ++-- src/modules/Telemetry/EnvironmentTelemetry.cpp | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 86408b8d2e..8738e2722d 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -314,7 +314,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) case SHT31_4x_ADDR: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2); - if (registerValue == 0x11a2) { + if (registerValue == 0x11a2 || registerValue == 0x11da) { type = SHT4X; LOG_INFO("SHT4X sensor found\n"); } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) { @@ -402,4 +402,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const size_t ScanI2CTwoWire::countDevices() const { return foundDevices.size(); -} \ No newline at end of file +} diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index b69b2bfae1..d37bb754de 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -285,6 +285,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m valid = valid && sht31Sensor.getMetrics(m); hasSensor = true; } + if (sht4xSensor.hasSensor()) { + valid = valid && sht4xSensor.getMetrics(m); + hasSensor = true; + } if (lps22hbSensor.hasSensor()) { valid = valid && lps22hbSensor.getMetrics(m); hasSensor = true; @@ -533,4 +537,4 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule return result; } -#endif \ No newline at end of file +#endif From 10b157a38d3fe353ece472f556b0cf8c97cea180 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Wed, 3 Jul 2024 22:04:39 +0800 Subject: [PATCH 112/211] Typo fix in logs - mhz - MHz (#4225) As reported by karamo, a few different places in our logs had incorrect capitalization of MHz. fixes meshtastic/firmware#4126 --- src/mesh/RadioInterface.cpp | 2 +- src/sleep.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index cdea337172..343b7f2008 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -521,7 +521,7 @@ void RadioInterface::applyModemConfig() LOG_INFO("Radio freq=%.3f, config.lora.frequency_offset=%.3f\n", freq, loraConfig.frequency_offset); LOG_INFO("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d\n", myRegion->name, channelName, loraConfig.modem_preset, channel_num, power); - LOG_INFO("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd, + LOG_INFO("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f MHz)\n", myRegion->freqStart, myRegion->freqEnd, myRegion->freqEnd - myRegion->freqStart); LOG_INFO("Radio myRegion->numChannels: %d x %.3fkHz\n", numChannels, bw); LOG_INFO("Radio channel_num: %d\n", channel_num + 1); diff --git a/src/sleep.cpp b/src/sleep.cpp index c9c45bf67e..1c1a6e9ac4 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -62,14 +62,14 @@ void setCPUFast(bool on) /* * * There's a newly introduced bug in the espressif framework where WiFi is - * unstable when the frequency is less than 240mhz. + * unstable when the frequency is less than 240MHz. * * This mostly impacts WiFi AP mode but we'll bump the frequency for * all WiFi use cases. * (Added: Dec 23, 2021 by Jm Casler) */ #ifndef CONFIG_IDF_TARGET_ESP32C3 - LOG_DEBUG("Setting CPU to 240mhz because WiFi is in use.\n"); + LOG_DEBUG("Setting CPU to 240MHz because WiFi is in use.\n"); setCpuFrequencyMhz(240); #endif return; From 9c46bdad1abca401ab51fe7b865436c6756bd71c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 3 Jul 2024 16:29:07 -0500 Subject: [PATCH 113/211] New new BLE logging characteristic with LogRecord protos (#4220) * New UUID * New log radio characteristic with LogRecord protobuf * LogRecord * Merge derp * How did you get there * Trunk * Fix length * Remove assert --- src/BluetoothCommon.cpp | 6 +++-- src/BluetoothCommon.h | 4 ++-- src/RedirectablePrint.cpp | 43 +++++++++++++++++++++++++++------- src/RedirectablePrint.h | 2 ++ src/mesh/Router.cpp | 6 +++-- src/nimble/NimbleBluetooth.cpp | 7 +++--- src/nimble/NimbleBluetooth.h | 2 +- 7 files changed, 51 insertions(+), 19 deletions(-) diff --git a/src/BluetoothCommon.cpp b/src/BluetoothCommon.cpp index 7ef1c39b45..d9502e4f51 100644 --- a/src/BluetoothCommon.cpp +++ b/src/BluetoothCommon.cpp @@ -11,5 +11,7 @@ const uint8_t FROMRADIO_UUID_16[16u] = {0x02, 0x00, 0x12, 0xac, 0x42, 0x02, 0x78 0xed, 0x11, 0x93, 0x49, 0x9e, 0xe6, 0x55, 0x2c}; const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6, 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed}; -const uint8_t LOGRADIO_UUID_16[16u] = {0xe2, 0xf2, 0x1e, 0xbe, 0xc5, 0x15, 0xcf, 0xaa, - 0x6b, 0x43, 0xfa, 0x78, 0x38, 0xd2, 0x6f, 0x6c}; \ No newline at end of file +const uint8_t LEGACY_LOGRADIO_UUID_16[16u] = {0xe2, 0xf2, 0x1e, 0xbe, 0xc5, 0x15, 0xcf, 0xaa, + 0x6b, 0x43, 0xfa, 0x78, 0x38, 0xd2, 0x6f, 0x6c}; +const uint8_t LOGRADIO_UUID_16[16u] = {0x47, 0x95, 0xDF, 0x8C, 0xDE, 0xE9, 0x44, 0x99, + 0x23, 0x44, 0xE6, 0x06, 0x49, 0x6E, 0x3D, 0x5A}; \ No newline at end of file diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h index 5497e1d6db..440d138441 100644 --- a/src/BluetoothCommon.h +++ b/src/BluetoothCommon.h @@ -11,7 +11,8 @@ #define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7" #define FROMRADIO_UUID "2c55e69e-4993-11ed-b878-0242ac120002" #define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453" -#define LOGRADIO_UUID "6c6fd238-78fa-436b-aacf-15c5be1ef2e2" +#define LEGACY_LOGRADIO_UUID "6c6fd238-78fa-436b-aacf-15c5be1ef2e2" +#define LOGRADIO_UUID "5a3d6e49-06e6-4423-9944-e9de8cdf9547" // NRF52 wants these constants as byte arrays // Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER @@ -28,5 +29,4 @@ class BluetoothApi virtual void clearBonds(); virtual bool isConnected(); virtual int getRssi() = 0; - virtual void sendLog(const char *logMessage); }; \ No newline at end of file diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 782febd759..555e45401f 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -4,6 +4,7 @@ #include "concurrency/OSThread.h" #include "configuration.h" #include "main.h" +#include "mesh/generated/meshtastic/mesh.pb.h" #include #include #include @@ -192,22 +193,48 @@ void RedirectablePrint::log_to_ble(const char *logLevel, const char *format, va_ vsnprintf(message, len + 1, format, arg); } auto thread = concurrency::OSThread::currentThread; -#ifdef ARCH_ESP32 + meshtastic_LogRecord logRecord = meshtastic_LogRecord_init_zero; + logRecord.level = getLogLevel(logLevel); + strcpy(logRecord.message, message); if (thread) - nimbleBluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str()); - else - nimbleBluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str()); + strcpy(logRecord.source, thread->ThreadName.c_str()); + logRecord.time = getValidTime(RTCQuality::RTCQualityDevice, true); + + uint8_t *buffer = new uint8_t[meshtastic_LogRecord_size]; + size_t size = pb_encode_to_bytes(buffer, meshtastic_LogRecord_size, meshtastic_LogRecord_fields, &logRecord); +#ifdef ARCH_ESP32 + nimbleBluetooth->sendLog(buffer, size); #elif defined(ARCH_NRF52) - if (thread) - nrf52Bluetooth->sendLog(mt_sprintf("%s | [%s] %s", logLevel, thread->ThreadName.c_str(), message).c_str()); - else - nrf52Bluetooth->sendLog(mt_sprintf("%s | %s", logLevel, message).c_str()); + nrf52Bluetooth->sendLog(reinterpret_cast(buffer)); #endif delete[] message; } } } +meshtastic_LogRecord_Level RedirectablePrint::getLogLevel(const char *logLevel) +{ + meshtastic_LogRecord_Level ll = meshtastic_LogRecord_Level_UNSET; // default to unset + switch (logLevel[0]) { + case 'D': + ll = meshtastic_LogRecord_Level_DEBUG; + break; + case 'I': + ll = meshtastic_LogRecord_Level_INFO; + break; + case 'W': + ll = meshtastic_LogRecord_Level_WARNING; + break; + case 'E': + ll = meshtastic_LogRecord_Level_ERROR; + break; + case 'C': + ll = meshtastic_LogRecord_Level_CRITICAL; + break; + } + return ll; +} + void RedirectablePrint::log(const char *logLevel, const char *format, ...) { #ifdef ARCH_PORTDUINO diff --git a/src/RedirectablePrint.h b/src/RedirectablePrint.h index 3f20c894cc..23ae3c44de 100644 --- a/src/RedirectablePrint.h +++ b/src/RedirectablePrint.h @@ -1,6 +1,7 @@ #pragma once #include "../freertosinc.h" +#include "mesh/generated/meshtastic/mesh.pb.h" #include #include #include @@ -57,4 +58,5 @@ class RedirectablePrint : public Print private: void log_to_syslog(const char *logLevel, const char *format, va_list arg); void log_to_ble(const char *logLevel, const char *format, va_list arg); + meshtastic_LogRecord_Level getLogLevel(const char *logLevel); }; \ No newline at end of file diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 3141d986bb..c8c18ae6d5 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -244,8 +244,10 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) // If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it) - assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag || - p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now + if (!(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag || + p->which_payload_variant == meshtastic_MeshPacket_decoded_tag)) { + return meshtastic_Routing_Error_BAD_REQUEST; + } // If the packet is not yet encrypted, do so now if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 78ef5a1d3e..d959553a4b 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -219,7 +219,6 @@ void NimbleBluetooth::setupService() logRadioCharacteristic = bleService->createCharacteristic( LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC, 512U); - logRadioCharacteristic->setValue("Init"); } bluetoothPhoneAPI = new BluetoothPhoneAPI(); @@ -268,12 +267,12 @@ void NimbleBluetooth::clearBonds() NimBLEDevice::deleteAllBonds(); } -void NimbleBluetooth::sendLog(const char *logMessage) +void NimbleBluetooth::sendLog(const uint8_t *logMessage, size_t length) { - if (!bleServer || !isConnected() || strlen(logMessage) > 512) { + if (!bleServer || !isConnected() || length > 512) { return; } - logRadioCharacteristic->notify(reinterpret_cast(logMessage), strlen(logMessage), true); + logRadioCharacteristic->notify(logMessage, length, true); } void clearNVS() diff --git a/src/nimble/NimbleBluetooth.h b/src/nimble/NimbleBluetooth.h index 39794779b2..45602e0887 100644 --- a/src/nimble/NimbleBluetooth.h +++ b/src/nimble/NimbleBluetooth.h @@ -11,7 +11,7 @@ class NimbleBluetooth : BluetoothApi bool isActive(); bool isConnected(); int getRssi(); - void sendLog(const char *logMessage); + void sendLog(const uint8_t *logMessage, size_t length); private: void setupService(); From 8785adf6e4f59df40bc686cebfbb4946b7816135 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 3 Jul 2024 15:39:09 -0700 Subject: [PATCH 114/211] minor cleanup proposal (#4169) * MESHTASTIC_EXCLUDE_WIFI and HAS_WIFI cleanup... Our code was checking HAS_WIFI and the new MESHTASTIC_EXCLUDE_WIFI flags in various places (even though EXCLUDE_WIFI forces HAS_WIFI to 0). Instead just check HAS_WIFI, only use EXCLUDE_WIFI inside configuration.h * cleanup: use HAS_NETWORKING instead of HAS_WIFI || HAS_ETHERNET We already had HAS_NETWORKING as flag in MQTT to mean 'we have tcpip'. Generallize that and move it into configuration.h so that we can use it elsewhere. * Use #pragma once, because supported by gcc and all modern compilers instead of #ifdef DOTHFILE_H etc... --------- Co-authored-by: Jonathan Bennett --- src/DebugConfiguration.cpp | 2 +- src/DebugConfiguration.h | 11 +++++------ src/Power.cpp | 2 +- src/RedirectablePrint.cpp | 4 ++-- src/configuration.h | 11 +++++++---- src/mesh/NodeDB.cpp | 2 +- src/mesh/http/ContentHandler.cpp | 2 +- src/mesh/wifi/WiFiAPClient.cpp | 2 +- src/modules/AdminModule.h | 2 +- src/mqtt/MQTT.cpp | 18 +++++++++--------- src/mqtt/MQTT.h | 6 ++---- src/platform/esp32/main-esp32.cpp | 29 ++++++++++++++--------------- src/sleep.cpp | 4 ++-- 13 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/DebugConfiguration.cpp b/src/DebugConfiguration.cpp index 9df402e77b..d9ecd9fe39 100644 --- a/src/DebugConfiguration.cpp +++ b/src/DebugConfiguration.cpp @@ -26,7 +26,7 @@ SOFTWARE.*/ #include "DebugConfiguration.h" -#if HAS_WIFI || HAS_ETHERNET +#if HAS_NETWORKING Syslog::Syslog(UDP &client) { diff --git a/src/DebugConfiguration.h b/src/DebugConfiguration.h index 874d63bca1..ebe9da8d44 100644 --- a/src/DebugConfiguration.h +++ b/src/DebugConfiguration.h @@ -1,5 +1,6 @@ -#ifndef SYSLOG_H -#define SYSLOG_H +#pragma once + +#include "configuration.h" // DEBUG LED #ifndef LED_INVERTED @@ -125,7 +126,7 @@ #include #endif // HAS_WIFI -#if HAS_WIFI || HAS_ETHERNET +#if HAS_NETWORKING class Syslog { @@ -160,6 +161,4 @@ class Syslog bool vlogf(uint16_t pri, const char *appName, const char *fmt, va_list args) __attribute__((format(printf, 3, 0))); }; -#endif // HAS_ETHERNET || HAS_WIFI - -#endif // SYSLOG_H \ No newline at end of file +#endif // HAS_ETHERNET || HAS_WIFI \ No newline at end of file diff --git a/src/Power.cpp b/src/Power.cpp index 18a527cee7..cea373806c 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -27,7 +27,7 @@ #if defined(DEBUG_HEAP_MQTT) && !MESHTASTIC_EXCLUDE_MQTT #include "mqtt/MQTT.h" #include "target_specific.h" -#if !MESTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include #endif #endif diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 555e45401f..14264ba21e 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -16,7 +16,7 @@ #include "platform/portduino/PortduinoGlue.h" #endif -#if HAS_WIFI || HAS_ETHERNET +#if HAS_NETWORKING extern Syslog syslog; #endif void RedirectablePrint::rpInit() @@ -138,7 +138,7 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format, void RedirectablePrint::log_to_syslog(const char *logLevel, const char *format, va_list arg) { -#if (HAS_WIFI || HAS_ETHERNET) && !defined(ARCH_PORTDUINO) +#if HAS_NETWORKING && !defined(ARCH_PORTDUINO) // if syslog is in use, collect the log messages and send them to syslog if (syslog.isEnabled()) { int ll = 0; diff --git a/src/configuration.h b/src/configuration.h index 3d10feeaaf..854d3dadfe 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -242,9 +242,6 @@ along with this program. If not, see . #define HAS_BLUETOOTH 0 #endif -#include "DebugConfiguration.h" -#include "RF95Configuration.h" - #ifndef HW_VENDOR #error HW_VENDOR must be defined #endif @@ -290,6 +287,9 @@ along with this program. If not, see . #define HAS_WIFI 0 #endif +// Allow code that needs internet to just check HAS_NETWORKING rather than HAS_WIFI || HAS_ETHERNET +#define HAS_NETWORKING (HAS_WIFI || HAS_ETHERNET) + // // Turn off Bluetooth #ifdef MESHTASTIC_EXCLUDE_BLUETOOTH #undef HAS_BLUETOOTH @@ -308,4 +308,7 @@ along with this program. If not, see . #ifdef MESHTASTIC_EXCLUDE_SCREEN #undef HAS_SCREEN #define HAS_SCREEN 0 -#endif \ No newline at end of file +#endif + +#include "DebugConfiguration.h" +#include "RF95Configuration.h" \ No newline at end of file diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 1dc6d7883e..84872e4714 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -26,7 +26,7 @@ #include #ifdef ARCH_ESP32 -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "modules/esp32/StoreForwardModule.h" diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 7f9df058dd..b309484e23 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -6,7 +6,7 @@ #include "main.h" #include "mesh/http/ContentHelper.h" #include "mesh/http/WebServer.h" -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "mqtt/JSON.h" diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index ffb16bd3e5..e733d18011 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -1,5 +1,5 @@ #include "configuration.h" -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "NodeDB.h" #include "RTC.h" #include "concurrency/Periodic.h" diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h index 32b32c253a..6ecc888294 100644 --- a/src/modules/AdminModule.h +++ b/src/modules/AdminModule.h @@ -1,6 +1,6 @@ #pragma once #include "ProtobufModule.h" -#if HAS_WIFI && !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 74f3ca5a32..a64720c78c 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -14,7 +14,7 @@ #endif #include "mesh/generated/meshtastic/remote_hardware.pb.h" #include "sleep.h" -#if HAS_WIFI && !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #include #endif @@ -175,7 +175,7 @@ void mqttInit() new MQTT(); } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE) #else MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) @@ -206,7 +206,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) moduleConfig.mqtt.map_report_settings.publish_interval_secs, default_map_publish_interval_secs); } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING if (!moduleConfig.mqtt.proxy_to_client_enabled) pubSub.setCallback(mqttCallback); #endif @@ -226,7 +226,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) bool MQTT::isConnectedDirectly() { -#ifdef HAS_NETWORKING +#if HAS_NETWORKING return pubSub.connected(); #else return false; @@ -244,7 +244,7 @@ bool MQTT::publish(const char *topic, const char *payload, bool retained) service.sendMqttMessageToClientProxy(msg); return true; } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING else if (isConnectedDirectly()) { return pubSub.publish(topic, payload, retained); } @@ -264,7 +264,7 @@ bool MQTT::publish(const char *topic, const uint8_t *payload, size_t length, boo service.sendMqttMessageToClientProxy(msg); return true; } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING else if (isConnectedDirectly()) { return pubSub.publish(topic, payload, length, retained); } @@ -284,7 +284,7 @@ void MQTT::reconnect() publishStatus(); return; // Don't try to connect directly to the server } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING // Defaults int serverPort = 1883; const char *serverAddr = default_mqtt_address; @@ -357,7 +357,7 @@ void MQTT::reconnect() void MQTT::sendSubscriptions() { -#ifdef HAS_NETWORKING +#if HAS_NETWORKING size_t numChan = channels.getNumChannels(); for (size_t i = 0; i < numChan; i++) { const auto &ch = channels.getByIndex(i); @@ -396,7 +396,7 @@ bool MQTT::wantsLink() const int32_t MQTT::runOnce() { -#ifdef HAS_NETWORKING +#if HAS_NETWORKING if (!moduleConfig.mqtt.enabled || !(moduleConfig.mqtt.map_reporting_enabled || channels.anyMqttEnabled())) return disable(); diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index f2eb6b1204..1ebba4afe9 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -8,17 +8,15 @@ #include "mqtt/JSON.h" #if HAS_WIFI #include -#define HAS_NETWORKING 1 #if !defined(ARCH_PORTDUINO) #include #endif #endif #if HAS_ETHERNET #include -#define HAS_NETWORKING 1 #endif -#ifdef HAS_NETWORKING +#if HAS_NETWORKING #include #endif @@ -43,7 +41,7 @@ class MQTT : private concurrency::OSThread #endif public: -#ifdef HAS_NETWORKING +#if HAS_NETWORKING PubSubClient pubSub; #endif MQTT(); diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index 1dd7a389af..aa51e810a8 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -8,7 +8,7 @@ #include "nimble/NimbleBluetooth.h" #endif -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif @@ -24,23 +24,22 @@ #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !MESHTASTIC_EXCLUDE_BLUETOOTH void setBluetoothEnable(bool enable) { -#ifndef MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI if (!isWifiAvailable() && config.bluetooth.enabled == true) +#else + if (config.bluetooth.enabled == true) #endif -#ifdef MESHTASTIC_EXCLUDE_WIFI - if (config.bluetooth.enabled == true) -#endif - { - if (!nimbleBluetooth) { - nimbleBluetooth = new NimbleBluetooth(); - } - if (enable && !nimbleBluetooth->isActive()) { - nimbleBluetooth->setup(); - } - // For ESP32, no way to recover from bluetooth shutdown without reboot - // BLE advertising automatically stops when MCU enters light-sleep(?) - // For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse + { + if (!nimbleBluetooth) { + nimbleBluetooth = new NimbleBluetooth(); } + if (enable && !nimbleBluetooth->isActive()) { + nimbleBluetooth->setup(); + } + // For ESP32, no way to recover from bluetooth shutdown without reboot + // BLE advertising automatically stops when MCU enters light-sleep(?) + // For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse + } } #else void setBluetoothEnable(bool enable) {} diff --git a/src/sleep.cpp b/src/sleep.cpp index 1c1a6e9ac4..735ebcf6ad 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -17,7 +17,7 @@ #ifdef ARCH_ESP32 #include "esp32/pm.h" #include "esp_pm.h" -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "rom/rtc.h" @@ -56,7 +56,7 @@ RTC_DATA_ATTR int bootCount = 0; */ void setCPUFast(bool on) { -#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI +#if defined(ARCH_ESP32) && HAS_WIFI if (isWifiAvailable()) { /* From 8bca3e168d5f89ab3168937a1384c32bda27d0d9 Mon Sep 17 00:00:00 2001 From: geeksville Date: Wed, 3 Jul 2024 16:02:20 -0700 Subject: [PATCH 115/211] Add PowerMon support (#4155) * Turn off vscode cmake prompt - we don't use cmake on meshtastic * Add rak4631_dap variant for debugging with NanoDAP debug probe device. * The rak device can also run freertos (which is underneath nrf52 arduino) * Add semihosting support for nrf52840 devices Initial platformio.ini file only supports rak4630 Default to non TCP for the semihosting log output for now... Fixes https://github.com/meshtastic/firmware/issues/4135 * powermon WIP (for https://github.com/meshtastic/firmware/issues/4136 ) * oops - mean't to mark the _dbg variant as an 'extra' board. * powermon wip * Make serial port on wio-sdk-wm1110 board work By disabling the (inaccessible) adafruit USB * Instrument (radiolib only for now) lora for powermon per https://github.com/meshtastic/firmware/issues/4136 * powermon gps support https://github.com/meshtastic/firmware/issues/4136 * Add CPU deep and light sleep powermon states https://github.com/meshtastic/firmware/issues/4136 * Change the board/swversion bootstring so it is a new "structured" log msg. * powermon wip * add example script for getting esp S3 debugging working Not yet used but I didn't want these nasty tricks to get lost yet. * Add PowerMon reporting for screen and bluetooth pwr. * make power.powermon_enables config setting work. * update to latest protobufs * fix bogus shellcheck warning * make powermon optional (but default enabled because tiny and no runtime impact) * tell vscode, if formatting, use whatever our trunk formatter wants without this flag if the user has set some other formatter (clang) in their user level settings, it will be looking in the wrong directory for the clang options (we want the options in .trunk/clang) Note: formatOnSave is true in master, which means a bunch of our older files are non compliant and if you edit them it will generate lots of formatting related diffs. I guess I'll start letting that happen with my future commits ;-). * add PowerStress module * nrf52 arduino is built upon freertos, so let platformio debug it * don't accidentally try to Segger ICE if we are using another ICE * clean up RedirectablePrint::log so it doesn't have three very different implementations inline. * remove NoopPrint - it is no longer needed * when talking to API clients via serial, don't turn off log msgs instead encapsuate them * fix the build - would loop forever if there were no files to send * don't use Segger code if not talking to a Segger debugger * when encapsulating logs, make sure the strings always has nul terminators * nrf52 soft device will watchdog if you use ICE while BT on... so have debugger disable bluetooth. * Important to not print debug messages while writing to the toPhone scratch buffer * don't include newlines if encapsulating log records as protobufs * update to latest protobufs (needed for powermon goo) * PowerStress WIP * fix linter warning --- bin/setup-python-for-esp-debug.sh | 12 +++++ boards/wio-sdk-wm1110.json | 2 +- src/PowerFSM.cpp | 17 +++++++ src/PowerMon.cpp | 45 ++++++++++++++++++ src/PowerMon.h | 34 ++++++++++++++ src/configuration.h | 2 + src/gps/GPS.cpp | 4 ++ src/main.cpp | 12 ++++- src/mesh/LR11x0Interface.cpp | 3 +- src/mesh/RF95Interface.cpp | 31 +++++++------ src/mesh/RadioLibInterface.cpp | 21 +++++++++ src/mesh/RadioLibInterface.h | 13 ++++-- src/mesh/SX126xInterface.cpp | 3 +- src/mesh/SX128xInterface.cpp | 3 +- src/modules/Modules.cpp | 6 +++ src/modules/PowerStressModule.cpp | 77 +++++++++++++++++++++++++++++++ src/modules/PowerStressModule.h | 38 +++++++++++++++ src/sleep.cpp | 6 +++ 18 files changed, 306 insertions(+), 23 deletions(-) create mode 100644 bin/setup-python-for-esp-debug.sh create mode 100644 src/PowerMon.cpp create mode 100644 src/PowerMon.h create mode 100644 src/modules/PowerStressModule.cpp create mode 100644 src/modules/PowerStressModule.h diff --git a/bin/setup-python-for-esp-debug.sh b/bin/setup-python-for-esp-debug.sh new file mode 100644 index 0000000000..edba43e72b --- /dev/null +++ b/bin/setup-python-for-esp-debug.sh @@ -0,0 +1,12 @@ +# shellcheck shell=bash +# (this minor script is actually shell agnostic, and is intended to be sourced rather than run in a subshell) + +# This is a little script you can source if you want to make ESP debugging work on a modern (24.04) ubuntu machine +# It assumes you have built and installed python 2.7 from source with: +# ./configure --enable-optimizations --enable-shared --enable-unicode=ucs4 +# sudo make clean +# make +# sudo make altinstall + +export LD_LIBRARY_PATH=$HOME/packages/python-2.7.18/ +export PYTHON_HOME=/usr/local/lib/python2.7/ diff --git a/boards/wio-sdk-wm1110.json b/boards/wio-sdk-wm1110.json index 882f4443ec..18c87adde9 100644 --- a/boards/wio-sdk-wm1110.json +++ b/boards/wio-sdk-wm1110.json @@ -27,7 +27,7 @@ "jlink_device": "nRF52840_xxAA", "svd_path": "nrf52840.svd" }, - "frameworks": ["arduino"], + "frameworks": ["arduino", "freertos"], "name": "Seeed WIO WM1110", "upload": { "maximum_ram_size": 248832, diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index a7bc18f1a3..72e00810bb 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -11,6 +11,7 @@ #include "Default.h" #include "MeshService.h" #include "NodeDB.h" +#include "PowerMon.h" #include "configuration.h" #include "graphics/Screen.h" #include "main.h" @@ -49,6 +50,7 @@ static bool isPowered() static void sdsEnter() { LOG_DEBUG("Enter state: SDS\n"); + powerMon->setState(meshtastic_PowerMon_State_CPU_DeepSleep); // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false); } @@ -68,6 +70,7 @@ static uint32_t secsSlept; static void lsEnter() { LOG_INFO("lsEnter begin, ls_secs=%u\n", config.power.ls_secs); + powerMon->clearState(meshtastic_PowerMon_State_Screen_On); screen->setOn(false); secsSlept = 0; // How long have we been sleeping this time @@ -87,8 +90,10 @@ static void lsIdle() // Briefly come out of sleep long enough to blink the led once every few seconds uint32_t sleepTime = SLEEP_TIME; + powerMon->setState(meshtastic_PowerMon_State_CPU_LightSleep); setLed(false); // Never leave led on while in light sleep esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL); + powerMon->clearState(meshtastic_PowerMon_State_CPU_LightSleep); switch (wakeCause2) { case ESP_SLEEP_WAKEUP_TIMER: @@ -144,6 +149,7 @@ static void lsExit() static void nbEnter() { LOG_DEBUG("Enter state: NB\n"); + powerMon->clearState(meshtastic_PowerMon_State_BT_On); screen->setOn(false); #ifdef ARCH_ESP32 // Only ESP32 should turn off bluetooth @@ -155,6 +161,8 @@ static void nbEnter() static void darkEnter() { + powerMon->clearState(meshtastic_PowerMon_State_BT_On); + powerMon->clearState(meshtastic_PowerMon_State_Screen_On); setBluetoothEnable(true); screen->setOn(false); } @@ -162,6 +170,8 @@ static void darkEnter() static void serialEnter() { LOG_DEBUG("Enter state: SERIAL\n"); + powerMon->clearState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); setBluetoothEnable(false); screen->setOn(true); screen->print("Serial connected\n"); @@ -170,6 +180,7 @@ static void serialEnter() static void serialExit() { // Turn bluetooth back on when we leave serial stream API + powerMon->setState(meshtastic_PowerMon_State_BT_On); setBluetoothEnable(true); screen->print("Serial disconnected\n"); } @@ -182,6 +193,8 @@ static void powerEnter() LOG_INFO("Loss of power in Powered\n"); powerFSM.trigger(EVENT_POWER_DISCONNECTED); } else { + powerMon->setState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); // within enter() the function getState() returns the state we came from @@ -205,6 +218,8 @@ static void powerIdle() static void powerExit() { + powerMon->setState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); @@ -216,6 +231,8 @@ static void powerExit() static void onEnter() { LOG_DEBUG("Enter state: ON\n"); + powerMon->setState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); } diff --git a/src/PowerMon.cpp b/src/PowerMon.cpp new file mode 100644 index 0000000000..3d28715e0c --- /dev/null +++ b/src/PowerMon.cpp @@ -0,0 +1,45 @@ +#include "PowerMon.h" +#include "NodeDB.h" + +// Use the 'live' config flag to figure out if we should be showing this message +static bool is_power_enabled(uint64_t m) +{ + return (m & config.power.powermon_enables) ? true : false; +} + +void PowerMon::setState(_meshtastic_PowerMon_State state, const char *reason) +{ +#ifdef USE_POWERMON + auto oldstates = states; + states |= state; + if (oldstates != states && is_power_enabled(state)) { + emitLog(reason); + } +#endif +} + +void PowerMon::clearState(_meshtastic_PowerMon_State state, const char *reason) +{ +#ifdef USE_POWERMON + auto oldstates = states; + states &= ~state; + if (oldstates != states && is_power_enabled(state)) { + emitLog(reason); + } +#endif +} + +void PowerMon::emitLog(const char *reason) +{ +#ifdef USE_POWERMON + // The nrf52 printf doesn't understand 64 bit ints, so if we ever reach that point this function will need to change. + LOG_INFO("S:PM:0x%08lx,%s\n", (uint32_t)states, reason); +#endif +} + +PowerMon *powerMon; + +void powerMonInit() +{ + powerMon = new PowerMon(); +} \ No newline at end of file diff --git a/src/PowerMon.h b/src/PowerMon.h new file mode 100644 index 0000000000..e9f5dbd59c --- /dev/null +++ b/src/PowerMon.h @@ -0,0 +1,34 @@ +#pragma once +#include "configuration.h" + +#include "meshtastic/powermon.pb.h" + +#ifndef MESHTASTIC_EXCLUDE_POWERMON +#define USE_POWERMON // FIXME turn this only for certain builds +#endif + +/** + * The singleton class for monitoring power consumption of device + * subsystems/modes. + * + * For more information see the PowerMon docs. + */ +class PowerMon +{ + uint64_t states = 0UL; + + public: + PowerMon() {} + + // Mark entry/exit of a power consuming state + void setState(_meshtastic_PowerMon_State state, const char *reason = ""); + void clearState(_meshtastic_PowerMon_State state, const char *reason = ""); + + private: + // Emit the coded log message + void emitLog(const char *reason); +}; + +extern PowerMon *powerMon; + +void powerMonInit(); \ No newline at end of file diff --git a/src/configuration.h b/src/configuration.h index 854d3dadfe..aad4ac4572 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -258,6 +258,7 @@ along with this program. If not, see . #define MESHTASTIC_EXCLUDE_GPS 1 #define MESHTASTIC_EXCLUDE_SCREEN 1 #define MESHTASTIC_EXCLUDE_MQTT 1 +#define MESHTASTIC_EXCLUDE_POWERMON 1 #endif // Turn off all optional modules @@ -278,6 +279,7 @@ along with this program. If not, see . #define MESHTASTIC_EXCLUDE_WAYPOINT 1 #define MESHTASTIC_EXCLUDE_INPUTBROKER 1 #define MESHTASTIC_EXCLUDE_SERIAL 1 +#define MESHTASTIC_EXCLUDE_POWERSTRESS 1 #endif // // Turn off wifi even if HW supports wifi (webserver relies on wifi and is also disabled) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 5efe962517..ec7d725b83 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -3,6 +3,7 @@ #include "Default.h" #include "GPS.h" #include "NodeDB.h" +#include "PowerMon.h" #include "RTC.h" #include "main.h" // pmu_found @@ -815,9 +816,12 @@ void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) return; if (on) { + powerMon->setState(meshtastic_PowerMon_State_GPS_Active); clearBuffer(); // drop any old data waiting in the buffer before re-enabling if (en_gpio) digitalWrite(en_gpio, on ? GPS_EN_ACTIVE : !GPS_EN_ACTIVE); // turn this on if defined, every time + } else { + powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); } isInPowersave = !on; if (!standbyOnly && en_gpio != 0 && diff --git a/src/main.cpp b/src/main.cpp index 196eae525b..1e0d998e15 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" +#include "PowerMon.h" #include "ReliableRouter.h" #include "airtime.h" #include "buzz.h" @@ -214,6 +215,14 @@ __attribute__((weak, noinline)) bool loopCanSleep() return true; } +/** + * Print info as a structured log message (for automated log processing) + */ +void printInfo() +{ + LOG_INFO("S:B:%d,%s\n", HW_VENDOR, optstr(APP_VERSION)); +} + void setup() { concurrency::hasBeenSetup = true; @@ -234,6 +243,7 @@ void setup() #ifdef DEBUG_PORT consoleInit(); // Set serial baud rate and init our mesh console #endif + powerMonInit(); serialSinceMsec = millis(); @@ -553,7 +563,7 @@ void setup() #endif // Hello - LOG_INFO("Meshtastic hwvendor=%d, swver=%s\n", HW_VENDOR, optstr(APP_VERSION)); + printInfo(); #ifdef ARCH_ESP32 esp32Setup(); diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp index bffca0c448..fc059ec16d 100644 --- a/src/mesh/LR11x0Interface.cpp +++ b/src/mesh/LR11x0Interface.cpp @@ -184,6 +184,7 @@ template void LR11x0Interface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** @@ -223,7 +224,7 @@ template void LR11x0Interface::startReceive() 0); // only RX_DONE IRQ is needed, we'll check for PREAMBLE_DETECTED and HEADER_VALID in isActivelyReceiving assert(err == RADIOLIB_ERR_NONE); - isReceiving = true; + RadioLibInterface::startReceive(); // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index c5356ad3bd..bd1ebdb0e6 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -25,7 +25,8 @@ typedef struct { } DACDB; // Interpolation function -DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val2) { +DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val2) +{ DACDB result; double fraction = (double)(dbm - dbm1) / (dbm2 - dbm1); result.dac = (uint8_t)(val1.dac + fraction * (val2.dac - val1.dac)); @@ -34,16 +35,17 @@ DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val } // Function to find the correct DAC and DB values based on dBm using interpolation -DACDB getDACandDB(uint8_t dbm) { +DACDB getDACandDB(uint8_t dbm) +{ // Predefined values static const struct { uint8_t dbm; DACDB values; } dbmToDACDB[] = { - {20, {168, 2}}, // 100mW - {24, {148, 6}}, // 250mW - {27, {128, 9}}, // 500mW - {30, {90, 12}} // 1000mW + {20, {168, 2}}, // 100mW + {24, {148, 6}}, // 250mW + {27, {128, 9}}, // 500mW + {30, {90, 12}} // 1000mW }; const int numValues = sizeof(dbmToDACDB) / sizeof(dbmToDACDB[0]); @@ -103,7 +105,7 @@ bool RF95Interface::init() if (power > RF95_MAX_POWER) // This chip has lower power limits than some power = RF95_MAX_POWER; - + limitPower(); iface = lora = new RadioLibRF95(&module); @@ -116,13 +118,13 @@ bool RF95Interface::init() // enable PA #ifdef RF95_PA_EN #if defined(RF95_PA_DAC_EN) - #ifdef RADIOMASTER_900_BANDIT_NANO - // Use calculated DAC value - dacWrite(RF95_PA_EN, powerDAC); - #else - // Use Value set in /*/variant.h - dacWrite(RF95_PA_EN, RF95_PA_LEVEL); - #endif +#ifdef RADIOMASTER_900_BANDIT_NANO + // Use calculated DAC value + dacWrite(RF95_PA_EN, powerDAC); +#else + // Use Value set in /*/variant.h + dacWrite(RF95_PA_EN, RF95_PA_LEVEL); +#endif #endif #endif @@ -254,6 +256,7 @@ void RF95Interface::setStandby() isReceiving = false; // If we were receiving, not any more disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** We override to turn on transmitter power as needed. diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index a4ceac9f12..f299ebff2c 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -1,6 +1,7 @@ #include "RadioLibInterface.h" #include "MeshTypes.h" #include "NodeDB.h" +#include "PowerMon.h" #include "SPILock.h" #include "configuration.h" #include "error.h" @@ -317,6 +318,7 @@ void RadioLibInterface::handleTransmitInterrupt() // ignore the transmit interrupt if (sendingPacket) completeSending(); + powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // But our transmitter is deffinitely off now } void RadioLibInterface::completeSending() @@ -412,6 +414,24 @@ void RadioLibInterface::handleReceiveInterrupt() } } +void RadioLibInterface::startReceive() +{ + isReceiving = true; + powerMon->setState(meshtastic_PowerMon_State_Lora_RXOn); +} + +void RadioLibInterface::configHardwareForSend() +{ + powerMon->setState(meshtastic_PowerMon_State_Lora_TXOn); +} + +void RadioLibInterface::setStandby() +{ + // neither sending nor receiving + powerMon->clearState(meshtastic_PowerMon_State_Lora_RXOn); + powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); +} + /** start an immediate transmit */ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp) { @@ -431,6 +451,7 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp) // This send failed, but make sure to 'complete' it properly completeSending(); + powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // Transmitter off now startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode) } diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 2c841a19ef..dd01d2037f 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -126,8 +126,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified * Start waiting to receive a message * * External functions can call this method to wake the device from sleep. + * Subclasses must override and call this base method */ - virtual void startReceive() = 0; + virtual void startReceive(); /** can we detect a LoRa preamble on the current channel? */ virtual bool isChannelActive() = 0; @@ -166,8 +167,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified meshtastic_QueueStatus getQueueStatus(); protected: - /** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */ - virtual void configHardwareForSend() {} + /** Do any hardware setup needed on entry into send configuration for the radio. + * Subclasses can customize, but must also call this base method */ + virtual void configHardwareForSend(); /** Could we send right now (i.e. either not actively receiving or transmitting)? */ virtual bool canSendImmediately(); @@ -186,5 +188,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified */ virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0; - virtual void setStandby() = 0; + /** + * Subclasses must override, implement and then call into this base class implementation + */ + virtual void setStandby(); }; \ No newline at end of file diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index afaa13b7f0..b564ba287e 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -231,6 +231,7 @@ template void SX126xInterface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** @@ -270,7 +271,7 @@ template void SX126xInterface::startReceive() LOG_ERROR("Radiolib error %d when attempting SX126X startReceiveDutyCycleAuto!\n", err); assert(err == RADIOLIB_ERR_NONE); - isReceiving = true; + RadioLibInterface::startReceive(); // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index 9e4fbfa772..fdb2b9a395 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -190,6 +190,7 @@ template void SX128xInterface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** @@ -263,7 +264,7 @@ template void SX128xInterface::startReceive() LOG_ERROR("Radiolib error %d when attempting SX128X startReceive!\n", err); assert(err == RADIOLIB_ERR_NONE); - isReceiving = true; + RadioLibInterface::startReceive(); // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index ba1f5c11ea..300afc2460 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -27,6 +27,9 @@ #if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE #include "modules/RemoteHardwareModule.h" #endif +#if !MESHTASTIC_EXCLUDE_POWERSTRESS +#include "modules/PowerStressModule.h" +#endif #include "modules/RoutingModule.h" #include "modules/TextMessageModule.h" #if !MESHTASTIC_EXCLUDE_TRACEROUTE @@ -115,6 +118,9 @@ void setupModules() #if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE new RemoteHardwareModule(); +#endif +#if !MESHTASTIC_EXCLUDE_POWERSTRESS + new PowerStressModule(); #endif // Example: Put your module here // new ReplyModule(); diff --git a/src/modules/PowerStressModule.cpp b/src/modules/PowerStressModule.cpp new file mode 100644 index 0000000000..c86017ae28 --- /dev/null +++ b/src/modules/PowerStressModule.cpp @@ -0,0 +1,77 @@ +#include "PowerStressModule.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include "main.h" + +extern void printInfo(); + +PowerStressModule::PowerStressModule() + : ProtobufModule("powerstress", meshtastic_PortNum_POWERSTRESS_APP, &meshtastic_PowerStressMessage_msg), + concurrency::OSThread("PowerStressModule") +{ +} + +bool PowerStressModule::handleReceivedProtobuf(const meshtastic_MeshPacket &req, meshtastic_PowerStressMessage *pptr) +{ + // We only respond to messages if powermon debugging is already on + if (config.power.powermon_enables) { + auto p = *pptr; + LOG_INFO("Received PowerStress cmd=%d\n", p.cmd); + + // Some commands we can handle immediately, anything else gets deferred to be handled by our thread + switch (p.cmd) { + case meshtastic_PowerStressMessage_Opcode_UNSET: + LOG_ERROR("PowerStress operation unset\n"); + break; + + case meshtastic_PowerStressMessage_Opcode_PRINT_INFO: + printInfo(); + break; + + default: + if (currentMessage.cmd != meshtastic_PowerStressMessage_Opcode_UNSET) + LOG_ERROR("PowerStress operation %d already in progress! Can't start new command\n", currentMessage.cmd); + else + currentMessage = p; // copy for use by thread (the message provided to us will be getting freed) + break; + } + } + return true; +} + +int32_t PowerStressModule::runOnce() +{ + + if (!config.power.powermon_enables) { + // Powermon not enabled - stop using CPU/stop this thread + return disable(); + } + + int32_t sleep_msec = 10; // when not active check for new messages every 10ms + + auto &p = currentMessage; + + if (isRunningCommand) { + // Done with the previous command - our sleep must have finished + p.cmd = meshtastic_PowerStressMessage_Opcode_UNSET; + p.num_seconds = 0; + } else { + sleep_msec = (int32_t)(p.num_seconds * 1000); + isRunningCommand = !!sleep_msec; // if the command wants us to sleep, make sure to mark that we have something running + + switch (p.cmd) { + case meshtastic_PowerStressMessage_Opcode_UNSET: // No need to start a new command + break; + case meshtastic_PowerStressMessage_Opcode_LED_ON: + break; + default: + LOG_ERROR("PowerStress operation %d not yet implemented!\n", p.cmd); + sleep_msec = 0; // Don't do whatever sleep was requested... + break; + } + } + return sleep_msec; +} \ No newline at end of file diff --git a/src/modules/PowerStressModule.h b/src/modules/PowerStressModule.h new file mode 100644 index 0000000000..2d449f690c --- /dev/null +++ b/src/modules/PowerStressModule.h @@ -0,0 +1,38 @@ +#pragma once +#include "ProtobufModule.h" +#include "concurrency/OSThread.h" +#include "mesh/generated/meshtastic/powermon.pb.h" + +/** + * A module that provides easy low-level remote access to device hardware. + */ +class PowerStressModule : public ProtobufModule, private concurrency::OSThread +{ + meshtastic_PowerStressMessage currentMessage = meshtastic_PowerStressMessage_init_default; + bool isRunningCommand = false; + + public: + /** Constructor + * name is for debugging output + */ + PowerStressModule(); + + protected: + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_PowerStressMessage *p) override; + + /** + * Periodically read the gpios we have been asked to WATCH, if they have changed, + * broadcast a message with the change information. + * + * The method that will be called each time our thread gets a chance to run + * + * Returns desired period for next invocation (or RUN_SAME for no change) + */ + virtual int32_t runOnce() override; +}; + +extern PowerStressModule powerStressModule; \ No newline at end of file diff --git a/src/sleep.cpp b/src/sleep.cpp index 735ebcf6ad..e2c9549f3b 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -8,6 +8,7 @@ #include "MeshRadio.h" #include "MeshService.h" #include "NodeDB.h" +#include "PowerMon.h" #include "detect/LoRaRadioType.h" #include "error.h" #include "main.h" @@ -85,6 +86,11 @@ void setCPUFast(bool on) void setLed(bool ledOn) { + if (ledOn) + powerMon->setState(meshtastic_PowerMon_State_LED_On); + else + powerMon->clearState(meshtastic_PowerMon_State_LED_On); + #ifdef LED_PIN // toggle the led so we can get some rough sense of how often loop is pausing digitalWrite(LED_PIN, ledOn ^ LED_INVERTED); From 4b82634d1a7951a4ab8b0c32615640c340bb2b3e Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 3 Jul 2024 22:19:01 -0500 Subject: [PATCH 116/211] Cleanup buffer --- src/RedirectablePrint.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 14264ba21e..1851ffbaad 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -208,6 +208,7 @@ void RedirectablePrint::log_to_ble(const char *logLevel, const char *format, va_ nrf52Bluetooth->sendLog(reinterpret_cast(buffer)); #endif delete[] message; + delete[] buffer; } } } From fc63d956e7eee73c43bf60c81eee277ef11b43c3 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 4 Jul 2024 08:10:40 -0500 Subject: [PATCH 117/211] Merge hex for wm1110 target(s) --- bin/build-nrf52.sh | 14 +- bin/mergehex | Bin 0 -> 2102544 bytes bin/s140_nrf52_7.3.0_softdevice.hex | 9726 +++++++++++++++++++++++++++ 3 files changed, 9737 insertions(+), 3 deletions(-) create mode 100644 bin/mergehex create mode 100644 bin/s140_nrf52_7.3.0_softdevice.hex diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index a9980f486b..853adb4886 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -2,8 +2,8 @@ set -e -VERSION=`bin/buildinfo.py long` -SHORT_VERSION=`bin/buildinfo.py short` +VERSION=$(bin/buildinfo.py long) +SHORT_VERSION=$(bin/buildinfo.py short) OUTDIR=release/ @@ -11,7 +11,7 @@ rm -f $OUTDIR/firmware* rm -r $OUTDIR/* || true # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale -platformio pkg update +platformio pkg update echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS" rm -f .pio/build/$1/firmware.* @@ -29,6 +29,14 @@ cp $DFUPKG $OUTDIR/$basename-ota.zip echo "Generating NRF52 uf2 file" SRCHEX=.pio/build/$1/firmware.hex + +# if WM1110 target, merge hex with softdevice 7.3.0 +if (echo $1 | grep -q "wm1110"); then + echo "Merging with softdevice" + bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/merged_fimware.hex + SRCHEX=.pio/build/$1/merged_fimware.hex +fi + bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 cp bin/device-install.* $OUTDIR diff --git a/bin/mergehex b/bin/mergehex new file mode 100644 index 0000000000000000000000000000000000000000..2a93c571003f60f7d94e7a588acbc00285af9354 GIT binary patch literal 2102544 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

$&*Qh7qS<%!@nUL*MI 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

jqWDRdU%3zsH=u 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�hF6bG}d+&NiOQLS&25sIl1%U zD9%4g57Z!Fcui&}xCz7phf_?-v%fhb+o$gBZ!iTlC4=E+7o}n6#UNc$=lgdI0t`8emS@J1&cNf+K3K3if27kd0GeDt3k5+rCiDT;=) z*|Ak92_`^2c}XC?=Y4g+iB`fMwZzJRUm*y4?W^|N$Fo;UBA6~W)V&-_UB(?^>P3FY zuf|^^0=$!>`cNQ`b_0rRIr0A=!uh{ru9iHk=bIu z!6abi-X*4bl@IDa2Dl?L$4{li1Rr^q1$34#Kdi9)I1yD?UW$y9Evbq@&E*Xk`JDJN zm&qJTG#q<(CHR-5_|va}u!?Ab(BB1#xLb50p#4G5EUcR!O9|>=8c4~GHpIYr8LvE9 zT2w!iR{V`FnIToeLtZ{>Taq1*3dRzukz{9b(@ko1EM@kYiE!g=>dJTTNATGCMW`}? zg!{Qt>r|F1qB0cIU0Y~cc-2t55_KDx4I&KSR*kTUeYYeYpd&K=ND!75y`3S=y#5lR zRv6vIJ2;@*h&=IT8CpuwJ))DlOC*mJ>e2eb`O)#tQcy(x9u4*Zl{NCm%>SFBP!S+X zF+cN(FCX_uK8AB-vG*QJufckZrS2I#vGtf<=LcmZ^kE03j;nx4LjHK(2pY!3z5c^b zfvvmjaCcgWQaN8rHAD|Xp!<`W(5 zqxr_BY{3vU1d6W5wB@v)??NMAg-N_|{F&I%t897#L`R0xyTouwoA58$Xtc{#=J(0r z^s<>rg#Chh*DrlZ>bQ$bN)e1q?G6ByRmDzRi1o zbBfH5jyxe>1vFv2>Djy!Db))`f=%_AooB?OhFiUh2+@dqzpn^4TWPhvWKkAoxLt|E*m>yKbWJ}m?dX98F?9S9lL8T7uLB$<0$p6 zHe?^sX{-*Dc6jc6$Gi+1LoM}gROpJR!<6$$3ZwyN*CAelL7wlm-n?mC>z&!!4_wB-&xUCD!5+o)&`t>9DSe`X%pR-H_G zGNs&wzwP6%<8aczv<}!=s_(O{)7z)bG8=zzfZ2^dO|_2%8-Li^Y)=Mz`=>hTpbg~H z@g)(D;C=SdOvffW>9I!;|3ct5xtyZLUxBl&>nDNy1ZsG26g~|WOutj$%W3TRE1v*q z!?W6e>K#EpIvDh2*J{uU&pSWKkkOw_S3mdx!+sPGG(X0`T7KZ`z2 z{LSA(9}oQa--teL<-nQ^(Z^G{zk@!GD=VOnyRNbH@!CFr4}J81aO3IYG$?ZY^zn&_ zwg24ovHIlCqK}ea|2_0^^Q?a(`snz{hUw$>?B78j!!|9TkDpy_>0{Ae5&DQ9?fWN_ z8G>E%n_H!@Ya>>hesgzL{hZ&>QR(mJ!?I}B@}lf;IV>m3VL4R>$E1kE(r#SAXL;Ap zl^S&#bJc=)`x^(dcvv4x&7uGCyX3p!o)xquroB{EoB3@)EtF5woZE<|>0ZNhEidHZ zn@Ic<@!%efRIO`&k>VuzU={LPEoF7>uW}npKcc_49a5QE+Io83X}H{&t@-NCsy2Sz zyH{8(x7O4{P|{4ENUyj0zG9;yyw>AV_m|D-&Yo``m46uRwriDFl(UvE55 zt=?UCTC(*AUB`7exkx|aca>ABus463V|tVNI<4YUI-zooDI;A`RmSf!6}Mva*}k3z zVDvHs$G6{7OIrreW-KN9%5=1kE^ahNS4!(Yjj2~-spVYM-RM#=D7x`2ey!ujbn1$^ z+T?P@{L*Ey)ELIZ@2>^gM_FFK{R34+FqU^X1cvQ*aT?<8T524wJIaH|U`@v1I@Nc$ z`lg!ls@0MuM5z<7YQ`6XgS7CBztw`+%Vugw9!=HGOdW9I8PCf2j`eT}n*vvF`%>ksPy?Y@Wmc+u9$C8nktog9i4aDzbA7_A;j^v zkBeie6S*=WyT@`N|I{R>lXCXD+4=_Y$hMT~U9%Quv)5O(@jgj_fq28oeGhBtf~pCz zbRPqg7%jK<^q&0 zqIZFOoWfmd|yV)a0O(Zemk_IMNmcF%~TNj0gWAJYl#kl9MlI< z?sl+Px*)YEO4@VaVHN^(apeK{8eLFXbByIrp7s8c_Ma8r!(+Pr*1we4*C_v zE}tJK0Ym9gRmXcplr`&V0b85{pkZE&5}J`1nN0Pv3*R&5TLUG0eEXC`{w|J>R$(nY zD0^d`ma3qoY<0#p3l9@ag{i7GRmeZ@Fdoo;uJPLTwf$n3yvMWlyMIN9@!2YLI2c@MHrB>{;+O|4ssxHxsmP+RKP)C?Pnb$)Cw zk1vX)l5mD$PB|4OSyKW~+8kqh!Jx2b!#pRmiJ?48iJq)xf82#nnQJZKI%0rNr2-56 zbHZO9pRV_6fX`gxJ@kJ{dHeGHz47K@O6b8GA2?m?y`+t#u!KTAH@G-HScJgIjb+Yi zLFf=*dL7?Mnx;1u7v(#kfKP}*GG+;M_pKsd!bF6NnNLOovF6H}!ONj>A6HZLkjX-o zOK31MMtCE3RBLJMwvmK;nwhLy)I=bV(POBQNIxN`qM& zWg<<-0=LqA_xJwtWBN?vKQN`kx4-^_oyF9rSZXlPYVt}~b0PVZy2!{U6)P{rW^&VIT&;`H5@r;jXouwB|`W=fxV(kv8!T1Tt$^%BJ)#q!J%5 z^7$M;Gg&p>_xl{L<(2WcgwD3eu=F2=!|yD~^we4Vo=%Q0^4IXjQMv5j4uo_pt+j#d zh_yLqUFKk&ZTN#1_)fUJmKW}OZFKg2o=B;JuWS{D%M6yh-BcO+dR_?)k>k z9z4S-HkXc9toDp4omu3SAa>_K6|%KQto2Uks+T$_sO^{Xzl{&7GClNer*eUcd|=he zmY^N`@~1p;U;gwR|E%amQfw;S_@&aVSGcFJ@)6=o{u}RVJXpRQ(|xFK>r~508rgcy zua*XhgVm%v+YlrSDt)?e?SI_hx$)KUisIJuCFz>gNwfUlOnB{H@|E!gOT8xaocGM+ zwLBRo!8+la$Ji6#uY@_`GfS%CZB?wp@uprP!I4N97g_)NR6?nJ;iQ7azcxS%?SPz| z#cy0L>^9fyP$?yfPd{955V^gF(Yagp>rlxo4oQxUY0*TUK*u!O*dSB zc6D9JRSG3*AgE(_!RnMG+klBkQ_vq$?cYtZ~^^U(r}P2Rpc zsLUkmdWj45(LhEu{-U9xY|yD%*-vzKEj=UCjeyz=;7q5t~+=VrY z3#nH;b_w;m*WYB#gl6d4L^^w;xMKb58P1oZZ?V)CAa7!azUMr5`<1tw%9wgNlCAFW zns{b)Ja*OGhD_(KE4+2QM7{*rI~6#?jBzH)0UXxQHc9PF!mdhS?1<1DcRf$p#IVLw zcDe#RO6Q!0x$8^t$BHnl% z4xly-TmytxW+x{DPf8gA6DKTe$ed_ZS_E>xw{OQ3Fzc08Ta(*iQ`%r2DJr@qzUE`7 zGNSDtD*E{b@*6}qNkYcbhYCCfH1sA^16l>%gm=L)7BKFFVm@fVpHLmUY&Af}aVSh| zFuHsDoBlvdP=%41Z@>mo@@pW>3Wjpd6Gj-9_JS4GUlzqH34S|3c%i8E$5<6m#$KC< z$@&wf(i(jzL&-}o=DNP^6MPGI3I-n64_-YnQ==0a9qnebPs@Uq~H+3sdtqtk~ z#acFH1VQj$z@cc$1h?r#g?#;n%w)z~O*PDC@xZ~*SL2^q3(Hq)M4?mJMoWw zin@io0b*G|$0YFHQbZg2EE;ITu;&3>U{5vSvA8^-=i4Q%CuXq1LX!5XDQERH3}vi{ zW3ZvjeK-{D+X{a{{L}wL@dp;XYfPW()nDV7h|$;my={1E=~~gqY3>YEBdE&BwXdY# zR+3ns0C58&4PqS9yPc{HnY!cXC!ZhV+I|taM-bg=V`& zl8C>PIUX&kdA!p7A=^PIVLN4=0%m4Oe-->=2A9b(aIi+jZ=l}z228kfrMvqKk$@$0 zGkb+#UVIGS_rerjg6GoD4xI@Pc~Wnq`D-tMAt70xto`wuK#z;ON;7zEy0+59W`B3`vmr>i3gj&t0F5*zQr>`Hwk~HF)mEzVlaYx2o##WFzSaDdFNBO zA+y$4{D%=*--rtUc{@?bn6J*;{WFiMVlls}%(wHKWapQm5)KAx>5uXYJc|Wu={4X& zD-2!>;4yN_IFlu;-lRB|{_Aas&erJ#R{kg&mI5{1-STWYxj(mdDkU|*2@9<|TAeZT zs5eIy^^i}p@*fd~d%p1+fye?4ZFq_xMkWSk{rOxqX5RN50Ap;?Zo-dPkVW1MNREO5 z_oz<_GJ?w#6tg3j?pE-KABiD4s&vo3z}oZIY}MVK-=8>>h&>N@1^Tc~0^RdMqYrOx zN;dp6^kJshjn;=pu}QDTvRj+6eSvCJj50cGriieSNt6i|WIEw+_uW*}Fa*G-MzFQrlpl50|>nnF{`a z`fv*Uu!lZ;BM%|jFQgCKg(P1ezOWa~&tHY>%N(OsxTrqtA6(W$A2v&7y@%uW>1b z*w=@>_2|QWHA}45M7T20hfA$Kyw)h6g;qkS4-XPvU;*}dQfaUH@FZT)g%at*igC31 z@J)h2^0`w~Y%Xi;x<;rF*W?xA9j6v5#FrVEdMLzWH=qz3dA@P_@F)WtlOvHAzpn%V6g9Hsda^-{U>>-z|BYw;!VVZ;7w}R=8i8)=mGNo!5VTqQlWu66(K8 zyXn72(T34958$~Z{d+;=` z|6a-6hVOgV|u*H^v z{%iK>c7)%y7wEqS`r|i2-*`1<@Y;0k>%R*(r2kg9qgqi7-$2XiuK#MoWmNxV6cuM< z^xtZu|C%1bpXk3?3iqP_O8vdTsJ{&ovs&kp{#z2&e@nXQzi*+3_RxP30q+O!NQW&6 z_1_OEF8#N)r~Z3%UjLm)Cmmn^Em0QEi2jS|dtz0&w?q{cYPpKT?p^=Y8_!p2xs)Ee zLH+k6fbXSpeb=(Enb$XGJunE((b11F;`SwV!EaSLyaV9RU4 z6;=z*yM@cqf)!+@M2p5N{D{!VcB|NBOSv*ZX6&MAe^w+RoT#pdNB9#xUoT=>4PxMa z;}3qa7yUPkF4H*1NnD@a3glRGzR(-2Brxa(+H0Fe?eHVbe$JKAej@>9zCSn&FpKzu zcRHg`{hi#q`a5(3>aW!sy2qDEt?VVfY(E2@uK=4Mvyi4PHV)okeng)3sx_)!>%y7M zRbD?cV-dK62N-W~1`HZDR>;t^X6md*!GOf1_sX$s;L(0VqAP}^N)5G51nX_0^Mvf}Kl+gGb*^7`&< zz_IaZZ9J2|*YN|?D%_#xMD^V_-Sd8y*LQs?L*Hd3-mY74-b`VP+IOhkXqF0t^YvYA z_75ml+^cK9E-yi`fWFojhbAEs`g@f-M4hzway{w424B9rw^ZKVZ}1Q|?@j!K^4dW4 zb*gf5sVa5c$cPQaf-RwtyuN=n-d-CA_WDy+#r;Kh71t8h8+@YDmCh_}?oj~PnuqcM zU?{p!Q%^11A9lPyS`)wv zp`X$5@Z-B)-LQT;@l;g5zNmiP^;@Z|zJ6qPZi&fW742X6Fty06!&whh=Qs;48m<}gxz z+}8PAHG~e{i*3oMgV$)!i@aY#XOy!OsySNCD9+Zss~9_XUs$3*y}cZDUFz)}ANMKB z%WoC&PA=4M%|SJ0Z-m)wSKXNXwzkrhgc%nJ-#;^vXV^ubCmv%CL?P$0)|>v(`#%W8>*0w0y!$^c>9PM~ zW}za!@%umSTJQc38ktG_AL~{B$>wz3%^Li`oDixBuhB|7-g{jz^vTzp($~c#MY6-2ZVXo&CSH|Kq*_gMwWO-?RqB zDJwB30{@Y*C%Wzb=&rBVqOVsSXY}~i$=Wkz4uCbhpeetJ7{PxMgJKaaos zeGE50emd_jzx9GbHGSj!skjeaqI`R}M8s=fbzHqr6|LZR|{vhq=Zet!O^p|gf=Ps(yk0K#NpwR!oGy{ntLrU*286tw+CY08{J_9R9iDLBhk~m6+mhWF}f74Hr$*yY}U(CEq#Znh;-bE*(g|;k4QdlHVW>wgBCZ2KR?6z6l>g@c3Z=7CJUWxyV0iE z+<0(q#}|{?eVeo{wU}u9L~hjSiS`Q}(;(ZVo`wWicQ_dzLB9vs)+D!NyzRnD-do>f z%eD&IyN(9UrT~KW+@a0jGS}}~irZ&?fxx9XTm4}H(EQqj?v-vaAJMpSt)IlA4T~4- z-_DLAg$r>Re4ta#{^WnCUmj23$3%=&=zx`Y$V zH{bpHeT(u3$9LEje+47-?NJ~x^ghE5JDLUuAH<>FHG`#ZnJamb|W`*whqDO`%raSI5%jRVQbjBly}=tOMo5VdGZUf2mI^o2KBifNd6#BK3;7r3+ez zwtv8;$wQ$`!(#0p^r3h9_O?{jUjS-YNz2y5;JI?1(fN~ss~?vzSnc5DftDwk=Qug# zQst`J$@vK3roQVytq&%$V{7V4{wJ3H6?F!Kl&9>UDWIk&H8>_EGmHC*xX7MZRqs}@ zaOWIwI>G#xFCZyHCBuHUf`|(F90qC4!AC7K^G$q27ulyj-{b*5qZ{)C;H7Xl82!~r zbF9QKB*6m&YA+|p?RYDQ3E+GhU%%Cg^khL7utxi7b{*}nkPQp$R$`?N{fMA~LKwYk zz(nYu=}z2X-2bm=u9hQH&gGXdlBhJJCw^{+oBcS2ng9%Q){j}tE*A|CHSfE#pvyS+ zg7iWbw16OrzA2Q2p)@-p3qw(KP&aHgAd8f_!O&k2$9^yL8OEhFX$_u1Tj>wXa;1+Sx^zejk0dGVTg!7;hK2$#cS=}(z#*crS;^>*JGZ1dj){eKy3hZw7Y z9=Zwdop_XA|IcH3zP_u-JZXgfH@bc24dj7sr++Z^CQi(bwf9S+BuxAT6Z8Zk<1T9e zUL80%0b!#Fyx99TMJ5LM$DL5lXg?j}m+5MMw-^kUw$CkYU)wkKgVb8E%CTu|N+VK( z7scLCU51pgt=KWxZ#sg2rEr`TZ$Fp^g?Q0E9sm5MSbBd`K2_BQKK0N0ieKIexhv6c zyd8;w;k=zuge#X+c{|WJaE2t|^P{57s{@RKl^lDWM21@CR(RW9qEm3yU}YR z1X9~#eCWOgbhhv5UAQ#Kehcwu=qkYX!L%6Sn?uBm0&~ehc{uEo^q&pbdG0EXT`~gh z@-?W_%|zrIb{S5mwi06CdpRwk1|Gg$4ZCp53;Xh^$NrJ5%J&&a#uswxLRe0Pn;oCL}5 z?L#MEywoq4w*v`8?jyA37XmCg*(1;!4qoRd^IY9BCpK!?;H86CyW?Oi?-ag+7~PN9 zL%}RnU&s8ceJ?P86V9W^!3y`gB%g^=--*z1l#Fk;H8iV+pW7P71vP}An40z}tjToH zu!y&+SA1#T!0uLF6yVYEHeXNq1>RofP0>BqfhhO*H&qj( zXJfgZ&Jq7uhM&dg>e1W`oH!5ujBtV`@iG--wFC970@K}yEr{d zzi#Ue8YNUF$XI6*X6G!^;|F$Fvku$Ko4E=aH1gD>649;^hiQE_Wppr3acqVHEWI^g z*Xl~?MZm7rV{g-A4K1Sb71)yg%|NsDpg%%3aNCz|drBTLce(%+zpf-TeA2>hI% z810#TA+|nx(ms5K{oq5YD)``IBj{mN_jfA2oLfTW#!3Q{x$Gnl-By95jiy+HpB(QI z$)zZZiDaHM=!=%);rl%vdYir5%f}`ie)k&JLR1DzAzB*t1JDJA_Xtii46LTtVE-2u z{4xcDaquqWgE>N>&Dy4oXOY{vyw%)U=l=A-wJ_%!?iKth`tQz1`xLpIkHH4P!E&W;>1(UkxqswY*L!|#?zWGwHpO!k z&kIB3jtYeN-2VCgifIGDUvBu&^8$ax$DCsF#r+jKpSyAXiWvuitz5qq=X@T2#o>JP z&-Yhc^475 zap2K^kH2CWUrV|DOn=2_5|l!$$ZkrWe-q&-Yi{{8UeW#dq%iU+`Bf z+ET3E!(XxUrvLW-iW{r*DtR}5MgM&_!e23H_q@O2am9AV(i`wse6rhrh`-_r&O+TN zf5mAO{9^u!-(U9y{1tEQW&IVe@+*Hu*+Tpk+b=5cSB%5i<@V)S-d}MNcPjqef?oU; z!Fhu5G0EH+bK*z&hX@iC&{&?#o}|5v+xUAM$1GvtdMzoCIZm*WZ0l^e8Z)Pnw701r zVVLMJLeA`XI)0Sf@H`Bm12C46Vm{M2JKH!rky&Gp;V~Net{f8BdYv<1f%~P8fsKO! zX?(76_i^xur&9vmed_vP?1ZQMmF`8%$f$x7{#sAdk$&1Fn|b=!_;K;^@#Ev)8owa# zl8J!y?YD8oX>YLcL$?pFu7O%xca9v+IQ>`n8r@?m*RJcj#$Ug`L%`Z|8DDVM{X7^k z4&PhhPS{gp@Pa#YexES^viv_5pNY)6_}IqG1KKT`$h?<7nQ=@7rz^5Ex~VP6v4P3# z87%3K=}6>mmy0v9kF;?K+ekA_v)oy0KE>EJj<)>50=oJ@Kukl}u7fbz4qcK*;H)hryp@SR$^eoeW4z01to9xJFU_j^G#IDaWIN33?87jsk zJI+lEc+^Qh)3Tq=E@8cVgFo$yD zqA_;cQi#3g8F%5=#V=1VA|0IDIV*PCm|14iZ<9{5EHm6^LxsB?VVTJNS!Cnnrrna^ zs14kpr?PtnTF9C^G9dFdnXRu*o-nyahg~M?R!%Y3IZ6WNj~&f-jF z7UK$~)0CNmlUgZ7-N6snJd@1)TE|L&f`*xII+-iSiShP674UoOlH!xTqZLQ0!zKQvR%K0an71zocF00K|hlg z8_BHs@S>M)rS0SiAGUu`*>Wbe32zn^!z?O3OlBVNQIR!o6Lp=jv=F@!s8UZtR7u_l zRbR(fExE%1skbI`{1>jlI0=gl>`rF<9LV4dmLlGboz-|NY(tqhe86J^8`~g>nScd_ z+{y{7$qYxtnoquAKWVxZQGIJ{U`}U@#%{Y(>Z;(?=+LLAH?(WpxdtQZekLu!Iy_4C( zyXwK!{`!!U*^W8L$qh@F@Y0*ci)I|=JAbQhkz2je_BRPU?VaU`y0tCkNlsR%p0hf{ zR{?b3%itq>kXK^L*!}inGLOOPA0a@P4wZJI{nNfv4m46^B|1Ej5AADZ<77tC z>q`VCBBkQk@e5$~`Aj*h!MxN*R%#FEddkdCte=+-e%Sq(fpRi^l{whF&x|bZx-mb! z8T@!tgqz6tWY!jrPxt%mVWm!HrBnC7l;Q4#f3^L}$Vt(f(`g4%-d=u!Uht2R_Vky)8} zJfSfeklB8Lt+$DB;!yDU-f7n;kwQ@cJr7*v%=@s9qh?|Tto#62_%_)ve4qLK;va4Z zUgtBvpYeBoKk75SUn2^b?p!1~m_9wm1ti=yM}J~XosluI=Xs1Z88S4ZmPhm%$b0Zy zr*2Kle#z`U$=nol%Zbq8M^5Jbrn!|D|I@_e{ufE=pdBKr3R8{5PU>5%lV4XWr z_i0N%x9(5UKQ#jmf z1do*u@uL%&r5v8NosKn0=FTdQAJvpuh?elaFD9xTIIsXS${0c(kb%n*NciFE+368E2}`YuVh%?(4LFQcN=LO)|wz z>7^|d>c`dyz8i!N8}Ap-7H9e+Vu)RC*)Cc9+QGRY_at*Al=!r`^$a1bC{gzbm8pf@ zSP^$rJ$R?t&4e3WN0N|Spd=&#{^Q?b1P~)A2%QSDW@t;Q+_x?h;&ew<-U*=3jt6qq zoc>KiODO_SD$vzt3;-rMp8wuF=c|Ja(k*^1-rqqgx@Z6BoppxZ!0cmA@hTs=w1oJ{ z#>lIZ7`UvZ0xY!<{aN-yaPfP?^x6Ewsa2%eI#}{ebq~b{)BLbLY-78^eC%c)G z9a-A-c%IvR`KI})lV~)3m+9X*8kL55%+Q6AUmNp2)8CuR61&RBk4okymeY$*G!4;> zcToYM6`wxp&re zJs998UvvB7a%sA@g;5CU#Vz~VCPwm5mmrUk&Nor+H{qkmj-P4A-GW90Q=~Ls_w5vL z0ZQ}O)4ZnscAszO+`8fUR`%1!u2TA-(9q3%jsE#TR(}U=IRIDZvO_idW{+g1TG?`X z6TwTM?hqtPXUl<2qUS_rNL50o5hbA1az&^PaWV%aMdE(PX{wVLJ--`j)r@bq56#Tn z^|w4knh!QLGsU)=DNGxkC0Cn@GHbei;Xadn2SaKYYz1`LeY>8^e;eSZhkn&v-^w1% zr&wGi9d^F#aepZ9(RItX_3$3TyrtnUF(=^|2UG4 znwU$L|4u@aiAr25YHGI=6s&3Gmx{gVakX=6&f17#dh)|BI+})IubEnNOcXNKY?fCil+Fkf^>PDBIGawHS>_Uj!BB_~( zzy$`6T~8Y_$#lAR{Q*}}H8VliOP2mE{qzsSpXK!K^wo|TE$tn6gYvnOTe-FTZ)rDr z4?WjC&fplLz7@?fH~c62_SJ@*vh$lt0aufA)L5mG4fk-S2&VYUubl(v`eC z59oV6@8e^f+|f+(NU1TJ(%9lc;-aN@ZrxSxw4|*4Z#ilG+GK zM2($9q2IXCj0romj+Zyw8wqWa(b=^quXl9)iNUb+B>V>L$20E*R8Qk)Spd#305|~v zyEJ5~W+yYJ0l@4K0KavOPqh8F<=h%X`-t?ePG9be{<{8L*uIg^eF&iYEcqNvK3OK7 zynsHfKtK=o1$0R_0nOC3VFB&S=YsDvp{?nG>@bnXm%N5|As<{<>hL+()qjR*!)A_7l# zdut2pxIsN&MjTl0@C2*d@=?STfTk2?6jJ56-|x;I~G+OvQhb?U)h*oh&cvo^PC`+c%*ZZjM$sJ0Z=vu_3d6f>R2y&`k_# z$d&QqBRFizxPzC1Bgy4*l5>bPRnMZX+sycICRsyfwY!Iz<>A`jg?PFbmybJqre=Tp z$>m+`6FbaQE{*uKqNCuA@lQS9&moTTHv_b0!K*ivVRBdZ%l9~ z(_4x=tDF2$_o0S(W~Bj=3GI3cb(cmV{l@_YWjpgwue~{iPrLOd91eqT^(RsH&N*A3 zhxek;mDRx@fGtdj!4D?~F7N8ToY@W4~Ci$4&{xJ0v&chC_10E=u6uh^3WpScJ9un87mhm_Jp-Qp?NtAcH5^c=sI-2u(k(o3u2ZqsVrqH}+IaIP%P zeGx$2kjRy6;oy6{SX)I6IH|Ki9hJvYXL4c8HP(wBbYDrmv(6*PE3_})ffdE2r{aV5 zv`N$FPwYGM!4YkI@U{H&hjoM~{y+3X_bMt&%1$t*tG5D5_4)XAqksLB2X;P4)~$(M za*2U<$lVrSzvs@N%eycCU6Mh_*FUtd{(c6EHoil~0pEiLM6!QIKIzLRV9o&KgGPZ^ z`j52XosfrT;F^R;`;)}HPx=_SHr`^rX`q|P4H=Ng4I5~T;Jt-!?`sA^=+IzvNA4^D z?vUwVr_8)HaGCcX8>X7?Zm*XsMA{vaeb*a^K{j~BKOhy`$K#>x7LQDqdL}=BcP^cU z(f^b{-2CS0sH_Y4GimITO`0-GFyIq)OOmnC^OAMW0nu|9NF{zX+7VY^*dvpvx14_b4On&-C&I7as=B;=-xOR z#&dMeao(NOynzDxNs-+c>T0&$2)lRD$i4-+XR&_L>D1|S6VW7Q1Uw6mhv_2pSI8|Uob0j7?q zm{*11XQ{V+zPdX}hGo>68LDpYZq)_$0rN$61phgU7?`L6k@+wlFCV5UK_zij;*n6U za6UkXK!O@L_N8`vbV>E8zYNs?DP(q=$`zx2OQ#R_devpP2gH zZ6fd*oiM_L4+`JOfv*^p|Mh#K^(N@-b!Sj(k|+)>jv<( zQS~pyl*reApsoKzTmN&X^-{n1n?crC3-~;nPxosAzAE!Qge{b-8&ia>PJVg3$>p#)f|JCvh#)1%X9(bCUL<^ct6 zq=0)Q&wcvQ0;Ck?%)QC1gSo{dztkD{P_k}bGB(Q0Y+u&k07Hic=PO3unMR+-!=l>-_yjD>4mAjnsozo_e;j z;_G!Z4*dPzbSkCJ_n)B7V@;h#UPVNu)mN_G$olrN_5E7)ZI-Vu3P;eN62Cv+RoNGo z74)aK@{gh|n*OW&ErsPVcCsg9zb#4Dy)@;Z#K8L!b&sO+y{r{1a-Lx8yu(O9Gc4<| z{)!=DEj!JRX1(Y^H{F7wX%+|2$He5h{eHfSuNEd;np}uV6U?Wwv5bGA{jJLGt8iMM zbZAq{cE<0m!i{k({N-HDXDzoY0e^pHDTP3j~4GH(1fIZW@o>?GYIftQRTHs@{A@tU)794KlV7>+f@0 z4?+7v>{LJ0i7-Tk-S?t8>LK(*vqN!`MzCG1&D$fei}#h+-g_Q426V5;nr%vH5Z z8ps=jf9OX}-MlH^{Ht-g4g4EkHF&e-;D#(qbMJGSpgR-dOW=q?xb0=)a&Vk>x)0Mk zo{UZ8E-ZmGoq=nW=Z8R|DRRtFMeBk97QB9}{svTm8J(Bm3Zm$o2lCmKKJs4iNXGcp zlkmhKDYWxGK;K!?_1B0zag6;m)GOjEBVQu=@EW5J&p2D`@}{o^vw*D7NpBel_vKON zLN#dwx>-)Gn@^lgb{8Q<_(16XNW=o84Sd?Djp@0`SmVo9Joy4VFW(daX=^kt4F+3c zWZsm~&cG!OiM*JG>~?#@?2jgMdqQ{5v{V}{4vtvirU4jaZkJ#wj~KA!C6Wza)=EtJ znbs$RW|4_;c_y)E{r0+E&7(4$uLAriP^)+ROq|>sero*kIF5`{#-}7!U`VMj0y^K` z%parYG4Iz6xwvH$r`;_+_x;Fd`t-~4{0Z@~iOi>dY$#)LztL&4XO(vCV&Ny!$@nj_ zLuR>O6{En2yE*L(iW7CuO?l~9|41>@V+oS{e2LH32Es1z%k*sDrw>Jnt*8HI_16Dj zzVx0zm`CU>l%{rI8K=WFs`N4;3=r*+AK^si(XIjDC(-^^@j2U$%(na*If|~n!X3d7 zi-lh6KAMJ(^w1wu?57ulk@nY@w4OQCTYrD9I&*{l`6`4T?TuULGJUis)cEsGNP>+V|6(^G)48Q*F11J0k^w_rE@p$}< z-rx`QnT+ucz(eO&;>_}tcuWwC0dvyh48cM35E)L@FzpDe`NR= zP|Kr?pqTT^(XpEWy=d$<(XgKTV&MozIj~^7*5BXPPv3BVyYpXFA^&y7^85e+p3_g< z_`X?}5xxTYhXGdrWIXEQKg`0Q*w{hZy&PUDCpceZq%fW1l_(Z9(kQ z0(Di3EKz($>aTl#%F)iicb)7h2)suy)lFNp=r^}D5)X-btCJn<{(??_jwYp+XP!dQ zS+ZT=|9SyM=b7eA+>d%J%%^vWb{e_bbn%|Af|1Vo(EtJ9Ueu3=DM`7Zr>N*o4%`R6L2> zaGqd(#7cVbUeVpcAjEl*=)?v9)?TXkixuwN4u3y@AG9Ze%RBdikOxPe$;>`})R&W+ zT&K5}!`LNXLc^5Y#p z3ZDcz+@nmRnD8I>@grLbY!_lH72U{MbQz1%*@KL=G#IT~5r2fIm{2z@RA4oLzA%uo z^&ns}L6k;5O0Q!1;bl}qx8`K{i-6>NG@oQ%$2V~1!*s!qMmBYpcU|pzFj|59Gx6Ij zE(H3*{}%j{Cw7Pb=7)NLf8cuHmvxmS2rsuy8-mYcg9hszMjjpIJAF-jQTI_0-wiOQ z7HSm>FE9hAK?_IcC~#^85sapZ{-#T+OR>=ytHdnZx3R_*2zaFap*WtVJ#9r`y?1R1Hd&oWD z`<}bO_r1utZupk|9pIb|4fhhXAWzdkyo=jh=8@7zu9E$}f~$m)`#wJ`2=pBr@h7qi z?=Xf8Wd+Zb_C(w}g?QG7Sm48hI1e?00@QR5L!g?TecaSkZ)>`JjG0XG`ky@I8&%&~ zetlcowfdD*3uLGCs84;%ZF3bgROdTCfz? zA1+g{@*4NH?=UjCqtZ44!LIG#AG=3Ol;Pq{IDaCK=&=R?yzQ-dNtmBb3!=n%Xn;s> zi^L&U36bu3RD{?j3KVR9_c4RbRs7KV(~gQxh(HK;Ec$-=7XHc_TXllJFrGUzFYyGn4*SZJWvYe+mvN|YRZOXQpvgey{ z-hS?P=@9pI3w~nP3a^E(!nBCWR z=#5`#W0nubW9Cfb5&1w#p?7SLs{=G; z7fh~Y?H_L58l&%JMJ=V!Z`U7~|A^%-bI)r3bRCDLmI;^f%$TCCSsiNqa#P=>w!S@8 zUt3t8?dUij#%^OsEL=Fo{N+J`=G7vH0{f0+(=FL}`?}3rH!~2#(%<7-_x+1MUDrs^ zzFPKnQEd_XTJj*+E?`H&pKYDaQGOgh0nc`RH}mml&?7{&))0}CB>;)FjG!9)6;9AV z%*hZEMsx-?+)f9++nLeTbiC6fj=p*Cm_*9S_BjuCF@+7JA00 ziLLu*$CQ~bz=!}XUxOZE z#|QTZt1P%j;P}opufvm0AX1A4N4B<+XV!sdG zmpCVkU}VE7D3}k>wFrUV-gpts5&~#v95W(=uy8nENwLy9d06&$a?PdL`cf{da!&Ee z*zY%Oeb@L?d9s6jfz^leP(E?S)h9gQ!HO{g^O3|9B>n_Bq)x9Rn= zmH$!n`ofC;(yOxEhxGHWrPt{EYOI8d-ckfFQ*24ZII~&b(b(#y70$XW-MH@`XH@&h zq`S}^e5@wjvZ_X@g$g(5d6-2QvX~V<*6)c$gP5NxUt|>bwCNnFO#V@uD zFbAAGMd4)TM9v{^|2P)AWD7u&=^9I)2rf99VUuKzT(}&J&9|-!lIy#r3O(-J>Jf`e zD*1Me`=zali9;*A0x-^%Veb>KY)8}e-xJ68n+^+LP-(wyY0ixVl&R64Fxz> zCP@>EVt0BKy5i|otiR9o;i8}MLbz@N8Vgs_!bO7@R5b$^-x|2a5uIou%AKf#0^V>h z-cpUzGKy!7!@!KA_*BhksGu(Kt4mtaUPn)FVe@ zsaNzOLxb99G(ma4$7$3T_osM6)nq-8%C3(of@W(K-}9T@X;11YO$sC7cc^Jcc{=*R z0K~xtGe?foH@J@8a1S=0s4TJ{g!RE2_NIpdaDxpX%mvMX<5McUa zx|tM;?ZDBcsp>g^n?cO?5wMHg3!n144+TsG5e$S-e;5^7)E`CX!2dXde?ljOLLdK! zfd3;c{{N;IUkLx7JnjSFh+gv0F#-?2vAz*lVm|6Q0!33-uVbFgUTRKT_ za2ALNJiSKaZ9p<4t4iFzOhs?y!s@L}MP0Xt`YHaNSo(Cn7k`P@ysHW#OwG9M&m%i- zdzmYZ+kDn5yq#6n$Yn#|QdtN@B+fhax=@UdZ%2fPeJA8Y)Qd~D2g!8K`x9y}@x8SF zf+=j;Z}x63Xy3r3?Qs;q014P58 z;rD2hs-$zI65ep5kKq^s-WwEG49%FD7P}`!Yijm($oDhf#UFxhb+L}J>*?a*`R{Vu zen0>shaUAo43v0mBSVL;r-BHtOAPq}X@$3~zU{E$|7xN~Wk0ackL~b+yU8j!g{(+^ znR4EhDxmpMJUwA1`XBN}^zLy?32*#%e3~w3XD{(ys1%ZyJk>#svVmlQz<=pB?wMgq z$oFsTAD@oK6nSUzZI2eWV_e-KW92a!p1TP*RmDwQ>*y4XIw|MngtN59U>XlhSBdmO z4b7z^K3(Td!BH3S7s#GxltO#H+5OEUpk4%(8(AON=u8Sosb^b^JzpJ&z-sq9KmbZ z9lSP%$4|o76+s>%_n8)}ZEOcb;_q&7So$-$;)ylcFPkK=*Mp-JNI)9ebzkaPef-Jax7Hw$D6Q?B?D42(*q+#5EZl#Cac&{5Zupm8#TJdF z+Zm_!k)`a<#dJ<)_vp)GgkbCO1*UU32ec^sKUg?{+6(MwzL3l+Z9S~OeqLHw%*esg zu0H~2XfKy`T`Rn=G%x_B*)Ngj|FB$H*Uc(t=;L$y1NMH!($Bw#KOk5iWWAM03!`_A zVa6jl)|nD3@ny^7?XMMkw=yyv}<-;3ChkfW$R7ZY1dhSv)d7xHlX3DC?!+NV=45-BIkgqwXxJC zhSXMQGE)54RL(_6q5I6_u@rJ-box(Rb5cbjduC1IfHP~+myq*!8yaPWBCKln|d zZ+oq-pG_l9_Rq8R4wX=!>e?M(KNYlmIxF(2xz?vc&8K&%Wg|}C)0DC0;e`lEYg?3) zJq<4o`Y$Delo4@ypwy3VGV^n`9xP5>>s-_+?0F{vlb*-3B~`4v*97_&!lX?=x`%|-S&1C2j`?{# z{h335K6t@0&G7|&`FRMcnG%```f-t79!pP&SCThM`3cv(nD;q(F{mQEE%jai`uuIz zwc&MH*R6Kmvi_O=i|Y?BipaaA*+=m3S{S5l6@+LmZcRZtX>=H4G8>*bab5YXE z4Q_Th6XngW&##cSRpE|DwLp%QOSNAwr8_VTrN#)|EBFZy~?^f7+Ed71J76_p$c|oGr zd0oPM0YfOd{gYoMM-lZG0FlETSdZhnPBAvf_Z_s>)kh zEMH>k3N9yynR^v$3cc%t_nq2ZA3W8T?L{BF&Xo1_!FF&>IOGJUjy796l66&8Ef)|^ zjRkBP-ZUX~*4>fX63W4?$WeonEfUbMMap4Rs1FQQ%m>wO*An{yc#+M4P&FS|%92eXWFJ?cpXBIbg@Cmg@pLE{fL!0k(I%w&=U;xe+~kD_gb~ zygH_=kJmwm1bE%Cs`ZC{r_wq_&_WkL7S-3Iv z;gT-gfHO2QCBb6LfF`9K%?rdQH>ovLFfn!(gcIA6;(xNEZQWt$FN;)%4?i9;^1S*- z>q$V4oG6CzDaU@Y#(jRFg@|GBeQi^XG~Lb=X4tJDSR;a@G6*DkCgpyD?V^QG@-$FG z6x(n8F}Vf}9y@tDMat#w34Mx-yx)g@Hur>4@2qRcR>#{vv4*}5nb?-s?)N8tx~>5V zuF-e3-WHbcz)g)%unCOnz3|I$KMrJQ+iM?Q`ve9~>zQ#DiHyzKY?iLl+Gdf^o;0Q# zva)GKt$lcz${H6;>q&fIjofA#xv?~d71$3bTVeJf8NNR&Sv55t+tR7_jyE8s=yp-w zo~YyCMV-NMDC`b4yO@o2Y&ZF4D^<`bxxK}lXVS3*0=!~=&?^-Tw{1sa^)&xd_ zjR}QWMni+lZwlDN^D^*#!b{m4(KnGx#)=8C9pKb`bY9#U_&4XFE@$2=eNzvUXW%0z z*7y`0S(@m(BR+I?GqCsX`PhurKu%_~Sn4;rz@gLFz>aqv6q~I3NZF=iBNyN?@7pI5 zl&CBvk5Yob&*l7>6=`KGLEyQYoG;=kt3rIRIK9};IR&7U2$Ux^H8~grrO9GKb62rK z2S7BxcqB6o?`$@j+z==kG1GCvY7;$a5(;6eXe(W{Q{1IrCm{~CRG2qHtQZJDemN7?SmDU8<#^9yU{T&Em%TBKNxaJjjl87B`OLMKb^~3uKODfI9>z zu0;@n3tKKm4Q{Ac$I{bOSK;tjxq*j@Gl*gGt~xUw9C1liMeeI8>U7xg)*1td%8A$1 z>dX0i%OMLk>!yIon}7x7BiV#dRw}U z-!5G9yJwP+cGeUD!Gd1DJ?8Z+|^(`PODBs*zctvHAZo_a@+VRaO6g(t!qBya5VE5eO2X zVUU!uktv}GoC`M)g+gDUT183~kO~P@%aEFTq1VfWDy^b|R>k*4Kqv~e46P|0QU;-@ zNCkm{4EvClmZ_~w`G3A^pL6d?2gLXJ|9;Oe&(q$0&e_A-Yp=ET+H0@9Hdbr~x^2vi z)`@8w^S1F8i+@6psU%X|gj)VJEo=QsWssjnjYI0>u*&2y4SZpSWn|fCu->M-`{9N^ zKw_leh6$ous!YwRm@yVYnpR?nV<V^#+hXfYhSJUX^UCE z?)zFKk3oj~u+R`|`KfTUTFCW#Z=j>kv0Hu8U^;jX#Oi zfW_hVKV=5qjsGI~6J8Ug=~{S8;(ZtCvP7}@O6L#l@JRkm^BmQpxNt!O)?${AOM%}; z8K)O>kqe6WPkNRYTQYK|!Dq*@7JML;#lix)>1gk1e1vZmH`30p;*FReN4j+shOkH& z_}Hw=#@1B0?uRL;nWCtDHu$t~O0+#ftsfWT<;Uq|6Td*G-DOP+Y!>Iok#1#ka%?0z zJZBk49YC$Ad1J??(JX=)t^A?~BD*GPg2(d6grCa(z>^xwOE)nx)|A$x1e-suCbfNQ zP2}IsnK#V$7mNw+iKq5p(fdQ$d}LY<{oKvGT|9M@IlJki`xUyFM-Xw>cu!v|AYx4&07=pfaho()V+2h2e`1JAM_7zMgJw43OmZ` zHxs0_A)wkYqPNM2Zt8fN9e{MPbxvsqAYEh!;E+FnV0HlbvdXObXnw0~t@e%aGV(+_ z0OVcns(jv?$?JCj$UEQi9&LH!9e~=;N$X}R)fT`J+5-4M^igQ1yR3K{-$~_;LX;)V z&j;{qcs12WhZ*`#SM$dOnS`l7?M?k@Z|ZN0O#Qr-n2q~2A|09f|7)JQW~P3!^oa0f z>Q5(3{a0EeWm7*z&D6h}FDg?%MN6iBik3|MCtA_6sed>6I^00PRq;2dr_3^y^-rM z_I~_`Hew>a;z;Hrt=f(p-1)KQ?w8S7?xd;GFh+wHcG|+TiP4<0F;l!<{Fx-x>^Q#n z-NO97%jw*XHh5my?tRU6l0iQ0wpEwl2FHx$%7{_*sRaCoxB$>X~Fg`C&A8xkrfp)xQ4zC(SC$3nP5S`55o=zmE=ulJMhKZ z`%Q8I=y;;<(=)Ng_;Yr9?k;VbU@6hEdMq8cQWC(a{WBm;RHiUSu_#e6ClfevB1#UcKjJMmzTL4O zzEsWYkEopji(Bkd(zO$a4kp{AMKB49B8O`fk$;_gyrEb_5xW6OK z0qH(lZy*4MRrdX+B)_zsQqxh72Ek!mnoMzY=8v{qOTs*G#u}Ys)LzC_+I> z6ze`{O7U`@No9Ybku412)IY|`Jo$$QMTKvFJe9qRPeGn)PUK6#rxSr_M~zzdVz7M5 zM&9zKy%u$PqX6P}m426vb;QqNrNxF!$A4Mv-94kyf&neMTKhWykkspVFguPQi(w=; z0Or1o$VnbQF6(FP3RR`Mm!ZhssyV0chb2F%3&vKbwr{Eq)08de_v@F)zv-`>{P@!; z8B74vSI+?E0n9iRa|ri73?Hp?SRIGEueOUom%2|ius{VT=T^ydj-O?j#Lr%^^B6mT5ty#$aU@x$_eCi$X)^&+B2UfPd{$jfV#Z`oe&s?FV64B9%17US_qxO zkmv$KrbUF7_sVt$T6?%AD(aF=pzcht4`ngA=MK5n%d9bFgy{%M5QkTB>ptsOqnq|; zMt#(u=T7qd`4Jhn)}LF+Q=Z_r*q`u609B$B_VYh#|4z2{2lVf@a{r#N`&B^5*7{c+ z_3tCM_gtI$JD|OPFxN!*eEHwCHwQY<_z9oULj4$b;wVGr?(PRx`BHZRxi&*)g*%JS zo8z%Gf9c>Iq|mfAQmC`q6Op(^nYr5Y>seOQSn$=KHoMl^Z zR-fBHDk-_=4y0sDp|-jEy^$T46V|l*y+Iupw-V&}znZ(=@9#LV6=&Y;pVdZdM(W1d zRQ@6y3nO}HN|cbwb)q#R9t3<#d{A$3bN(L@9dOR1zkH4U-^|9j%QUC6+H`YIm z>roYR)IUrNzJJZc@ow&3IxJj+9vHRb&N?9;2eKLP;oh{-ykIDg;bP0#0;2746<=I) zsl=D#5^s^s>sj||G`(%X*0aqz;ZhM!E7dbZkJnR=&)>YjUYrqsZ(bl8Kw)Ds)?<)n#^Nh*65jGuk4wUD$G+dTH z{^HJ{um#4|XnV%}?cOGxzV6-vbWL5iA+BQSg#Xzwy@L(8QK&E`VI2=pc~~t1;w;!q zJisi+dh=E)>K(ij&sqyaA-wt?jMtZLntkW9eHU?+$*N;}BdLyi-PsXQP{S z`~Y!IFVN*S#au%fb0z$oOF<39o`4Y#M2y7+?x+F4Me7akrt+Rtg{|Uah*ew0M;)>x z!pE==$HzmE$UuGWKfp&@ozYj?%{tC^D?@FiZp{}N@W&``f*PDrd0$3PiJ#mNR5U5I zwkI)Hg52?M1gU*{CZ!G>dMo#iT)2m;BU|s_6IF@Gu+&oDEYI)3*Lx}+`pFT&VC~+> zc%Z*7Y`z_T(c|q+zyI^i|IHq5_!SW4mNBfp+()IqS*_}C8Q)9F^fxm9q4f7fwN*MV z5%V)p{eITp_IATRyFJ5<%9GFtN2z;X_+#dP)Bj5sToM+01E)CFu^D{~Tg;zQ(Cx23 zV7;wh_HA4qU#$$LFSBQi2&_~NAN}ATZ=joj)+tQqL8M>G;!*|N$GDgGv|&8R{i($d zV~%kx4I}s;RhoG_cSE-rBUxZ_*A*yH9;?1TyYEnRVE@Xl5I!`@u}RO z#OJI&SGb>U_I*C{x`bodUi}f|*Qr#Kq@R{Dzdm}^htkid=*K|(ieLW%)x_(SQ6{81 z>RdmEVI*t*@R`JD(qRKO>d(XE8Q5Qq?Ew1x$olma*4_a9I|#Dy_xyLC^vb?Du4VUx{v&+8Z|f)H>=>_yC1wTh?&y`g<)1eCZ*eJr6uD#4eJI>b>SJnS#E8O?J{>ObS+Fx@&htSGZmB%k0y${h(zeb>~ zE3MIlKT3-0~+=6(vKf!Df4eG>}UFQtzN3^;U3wgOsxmI4~{5N>lvea zBpuw-yxN3bO>9K#)M&W(;&?6ex)2(FKH1}syguomnPh(x^ZTmrerSI`M-R$Pmiqg) zOf_>vV;{cadzj+z?U&sHpE69icRq*Y!qOsp0pe7~7g<)k=!FQkUA*Dx4;8RIYBV8W zZQTEjTpd3^u71(W)w8@@JufL&GlFh&x#~|Hw^UR_a<#-yUcN3bKbw4=Uw$_EdUN^N zhB#ZM;W>*@Iw`2Vkx|GzHcX*So;{KH(FhZ5D?{o)|5Agf$H`azEM4Y4F1oE>|) zxs4*7fr?0C1EC8%VOM%``pcRnkTA{NuT*uvzF=NZe8pU-bk?G(<(*Z0orAKqoBJAKO<3{# zDVWG+@ltBpO=J$%=KK6E-UX?abwLsPktW#|`JT4a)w+iUebC>xf4RJlPc<&<{AMuy z0|V!(@6(x}a=niSv3f@k!4}adZL`<1-RizK5|U(tsdI_@;$Bd%rEonLm=Yp(AE}h~()y1D?dps&6$R`yN zq@&&ZC){u-)^H$<*!AUcM3AOXMz2je58!BCg5D$D9(%)gR6FWXyAO52VYnmf`tEcK zck~(}N_2QUm(*$YRr=sWdZ$EsN77~KG|+yj&Cs{Cfa_kpnU0yxza-zQ6hb082>fxs zJFmCt7e!Q}7{e>NW3798rf>}j&N-vFnibJa`ZK^+`)3?3oBRY&glu5YNJzFhVvlK?vfq)J$O~9G+M65VOxw#+L zaRsheXU~t91bQCkZg_^JKO`|xvgJ9bLKM^cb5RFG?xlnTgbvD0l%SJ%2pUaVNvqhJ zfOy0B?tdj9{_C2kbpe_b5Df-aBp}S~>a&(rt;FZmyl|LwAS9fB7OS7Tbu9yK?v>L4 zi51vBY3i&Jj^*?~mSrIB2_kp8+6JjIBMowFz#w39V(LOVX+1V|;Jmeoco1F<*({$z zt#LBNqsG24s3N@3#7`6Vv~1q^cpC4U>E)K>(+*W5yk7ng)$0u%eMwlT-$2+zoV%3jgsy}obu&)-J;e9n{Ii+T zC;o|b5ZEVDLxTK}I(H}oKYIP>es?L=n)jgMb1~D2mMyqjtqd0nhx1jMB6KevED{XP z{pKk@F*ZaKW0iY_+u}t3kKN!Y5AQ_Hj?q!{taKRBeQnTqWL+v-{~=_r&=20FiFvVB z)LSD;iz1^nl-PR<^Ws-Ic_k#`O=O|bd_l;v(V*(UM?9VvtK6ZMSzV0@zt&{;`TH{~ z1_zW?a#($AmHY3HZ8|`y+$>MeGRJv;81pT4yHHrD`^$*3&8M$ye<;&uD`MRJN$3}% zHk&=G!w;a(nFIO5MnMt@)oX3|Ohmx7e$uo$`tEgkT9%kkGf{qQYB{}4BJH>)>p!I5 zgZ3XtzZc3Z<7b{nsO{g;@0*a)X7pS3x{>Qckst<}?X}3HwtGy)u_k>n!CRlG}ULsJakz6-ww zbl7I2n82${u=kQt1db-~ZYmq9*jDtur#bjo^;^k{E$8}OPd>s0To_EsoBA(0i*&_LQ0JJ3f zw1cDx?e56B@MtXyHlfcT&+$M%TdxgwC4+RjYEPb4Mc;ky)osf%b=1WJ)q`li`J?JX zKd;|RAG)DTmH*T&hW|#YP5_vs!Wf-bP0d@D&cDOW>3*xlF7JJ7Tn1;l{9hLJRkP}w zjGbc!c$tJW)jl31SK1-W){W=u=$&sO_;u0BEODGOxBU_ z$~KmqC@+qKEva=|wu@TLWRuDsU~hY{QN|x% zCf%xVDc*ZW5GJ_f;9*eA^d;(5OMYEKo+<3X3W{d(f3qcP3%1P~I}pm=rF(X$d{;?v zxP$lV?^H(J?M$22*kbqau*6!eFWX#fsywnXbyW-4(1ElkG4QTr5SsJ7aw1&1u$dKZ z_UX+xH0-%f!4x+hkXfyjJb+^FUf8b5{G7pnx;!0W`nv@-O4^I^#NA_d)F3rf>YJ1$+ zv1Pgad`oPU2(^84BfF&!Yno?$M9319H_;Jy2Xz_xn$6p~P~H6wUPiN) zb-y!`<$80~vQ(}PsPZH0+>*Ts)i)ASV^4-aeb|}2{BG{j5&KW@nC3i0nrj2HUk6u= zM@L;%s}9k8k4KP6IDmFWH~TcF5O@>g{>-Y^`wi!Q08+UhQdNktG}3R{@*BeA;HkL( zZH4n2WWX5HlK%i?N+OM+D-2HP=0XkrUc=Ok4kP=eKK7MjQP!^`P*)~(vI~mYI%&dG za8E@oWS8%~cLX&A#T)9{fh>Td+)GEl!^pfGWq9shDV1&oFI9RurAxZU!_Dja&1jzO z(YN_lLodcM7K+FocWe1OFS#QWl*mM_^M|=FS?=fDl|Q9s4a;_*NRrca#Bbi!ARo4u z@en{%G~4-UW252$7mptXB+mtQ*f(q7yU(d4i|=YzJr;ReJmC9N$yB_*ZU&9vrq4TjOE4e!IEg}ZFgOx4QOO2=2Fa(TdTyHW#;Px0;J;@7BnX+O*L?HT7NHNYL$CHiXC z09J$t#Pv7NN77YDA^|4Tp!P(#>1 z?NgRV_@a1MT|m>a|E=5RUB!FVx{BB`2ZZMhtC$2Wj1tWe`lMD6^QUw}lxF<#YM zQ3dHHeH)X=*OW*Hahm*U(#?5CJvjvWy5A~ryRUkW7rr(vq6@mc=?y=VNbg0u44t=^bDMbn zjr`vxJ^t#XMQ#vh&Io;k-vk>V!J-$i7CzVtl`L9S#s0^(>(YgTf^8oNzlOcMWY0?K zM`$D{&0Fe9U$TkXlUgyd+j*kpwZ7%%Cocgko>T)w<78zgd7JX0hUNkBsE4;-Ap~mLN>k zRM7dLg$p|hI)zIGB|~7k5E}w(4ag+`NxUzDxcGQqtVStu945|x z8}IA6T>;|5<9*$)EJy60i1(H3-$_8X<^E+=&ic21UFSn_*siZZ7>xd?c=QKcE$roJ z+18;ewzhD>3tMV@UZQ_j;xd=%P8@c>g=R=)k7U53Y^ErlSyy#re@89$C9R9KM0w!v zZ249eI3d&htW8;?H3x!R>>T?IF;Y$Cmg!x$&V`kfR`2&E!#zXpk^h@~b_8a}0f0CJ5G%sR5^oRZ?Fily!`MoN zzvCnH3_pOTSKNzmg8Df08>qq^{1@-PN8gu3-=Ed@XU{EtPaG4JJ5*fV>?nJhoZ+_T zDSMV4B+j#r2rWM+d{=~T0gL|tY18bbMRz!V>gc_>`?Iw8_LJNF(cXS8)^PeXV@QPuvN77v~OA9jHQZYO{%T4_ks6 z^V>qw)0e1QNdaPbaEmD}#d8YdiwZKHOo@e7_C21Xb#Oh3RJ0C0%#ste_`S%I)wT|{ z;l5Z!+LE?(;*DASqk0=9OA5>mEwCi7k zJBjz~qtFG7C`v$;%8sID4zCoy)z8@vat^ws z-1^0}soZc96ir=u811_L8uV+(Ra>iu?{J=RVG9ytQ&2m`Md)~k%=dt_{)PH)^q;*a z$0xmq+z#H8V|Zj1SSYpc$5AU<@%vUd*%$M3{#mPQbdSNkesNRhxs$Xc`T_8*?`0`@ z1Bv{z`KKl=>Kioa@z+pIy8l^;j?(ondiZrPk?m>AZ)}>;QFp9n7Hl9*ZK)P!x6X>T z{PQ!;tZNoiG;!a&oBJB-*b?fi%>t?WY7u-QOv0+a|; zgHnMFoAb|dPQPjrVYs)M)QU;>mTXVw&gJd86IS}2ejP38daPPmCZ$?G&C>ZbGFLxvt-egNXnsh#M4ZOu@4DG~u!95lCs1&(F~3?p6YPqoy`#_^^fPVy8lrHK6H7feqRAQXB4vw^4)EDd@i(TTlG~;UpFE1NjctqxdTF;T#|< znbd3C3m2(X-=II6Zvhh}e@vs=VJ9>WRC+t~|1k~36nDFo;n=_SQ74x6Q72k~=SQ;4 zEqDv_Wl*Kz&ONMon_dtR03N&zGVw#Gp_^=w?b>x^G<3Iuhyi1hJI->Hrs5xVX>RRR zcuNeny~zq936sP=d|{wI~Ea=#)c({Z>yUQc%Y3&f9yblj(Q@+7V!IiCFGZeW?FR>uU*%tKKD#iH}E^W4ix|XTc)!K;ovKtaba~nh;K-)=4w( zWz;Jc($9)}^k2x*3|7aFP|Ng%&}YRx`Y(LlU}%cv%)OG4Nx8TOa4p0LSaFa33;!PX z%g%o-q_-9K=)dqcQ9bu6+d?&Rj~N8MAHA3KM}Lq)%g z9~5a|l=m?C$#d_+cb>6iMWPJrl$bqOa>`bB=-cbC%uz=D=@MYQ429vwMlf7WyQXn@ zov!V2QALLsPlWU~Js(I&eT>UMz3wMj75NH9L`VBu05{p4mnnCwX1t~w=KnJJhZw5~;P zbdg>2!%QcfY$iy4e1S@BU64Fjy}2Mc+sY&aNh*5=D`s`b3zJzC3IkrP>mF1YBYIGH zBILHtq`S=nUc{Sl!8$mSkKy6`XL|Cb5;+Rv{I9=i$$Tl(hT@F8wI1?*nOEVfq~Zt} z;V`JT^l+yJzZ)BD3AfpsO>kX`j4xo-h0?0sqBqv{hciX>(FllWn>^9J^pDMmwkams zzWb3*XwKi&#AT@iY0rIko$1rWAwjJcB7*Q-5pD6P<;M|W;*{fjFUtJVFNL;v)GhjY zC|{+zGBt%`zfw-0ok(AlNVg`^YbTcTpOtw3l|=d(@|5-C|G=JcTT0sK^ZBO|>q_?{ zoWY}sVn-TLXA@iLo7gkHu{OB`uuk4vid~jp*L+&A;e|+Bm#Q8tdUY^cliwkT*%vE= z?tVg<_dve{XsnV9{bLjVxzqN7BysFCr#&`U>Q@GjyG-$r2il5t&$czbe9>;1{F~Na zAHi&I%RiVH6Btkbp?KZ|Da_Pu#Jq${S`_V5mcMbeX^ic#GQkgv-xi0!T&( zn=qeo=-Hjf3d+EhN1cA%sy)i_J>OC(l#BDW-%@Yi`*VEkK??SOGiH%3~8-o9sn3iLkV1>E}dKXNj+f@Y4q++T+CdI59C!OpX&% z;>1*+@G3x@o}mPPt_Lxjfyy(|*NgEq80qZ-fXL68%5`kfE>W0HcJu`OX>4{$Z6D*+ z_NUQXyxRU_x?+)oqnb4SQq`}grXZ=R&((`qRqval>bQUF{<=U> zhpOr*l#UNB5gfr@cq+S_wviQJXI9-D70Z)}wDmxiS@W<^q{CT0)O!BvXrS6_<3RA* z;ZO(lr?krI&t1r1csQtOYI^>k9`S#wOhdw&0X=R-upe$`+DVvV5u=NjHoYHkHn)Dc z9@D8idWh{kU-e8>&i2w<^rfR5oljjA3I&airn0ZoPuXN@g|+V2MrjY{Jz@b0WA+X@ zYtT286%Dr_8Kq}A`#mfqfj-NC^DWq^fo@CsPONd}BlLiZIjTcC#V}>e-|riN0;~>j zq004V{vzHwq56y-_}mnImSSMA~H2w!U~$7QwDi4h-|wtUajN-fhF+Z*L2VQ&$3l z`;_CtWmke;>=hf?^CGV(n=Z5AaM?z;EA69JujG@n4FU4G zpnF-RJB2nq`Qhu`p344Sq)u{bCpW%$br}0@bg!8C%-eh)pu>%k4!73r@fWYd%~YTK z!efkvY7Wn=ITT`hq4UcQED~O=58p+`ct6#w@weUIc($1yFO?VAYwjC&dz4wV6kDh2 zp~Q{)^?vCaMA6VI5z7S$|ug z#e2?D))-KFA!;mD2NBHZ@O4?8F*WMJU2a7qVCV=dYvm;LKsR%qp$}OJy zh4%>uK2u~`mTtu2S`^%Ku>TvZF!}OET4LkRycpHcG$1(sBnZZ9s+WEW=-5Z~q`yU> z|4B_0|A&PBWfuy05qtfy)caC!{8;o`z+Cb2RL{`yJRme7S-WiDGE4=VqNW%9ct$Mw zb)RiexRA@imaT%^!hY6E@jeKC#h;O1F?R`r9Qnp=|I#{gMEhRwEw z%mRa5H{v+_>rG25{GT zxMd*pE6vki^pKl~*b3z0_i#r9jfc-{EdOIQpq512(Jcd2j~*7`GK}X~W=9IfpXU1U z>!G%Q>2igB;}*f)ay@IhB#t*9uJ#$ch+1KFT5=~?hPs1w^ zPh7+ikGnWO4$_=@v&`_}rNaG80XNft+(b`+kTLGW`dx20+1n{fafE->|F$(eLtThs z2?tQ8p3|jx!rEPuQ!#9lt?Tli=JT#JEh?(8GP%L@jHtr;Nb%*$)7Xo%D-@hA+-=XA zCikb=@UJGrRGsc`@rn&My;O%UB6dAJ>HeMuDv@vKKo$z;d!qC7y=8%X@q`4LizPLI zE4R()lR)%y--=-aOu27YL{8(*GN6}&BPM{(5u|wci--J&!);2pf{9-tl#Lb zOx*CIYR&e5VIVpuhAyIen@)!sPUgDclg9*Q#i0HT-Qi@qOzMuuf?^9AQDGe8&rJ(b zk#vu6amaLh&w}|S8eo_kS6+At*0|xpew`Ib>)Og-(FcQNUBj}L&OgB&OP3rKbiX_N z;{7d#3G%tn%Bu4zQhtr!{P~m&JJq*14Q7xF(973G&Tl#yA_6p%#b*JX<=w0c@R zp>X7?boY`FAe}C-IP{EH2UxwR z*4C8VQc>$3JWYIkL{JjGb2;Cdzv881FUw}TW%O1PpQbQz^2BM%-RBF97Enf%x4rYPKY>Z<2e1R2SOEGfxJ#AL?Ak&Km&es0*Z?F7zzjhOZbB4u0BmC_ z*COerJ^CAId3_VXulGsK%hc^Q2E1|mEHC9FSrzU}K2LYV!QQR1FAM(@bw&<{)g2%g zOxmf%GJcT9sqEnt(-C;|Ww@wriad)sSjNUbb~(2#!8UE@z}p0-kd8(0?JFgM!H|sU z;X2zh@+Ps8EtSiWeK<(A0pe)@w>@hIZurOkY|&XWU)>+6eg5Cp#X=@LIvw-K;&4~e zC3z8)Y-`P@bD^9FaVfoK4#QfSe=_w5 zEl^ipx~B6>(~I68OhqA{>20Z#UpujQp6yet0nY&YOi;O4AVV`MNc8GO?@Dt2T_bcY z2Nx?s`Na5fNGmc|<727pVqT^5ho=iCGanPFt1wQ#1iQydG|%c~J0jo4p{v#^9{r-A z7288=tsdofn$DvscvBF*r#qaYQHN5Z0u0$Q^x(d;c-_4er;FZEL3dwe$N7q*zDA)z zHXyKD$$L+&Qyk}8IRMQp!;9LuQ(+$7!!&4qqgObtZS=(O{=(TxgHe| z2-~hpfWYrq%fhzz5u_Q%l_(yB^d9I18q1$xezaG%Z?GZMKJ%iD#{`eRgD_V+aNH0k zijnLizf(?I;=44WRSC+XgibrxfcHngWNw)Ip*GX6sIbS3P-ImF4oCr`3tT7tU zm+e#^M0SmC8;RO2>7tqz(G+6C3m4Ypey;u?0BRQ40hU6Vt3mEmCo_#}G&HG`*9655 zXqy{)gZkICdy*efXXIS2)(D$n(cRSH&J;F2OczgsuDKM))AeD{C*Yk1O<&CKCHgJX zb~-O&Vi<>|dyn_jEx?Yi<*}A(NnZ?g9~V>i<+bjRcD*g-j}8-l{3{|Ih#HZ+77~AL zR9oYQjy37R;oSO6{YUGPOQY*_0Ul#<6w&rk!0jsjs$DB?CO#d>dYaL8I60OQ2&2><0l6oKHo*ij(62jSYw=&(sVC3o7(2pBrOYv=N=FB?)uZ&d7bjzZ}KO8lP++smY1&V`k)bwwK(0md}}IH8X&i zrg*B%Z`%a>9f!DLE2eO9H7X`Mba$_!Xi)t0OuXW2Ddc!;!$BVGwiQllXe)e)jqQ!B z?;cS8O#Z>3{+&$y-@R^%+>_ZeQ`}#hJC9|GBfpNb0Jq;oKnqXr}(<)Qk$HyFVD7y5_L$NX47%`)dEF9O2c3T~NpwiX`p| z>gh`BL$^pJ$lthJPx;&md+GP%gZgFA$~^utx#i~b#f0_tY6)STy5_5!w7J~cObFOg zn};Ms>^3FoI^WtZjsTz=ZD{kT;8?V|b1}$YRMXb@QtIlH5Dtd;!bvsdSso16rVE#k zQq;@(2h*Sj*|@x|^7+(^R)9(iylV&Jx^-f4$W7@ycgV8N8G-h)JX83sb-XY;>ap0J zX>blOSQiT(2l>03?1TMqE$a1|;`v>8GRz2yvnT3Hz8LU>zdp1#-d;c$6S^|_)|r`n zQCaxe=&>rI%H(Iuk(eKACcj{+J>A&Ok6ZpzYAobDeHR5_I{&5Wzyq1_Af@vsjS33m z;c&?+ez-%o@!dAb$b7L%l@+4)W@{8v+5M^+s6tV+n#n)P?2n2uTjZ1}7z{ySfdE6r z=pvhF*!owPZFG`vqaSo`-1V9KpWTnlDA);>+HOV}m8@^0_fjW@! z)n@WHsvg+`Td$A$Cc|XDZHBLx51lmJ5EOqXI&g$O0tZnO-G&PQwkqQmIjr7E(-E)x zPkEKNTRpa|T7g&e-4c|ug%}{1@1A&D)f=EefonpzJ*9xsP`C(QXq$_m7Fp)U-5lIo zve`>T$wL{bJ01eo`I&mi>r1JK`me3~IJ(WbFRsLZqFkwYCPw=2R^x!eXh^^?coI3O zc|{4Kb|9)1M1{M@@Z(lo-`_u;D>+-2m$YL}h^UF;*(=Y8gQ_VoaFe7$6MU!+W$MLb z5(&NBr&pP7T#~wKR~SVHM=Bpp&3I5deI^$E$lDJU3u%)FV;vQRZ>XQ85CnFB+BQd zMzh@NB9iE0CWVY?ON`>5jNI);9OE3@!q*izp7gm5rzX?*a_SnnIwDCL(uI@8lqCsg znwpR#0dXDD^?!=geAib0QfkKUC3?EwN0NLWF{`0Q(@f_dJE=HwZvv`$fdC1|0wE_> zHc3IQEAHl+bP6VNA`xOChW^}Eyj1>RNE0tRGWiLxdh7M>Q^tCm z36G9UrtoWZDAHR^GQ0wQ(Bzl|#+iVS7HJYBk`j+9ifSw+%7UnqsnP_2!L6n0rh>p| zN`l~OtD)#cmFH1$Yor-O?1{a{IMn#R&@2#c=F+BWevvB8HJ;5QuIA=Ck~bGwjXmsrFNxVm}Ku`X}Kj$VcMQw4M^Y zg-D4i)+mp*Uhl;H01-ZhXO@2L&kwMuEPb=*7pEYEy;0;eVRsjV*NrJ80R2qoa zt2U@LB}rmv@Y2%TKuYJi+v-;vB-yjrP(HCZ@@uU8z`q~({Omb2m6|tO(t5^hamtL@ zLNKTw)y8Uuv7TX^4~o(CYEb)XA-1kaeSqy}21T3xgW>}5E_8_?K=rtBqMizorZsLp zAt`t{*}wGE>9tSK`s7?myP5nr4W;A-taUT|G}ry)I#raD5P-2w>J*BS1(fkk=KRp# zD8gZsJ!urD+Ec6~2#=7>TwZ!RPc-f_D!s<6?uYqNkQ9;m7!w?+tgY6g%=t)X@js9Q zq@a7<3KOdaP{RhBonmTeq*6}}kD=}+r~$4MUq+_0X|?#V)Vlk=Q=&dk6yKl_V_!?o zfke@$E_rGZQHW}!>z0T@eWlCR^Kx%1+rS&||5%tVH~xIqKcRGvt& zBcRo@iZa_iE35FBjl^3D{#f<}enaamEwo-S$6B%sMcR4!igKV+{Q23V)Li{Ccb(I! z#V=R*DE&f<7?vx{9Ll66ON6ax0V3@p|4RT1C-FU5Z&3fJ8}y3!P-K2#s=e@cZ%=U|SU56aLS(A1=QFn31d zDV7C|HmrHCvY?OTrvPUXIc9_zfSgWp%w(5hCE{1(1i)&eG$ekF6pvLj&e0$mIcPzY zU;73{7M2I0)XvNCAiPBmkmc<~i2R>M6TUhVsQ@(X=_~HW3IGYWR~HHk1em8z0arv7mxX+Gnv)hxAEgx3L3Bv)o@;#hxdEn2rp zS&pF@2S3n&Y|`LuLEeT1+wxX_Jg18FNs8$?wq)gdD8Ko987e-q_GKi5R37fEwrp~LOY_0s>iSoY$mC5pcs%!M9&kh3A2(h43;y2u11!8)YOSC7l zXk`~qWyJ~TzJ892W;}&$$W5jO3Wyu+_??}f<%O4WxvBp14582q#V((eP@L+M5{grN zQcFi;43=0VSNgX%lN5tc!(5W$50dj;*VWdxXsV6P^+K%WU9SwD_*jD?nHwlI*It^M z#~XBH6CEU*NY3XY$sj0HdN54~1V+;V0kFB|l(PCK(LIwA?e2r`fxr3z{2ucoR+-Hf zLI?v^Q<3$V9t4C^j*ZWA{Zb6YQ){$5D_?LB&caQ>(^08jHX6`K%;LOY_;oz~JQ*^^1EGa-s85R>NDC z34gG{2R3+TDX?epsP{Q8;%1O$@nh2G=Zt{g#O>|-M3e{xDd*>0|Np!X z>iXR$R>?QYNY-|bVZGRTW7>pa8q*VbHu_N#sqGt75Saz4`y zTB|MO=iK+AMt}L7HEP2iwN_-kiIfxL_$QMtnhCI z%E}m&zpVn4NaYG`P(6)Fr%MT<0EbI)!iv)baOFI7RK?AIqsRP9$I@eWwLrv z!=IvIopcy^}W{wEfDl0Bf+U;tU8E%83=Xg#Z zR72aw{qov4fm(qrX=7~1HZB{ZVvHuujL13nFyqrwXlU;KpswRP?)|^LPZ+j?Wta~y zh2CbGj}Ti;SfO=Vm+6^47?Ty5j8S9lu{Z1iI@6b8hs0F&`}B&@RSuV%ul|g?*+LPi zx@cp0PI#3SWDM+B#xt`u5ii3_H+vAp-2~u?W18e9TU%qf#gqVN+1*rqu`DD-AT!j~ zkGs^apYV&e5-~E#7d0HraV92Y=#a^e2}_`tXhr9>wni(jDStjPmfmf}dQIqP^o(e{ zu<5lQy)+UUNIGX6T!yZ&KmZ4cO6c;wnti;DJ05z8F!vcN=vzO+NXy3Ez|gpV;jfH) zG1ov|oi($BU=Zu{=Em^ao_cdlWa419Wh{QXI>>VoID7vmV8`M>Y;KM! zsKn%Nf+q@H(IcaLOzXL7t5xUGk5*mX#>cn;$%lwsRs&=uun1&vthmHlXG6!J^FVT! zyb(P{4h{j;x<7wib>#%|s2D|^Q+abeg&M5ikxDgNm|+E?4?cV^E$9L8)vfSd>WJ3Q zErsE&^11&bdcHf56Ft3yk?arw41KHCH1k^L%30U5VmJkL#PmxP8EUEwuePe1M1dZ) z3v5`2K0!0y3TM5qNM*IMV!x-L-yAw==A z0U9MF*hFF|gHhIb1PYJgA&hIR*G0B^;{`h2RDSbfF4j95Jq27DG;*ph5n_F02^uE*V6 zDi|nR)<0IpZDWMnhp4NiFu0YuJ@=Z`Yx6V6v1$sRF#VzNft0Dxg!ekWI#ut@7r)Wq z?B2zY08PXzQzC@08{iH%aJG(+b38bbUS7{S&0gdrxXRwiv;AXqT0N)SjH8WA-jEsI zF#ryMZO5?YTTVk<+qJsaE0yi#mF{0kX2$<`?*2!?sep0gK0irVHRgk8-vEz3Gyq; ze8Fdk6`nSm#N=CrJC8-h_MRbTBe6*=T0}3fdV6hwr_n%(VL)t+*K0p|xrIsWhx=Pb zK@PDCX2iOniYjquA7xNkO_Bbhw3}cB&BO(hsyiJ!(V~H&Nv!y%x4k?{s!1@w=ovfOnrl|x)59I)FMA7;PMc3-5MA0?&XjFCs?ht3lPH67l25jLRDas%1;+)u^weMA3pO zs>EIQIfKe-iYQuXSFnN$s?|b7(NX{m3{mEN51Crl#P@+HImpg5L(qkyK7x{V{ghDR zm%AP%<2*_%gI`9ZvbWj0%TU7G=9nvkY)0bnpX&n>&T3m=WqNJl{^6&4u7{SFqPBUVibBLXVM$n-|Th}9KgL}~YJE9gyy35*yZ!pLtPgvaN#_88?$ z1f;SrOA-PP4_3R)3GB+wwh5HYFGLH<-U`uTZ*FCj&BSPse=<@bQ4nV;L%rnaRHgD8 zXB1Z{QF1ktBLyBFy;0uOJd;69WB$eMH_$FovVu=O*!}#VpgY78=<6%^pL}t=szRl_ zO5yJrwswiX{k-~`FShF|J9B!OFHW)c@dsRv3L<~N)U{KTI@f}5t<(XJ{A>f4rJI$U zEs!%sQ+`A#)Nk(>_^RxEd;i_)PygLQLBGdGes+y-vQ|HZ*+L?#luJ>-ljL zS13cWIlO3VH*3gno}Vq8(-G?=PES0A=U^#j!kR+c2-yUCUs+~veGJTS6wg*u^#)%_ z%~qc`MFF!?%-D*nw>8G*po9q7YRq5O#mK9wi2Q;=D-L<^F>COddN+`t-`Yz<6j`I= z87fiSEj~;cI%mcj=1jN9iY&0^Jlzr#&(MeYNrby@8I#PhdQ+Cb-?a`|SKXZ7$iGz6 zw$0E932f7Cc-=;dM%lc;@b6|2v1V6A?l>=r#~$TCe6QbnFacz4s0-Q!@41Uc=`5nx zNyAfFJo?%;tY9~5!+JKS``Dy@G}3sq$Gmnq#RdrNAdj1!7smBC?JO_*w?~qAQTThh z3&E&MCHOVeVKpQKZ*-O3Y7|4RSXB0Q%bpmc@O0w|@lZv0JC}lCeZS(J$_n=}0=q7= z38f+&N?YE9x;Xq2cU#8k3lr%tB+}nZq<@r1AC^e}ERmj`NZ(dU_lCbOr5A?>ZIUkU z)yaM)i2Mnvx1%erKjg};W9(#(qAs$?(~*=aH{#V&sIe>!=@?NW)YxXXcD?`0s71l*(XiA~jFo7m)#o4+VGRR)c(IL(qO(C<4rTjNh5sfB`$K6?< zQ6+2LxonwP*p<{(U8XJia08|AI+VhE6CElqMuB3qG-|198W3-12US>Tt-YCbEg|8w zsN&{@S)6+s{WMVQUa7XR6=Npi#-EAGb`=e#=ABx%`UssSruyeTXDoX5d34DbS_LGz7(2bv-n#qiP&pQ+U%A zdMs$MaF-p{&lGQ}Tg5xJO)bc&*69mRR~`3DRtyI_JIUB*xY8uA?EB6r5zqx1Kw_p(uISh|{06w6G*idocIQ~!ZXKO= z1ddbja?g#*yIs%3L!h;GaOaajBbN$rNhlW|cQ0<}dn&R=WQu3ks+A?X3ptBLVEG5S zUl=??6q7q1l9LMc7MT6UO-j{qzLjF8!Wd zD55-kgxSXH*>hJ1TuOA*Pt5UQipIyp7+zIsmkEDQzjzJ>SK*L4=YFo)K4PnQOtus? z;aRIi{j#`Q>-1Y5YAuA1VuDel_6e9PtPPDA^~;K#Xn^hb z^qu@>#ZKHie5d6Hppt;F$nt-9e=oy>#*hEfa2 z%l(bc)ISjqvT0>HC6^fJtX)|kEi7V?;th3O;wZGBsr({95T$3Lp?RszGehJaVZcC$ zG_$XuUlXeS{IteSc0dW&DTJOtzhd6=Z+u~`wXt$3oE3C}%u3X&Z&i{mGn1|R)j2{* zZ}sPnWo_HH1DC3tXTH%kCMP{7@p+doYE)%<&^}y9AjtqQ&-r<>iyDjw&-{Z1#dp3$ zSE<~=GNp1~AUGO$v8Ef&va-3iRUjA&#`}Z!v7#AipL6sTO!io=vi5m1&-w$2bM@=4 zHUjWkXxC5*#dhJ6I(itKez+;4?JA)QY^O*W{Txc9l+nXcMh{D6ca-W#q@zI1u2M#5 zbE*cZraZrCJiInKrmT%-s?J`!AU0(PxpB>PqY>`4*>z@6B9`CQ4V+G<_cb2b!SbjC!2WgF7ZC#L>f=1e7 zucA1R%+*$!`BlhN^fO`7=D9nRk$G-~eTdXVXh!hqFA9{kj-;rhN56d5v;InYK}#{m2hn}^;{lQ8_aL|VuPjsu)h9+vVdXm0LH~PD@E+R%$HH1Xdj^?}O!ng{Y zYO-sr0>+=USBa%HS--m{!@W7j9ztbX=2%tmzv0&(&`=5MWegW~(CdgK{CIzk>0d~n zE0~3^Kl~o0ppLhbxCQ$HFG8AA+ap85KWJ{=y@@Iilrdi#OQP3Lm0tfjdXiWpqu(En zet%fUq43pV7-2Sl{2 z#sYZE%0jHFRDTgIw_Age#N)G`^(P`RqKPqG?e>rtPXw#tb0jN+5Z>5BpYO67N?Mz$ zbFNxn?)Uvx(6>h*FV$o)X@GYA9RoB^`n~D@+X(hpW=Kd#6|D^)XRLx^#7yWDlS}$} zt$Xouua~bd*iA1-f%TG10%VNz@+)R}y?nA7SI+Qq8~zrWLobZt08Te-bJ2l2nf&4! zFP|bBiv&lkA6hj}QjOOS@hhtp3l9-lYRGK`x2XI1!Niz3ER{PJYKp&0Fk7Z}Tfu!5 zB~|q42NC+j;VFF3RM{pQk2%)2P2`qGPmGkP!!!)edc$K%a2c_NL$;&`i@J~^?km^% z-iksz4T`AZeu|F5`$}>_*A_tLrz+IzN{x#r^%hoAx^)m_WPz575mOZuWsbFTdmG%V zPx`^vTMcq`xj7<52;EhBBL^u(dl21Q7Sa6_dl9Wlw@mk6Ru*KqRS(@;Sx8lt>Mx@E z+Nh?Pyb>krS$|ug`}&Uy3a@xGbjn?-4C;Qz%m;V*D3oxEtyWZ>TeqDGMxd0%xIrYU zuf2o7OGHr7rkVU@LT*My7@ESMg`+fiof2OV^ z2T%wJ-_Rn$;_PgOy-YrmOpzEuS+`p^wjf_(np2fxNb6BdbJs@elqNoU=t~3@vTDb8 z>I?X9C0N6gwT4-9jn*(n9rqH3)5jHsliH1?=?)Z)SufNTrlRJGa8LAUudpsQttPyj zyIrFf;Yo>fCXwzST^8qde_HeD8S_oe6fdb(1Tc=Z%85 zyw`*J(LI^`;Yk-9O$Y03}zTFm4*zTllMkP>c|atxL)%bOZc znwnxP7U{;F=V*{6=p(h-8`>rGr5~TBT49tf%BCAXNM$>Dq1`FdqiyHG`%h|SI7gW= zr!r|ooD{3*5pRemqOGm6zC3VyYp3BcJemk14PWZO>Rt4qtU(($s6zL`$Mj{3O7tgg z^DCQ)rIp-7_xmV&Q&3bG@_6ajZWH>;xB3DNr2-A^yHSB^6{sy0sI>xjTY*hNL#1*B z04s%uT9vR)mE@Ng?Gv&WbhKfrb4Q6j5q(pI|HO_C-3sr9@Hh2Wm7)_58D87r_hbGO z7j)6OxFD*o?+*7`AzqFx4&SUS6Z5|k>0Z)h0v5T)_VS2s2>_HJ-7OI;b7zC7xz_E< z*%4%#LY!hOW!3;BSr%(6+(8VnT#hF7DL<6S9?Y=tx=4^g^4!V@bNt80)k>8cq+>lDN1|W z)Q#>145{pV;|duF5FFH_fHhJiOxM39;sO{^YjC<4Sl@>kpH0+@iFzT?+Mo)`J*{EE zBW7$8P^E&9_*&4X{7E|Q8>V;aOpF#!!h8Pa?MNit2u*l~FP^HK2iVx=L^;!|`|V?>twRpBI}D^k-r&BFW;=Cx&W#MG>bE zXPCf#Mmj>;ZrtsA;LcD}?&;1iGz-PW_WovxFYZg}s6GR#!MYmW^-Hd!V4WRJA^q(L zq^CPatAMWdRe=!{=zOe{p{7stJ|Bkd=Zcs`RNVL5Ni!4ABl;fo^enL4DdZD{Hb4~< z!ll28{5VC=<@xa~vP!ReS0|3h801HAt1Oo0$UKcz1v!(LGLepuTwzfD4TiqI9X6zZ zpD!DN!swvz`KqAu4Y#vIxPb-~$LQjeG3Fe7<@XV|c6BEVG34w)$fphN$5(U84gpPk zWb(~V2@Ynk@iLGyd9=4RhC!+o!ILhIz=r*=i}7UEu0-Ppyw)}WE?`%_NGVm8p|XHE zfVmcw(jCokObD#a9#3UIus+(0fUn9%l+%FupC<@i3odRZ=xt&~W8QD71|w*#Zs&V9 zGRbOc)qZGVGC%*9n#^@aXgr%Cm08M+i{3N08HACcexiLGqmRX*uW#H2kk6v!bCJ9v zAdXmr;4({o1%*Jvl2F8m4>0=AqdDW%@0zEptEXx@XP#6S^CL0z(`~w%+X>9$q@)!L7F6 ze)l53ke6Hi>-c2c(!M8DrthJ$w2kF+_sj2fZUgnA$3$KX#C0ovsVdiV`H9`GGAIsd zQW%y@@oU?RiR9kEkht>z716bMNZd7ZKxOyh28F+UBsi;eNN=k~PO|xo35vYed?vvZ zhv2qf6)qyLU*DV-6pybWEJXb>3yjMdym6-lXF*nH9u6_=Pc+Jx1k8bi`1)tZ1V29x z2+_Ou*5H{C!9&5$N3@pB)W3a3u;~3EUtcqhze=Z_6=HPS&1z<6%dhBrx{NV{?-T-7 zGpO%MmE=SMu|;+5Z=(M@fE^?W@$5apZy~9v$D{NjdvMO-#^{V%DGQj3P*!TfHc4^?E@4ESsES!3PKl}-8Mx>=0 z&AKPiLKMGKH;okz47y)>uQMfHN#syK*5U+FT6!R*4TaKxcOadegl3b#^L9ZY3cZ~B znWr-w*NDcfB@gfMwarqlE6g>4D_J{IaR;_3V9w~=wgs?#dkUo8-COJ4G-Ni_;&ppu zCHIxl-z8Pbwgvp5?+mDaPzM`zV8>TJg0@Qaj|++y)ItDj(G{xPHEKlK^WxOJrrMx* zN`o~Qq*|VGKj537Y+S4(kYf#yK?y*(mptO%IEHlO0cAl@gTj|F<$aTg)`w>l=ChB; zG+;mxF>CWHtd)*a*u5H_ns@9d|9B)Jmc8?aF0IX;G6WxWj;B6EvDVS+M?amK*FFl* z4nCrb6ebfXcxqMO9wmA3MP6J;FwjIDx%FD#H1_FEn$&TBkt(!fWL2xX++QEQH?;@# zxFdcxF>}U?1!DuI7;7$I#+#}G@B815abSR^{WN9` zFFf-g#HFsDPIdW}qMSu~&B(B`&v4A{*|0LaomY~7ZG<2f@-<;s&@U~KxxRZRB^ipK zk#MuiI(O*XC8l$#p^^^xrqx(-aOY~HF~}=KXN>VG&e?~@aG4pzJyHE!a1_q1QdF=^ z<4d}qB6ZvoqJvNCzV(<6s_31k1H79llBs_wK$kG)c%5G!d=G!lPu>wIH>V|^hCn_1 zJ3R~^<%Rm!l6QKOTgdZfS38jUWZM*%dfN>P)0u;jxdyD0p8Ci#J0_Eh@z55N;}eVl!>s$ zH&aL>?y^nKFP@d?#0e+t)VZ&`a$ET z>pISX%|;nLC-lIe@I@5Hm6mh4K#EcJsDI#pNK{ui8Hr}o3~%4=oDYSYcMb?TZlMDH zKib{|PKxT>|L$f02Ssb#2SptfbqFY+qBAn;3^N1W(4)wrxPlksZba!8;@aBXLZ#D6 zZZw))jpims6E%rRMCC?g*hY*CYNDu7h)bxVRZt_csJ!3bIaS>~U~c^1A=fP}9*V>`Fsjbj1{PV1(X}%p)o+S@iQO2!8z67Q3oa zB25?I>m|rSYe^g)ZgHeB$ow+z8#C>a4$<&j-)xYMfqongZgd|y8Cs3uh#8_}Pj*E@y4U0k>>f#L)I zT>eto?mtbP@M0BgaoRe!!Lak^s<-5?I@~V;$dQz@jWq8AAzo{}TdzPl>FQL&>JEfo zmLP?8ZUX{LXWU)fG4LG*N7VYy5E7d7eQnP%E4tb;UIl2HT6 zU|uIM;$ZCl%@j2I%&zK(lr8QPz`J62+_f>B8EcSoF6?TFg_4 zfgZ%lnSGxSv2i6BNM_bIHF1NI#ekurZwvG$H{~+o*(_e(0qgVMGiyTs$YcE(TSzXZ z^4>yaI>juJ@fR7s8BBD>=wPDX;lb-TcQg4hp7uwEMb-j~abb}QROA~JF<{cC;o+x* zJ~@0Uvl1hpTY3JpP~Mg#i{8McqzA>^6`@eSmxOwq$Tp&_`QGCEzzE@?J`iXERmtlm zsi&#~8GWv)`EhqC-NWf%iPQE{`uqBZh`y`HQYgUpkN_`w`aE9)8NN>}b4@j}=k1{) zVdZyo$+A@*oa_|R?-we6j&M5 zQ3t_!5fdMXq+ych8%w{&Z#=e3F{brBq~6s0?tsaB9JX9^9i{NS&z;<25n)kQoVaRa%npAc83N;QwO9s58=9D*sv^Ny){)1QWZ5H%VXC= zZNcuu$l3dWyo(EZMR@);19|rCfLgCh z4E)&hFM&$47z1AipxClEEB7e5_(}UbdnFxGoMN%YMUVwfS>ibwQ|NgxPPHLb`qdzH zX^2KORN)Wf010|0j2ly2yGQc(^>Zd|MDT$0^#c|n_&0N1RiwlHvbYQUBN%UyS6?;W zzh5=1V!Sf(!J0qzj@F>_{2*yleBi2Xe0gKS<-&lE1%{hG2MmVdt>-H1m@|6Od|p8G zo^x`i1CKcxx~3Eu6EPqzXjXxIi-9Z4ilM`8sY~|C56vuVmaQ;GmW@woC0OU=0N!Fr zoz^3?gW>$@Q61nHIkT&g|F0*d=Uy>)ee)c1JYZdHAV*fQ!HOwziwuw=K7a(EG2M7H zhr8QI6;EU#R%ZZ&b#W=0<6jxb)3H7)D7;>MtJcN<8?Zw}qKOgs22+LfwF8DQI1q%Z zJD|r!#=?5UlmU{!PS&Snp>%Su2t5hxE-;I~!#1FBV3GK!|5vkc1?%6!Ddp(Ypc?F*o7%O z2#qZqzZ+VH_vgtHDuPd|!%v^_;LYcgxRylEANhBD`5G+RUDclRlTWvH0Z>5dE^;UL zjJZ9z*XG@1pZ5IV0qwaDQs?R>9(V7Ud-MRAeDM&h@h7A9B6r!AEkhk&4?o8ws9vp89C zbfIbSoC^6sP7V<)46Au=SOfD7aYFlYTagIb*ORt<1-0}W zMCqg8Mha|{siZ&lXc|}R%w;Tll^K;GDS~53 zJ}C5!$2$Mo6Q9(M)y}+A)?2$^>Y-TX+bbi<`|y};Oz19A67$S{lPSjX$8u{Psj2oN z=IxY)6wj=U%3wPCPV@D0IK?FRzR6ljvuEuI)a>G&{wj;(Z-;-adh z9Fa@SkBtDe0iNp>=i$FLCfwq^p}Z>8prMM5WA!dv|B&l7USBa~7ZTlC*TTJGnfIzv z{df-t@OCwy%mTF5`6mEt=#R<0UEVI%Ulp7;3GD9)cPW7RBV^-3dHlN34GtH@$cmIr z8GdB_u_pWrIWbuKKy2`?T+PVfOh&4*X5vX~VMXTf&rpSO43#f;jLKowXBFhe&Al|H zko*R>pR|1{p{X!&DD1HP;|}>yTcDn}Of$=NV~QORol>Nf_xCfE;s$x7<#8f`Bl2Lb zi4}I<&W!HFD$mNK+HM>q|(7n9%E_1xR z}fxHRKk|?}|OE9J{bF!CER|BkxH~!g~{T^K`>sfoYyzd>v z+Eg!Vt0jCR_W}1he^t-lt>}4p&~xWyw&w;DGNrNnnm47MV`0yPlGvVO>RI8AVbAe$ z&(_Dhweq~zM;UEk!cboR4!p zuuIIBo8OR8t(L!V;q=;{jpEdJ2{wY>^{giLg5xtaXsJO>>(;u1p0eF!*N z@JVlw^NrN$+!R?Dv(@dWR)pqG6?_Z(cDN$zwvJb@iJ{7=WAl^xni_qnk$S#+F|*~X zi;pA!&)42u?{rS8F8)mPwe-7haannFEIgpw=DJ{ww%bg@;X1)^$0Gp{?BY%`u`zua zF4rEzIpND<<}5}K7t@$;S5%BU$;8CG8hk_$giou^*3}_BHk*@iwpSM))HqAO`xckz zx50t@4s;^v#Pa`G=EMjV55wQ>_tV0_s{BX|4exBo&%1x`8Jjkel`Uash!3nj+8PX3 zsS0}=RNx{*iw32_74{}j1r(9aajd-J`Q~aK2NYt__0A(ZrapoHnUDL}4_JE1#;Z9r zmylBG{|>~DX?z5p5z|ZM>R=&*-}D@ETo*p`o64HlGIa@A^>wRpgP; z+Mr<-tSmcV7H`GPh-`bzXv@HW%da3PwE)V=-e9-`GzRK&o(8LV8q?F9#DJ5f8acUN zsbYyt?IDpNV+w7DM3NlS|HN2L%(+i! zX=30zGPOQ*!`{*xcrlcD}6MPh?U=Mb2|)v7FB+-tg} z>Y|sG*a&Zb=*JM3$j9n7bRyuL-ZK)(EQ%^v^rRMdh1_TRvdk^=Ah>V2i?GDBxr@Ob z`2E)8mEeV4Tx+^Bt12z4rRyAbn@c` zFY&shJ&h;ChgmAS3|r`dX58gyX13!xufHj;t~m-!TvB#Gn&Kva=#*=Sx6&K!;D|IkG<|eRHVa56D=fhrV za|!3_sEcC)6EH6H=B~%np^NIvrZsF^C$ns_ujOtR0pV0*T_n|)8BbN4AA*3IK1+ve z*w}=3>o_)3d4IBaR#UN`Xp8&YjXbw57R6BbItVR0r)*BL6yE=`8BCpbPO#bqR`O1Y7?|!F{eKT$S8S#~`!6 zL3+eL?&P>3!5D5VQ6ZS4CZIIMg{2K@Ht>Bcr-+CDXVq|@He4ZlHx{X?8vh6U5fIsI zFb*Y^F*r6D0)T(vfNl;2ycJxyYXdSkF(evMK~zJUDJWMBeR?Vku*4|igRsmrGJI$DYE2b% zq8SX;in3XYrA=*e&DdZpmuL!qVzYL`fVBn#UYzhxFu)SoY3iW@1Jt&~YaIYK=r8=% z>w3}mu3GM02c4&^Z&@~)YdGbu-p9WU=t>?6S?*bfL{diu%y{NnU9emuE2wc&<8V(s zCUDo!Z>E|-Ie!MB3GkB+cYVMmR&@*nQK9LuiQY^_{!ruQSX)Nsn9~N@t}u)mQ|EP1 zltkk~BKG6X=!L~QXb*m9SfOQ#U&RRhO&crlPzTQwdNGYi)WCF!#@5V|UaRA(O1 zMGSqae`ruGpaCIf#k(o z0n=WE4i?k2p)y>{4$!f>6|xqUfs6k-*lN565>gsrdff;NHP*P^xe2=tOc0;Qhu-LOzS!!| z6cjKk?`uxAoB}!YZaqyHxee!qjRl$D;ds;iP6Jl4U<7v~w4YRC_;|?Ykr(~DC{%f3 zt)j`|gNerVS6;jw-%E`Tc%ID3?uTX0=l}3*g;sxrl>^(@ZS{ef`9U7MZ;h0hnNM=@ ze>?m%SDz;E$$NgHQFSN&7FBotgWzabwj(Tip2{8;HlrSn3_r#7sV|>UmUmMNv%(fO zQ*5WO*g-1xUW+wqOY(W`nNX)*>@Tf&{_Y>k?+X>rKQ28l_0v3;nQ2KMu*yK(4bCIn z`2L;ZdTvvtaSOELrO^nIz0$`GNlIIga>GiAj-oM*58lB4jc?e=J&cqFK9NdC=+ZQR zZ8WECzznaQyKfXKcsJjTn{^@&!n~MD$`1E^UTFUo>`}5Yg^7nSB9a??CPa`7B~kBQ z{dMmekmj#9?pZJn3Rw+%RjA~8IY418iTL}W>xSDA&(}}Rhk+q|Z zut%!!e7r2{k$hgV-eE@8`-ACGr`AkGq&l$|{TIvk9S{h7_v$B~^jH6N7x>&4OdRr= zD>O(uDow7Usb$P*u$e=Uz0SH2)_I4SI>8u_`!GRRvC_zWr(eNApHM&47p+@`{P&)f z|Fp#AT@dPv`6E%SlD@LsT04N&gr#614&UuC?8X)J0H+3*!z+W=O+QeZ`Tm#+-)51d z(zTu;+BFtFmOx3GeWNLG7Ay=b7{+Z_zVf-mjF7}_W$V39P8Mf88Dx43lW{zMB1Ym^ zBUdnTdJ^g6qeOJQ*!yH9$j(%Xob? zvoHZ9c(S zY`}x9c~b|6h!_=eH?nny`(8_CVN09a3BN}X-OnEmGz>ljAZZ#z)GeS3z%|orLAXPb zsij^NURy(GL1I9?|6gWUZ2{yl31k)I)s`pI1%JgJ4z!0Q|4L(G5tp7KaEh)}>{))6 zc!b4z-!%$KGyMJ10rd>tOvcWDX-SN&31i}{qhcr{i70xFjMo<}ln&eyT_|QWRdSTk zUW_{z?ZrrK;My$j`FAAfb)dnNoahL|Go-;p(O{-XgDJEj;%8=&YcqQ=5KrLzt#`7& z};hRZftrSt<;{1at@NS&&e3@opmE!)Ppx&znK4m$Zr6 zqi}*Slz@@0*BmtDjTUSr4|IJh!&qw=mg2cpYH~?isjZ+70q-1Yh%1>Plf5{^+m0K2 zEsaLv1K;vCE;A#k^M3uDMq=gOnhrNr-%ZTbqE#p_H_@x&;t?t z{%nwy_!dww++T@-A8}+{_*3KU92Yw9^wk?nfh`@V=Ql0XN;E#hUNRMj8Wa@B{e2Nb zj9eLNNb5QVk|7of#GdsYj!CfOsT4pHgojp2mY9I9F_IZG#QD%`|iY7ROb49Uqpj}Wf51MNo$ z;B7``H|;<2M~g;QS>;=O1;+W`r)n$@Gj%Z)aSG9eUj~f1#ITXvUNqv}^g6l2iIb9F zQ>OqmDR10zHDL|~YJ>tV6k5Vz4zhS#@OQovOIoAG$)Z3JK=Vz|i_u!rR*rU$VU9^|UH(=WPZV;zVi03pZ4I z7u{e&nX0=?fka_?bv(MN&AqT^%$1#IOLA<&{j^kHq%S`K{AH)LBhwtEJ+_Rf#8?3@ zzxLTc?csbY#BZ@V52P@zc;l+n5-n<+{nqBzhf(k*<(Or!Z`*^_!XKrQj| zG+z39^TWFidSusPvH!@z@VU$XP3d{5-^Fu@ej9%S{%LcMVch+~L_LxsJCQ$>BYE8b zO&F4b91%z2OwK}?xSv#$ywJJb5sz9j?^Y%HyoYST#IZ0`fc#v^%9$lG%;FV7BmQ{J zxqv0#h2yHB>~S>I*xu9m?l2zm9T6I;Aq!P?V<&s8-Z`n0k{p4$el*(*-!7-6*2f2~ zE1Uv=!mTlZj=0B2NuI*9IW<^INsVmusD*z3=2tZ>MiY7WXyW!yNWk+ZcVFO z+r^QwX*|Gb&GA-ZWO_=xl$5R0Oqpdvz30R?@~s=W?3N1|imBD{%r_&S`-+>k^t~KO zH?bm;j_9hdJimAgwDK#%>6U)e;2>juGxaRTaUvb84~x-aG2g$bByTffz{O!}tf`&v zg256QqJQyzdhMsg4o~M4=JWuQV*pYIZYgSN zN0@>=q8A31ww+lJq()7Jn1illV_ZjXWnpIP)_Et;AgVyT!0ls1(Ci$~k0#!d!?CIJ zxNS7k#j$U|lX^zZRR&)x4^s^iUeAjbn&ZAJ7`eZW0hRWPMpln~MMQ!cHKGy&pXU1R z6Cet)JBl-~7i;g(-xy!G6vi$r>>HT8=3!clm zf%uJ~2R37re87!g;$=j~Ad1!dsFBS>Iyjp&Ww8b)eR_@e00$%F$AvOE+{OKh1YkOYwh*U1}m_ zZs9@aH}QwJSA%hT7%DD&;01z#4KnYY-wkrSY(k#&4%a}ujH z*u|WhtWb81MRu_>`%)1Mb9PIG&KYaXx#n~qY1Q+oYHtkhVwrE&alZPxI_VXE^Jc%w zzR9ClOxqzOMrJS_h4Xemji?6%@j}}Up&DV%^Dy}qx2uI4N}SxU4PyiICxdpDNV0)y z*fFb;r&u~geK22)D}NMgn#f;LZ+K7iI=E!0 zLTu#u5F2|`>qxX!c@gC|P85dkzITtv|1i{uuj5ytzoQRlLXYKb3yxR+hb6ixBX_LN z%gNuGfeAj0Dj1P>|NL+`XKOfYfjVMuF#{m=iZR9ebakK*)oF-~$^?pr{h8%X`;J&eh#^?tZO+q}EPO6Y+ST zQnq17`R)ZGo*-8HF<4M<(~rXO8!(c2XWbD}fW`i`Pn4ghS3F-@@jRL5ZRi1HKxfjw zW89%;;~yYSP~P~Z@~08$9-0ItvfcQ;q7h`00KKkKm_Xk^eEY6RTFVg%i8F|q_(*Rc z@&RRNUn~a1P1FHwZmQ!Dq7J3ZNem!)nU(JV&fr9pGtJ09!$q0!q@lKrqaT5df134f zYQX&KO4dQI{wWJ^!=WyOzyMo3NJ|Osb8^zujO(bpSBU+rfzQaE2U0onCe*o`6xYci z8AY)V#PlGs&4kCLuiZ;-`^$JIG*RPFCoDwG8@g!y1H>Sm+E@ckxsm7QETYp!=B-&d zxpR0G7v>5z+5ExShk7}A{EQo?n=f>47^Lxq-VKD{9re0Vu};l#0MW?}kT0PIZeWlI~((OWtQ)Qor*rpnXesl>=l)vzfEP@?g1$#xBPt2x4c++c?y$A^qI{ zDEy#cjm|PupGJ4h&b$xodVwahWCp&|G^i#6a?- zL$0cZ`v1kBl026`*4&g)`mO!6l4x2ZL_(w$i!gCOgZFpr*0Q7E0k}@cj6B(;h-_i8 z-m339(>K2|--!A@GejS}S@XF$j^XdBZs!tz?qv67hjO%z^8kB?M54@>+xA|`fuZp5 z8@Z7wY)ObYNEz}mP706PfVg}m&4QmaH^8L833Q~)4&Uz}%K zD)m|#-3-JzBWDHH8?#T@o=v}F-rAm@2Wp2!!Vvm0;xuD> z*>)qCEr};7ZAP)m->3<6Pl9R2<6mOyr4WAeLiPG~@zhCKjvA^%{%4PajJU>D^LHwdDHBuWSFKouX z$bxN6o+O)CJl?n@dARa9RvN`&)EL2)%B%62nNv+FEctYIjl`V2vj3#exfOV%+TX^Ql&R$S&AY|6>3h%9BQ4Q$DQiMlAJh z`%w?>KI$IiyDN`+d>KeVf-3|Y1Q8?In2`UL$CV%fyC3^V?1a->akf#NmmCIymOvcT z7F`JDw*;2Oq_9fpjC8zk>QFP&gwyu1_cYDls-5X`|7&$qebv8-=*LW9x1f4sV z-ys0{7yzUhM0vf;8H<0mW=Cigm1|a)-rOU3Nd*XooXzr-tb*sy4c6^FLeaW?3E>~k z@7>=s2Rk`4vE->uJyO35Ccy27TZ=z8^11<~g`xqd0i}1$Pzhzg@$7C;tsF{#pSH!0 z!u3PFQ)pFq;;L(s4P{#ZQ9M6toCeUt$teKKWK&w>T}4sM#*qCKq6hH{l_n21>9}CpOEMigCzuvLiGX zP#ocl^|4%lCk_o!OL9xC&`|FY0#H8?+0jDkctZfr0(hT7XW(>Oy`P|~s*#~#*4qXm zO`PmnRfohi#~Qad*}i6=Nja;Z=a~kA48cZH4!e{~u^5VPUhsL{;G5Hve=xMZG7Fvb?)NFzJ?m+IrsRb_au9 z7P~;7`I{v-6KdRS^U|6&iu1j152H=a!WD+EyN64n+(lq*;rMCy!uHFAlnA`^6pBws*@qHKQ^Z$zPAE=-0@!dV5 zguMQ@ep!AVU4FJmePZw;xDx<7tb{b#V)4{ec+~2N^Kjpj@>JtJG)S8X85AWHM_OTG zFSH+F-of`XIVj5;fKuYn;y(yja$q$LkfMadMu^l0B1i03bOZbXCK7&rK%u^h!kN1t zTpEDD8RA+^;gG-?3r?M0bSH2@7Vq&7G5|=RsiKiEs%22PZq>GED=DuX|4nwrj|-)8cMcRj{S&g+ z=^mYGCgdMgF30CQ*EGIkexT4`Mw84*aThWKB3yFuWG7Xr_PL zB3>N;Z_n*y)x1GiApB2_q@ndS<8wPrY7Y#w$s;Y$av{(-#g{?kPq0r@(=eL6z=?JP zp0EaID0Kk;XrUm^BgSAX&ra?XG3F7Pzz8z|bF!1RQorZ0VEVWtoa}l!QF71X{pCF= zQ$>pSb(KiHT`YjL+<(PPojJ`6T67AX^@$x#D(zU|N^a4@Oy({93E#@r1uyl0w%TXj z*^i+~aFQeBKX<=NNJ-{{=nT#QU^?ZTCryKO$-xGvvODuLP+_j5s0wi={y2LrT2MCi zCu86lNf#U1!S&qfs)TdA+Q~jAxXA!p{DWO@gI2{KmgJH2)lpI)_GT?L4F8vg6>6W! zX0#3-VVm4nO>&`~!HR<`_@%Y5frZ{8F_aJ=>x`BbnEd-YxwjdIm!<^$?{6>?BMG+z zKWWTH^k)!9eI-){eX_3!x~^v<>vFfzrN7Joyi9Pw{8iq*_t|czDmA#1eGqgK&$o2u zq*3tvJM~I9QD<15!3ltPyg>$G`Ne8i^WFM$JKxk8JJ+moU8=QeKM91qRfn$MI_xE1 zas__|^N~LstS5D&zXN~Fwj@WP0e^ubX9d>uojjrN97G^Af_oiT04B?mZ8c2{k9rNwK9W^C+{ z9K*lS6uFj-!O6+We-rGjy_mjwpm~!IS&@UF$h<@&p>j@^^SO)&^So^-H7{r*wJ<#^ zdPHiz%vCc`73J9e9j%(*k63MCF{3r60jUcRNq%-a*))-y+J%w#CV&rGCUGv%S^cQ< z4zw+1CxbpB%k?@Ng4S{M13jFq;$=(CDjoGg1U8y*vQN@OB0uJ7V|I%-E_Y_1PCT(p zZygFd;OdF$pk~Dpm%^phC9C;i+6!hpTC{qNsLuO61Wo-LH5xC9xP-B!cOVtMkQ{`` zy{4j$k|ddW&yM73$nNzr^&BuAIagK=R&$Vnk2Lye?NFVbCR7Kxp%>%X#?@Nq9U-!6 zpimADWI+iIq(g5ieJPQOKgoz1S{s)bT^8;N%X`Ye_xEt!2WN>b#j4 zz^q)Y8>~xg;Vgg)AZNu$grd~SO{{52pdvb?hRbuzGV>UBabE(_>bMcDbyhN=;;aw? z)*l9FvJz5e@mHrswY}uIF`{ycoOz$nC5$h2ghWS*}0)6X^LSLzn|cmS9$z zK&%jWvm`bP>A_qO5$J`t^?C;zR6s4zW;^vwji5YMIKw(Gy3H^(pl-t)s$urxt@HvG zf;0ZyEc!aAfN6?e0}Pc$ubnNyP1`7aZH=6+*BGL()qCb%q0D(2?9ojBMny{Opd^1!m6nyhw{%}fnZ;OeY0>0 z9k25SFbXUoArbqFd=tDroY$h25p`Cpul@^sDsvRIT6VhwV~we@C#^}0ag*0W@MJk- zJ!r8mf(&L{ghpEcdxm;*@79O|mvg;U&6q0k{<0H3)zR5H5J6rOEm;+YY=4f%V&za~ z+RR=`{nG3sr184qJtX+F`)fBa#qO_ap8Qdo-Pa%Z#vfB>U&KFx%}^kW7!dDTs0Y81p(&Wa^b;(z*41YHvGDa~-f71_74vRsMPK?8 z)$f9G#Y0^~$OfpS1RsKa=AWT10ZFWDqe9D9`gVf8VVmnGfi*cvOH=P1P)BZq zK%bvgVVz^E`7Z#-ZHNj>U~qYBf9$4RD~wJLxVVMr&+YYfK-pNViT7KGssdnXV$< zKvRfqE5i(#o<7s2h2oi=+iHlY*|6-=ao~uq>H(uJR9#+8SHrw%wJ%zyN4%B0%7r@N z!g6XT&e-kz#ySkHXYW(#w~P&Hy%7K3%quwNMWmk;nzII|E`8`CHDincd)V=RI?h_+ zn#Ci6Fwkrwk&(|Gh1 zQk)+7{V!P=My#5J)V(qHwM5~`sZ>qmbLz@q&Z9A&PAc?$0MTo1%W1Lv?HbIugj-Na zZ@>TCy7in`{!#si4N9e_#5%vkWB93(@)*HXf^`f0GZ+Q^&gWv2V9v2Y1~#!lcMC*H zqYMf#A~$Cz-p-(M8o*OSnTxlAjn0~Sa}=nWe^MWG2(U2xf)Ao*H?I2O$6NgxBH=3d zSN`ldnx&j^TVtK?kc`qyPI(tx+pV^5sZ(#?KLE8tuRr{-cf_VkE0J5XX@ljZ6-`-T zT*l7Hgak6P9J2qbGdDMmSFE}>d!Zx)1PHs_dcEy(KdG0&iWiTl9KUJBG;HNH$sz8G z2@+S>g}&}uW4>F%ZAk)t_eH*JFF77%gRl$iV&HpJE65rf80T-d9f#{&AFqN~w4ACH zRyl9%Tory;&u4TD8a&{1v$Wsjr&(GZ)ifGn6+M9+rnN!059NETb8`>iVwSdZV-LkKjpqm@p=f(<0=MaS>-qd46bK0LSsg!7$g>SBuE*W}+OL-wt+?#1( zF4yJSP2rP)VXODWUS)1IiO~e+TYpXP?7tsAWX)Jh`II=a_Pm&n;XE7@!);~x4`(qd z2n{YjD9vZz1A2vCHFtF9JmX%k;5@&RHQREY0|KUl&xiz)+cKRorWNTDmg#s;>@Kb! z#50;rF8pY%Gu#F@(xzM0dn?&fke&nXQteH6*1U~{Y$j2-2G-Mx^?a+ik@vgX`L0$A z*N@{Etx3MR)_e0;+M`5UiI^il;D{L1^N@O0Lz&E%#41R*_me%#r24_{mtosg@w~X= zxs&I>{t$ORRw9~HTPDTb=MwIV<`zRFj}XK-;41tdF+hA9Xbp%TzP&q$KUi4;G4WSp zOCTO%;3O5iaLx80USnD*^L6jk-MWF8h3XFCAKbD%h-mVtW$$IOZXWTZ5ZnJ;~$tnRqxf1a8dz68F?SGb^ ze^c>1tK#`*70*{zJWmgw3%&OAqY(`9_Phab-ct}V__u@KXK01IrVXT3@?I9j;6B7^ zaN}(M(IYGFL!|zfUibETRkU|e<3Dfjo7=Rve4F+@y{$aHeqW=#J;U}gUyhqOHBs34 zE*flc*N>gn^G4E?o}h$xX=W0U%-zgEhUADg4tcbV7(Mv9Vex4TTa+=Yb9Jv+)#y5| zGZcB^s-DsHF0!8PMU2%3`3PmlURsfV-+eKETK$OA248nVY}z7Hac$d(ds@BxGj+M; z*Y}Uv6K!41f@vh?POmAqYnp5mwLF=$_0gtpVeg_)Vcd%J=047BrSE7T_EN^<1Y2j6 z{oL{d>vMy%VBv!2o_+RNUHg?)qY>V;A>mVKAb#jyze2{=gWDPxU3*w-VUKjoJ-N26 z&~qFe&{9*Mt6t=GgU?pB=U!@a+Nrm2G5IZN*Is&H^}NCUO!=$DKaIA z0W|OvnUrOtYrQRKRKeHO+n^{7jIK2_)Zni^IrD1Lo5v^nrZ=BV%3*gsA0ln}lVdH9 z*8zc+LYz49@kFXo**!T%juTxOFuIm}SN@wY4KpuF^=Ntg0Lm9%J-^J}=Z0N#*42(3 zHFiq!K<_+;g|skiVS8@jtR2haq3<+}Xfq+oF#Zt~q{u#*jeV}iBz78y_|wNtNxd2q zasbHUVy0Z~5ae*Oa7k{f_EpU^Ay$4u@ly)Q0WTmioG;m>G-ss2TLBLQ4)sELU0 z-%zWyL`&?IIdMqRTU^>tTT}ZM_b-hnw}E}4!XK6k7c2IgN$yyq$`;>^J_(oMAf?iw z7_C8(cqF2XM-SF5D}U9C0xjiL!CBgLD+V`ttDh1jF%O^02zb5mRL zK;eqrhmS|8lcregWiPWj8seQZ@3d%Pq}vqbK9$VdtJo5FNcyZG?GYu~Kr00tn5@vi zV|IjoV#jZ#mE@ro!N0Fp&2t7LP9LPLQ$)MmGdH)}_`2s4a9EvM4)=$pmE%zDXm4C0ZNFy@+1 zZFA1sGtxHaKFv1X_-69>HfP?!7AUC~k(kYNbLHu>5w_lLXPh%LHk*IgOEzC>1+v(6 z(tdu7;fAq&hyUo^Xhb_YGa@l_pmuCqE)t7+h9xya@0;1L3)vL_pvSOw3BKNmRPRRQN88#ov5D6MY` zCk8?Y7jM%3?Y^HaJ)D@jAf$(c%9CDwO7fia=5HlW@eq4~XBxM~e8j!Y*G?zJt$?y&bWP7>uXMwJI9j)H*%i>?bhvHv_Z~4)z$X)|iAnmxLV-k4Y)2IqN{|Z5?Lhg~g zvyGS&tLbX4-IEc3cJPnWYSYI}NL`M--QWnWr6?gF7a&G3Dei8$ePL?f%-^EAbx&f) zZke^Mr1LjqrcD>(6!v_2pWcxtl%gtD`0X5aadGD|e{<&T*zmNIeOO;Ji#T`maq4}I zzkS#n33ugUl+TfdPdf`nMy+r)^Q@*R$*IUT!(NhfGu+a#Lf@APi8(6>kH<#OI2QEC zF2rpY4thZkDz&=LSdr+e7Ynhc(wq9t{GqM3yx0}uQ_~bDr;yfR%NtK_aBfZ+?mC)7 z5B;Au<6&PE-($by0jy`c3GqynAGzOt`U{Hg_Bhdvr6x ziIaUqFY_a7^CRn`qhpO9IfV!HX4-4?74LkfSE6c4UA#+|5^~D#dxZM>@IZ5M(BB=VP;_YXM$(a-S#M*B2zH!?|oPPf!w9%LUbvug2Ud%^h5tcxZlf z!-&yM*Kxo5X+vYvo~C}n?f=Y~?r2ohm2CH{`q#RgsoxB^IzO_;9|M4R=L=A{;t%6b zVcb*c&HbF4PiH_TF=aP;fR34%wl*HsVdn`6ve0IHGct}ne^P7!-*VyymcBdL+x5*z zcDL&_yr5Ue3&bMe2hPpEpbTjf3|k=6PiAA)^-r{;uc@ie%$HT9 zNM>KryRX4`0#@svNGl=yLcKAhpM{b4(0|{;$X}>&{~C&_=bQfy@M1S^5?ga-ui*zY z+{xLiC=7(SAi)X-f#hr8Gv};ckvVsZQzqO`{MV_r%yPzHxJDk>jzK~*{wEw?DQ&fp zLEus|w~K&)m3zIQLa?lh0@#e1NnY=rZ+k0>JhZSZ0O7M37Cib$*8~Y9YAc$^Z5+nxy-Bsy^ zQOOHDIiTcV(3fB2s|%<66;F-mu@cZ3osik^S*8S6`3(50?RPcx@)H_HOlWcnT5p&$ z`2VpHvU`5yPH6DY;B5#WZ){)n-wts!c#v6pF6#B6`}dCI$JVoiFU30F?iGtJ8ZmaT zQ`mA7%xf9}RLi0zeu|wa&{th5z)ADt$v1HrFp5q<_nA@a7g@Fvz1NiI?5ZwFkqcck zL)P)jaLE6|bN3-@W*YWS^@ZxbI7a>wAk}j~`npIw^*{Lu9M1hjdhqEcLk zIJ1}Z=KK7uRkS{vC+DY&oXl@{$6;S;{XpKe`~*A1wbai$YPDkK(~O*;GZIU*P0|f4o4~y{ z&0yzRaA3KeWZ2GsZPU)aw8LEMP0>YOA}lw9atY>@2xbA}%!&bLRE1R*YhTV|*@2=2v-_(Of_fvLE3GO)yjlZbWSOukxT8HnvKgc<1UnSMxyt z>|%C$3qA;D|DNrxgd)RL*AkknqQunKf#z?g!T4Oz78q314+nL@3uqQAZM9b zN=Nq#^JN}UJKlk;j@8};>Q9V(r{^8fFUhRLju{`%z zxq;r!eaP3V-p7BO>gnryumz99ju9f-y}V6KTWz-x$&QdDry)sl;TmugvbAuR^hh4P zV~Q;KoeEt7kwh%me*ZyjbO^hp*nV$A2(5_(S+*_e@TP5LtB1Y%-hFQ6m^LceFERr)@^esonXNrj8TMyCxWe|KGF%nXc+a{S3eL&^Iasx7VTkej81D zL$<8jS|Qv^K9NOli_SGm!9XOhX(w1e`ztL;V4&sYxG4Wb^d)x}Ulz3U5022n&L`~B zJ7VGNel+k!_vudWfaudNZj7!#AyJO2c%f-I_wBYdpl)72(OrhN_zD(GYXdWIZ)-Ru zntInF({=B%js6h^9ci#+7Sc>`DNmLcGT=vxzd*l3y|u|C3*+Enr)etVqAlr-SEZ)4 z7tUDGlHP)qzZDtB+YIYR%Lc4y*-qgyiI5fDmi-gPwZPqFV=2+@EO-OG`zU%0+zV~) zWaGE+kKl7ldh=CI?p;I&x}4_ZB+2JbOAK3>zg&{rZ42Ge*AX2*Nf{Jr81ufUK!6~3^IV7KTNR)+iq%ac5Yin zXx43=&DGDRE^j<2c%kerJ~_M^@f{2%FT!!m>smNPjZ3B99+WkVGx%m0&*T{ zJ!tHNrX!NaHH}a9Y&tpBn`rs=dSsI7iK&Fck&_D7$XvAFJu=TzBB=woHoF1U; zu!W(W(9i>{WOrLU*LK-3dbggbL-Qw3ym3Sct;F9^81rO$Qxtudx9QCZC;MOKVUm;kJrCA+ zd8w2AGp(mLC!O4nRXd<0&b(MOy@{9P&DKk^QK`~Hx^h-`L1Xi@H{W>^Io$#1!6@U9 zs&?kQqmDMg=w4To!Lp#l8O`lpMIKeyamrd7b3<|Kio}HF(-uK$@mdP*ogyWb#ii zgXS_M?Rv>RogZry-h8Aman~K(39)p;rB3eKbb@c}A}4pbdFnx|=r;|PuJVozIy%iczTI(IlJC`oM<>ah#Vm)sDEAWpp zzU5~&%i+3Hei!U$jhRig$)nSoTRG=tmVZ{Xa54zjiz}@(w!-msE2JJRk4@`)Yb?6y zgsm7m(|n2KPpw6NX0+}z=}lC>)~s$@@((gjW$7{WZ|Ro%H~cGkW3x0AX7zwu#N2CG zKghQd>L;eX4%e`zw=>J8H%iG_kf%hvtBQ>pX$c%dE$&#Nm}Y?DF>r9BzlT~!7m5_` zeF7|u6o2@H97)Chd;;u<6!Y$j8pDU^1lTtNm#e{L*6B>`*w8t7j)Vdeb*$}U(ti%- zdwLUk#lb3QYD=a!Mt(xvHEkjNRl(Ap#mNid{jy*SI&)-RFnIsASu8DQYi+n5NlDGCaPf+Y z4o6h7%I=%YfSc6&T@lO_A(wP7gh@`X_3bgF*4pB1!JM82cHMiU;7AEA&Vq40Y}Ye6 z&9x9`->RTzuboiIyOF+(hAty68v0~j8~DZY z#FLl&4o>b~@Q9sN-~Hgu`E#4jaB?ewkL3gMwU3N8jdrp8q#^5lf6Y`5Z2dQkg}|Ampm%|sLbjwxGs%GTQW@p zs+{a34R4zvE0>!T2I0If3DD5DZ3;cD9++2X?Q5ChyC@T7`atiqcwvB~F=HH3S~4>e zCB(~5Y8WvI)1CMRm%<08yM#O7BX?2*SXnsbv0=+`NX*=wwFNZ@FK(~(mLk$>Lfeey zxM0Z4#*B*M6$2ahrVvCN_Ox2>9jQldCrLC$v_m&~3INkqXsfl?8yjGu*R?MY9#Az2 z^hb>4=*uuI!xBxA-{6U=fm8^+AClak>qA5{ZiJxkr8 zd~+=eHEg**fIk600DceH#rMC|7UXw5Lyx-)Nh6rt%M5{QixmjUr^^@!pVC_MHvT@-dG?Lu6Y&LGtEy}2Oha4KTiT#2V^_GZ z58Ke;ZcJ}F#JTwvK4FVBjt2puIlIBhIXsxD+|1YX7WUV3%ptvnec`esW>yo-thPGY z@uqNxlZ*3UaizW17r7PQl4nK8lUcp0X=3VP@6Tr63WQGX3DD7hS=54ZPsnjLzny=`?|E`KZRx5MR0PmzlQvY<)@ne`=CAV8Wb(c6>kgH(}+1{uUawZ z5zR;x|3}mi@GgGCQvAiv9AmdM_=K2qwZ5Az(2kvTop&SzEfCb4mV8yXsb|w(h}21* ztt$w}2$m`?YUpaw-iUzYUD45cIK4LEo?hesoz}bqK9FFYR)G$;34Ii>%HrEWG=@zi zU{Y?7?^vdIOMn8=AetcYEJy*!qcl~7QSJmmMj;3Z4IY4_a_a9J6_K=g^iBYnj@abK>p}i)WO2!r( zpm9g`i9DqVD5ZEI_HJg=(KDSG+y3RZW4Vu=To1kx|B^aJNBHa&q@9%BrgFZvFm}7D zSoA@6lLaF5YiWJa@o~cbt*Jf9X@=FN?{aJT>I`B*R{HV-J~POSW=? zy?|hTJfnUowaS(^``d&*2l%idvvGK{bNezwNzR{ZP`R127`7UTlZ8B2YsBUmZsrX%{((y&9l@Jd|Q&&5RRByqm#3mCMJ`}hx-{? zvIwin-n3GDe6Gi(qw>e>&QI(k%9@tuF_NBzLYI9WuErdZc3HkzJ-!9ks!AqkuNqk} z_Zxi$es_vo60@>=L7bZYR3TsqUVNWrzZYHhi-h{4DG+{_Y$+{9vgITEWsKj37Te~= zsJUG!?LCUxLHqbhHA-{Wy7v?NP6Si$Bwu?4-Z3P|mG@iD=Rv;aSO=uI1L${-sAIsi zys6S<+GD-sy4opdMNUrd0xV(l2Gut$->P@h=!bVY_@dsf;oX9(_~Gry5{OKSG1=V} z(WE$FXD0Or{xT^`e+461jr=B6zfjfxXos0yA|M%Cf~ii@NK?IFtAEpwZ&i0x{RrqdyK)@y=| z@C6IC`6A6X)48L*9Av-Xmo#6Ll)>A@zS}u?XO3uWUS(R?EqFJQa?*QD6kTzTR%c$% z9&t96!fToaBzKCtE4Z?_y>amk?u z-BNbH#ogt81204TntufS`dy$@NI!+Kdx^I(Q6=%W@8=IuxqC|G)Pq0N?3Q)jV-{ro z30h*R-yi(GEcks#@LSF4ySYz@=I`YDHvH96#)OlToEXE{X6)NUbUE|JV0?n&jp0Lj z(;3OjyoGNW7S2SI6EY2lIoV$ehWQz_El(WJ6R{FTQ1f|CZ$_ZbnkGj@iwBnJzf@0P zhNVqtZ;FXrb7AXyn54P=HLwGku3u35B@;liQT)XHg*{dLwa)d|Fzh1;Spz_Lk1j2z zer0!7D-s;dTDThf(YXF_yxt_l9!N++e&`bh7YfJ!W>GZq$jV)@^E#{rxyca5`=pSIprslICjfvS<*W6S6KtV` zEX0OB6yjeH|6-!LVT#h^F-krk0Cj`@q9D(s<)-tKBW*aDGh19=i1a)TF{{c1t81iO z^o|0g5{X5bK}_yXCLi#dtE1DM><`RH*Le%D(T4TgXcJv~BPP^adCY7)n#9bWp1;SySX9%y0d}XOD$KTBx*+Xb`Db0${KcxC-9Y3aV@3ZG|I4ES)nRAOeGtvaq z`$qkc0|s_PEE5MHl2;&q=O@*Vm^Aph^ApqFj@@Z2ZE{V1v%)nw$+#v74?&P+dVVLX z)N~PC3}f$~c*cfuDVaog()f|^i0G;1V^+BY5M+`&QX=Bye#I2Z@?Vg3HBGaTP^~v< z6u_&d%Tqt54tSdkTGgQa!}wwNb*cP+L9{8aMNqT*16AEk+{Bzz;~|cjk@R@M2=lwsyUYB3d%a+MAl{daX6_{a!zPA?)D-Fs&-)!8nnkU1c=2{-N_wXNW zvvv%fCc#!X{wl-5%(8M4Ip8Des#;TmS1~95DZXeN5{+}67Utd>BjI2pDUH{})~TGy zS9P1Xnr@R&zPjDho2Mr)OmDs{IgPWc;6!RHKp2;5Ck`=^I#C^t2D6#5GPFI&q51`l zc8=aU9Yq5YKd9gbnMGCjzl4iR>1D2}PqxD;J_Q~gHzAt3Q-eoZPyMGhn>i*e13{JI z!==oDr^tuVX-+l=T+$=Xce4M@gPPizrc7F1kQYDW^9+Q+vbUC)C#{(B5tdekw9stH zrDml+E{*$G#x3A9n0a*iPZ}Vm`32LfYN9{oe}P=&E@uv;Qj0dtWHX=34Kn;*FvV0` z=cVnSgzYJ`6P*z^S|r*J>}3>R0j-nW%RJ!7IEc#3i_zBdr0JYs7<;F`mfx1YWHz3c zx=u)#nrYyFg^C@9tFDZ=PVVq+5bJ(0Y8%9wxZG6ndr(yCZjl}u_ZQ&^n<)g5*-_#T zETsPoA2S=LCr7E*pFjcW)qhGfWged9yD`~awNu8slG7lwtuJPscg-ti=Drku)p`&S z4M_NkrZw~Uz2?Ckx(uZFfWe136!HJeN&*bPvXjsQGTUuL1A-ALd6tGNuQAq#PJUKM zJlr=%Vuu!UPcg@u@C#-CG$Fni`9N7ELa#ZI0-h_ z{$@~_Eg$xh8I7&$&+S6wz2^09F$>CLu(cfY`bpgVi>6KJs6t=c z`)yE8pq9+vbSo1v0K2qgmhI2S_I@9`I!StKYkVWF1s6nrpz%nr1pCgMcZo5g)ut*k_sK-qZ}B;N*7X zhk?X6nh+%Xe!L0gF`5>H{9fi=bEKOH(6(zd7Ph zL!kmb{w1h>{3T}lZ37>37n!yyRQ~ejuiCEi^JK4O)ZwOO{}u-aaAUqh_@tvtS1c** z*Zs9$jUAB6$wB(MJ2MV;=pVP+p(mSxvO_t>xDb55RQKz(DIpTO^kqXYd9Q;o+w9Z5 zRMG5HjY9j>U%QxH`sY_tmZRJ9zm|y%wwgLJzavQk zGMmQDWGcho;P!V8wN2~!1CHY;q}F}1o`M=zS58&<9~9j-Rw5#pM3JhiViLeqN^6l4EP_fbz4|@^<5{31(=%awbtjG4t`J10HiPv^mD& zm`=*W_aB5~&F#>H+VW2|P^%@++H6hrHDXaO608yal-YQ&ll5U4v3$Wy%zdGykP~SKnv(h8eG2m%@JM{EksPDG{DiEIqu9Jb`5z zZ}G@bp8tw-lb7n;4Ak{tffL2&+*E|EAgg`~CC&&HOw54fyx!!xjBsW&5xB=lz@cH}w10@oz$9 z|KGCxf8G7pxAtG}f6+q~^H19Tov%6nTHIv+D*YSs75(q}&-*v)|MI_q{{G~_?dRY3 zYxckUKL7gst19~s@PF^G*?%7txqlV@SO2nN{-@gY-{EWa|Il9ldjB<*{RjJR$FJG{ z$GGJFwfX1onT|YEmPiur{d$qe|JsPhT}BKCC=u@?grD@2lAfBluNUcS8>#DudS$#r zMtrK2x|*yQ)nsHNPjZ%R2$AZ(?Hl?9f@4KPlEY504V-`sY=-6DtwH*a6R)AmQ)?3W z$F>81 z82YEzn#h$7_mA?>`hhmUeFMZi4nQj0+%vUTpe&eZGkfhTw-Tb)mQ)_u z*Q95R=*gWHf$F8fpr#N7NwY15Dav}-D-kV{;Db2j{X==X(7IZu&$Ex1&KH}nDSw+K zxL7J(c?k%=udZB%It#@*?{5sE_)vM#kpd?X+}QHunHK$fc|DDQYi0f;(Emd@urg1| zHnQmVP%{lKnseeh5%K>Z?<=o$4SCTijPjN#f-0*_WBw^M<$S zk=UJ<0?s{3{>8-5w7JOveJRaURx_32?pA)){SWONa4!@%DBR{gtbk>ijzg8WKYCXi zS>gL$|K|{vg`MvfES{1UR%GsJ{+8!Yo{~@&zgGH=*$|}rPTtPk8v_~q#h9y8;AZ~e z8Tdde>z*q{r^Sc8WPRN~4TOMD9ohH5Zi}gHaJ^l?>toy74*D=$gK7U*^%%-gIwPKSv4p!G!$Pyb&_VvLGyDfp#R9mrVF(~USnBx9 zmMUlV{+vzv#JN1;zAilBWV*9!+a5!C6JviR_8>)JVoyM6G;e3u#2(FTH`~9A1&Y~| zIU%#QAN%U6pLO3jS2Dpi47JS((!EltU3V)#_933YmC76wk1ow@iOTvo$qQFEQ;fzl zAJloDQI(IWcLJrq5&?F?CgM-08M7N?*ZB{ip$<$d{}1Mg7Y7ND#{6*BfVzM{C|)SH zE6p#c1AH>Vd}kgAzWw@r$EddkG7K+N9JjLu`IihAR_u4)eHBbA5SsVJUJ&ln5J$J! zqb=bc{lDsq=eJ?65x2$laIdv6{eRdxQ4&p-mh<_!up?olHW6(tIq5s(Zd zaK}zG77<)fEETb8OJzoI0fI9lT*ra9P^nc*T`H}%+Ny}klCUIT60 zD%eYUZo)=b5%#&JBbVAaipg6m*!`iNNGDu{iySa${~B{%5VVv6-UWjl_^Rq*S{~hl z-Ig*{)C4U)&@M`g`|-B$S{uL4dX?=)=}u7~s$8=dnCZe1c9OPs5@~FFTs;vI?U;~* zJ;cjMa%&mo1-p7oN?Pm@ zNWx$mr=nGX`S$?XglU|82>7yE$C51`9{UHqcRq=WMiV%@1u-#% z>tsTSk)XA~_%1T{&fhA#htK7alYirINpo?4-+NQvzk-6;`GCcX`848D^phx>)A%DV zu~p58XWVH>rKsLDjk{?7S`Q6r5s^8Xo9IDd9G5c)3socTXQr$fYpcmEIS zzp#b+4^{s&3BVOz{d48%7Fft_&}kh=dU!*v0J8t&0$YlFn(ogzc$=PML~p3KKEiej z{RrL$;N(oKMrUbQWx;ARJ{BDi2TtZweGVXtJ$X1Qh5QZ=6) ziw>SM(Q?i`z>^I8M6DZ|~vjRPv~J-sonOe@_iXx{BJqD*St zcBV6b9DvTg|KAbdcMHJJg8JYf!`2NQY9VL$gXi2#-9+;NpMUV2|7khr@3Dh*kk(FU zIp@W8&I1V2m$aO7%)#p<5L@WyiwDp7Hj=cEb2fI$4${v`DI9!L^aKmN5D9s?A~gq4 z8T`5u^PRE2Bw6gmeIOC#L)_=Xw1edkg zlQ8H$Tz$|j$n&%1mKJc}Bj_Uzf&(9R;fOa|4F46u2g&&al2De+4MZn;a4fO{3%eFd zI*%1NV&69{2pm^BRXJD)99aCI&{I}m0X9B7W+BT^X!-vcJ^jIkv-DtXE2(?lf|GI^EB4umv@|#z#-L;U+fFvi4h;zH)&-X99qA^ zH?9}py&+m`6m}3`bek85HsUz_X^b-VT5oND*99JB7t7L95gJGiYQ*MIN9$HNp0KxU zEFU7GKeW~2zXZ*T#wO7d%DZ@9e8Qg^)X(ShZBIWfULahdIET(zd*W(7RNJ>uiytk) z%`olHY?Z2)il%_nJ-spbP*<7-a9H|d^w=G$<*iW`iv8=%q96Jq$9LLuD7 zfSUpdteq_1Hj5pIEF#{wNZM~1Zqj}dBu&-!&gavr?bgU|;~`1=r}nP3Jdg~&BsdZTOdS=;Fd#5jyQgr z43OFCA8Kf>`CAjN8@`#tQjlr?_>=9F`N7d0ALe{(>vleeGQ7#;n9|UExEjYKKebK} z5)`r8dLIOJIHJaBVkAKqC_JPUZMZRVEDrYkCem3BD2a~?Y(SL)|7qpw*JAhKmFLK= zMl!g2IvxZdXMp0|tCf4Ox0=2FOd6^+&zXe{Se%<`Mv*(YuCysK!>iFXPmmv^^{(IK zLm|p`-5e=Fh2tWZNV~8<-K@;>(q*=+T)pflX}K21j*^^S(&F>vjR(shDK^@ErMH?{ ze@g3-$t$}cXA3pS_^tY zXJ^(r8Yl!SdTWc6*KAy-LApE0JpU?iYCug1CSu&H1W?)ttgIn;gwVD~*J}mI!7M!1 zX4EE7vb&(ge}@ouWVE#7CvP57#_f)%J^yn8;Sdw&lDLw+%Wzhnt+d&O`P^e@3eJ-W z%LhZpdSp%1-omt3B>#C%@ssvXlb_UZXnvPs^Pe9oKl%Jf_(`(&GiVgidFLNFAK#v1 zy?mJKk|$&z^5BL$4sg%jLEv7Sn>Z#4PcgAKs1G+9VK}9Xt=uM74FTThS_j)E6Bbq4 z)D@p_Fy9WY-B1=^ti|5MXS5MUBp<&cMkK?x!EU6yuC{m^kpcX%4klTq$RV)P(mKPU zM4f+uFrsxHz72O9AjQ~qBBjhk8Hr<1AzFgU?tIL;7R9Ib$lJ_pA{3cj$b*}6oIg@| zp5kJ%f$q|BEqaulKMY`fd}!%~mI|xHT+O=ZJv1D2BjZ|z8m+q#ayZqVbC~J-K*ma$ zt9<$hYNXVa3R%IBAVLx|hGRm&-sg0=Z6WbkIX;sC4sw>BENPWfe-zG3F3!PCvRdq~ zz>H9zR*@~ZeOO02+{*{|mXU7O<5?N!ZTvOi?2!M9a96N6c%X!cb{7)p317%x9r;4s z_`~Dvx8^Ho1-(o##q)2IIx%N~pPs;xe~o5d5Gsvs#8=Gc353-XB;ZANj+Zh?z7Dj+9u1v>0++tmO(am%d z7v7ec=_>%Ng$7Q^$b^1HyJa+RBI=TLH4hx?)8T5D2aZSaz;O-Kd=5;_ozS?ZdjAVWx(5f< z%i#dQsofkd8sp6N1Z4Ty zBKDzlAMWXn0^>cChf-`eCKKU(siEk>?eym3Yhe2-J-)z_?8zBuxQlSbFh%dC zNz)x@0oIY0qU z>%^B}bRs0clN=C1ls4O*3hd3Z`*ariL=PQUu}U8L7!{#2v5ehmCcN<`N*k6f3)O!| z$%oQpG`AO|CmF!##en-fU~~``o4HYcK}ajvU_DQ?hc#OC;(~B{_eofn-CG~jX0^sd znTZHI*V;nkM{y=OkY4CPTVbtui%EYiFkmdk*<=wO03#2K@36YEZd=;e=ucjU0=4N^ z;hh&LC0^s|U)`mYrMHfAg2O%QtTb8$yeMvb~m0GGu4 zvl<(Kx{f3;@Ii-(l><%9F34kQ{AtghZ2oxo^TVI;vx`69@nxJR9FX6p9ic5GGdu7|z;LFzAxi2%uDWm4) zbW>Ii-5g07ZZAqw^@oyYRNU$Hywwd&;x;#q;%DdsgVCjq3H!9`y4rUjmiae_{|yhN zC+6Fzz2;Cvq)BzR$4Ehq>Iu8n`Bc-pI=v#N zK>CBLlZ5j*>Y;X^cxl%mDmecGqB)fGHe0fWsPy&)@3tP*b1 zNp_layVsMr17|h0cz*_B!3b59d0e#NXl?3A3>lR*MfWb33*E8P@dz25o`{k@D)#1K zrxTpc!H-uNCr3>lVZ3sv$(3A9R_pGe#0%XSZ>+D03YXMtqYU7m`3y@@r8?@}sCNS()Ut zYcyMs zsG4Xap<$o7T;KQzx2$SfXLKqWEk>XhMH9sMhqH%hK^K%Fh-{rDB&G1z9xr1RZXoH4 zX=$LKksAo{kOcj7^}1c5gSL4Jxg7d9^o)OGMK;H~R|bxPk-!4r&eM%m3fOtpKV5Rr zPnSQh0D2I6xJScr9!7i~MhR=%3yyd*cA6}}nHYs2^0SiRN!6kA&%L#0fdfX#z& z`^3zi$N=1bm^n9~5{8mJ-o1rWzD%iQ$%(CGv0>v6w1-i+K$AO??KwAnMxo6A zV;FbB&W+d%hWm;KpI>a&U;ht6Ih6PXf57;%nd0PRbLA!V)GbSBP_g!ra1jfw-#zX~-)@fk4rP%+g>YP!q&cl$H|C^ej@~8|9(~ad+8U&3G)Xe9a z_QKsNp;V>t^%|OLdwBacJxPIKn&Mp*)*WIV?Oji{;5O(wT>@RY|Vp z@qx^F=oXx&Zc@X)B)gj%j!@Z0fLiUjCU8Bd74uE8FIse#7Jr4n<}72=Anq@w{15Zc=(g_E!*6)x@$#*Wn4vgM)BPl#b zP8|!FaUUOU4j)rfiRkCL;3jOG&{sidVD#dw@Zc00z0EVz(YKh_gIll@aAImiB{#RY zT$9N+EL|z>()v1HBbq8|@=q02@fL>@lbwuk_zp)Z*q=!UPC<|k`YL)r78(NKK=|n> zTNQ&X&*{wPCfYFWgK?A7B`W(R)lThc8ckcu=%yBFFp{8EiS`!06T_-^=8*ciaa~EB=lhow6@_ z@%iDC$)RMRlu%(k01FH^J`CV7B8=H^AFbPeZ!aimqSlRYQuDu@KXj(fj5Ys}+PA0p zr_zt1?O#)d3mW^?(rCvJeadDZIlM8`1X+Q-^mh?b>GHy=Kt&_(t;q6t-hg=%_4V6-+;q$Ft^y$``C5RPYXOGl~;ba6p@b=IfAi z@qjB782Mqyk^}eC@BGwFcrQy%>JX@y)ZvDZv4C*GfILQ-KdJUs^ZTw0s84B6#Rft*|sCL7a7BX$5{?MTl6 zBa3$=dM-2iE(6FQ6fWR+7Ve7v06XMH-e^_0B3e^o_PLFMPz%zJ(fIkvk0w@Q`j#wH>K39%T!qG6syBtw$M@@V<-=MpaX}>l; z){a1$38~l83Z~U-OQ+e-O8ZF}hT*gA=N$X_vi+RLr+N188XKofj5We!V{+Tt(wIb! zDt$3AbiOQ{#o2jj6@#^xR>iAy?Xqg!_<}Yy#?bk=%tW8EQ81$5JKg_Ia}+>er2Y(r zV!Y!J*Kc8T<7?CeXl&Fj2L|CD3^CFHdQJI4mG-vY5<(#`qclO-EFi2AneA*c6Ntu5 zFPp2e`HLM>LQ{uV^TbR-5s@{q-h{QMaVEzgQCa~ajaLP5t9X4U#Tw%1ECNHuW=v1Z zT~p*Ke z6*HGam$b6p$0y@;g;!>5Ja(7?%tV~X4r>*w7HEOIw0PyX2jLvuMnWJ26Ojqwt}GZN z0i$>~2`{Xabp)~S%SyXI;WFCXHoJrYfzoVYLq^)u_gpPL0yWX+da_)drTZ4$=N%_s z;~6!3_HBpU+SH4XN;kIK^G)A#BfsHYDiS~bYP`16lb5zimanSV+YXAT@t>=CmTBnC zTiq0M=eGJ9UUV67p_AQ(4wv8Vuo%0=anW_iQzi|8EXNBRo*`1*jVHaK6-{CkdfRv!@5~UK^!GgYhUn{8v_;mP8}BLIla9^sxl~ zh7Vm%vw$4v#laU4&N}8PppAL!T^S2bdUVE`4F7!<{?S@IAC07Z0atL8FI?Bb4}d3+ z3HU!IClKuq4}|A~HVFe~8gdmDUDBT}0&7@>VbxcTE(TKq)3XMk0U zc`ygLKr2F++)KNjqmPx=OV?mozUW+lO^LtVO`gX}t2ox1J;c0LL{dFj=3cqOXSWhn zOQ!Y3`bz|M-T!X*G6+Z$9d*nht-oyla8Na$hW6AyD{@a^m6FHYjhVeuQL7Sq)|=a! zFU8?%)!k+E)4`?^LqJJsRHh1-ii>=+?;VlPnt<=2%(9w;FMPGv0bD2<$udWxJ?{2y zgF-p5fZ(-DcKI)JuV2pr{9fRKCj>`+u^|{{!0>hlhVa*Oa1?abu+Nv_E{U?lWL)ut zktF>jdn_OBT2FUpYm#NK-m%v$j(qJJ&(wNa_gmpXXv^WPr_97^XL`r_qLhm&6EvJVbCr~LOZe&1^+?@eD{@?R)%duA|MQR2dxh@GS^|8p-iO(a(b?ML~}_1Aw4????C`%L*mV$;Wd1 zo`B4{a^8F$qU4_XXYdk&(lK!dq`^M$=pUUTAzKuMZ#6gE$yEZbe*D%PhBValwy6aN zKz@|%*77D87F`Peho(aXAT~9Bhv;_-HRC2T6mViNy5AcK*0v_^fmL$-t9G$KF8O|z zdQkHZTVd$lE5AN5x)PRnk?*a^h_>-7(Kp|$MFM7gx0aVg%1H~6Kyd}_v-R`LqA)L~ zQ1ui3xQrou3c-3j!0$6}fd(5B)Nxg$-Dur@k&ouF1>omQKZF@h(2XC=r)KSF)aQ9V zcz^!N_3w$Si*9Ti?it`QGEwAp~ z9$#_SW@ed}s#<#q1xSggRDZMO@Fmh-)B|XC*WY*rOor2>?%i+8UAngLSTxYfGSEid zzdN#dNm^VI`0BW_c?UcoMyqfpp{=!Ih5$1?UR>{+YcU=)tRjOMVZ|RJgiAag*3UbE zJ_=k_X4Fva`mS8byVF*?=7#(@8}UbEDoKp$0_+K2LwUP;Q_B6C`W`$$*! zV)(t&aOg7JNss>cWB80qj?_p}pX26pD+6 zdeR?ho}PFjpNpyxKDtw^%E@3o!wai+4eXMGizEl<7z4Wm6Sw<9ec%tw-cbUPqlB?O z-M=M#e8oi1Sz7EbY%&OR(^%yaYzDrO420ju7zlL>4iKD@&Exu)C%aq}@?V*sQ&W=P z+k=%$vZTU`8+R!$mE;e1tyrEydTlOJ0g7WXK&bFRc#Yi*E!GC9r77`8v(OZ2qJIqT zm$(y968z9%<&+~UN2$8Z*o)^yxbA#+s9-xk^UlaoR@8Y;6xvAk4&k%fZ* zopOwO^RG0vGl9-uGI?X=azYe!jBI5YXaKC)g?ut z{0p_%D)t!{fd`|F`?c5|_=;}$F_^fwlTS~IpIKbR6*BgNTCQkBA-pB5X9zzKfQp11M1+8o+hya6df-uTnVgrZ-Gf zsXByf4G?~BeqIO^RD_O%Feu;!Af6IX5XhEXfG%~h$%hmHV`;!xk{;a|r?D-kejJGI zX+7y8UCou)TSWyPj;q&d@U?;PQDR>as@+n{X9mC;SO zn=+0M8T>fsKf!x#?!EaJ7U$iYe-WwaBBHrm0((5>HEU|RUgBB1fj(=lh;zj({UWbi zTCC<*8xMhkRJY;!?y7KK!p%D^l;2y6PiArM`+$kalLCQVOTCd^0EN@1ZcNt;M9FM& zEwJ5h8LJ({cqx|->nUJXP>8^0I&g+s-F%(Yf!%RC0b&`5%uq)!?c&HFy;;#Vl z9_FnBeA1ANFBWj^YC{^C+#&E56I=aJet@@!V{t42qmk3Jev1{TBY&v*H#PZS@};e` zJ^6xz;l`$nNu~(CXSz?@(FjVRma&Wjm?-VY`EE{*7Vm`02&UY`a4=%HOZW;2g2uWa z)OVL9`(kOqS%^~?U4oV%E-}=j_qj43c0ivYsmRIQ@q#kC2ilclsJG%~=6X>4<17hN z8~7P03dNvX6qPAZcyKGKQ4J61=P;%xL!w`Mfj#s?9?6bw^oHjauA%hMRR@nOj(r>U z1rylEO7L>+F5st}#c`(?G^C-#DS^fzJ*9);3LU2_y3;+#eI;re&&FsI0zGkh6O9ZSr8xnub19+ZV}_IGfMxxS1rbcU;Qw2TA1kw6 z1p+0s$TgpS#<1v8y~J4OnoZLJ1Q}mXNU=HL^Y!T7obWk%;%;<>)BJASn+&XgI1>Iv z$+Q#mP0uY`xpF)aYX~j&XCh2(DR(YB^+pOG0AX0=qxse`Xw>M+Ie@&#;&yA%_^T0- z8kRWk&7?ev?op{ZbBX0=MhCwjo)I^!O+dw9Z7I9xajLa6q%^M?n^F90RF}xg|DNNi``3lDD~def9;ses zdU;IyN``@MLyinJUM`MAoJDNa6Zt^&3=yYZ$w^K z@fajK{%_`aH@iV4hM~+-x5kcyi=K zJ(1n}M|9W#b~}w+Z1XdwGr=A1{&(ahr287L8R;H3e?1zVQSz_woP)Q&%7*{PRi8qG z1o$6K`1kv4U44fXzJ0dt<1L7F+Cw694aRk@zQm-{A7`JBrhUBPQ|q&j?>;_~``Nlr zd+7T-9#SlRP&_EC~Q&(xpC<1lm@}wmlB-z@(&S zg|zw&W!U`)bLda-P0VAkPT|G1L-fQ+Gj?W!bAKA{WOhP}$pw%53R;N7#3C$0uy)z2 z7eEcX3al5m)2^9(LVd5)cKkUu{FAr+SRyWRU4bH=MC zf33rMqg^Nw@s#?zh0kPtVAosCy=W<`eBsNjLfx77y$2JMeCEwJqBY4$Ip+0Cc0dQR z+uU{E4m59Qk)DizQEm@wQ1-LeM*%FsM5GAZth*lF;tLv)BDAc;Ul;Di3je|i4ZFg& z?g}0Flo~g6uYW(yp9Nl2!iYo~z!#Qcy}TE{xE zM&D{Kv#b4h1BM$Ykh+f+N{kBN2ybz(Uk$ux`?a~*$?k0+e!}lYGW!9%E=i9cIt1Lg z9f79ju^s3OZgxp#--K_LOS~$83^Q8WTBRqu&ZU|l*?TZzwSw$o^$0R;ZT4k&@DH!Q zOuy>s*V6Rs0Q=Sa_Ik8G*>B64sD28nN7dipU8+vehs);jEzCIl(=ZTFr;W#8oQLZ@ zLItKEr+=LmJ4VEiDySqx??+2at#no43eXgeyK_hC;p$MqH#%2y|6+SNeDC6=@KdN8 z%8c(q$&${#vVt#kBdhb}$-X`wiTsWs z@ivGQ=k+PJn1w(_-j70U8|b$T>;8#IHv;mIb3L=zbV)yfn3Czl3Nnz6`SmL?M3Apg zM`TX@{PcLe1=D~2O{R6R(IwwJo?xRagw0Uz5~~Pt)T{W{>Dpin--*jODD|rW<&ziD z&iZxt9AxV+l)>CiLGusnS+sj7(fiKtvfa1GLg3*{dT%~;3qbz$pi4sUuXPYi68Cfu zOp%spu@6yYAUW6@O8y2bHe-u1usgIq=H;*NXk0|qsCm;LcR;4bq7J=Y7E0cpV}5@F z)tdkwLP~vRK9VxaZHv&m=tQ3ojBRzEaLq_p&Gt^@X1J=VEpF$eyE`E0$pcOhy7i9I}NM`Qip_2fOE=M82U@=yI^ zuz!(6^$(e&&|VUkZY;6>w%&PPW_3WNY4#!TWgBvW2DqJX9u>B(IY8nOrNV7`Jy?3t zY>J9-*5MFL_Y_KTqDf8KrfG~+0Ihp$0iRsj>klK+a z$ZcKqZ>n?E{{RR8^^g0c#riwC>aY4-4a-m0|F3(~_5TN{o%#!_qy_9fv=}q13<%Z9 zY+tGwZO!-JAeLawV9&pV8~c1OOG%wxwe{B|njg@AtT5J~G#v{apDOaT^-j;)>Ph16 z=H2KWG;=5yH(4LJJ*(20&61yJPshV+&%|_*sy)}W)E?+N-{X?=L+U%hHF&@zWGtge z{BTJ8AktWVB@mq)jY`j1@(v=%kjiyE(S}Qv?q=KTNc$0_2Zw?3vdq6xi~b6HTlTRmLgENGYcF1rKv(jDtmfCyE!?h{Im%>ob!&`_UV`PzM4MLO++Twvu% zF-m?8`6He?yQ2xxM)0@9g=k|iT9ai?A#4F0$iGG{(~aLCRR!jA&B+QaS|FNNqYs(< z!`Tm5Y2yc6UV)z8l_L`hKT7h)>QMb)T5XCIXp3M)p7|Z>FEjdLViT;m0M@@+6rw$P zg*_}S`kf5*H)5UzB{9t3= ziTE@thAaMwH3B&y2-_TiAg(`pU&SY;>Luo-2m*tnQQo6?&|KX$=a4VD@}Feq-^pQ8 z`P(xH*{C2{BJ&||#kSED8;T(zV+k6d>&DP|f;~pr%PvMzx?C`(w92d+#zG;tl~%$G z@kzKJ1}QGql>uTwwI1ED?Wax7+-8kh{B{yKbX{5~F>xMXu1D*(q1;)b6N{tZP@jn} zkDII~OXneYcADdd61TrB7+F^EBlg72|NROp5;Ov0QtV|8rLhb#dLl9#D}`Cu)Y6TQ zkuGEmonwx~2!#?u=O`q6n$1s?&7+_iW0lxildKb8F72Gyr35>2`>*O+JusKc>_@#0*7u6aw&UJ74$cbdyzeiUx?wa|10qU?RnWM z6Xd8ssgPlZ&I=io;CMBXfEDv8ut%F) z)oztNUk2flMAE{pESS)9tWBujUKh1o-bRelVU%|>k{__VZim;t!3S&Kpu=llZDx6( zKM_ANHNjMh)eiP?(FS_MYYxY^c5rShynr^%8{dP7lYDEHB-mn}|B8}}Kj9M`#HE&@ z?~Yvh?zrqqxAf!4n}MrB$+;|s)4>N67xsa~chZ^_e8u#?Kv5qP^lo$If20mEk1+pm z%^qP4SldEYRB8d?54#5EWy`Wy*Gg(#yvC{TVDVT_Qho^-GCzGF%S6>G0P1^84`>!x zy8AGNf)xQovFKPcGGR|6HpY(iM6Sp3Zc;%_YwRFEe)B}S&&xt8rJTOo40$(o7@TL+ znE3*;!{$1Fpq=SQ-G1SSYzyC$JN!!TbkpcNRpcVl$X{ zG0Q}H=uxo#EybE*dzpWm7R|?;%sWVZ$N;s-AaBsWOq+sM9}KMTp&Yba|Flhoxjn9*{OjarK`Ne^cdA=0e|wqX7gd54SQtD98YZ zgwZF^#vs5F!oZ+PZ8|-5rSMRTam6a`x@4UgG}c?AP*%EpsTqTy`VVxO)D?XX-|E6F zs|sZhAn_mBRpUeHj8w)m#;M9ASc|tsYB8g*e%$A(shj{gJ(XCCeS%m?f{4j)N@nX5 zR3Nlrtw*ex4F-y)%HUaT5l6lakU%?TUANj}@7nR1ojSM3>yElIR z4T1zY>zU*X{L4)CfSoL@kg)#L&$a(dx}SC($Pct%mUvZYKbRPl6YMi6SBrK=ZrFZn z3qg_eROZ7i(cDE#_ZTLd+H~%;ieO8<40U8}faqn3LAX8hv5*-#U+@a6a3-*JJK- zN@)j&60MVvL-1RlC%Gm6GA%}>S81#;003}ktna=lt zCI^t2uSkEx373k{mhc;BN4%@xDHVRM3ai7N9eG8Er!>{s)F3(hD`*VLu|5Ee2%V?W z`5W%MmKIt9CVcb&bYv_op4dTSv{+xXC0(C%$?A?Ut^**-8N0#GR2H6YPX$>#*y4N% ze~Nt|@sn~m`1KFD@|RnEkl0Ly;3o}L#`htiY$3|m7JkuMWG+1qeJSnl`ji^V6z1Nim0YsD(_StqFn^dAL84$`YQlUXn-ivvolL#YKoCu?5RH$M z5_c_#AX;oR0t>(8{5-y=Hn)0L$sli@7AKE|@fl{?ft+b&8w9fGH(t(VoW~qm`2Yz+ z-o-&&?t<{~M_buMbMkXeT>iy(w#WUqyGkze=7qn7qBexp2%K+F1zpc7pzsNL-`BnG z>L8J5SLU7T)BD_pmOc1e40NC-D__7PJ*q9qhKL5G?uD-Kax++4(pAF2nj-MEUBNU9 zDUIj};{MhSivs906XUKB=in4&Q61+fV72BuMuGbC3Rt7hsc2uw~w zl`LK6W;-BDwLQeU6s(KU^fwUT5wg1kt?fI;S2=V3kVE$e&98+2-hv-s5&*c}~oT zZp@0-w8BBsG}J_y;pF8Qx$q-gDwTW+5=ntv>^U+^codCr_?gpGfds5pehFBhkno~( z0cvR6O&Ed#q$c`!N+$$vVhr60&qBOerxSF9+K^mp5<*<`82qm@NiKmwh;?J?Q|8Pb z_*CP|ERH*tpqkT$%c8-+WsUO4kRwwY9r_8@xyT6)ENM4Z@NPx-VlsBfZyV77< z!d9SFpDC&9b`&A}DlH!`Rxv{mla?o>omZfF($1$)2rX=UAS!fk(v8l5%UD|)aMGp+ ziAQZJ^+ICwB%hO-tB&{v5La|%mh}mq>H1RgDkdm2q*4l&&9NAYAe2(_JeCx8XJ)(V zrI_IKdfacptFlxRxSG(W$4Sv?B-LWW5MWVsPSJ6?eCv6HtK5^WcXCNrqywiSR+xfy zEYmp+D|Y}Sc-RF|PFB(EY@{&UI#sa1Y4X!js`VAAd~bQn+hRDAV*NKKff0cIswWtB-4JiK75UYvY`ygVauAztrAt7Olz-`ff%#jKfB*e6 z<=@9pCh6{{_N6pMYAg@fX4C(xRm^@idp5pX?OK`@Zd>C$ol69xcFHD-N>dv78x98MoqHCb zl>9@h(ItjAwkC23&X;;|MOC=OsGjnLr%z501=4>++&igQvBrY2|_C z2jn%~SQ%Rr?lJ8b*c-)+&ldDwa(v9!VVDUH%I zIRdaTFc4|lbCN$DfsvC_`VVbxR(oa*XBQW33x9_no=&)|v0~4}@xJ1s^R=fIp9;Nh zYDX2vtYy2q{$FYNg<3@VVM| ztMFj{EZ7_}^7DhyecJdEZq!Bhc_SBSb4xwb+Hy;d8)wES-+-E|Gcgrm3QQ^VBH;Te z!@**hCwvwDp#H>4vD(;JxW*iE_C73ExU~k&1Ga>?z}SF&N^@^9#R)08{ux+pTr(4k zoUb2+d*^MJC|)0c_VlBat;YB0elyK((D=&yL%Y3=i;hAku$sy-pYfA(VN0mSoYfzN zefcQ>MXf8`KP)p}n@Oea1!w{#noXZknBEjX#O5cPX?u@C$8f;LUMnmyueO_oeIe_S z#hDY1*e47%cA8;SXKaBDN3C_&$1eSsEq_8E6H5L*M`>ZW815RX}FDXdRXw}mCZYg?! z9V-sR!!YKUf_)%J*0+oZ#NvTLXe|ukwwSMBOc-32I48e8X3p)4&tyOC5unoJ54(p* z;D2cNwEEBcT=+EPBGw@Iqyrx2BN){*KHc<)8=oG-;M@50gdD@mAe5%~)DDeR)Vs_Y zQsr(e_zfeR{lQRje2%Thvk_*v3t38+2NMBbd=0UsD$<_^7;S7xcDdht7S2E*qAgF+ zD^6Hb6v3_;vBmAILB@%84#r33KiBarz<%P)hK~ei;E$SEmYe`3Sm|u@#m7O`wWU=Y zTTx{X#LxmTrE_3hhSLlfKWwSZ)<^L;9=7_D10Y^FPErbhI$vOqaz{&UF?PW9ia18m z3*MpR7{3wqhT!rqfhus`M}skBm3UT3mcFbfxuqAG7EE@GqGBvVhJ}o>*}n=IpKz-Y zI^$WoF|iU&Yb?k5v2-5y9kDhpgZEF^eFBq8=a^%G(pY@V#v)`6&`ef5wdQYolMra7 zHOIV+NROOMb@lZ@|7tDv0y+-%gcZje2M*@zz?C3e#dB{n*(;tUNvffFK9=lH_Gg0y zRqzo5uP{rS_Z@-g`zGZRWFPIp+rSM(-v-!K+?KELjG%XQW27<|{dya%JQAg|g2{02 zePxDq6*gL@HI`$uyI1~jsG+Vw6Xub6o?H1NR9K)ig%%tnp+BOA!8j`EmHtMYOmJmy zjs*)n40`#lwVVH*-YZ2fxqzBE>O(iZ^saQ%%gw+tn_h0?iPy}Dr769949?`x%LOn^ zPEVE&y@3Dj_#nl9_uwdJil0b-Qrhs4GSbMj(;?4YGogJD%gE>i(-Y~X$lUy5<<2He z)8ZC~7W1Bq<2rK5_W|Pr^L8|&MDg6G-&Z{M-`H@#6m<{KaE#B~2UOw4AQgGb%>C!v zxVFsvlKh4YHzC-w)%-Q^5Q}j#$N}Pgs1Uho&BW_FfosdKyoS2!2X7b`RB(k)rZ}5Z zAQU@&dYro~+Y>n_XmrdM9TngN^R9>XX5*pf)^8HI21fDIN^|R1D>(yeHqosGjS(Jj z@sn~r^;PB#Y*VsdPe|S7z$AqX;ZKJ+KTr9io1eBuS8aaUfMU&o1W#&y?mFF#AA^BA zHhzR)NO=(ac;mt}ew_YROZZ{iTLgxd@$@dXXSpSk$xEByK#^?NZZf~!PaMc#qhAX< zY|cj2dLv-KWLn7kov_J7DR@7$S1_wD5l#t4Sy7I2Q+arqHyr%^ z8a+AmC3A##7X~LQU-mj({IHh%a3olo%*Uc0)L|fxp%r2L>{E0o(Ry~nKvE3?c^q0W z+66iGJv(ia1jy}e^@3%3YZzGi7l%(3JN_-^t}~bur~6?|qxZ9vfWWboP1sTpUsAhkY!fgT`__aXG48IljG0>N$TOb<5j9(($Kx zY#OHSmwy7<-kk>(v(l$ae^J3=bXQc{>@yDaa|xn){pPvNdflXbA;=}6L}z*yDA>+6 zgwEDz^pqKg>33ahN~9bjbx)Uj?YM5AC>j!G8>(3*fDnqFo^|K?8ajJy7F4qfyl}liAzKRg-%Au3P`dgJ|$9kqGz#_0MkZRG4 z@3E0@{`nNto&u0PKHE#Rg;f|M>-HY*(X;t$Mt_6U<+Rl0^HCuHXLorj>OzDc*aPRum-a{pI-2;p6vJr<}4PZ``-?q zt`~qz*3(+oT>1pdby2jVUp2=0l#!zlyW4ayH9kOu0Em_3%%ZI#SUR}zHItr^0_W(_ zfD~Q(aC4bW*Z+jZTIhN_w!+O*PIBX3s=lECoLKq^@)jVy{#-L4x!a@Y8(z(}34;MA z0vrevF8K3deid7} zAcP*MHO*~O{KSFhA(j6I&@Wy7xvKmtRr&88f8^y~ol*Wu7%-##JN_)~zy1H9{5`IeYWpYbgN*$ZIxgKIEc)MG__W8?c{hG`ljw=+{`f&!q5ySD2?r+Gg zX@%{$&$TEC9?th@S6cvq;Ro-eB4}bUk3bS?EFYK4br1Hrs^_?Kr?m=32X%+P48$Up+;HUoeB33X2sIGs|NhQ@qt^Na z@m`y|%~Af2LCKNjff{U8UW;{0%GOZnQ&ZbGtbe^zdi}p0{*`EpZUCN)u5y}Zo$Bas zn!!W3CXT@q7JUX|zj7ylQIg<+y#O0B*a8Dc`=8)$g2<7}1VY~sJjpI`B*FILQr$ZQ z{W1wAduJRzJXj2!9bms6-cfj-5PShnN+!PoojQOusOPvVN(@M4P|3prIA{#&uKPb6 zcN0bcX8*cDk1F)H#GPdrOpJR5t*ifs-QQ+lvcu8361p?R_z|9A9A`w`XoDJu5AXP^ zns1$kme)Tn{yTIu*rMw@yBxxcA{C6yU?CC0YK_`-nDe#n20jEuPHPyF$zfWxo?!Zv zeXAawoCD1{zbvNfs2UWdkkyVO22$%_$T)C63N!zFljD!82r9x1^_D!9E09wWhb zq=GxB;IR^XZ7R5<3Z5XrC8^*}5*)7phDyv?sTg{B)Q$KwCnhHq<5e+YO+rxaI?aJX zD-|=#$@9NdOluW0+lg76ipf$j+*X$s%t^&$tC*LanCYpQHY#SG6BACw9Is-koS17; zF(;^)EW zS(u7BRmC(oG0&!APE#@BCXBFtAQf}EilL`Mf!o+rOumZAabm7Y#hjsHa-EpIshFcw zOr8^SS}I0UF?16m_4raTIVy(EJ|$*Lo&$rRWW0nn4(lnu8JA!#GLHJ@EZ6<$Enx} zh&8hqV?-;M5<3=LE6e<2-Z}*eo@A%Iqu_uc+4Wc)R3^s~=4|N2h-t?dL)Y=@Rjv#bnWGk9r-0*Inv$EM9l2*9mz2US6RGHp;Pa*>&+dtYcaQQ774Hql(N!WOqdF zhMa>)q10rj)heo653@G05V&L=dH>~xfh6O2lB zRVkTI=WzQu(teJypJVOk1of<_;1hp(ZN)V8#@EX9>#X$a?DXrL z^y|y%*LmsJs`Tsf^y{kh>$>!7UHa8bzivyvHl$xY03iR+NMefpnv;Gd9@wFI=~s@j z9m+wqUpa>MD~HT})zh!#>DS@u*OBR0;)|VaZ2FbhV24)NuQe6Z_y%s0W3AmKTLLBO zJb8=q*SM3xpdf$QK1UsYCbqn$PB**6uY8yI#p4Z1{5t9_Tl`uyLU7mRB(|wB_sG+ z6>GJ^Z4;BvEXMsQyhJls4ZBe(wKQqM$CmOh9qa+m=SZ4ikZ!r z!5J|{Dux7U_Q;6ws~FO!c}zyk#VUs6YVOH(_x>^!Q^lC|88Mfu7!tF&EF-2|#gMkm z7cye5P%$KR^P!BGU#XZn#*EL18KPpy2+R=~F;}V>@&$8XM$AwZLpEU+WW-#hVmzQd zQ_F}Mreb`I*?FuR2E$bhd5ZaIM$FYJhAhUc&WIVHV)7XCd`8Sb71NzD$&8p16+?bx zj?0KCRWW2w=G7T7gH%j0WBO;r3|28ZW6sEk(Nzq2nb{#DCa7Y_+RX2M;fBGbDrO{O zKFWysrHUEDm<1UzAr(VDXg-q>Q>J3b7EJ>&RB2(o8!{>?5QHfb&KH#YRX<+jFTJhE zUlX%AVQ0u+7c)l5Uwzao<*$%>9f{XJNgkc@*T2*&<*)y$SIS>~C9NZHeIgOlNT%sH zk|w?`Q7K7|_$pRkv(?uC^+mEnT#5Q3so`so`XYJZOZs9=t5RPNtNKVrh%drR2mv!Mp~dV4aE_s3P-hIq|F4kj0or(m+lHqjI;L*jg1$3PFM%^3_EC zDpqYFK_JOB>Wf5xuiMlY5g%Xot1luuzV_jG6Y3^{<7>bAB2weaqpBq$y5}h+6o{k*`XfUy!N!u#qc z{<`XNk-vsL`v1#c08nj3oxnz3$#(gNP$Com@Jh7dA6`9xsr^b!v0sTM_A7D3e$7k2 z5)Y3>UMkV@@^?RfWPn&)}_tL<9-9S6?dm>G0lw~J#xc~ER(DLc5%tm*&+As}{R zx7wv&1Ux?YlMOF-`bw4FTuxI$=9|$gvo>2kR#u8b^yCew=M?7{ObrguvsATm?xH*$xe;%LnDdqb0s3wX-@g*pEAugobz>b zzJtT-YzX&gKM0J z+QegP9rj?~6Be+3M}Q7+!38y5d^K2Eidq|n^SUfAeXQL~cE+5KrsctJN#PpI%7ET2 zQZ`(^sIqCsr;3)z4K_SZ$yh_El3`@WeMj2dy9*zA>254F`sRn=cw?f^fZkUqWOj4!;$7UyUM zbi~>b1K^^!-|Gm+$s+4AgjXs&NP~Hs2VfrGd0(SNle5v4a>Pgm3mdDAtK^uMx#{SX zMNfTK8&}dD`?xTpV{hA^cE{f0C+t-RUZ@s(K(qQfmQlac;WzLXxL{qj<1g^H|Hy9c zFYrmko2v$;`~{XG5dcAdfn6VZ7VpX4=QAkTug?##6ltSzSo__~T#pYH$R6Y5Nb?$} zenD#+rF|yPKZfYlWxcqCfJYZ|aB@Ef$DGMZ)u7N)1a2_JegIj&OPo)i7l~i_%;Qz! zx6+BRc1`VRv*(%VVZh146F;5a@kdBM7PORVW__)Lio!!3#(>=n8cP7H+sekfS#%+f z&wOehA8*U!<519-xQxfO_}3so05sQSNXIjol}*zvu+yb6(6UOf2kG$lAdGBy4#>-8dAe|FO`a{U3^PC&D=m46l1U8IkU^x-Q?V{oJ}4biG!?jzlc8ygy}*M!r9PXjNovjv#KJt&WTEtWHI zXcx~{A1$Y>tXx!p0>iJQE0HYqPp9!Cz5i&~=izw%BONapEZm7lkh5O*exVlYhX?^4 zfM`vUk5bM_+<;wdRiG&Ic+du0p*3j*nhZ3cF*uL5C@Pl|V5iK)q~MG%!;cgn=iPj8 zeEi}N@llMSMZ@TrP+Kb^hlG#6Lk;%1%?xz3;cDX}E`G%5!|@St62~HORtrYcbWr=Y z*bn%(11~>R{tE;zlN}!tub*Yg03U9XwELH%ghXfJ<-aoVON%!mN{%2sh?f>{Qn@|i zIH!&up`7rIf|r%Z(;P3qX^SIQ|7-y-_l&!PCbiYraxIfB*B2b(99Lii!pg?b3tkaJ zo=I1#@buvfehX< zAlc);?`Fea9Gu-hfXuXN2P6PE2pnclb`kRo1StU8zcn&|Uzoj8K8WsSh44Y7W)qAd zs_$_ZO2n07xwLt}j8UrWq93*CGTN{F&xHSlZumdXS~YWW0`UK{z`wcuv~>fTQ|TI) zT2pH;VnQAK3W+~hTfQF(q2g5_AB_>4qY(^9d7g4rqy!i>b9ze{)&DVIRB0288lJ+a zS?6(i6GPw0SzrYKi1ZS#OpyziXhdUOir)g?Mq;huiF9-K_gRH+GcZ8)vrN5R+8)N$ zzmFXGMy%zMy;twHFR9_JL#Gt--k~srOxRc+ivn;YTDjB1D1hI%=?NF>D(?}I&O!gS zJ4JKG-Iy{&M~65apZogE-fic44WDQy89-)-w3Fcw33A4K#W?HCPTEaTVMH@R_~ zVQEo@1fAvq86n)GFrX9c?Oe>zZsO4hK`d{PY z;M#hlI=HqDZ|&9w*IGbIWL>+FZtmXJ*8(`(g1f)RVObO!++Bw=BX^uog0Hok;52<) zHokG`xPh)v0apyf8`P-Y)%YknLv6^9f4D-ZDsn;)ogRd0f^6X`K*7Zy5bEDH{@Woz zZNWM{`h9=gN%l*GX!or_>x2G1>OM_YR)GMV(_7&J0*XWP(HQBwf&j{|e=3a+qm~2& z5XQ#=)5_BDQX(bSr)|!OI7kCY}s}dl5!_bXR93X*S3#2~`?*4*Ak1qK?yrXRd zlT+=ujhZ05Y*LRe)Z#7fWY>|%Rez? z14k=#1NURVl}fasv%2>xP%+<2y(DJbF4e(AFL)5hMmhw0Bsj7F%oW!z*W#?8HnX}o z_Fi})UB$nF)2ba?Mfdo|TgGw}$VUqB`6@ zQ1OQ9aob?@F5GxiL~&6n6Kb2MYRjqU*M&7`@y!VojbqejPZ1HNb;T;c z&AOBPcStdWP%ZWzQUrimpcWX5;&f@WZfu~Up{EwR2Ml4nAMbgQQK3ZT9OOin@~|Hl zCe>+uJ8DxOVd=@P$73Afg;5`sbsr?IOB(AG->+yWj$De2l0*_;Z;V`hSK~G>J zDn`FLyX?8NsU;|`cvsCxEq*cHN(Up2cJEfE?8vwhF6Q?v}MLmYuSho{VH_=VdX`FW^8B`XD&Imy4w_bH4=_ zxuIl_vCzm6y$G+ z)=dW2L0|QDi;H886TU)c#~&TtR1B8~wN>mSq7fI}GB&!uvo<4!V)aqG$`T!S2X;+W z=-dIcNway7eiuyDcP!8LRP^l$^c;r7Wr=n{?`q?7_#~|7eaf);^+LFh*0xjaiSF;O z%{Uhclh=DuFub+w$O-!QX;bOAmKPNrjX3x+)kl4bdH#Pn`jn-FPI_5v&s)(g<PQ~6X+SFT+LYuoLII3hO{6-P%HXgDogC#rQS0lM9_MWay<+>{RO`D3n zCuvj9aWZH9G34Ebyg=T;IP8CK+t!u|e!wzXBMrfk9M)PNwFHKcOLM?#|AkVJcrtFB z{K#5>q|)4vrlPq+8j}Oz1gBOXwFZ}~CqnO|wPA|fVZ0e=yahc9(xBPHQ0(QckP6;x zl8+-ZF14W3jQ6Cu;$A|^oy>9v?iaA>vs7d+yM3b&hxVaDtG69gF3B4+l4m0>G|EPW zY-<;!z!C>DvgJ~ukhaK37` zC6Fh&0gUWEyrgLygO-mM<5=^Gv=pn-;;#Y)!LF7p zVP!d}Yz{IAH?VF-P4tL?+ds9Zsxf>ktSenXPpF^(gS<>-UC7t9U-0#8dA0bOC$D?> z+Lf<`lD0ix?ZO{bCG7@kIYCdVps!p(e^EiJ8FZ?YQA1qB$uc19pY+|3!m6!T7+WB* zb5tz-3DiQsg-mVDWRUifL>o-mPF^SR)o#m7Rm-giDoqH!j%4g^9JH#nhRQ2M{aWi% zyxMhFH}nq{RtF2Jt===KR#Mc(C0HUP%X$$yd;|m7Y+O?;#v2UwLUa9uF)Vz`3 zzDQRTNy7OEpVm>)t&LVY{$$~Yy0M_KKQ(1?gAcm-w)lT}4t|E^;RpAW!DyUsHy7jQ z_vKn=+$xB-@gwmwd92nslwXdwsTG*K@SH(0O6z=O{z$F!b@^iv^4M$@^A}FmTIXl; zE9Cj2T!Wx>el>r#e9zBU@v;0W`F=2el{_EKuaoB!`P=Z+6H}}3K(Wu;&zG1C->=u< zscUc6UBWuBRe-u)%;#Pw>&U}%T>Fao`KRE;gL`~n{yqU*e-AiKz!AS8RNk+IO050! zg0+K+kk*r^C`KN7thk=bsD%VV8MeC?e-OFK=$!zig<8+zc5D4Lm>(N(J?qm*DiNenJu#1iV$Xjq zjK9rKs0b;>#m0pz%-z^74Ps4{%;Q|A;^{;qq904B&z!_ln4;uGN{FJ4Hr%UpY zb@bu4|Dl~=e5_qMVdD>cI-^nbd8zpb2Tvr8w=R|99HcwXTi7T+-mWnz4aQf2yTVv1sjLoj15$)8}oiz&`p$)vSYNLKt4 zA-gB`DWT8A{RD72M#tv8cLBY)qrFqMv!NCg&oxf_f{90k*7Zb!Rs^^pynnFuqv}Q! z|LSpNbcLH7<~3@f8>_I;DGr~E--_@U{KBt6-}AJoWoQME@qQ)hMeF**aY%F|%Yv5; z?zu!+aLB*)jz{RdB*S${vB#)Jj_4QtEB16AKT5|fp2$^O(i*)0J-&_oMQC}qvS0hdC)i{AgtrL8H3ehYDrOx<=TX=DU{<%mJ_18 zEL(0~^BqgAg|gb|tK2&&qLc%PXl<)BC@lKx(q4z8m5y%hie8QAL`H13EA|z{@*?8c z)os{@hO)#WBETC3Xg`}_e9pDL5oI7dOTD?CkWV|!dT6$gCS=UB)4&gmbsdrs7zgTq zw6XK}qvdM!WL6)*6(S+3$YHks$KJnyMOCeT;P_S`F|EPUGP~^x3saEcCYUA&V>2}< z36_;M4luwZFfUf{VgvKs)P6coiMK39f=n;&Ie6Yj7GQMdoYj?Yd6E-VM9fKI~<=AK%<-0xDK2HvQ~Z>J~^uAu%B zq@e11w{UT$q#jGoM;1hX`(+qMfvDM>kFpk&$Pa5 zgc5qX^~>O1&D1q2XOA2Y{O+N^OgGZqgMoZPj(lt6Dn#QH|9*s1=sz@C zxxYUW*01{|vLz>(wc$QoGQ4R(uce13XZN;{k?ngs6Axg`@@u2=yLrWtQS)!c27tsfPq?J4gljg=7t>|YA&3s6L zn;i_EH)Cm*SHI3X26IY1CGW~qnpoV3(;s+WO%A*gA#yz~s1xkX3qz4E(lBI`!E+}D zVmrN?TK~XI{OsNqkRE{zWo^g?W)o*eXVyy*n)~lXO=Z0gjn5PL{Q3cvy0MM*KSp=c zG{oZrM87`eUe|S$-RdTLJ(>~BO71rF#spmxwbKj}C;&koSmpNXROy!?*rukt@gG{r z`Sr(V;8_h=p!zj}abKfRgwBo`9o$;pn!@naAD^gcd;($WkLTh2ZuXI{X?&J_jMX$v zKnDs`6b<)uURHnH=-Pr^I1CNc{s$INVw$(|k$`JA(?bR!Mi!lp_p#d#(W8b7vnEH-;<=YJtn=g|nikD2#?g5!=BegD0ye@x19lMR}tBy;FJVdw;{^Wm6Mn zuLqci+e$~J>peGt#hS*oq@cM!_DzII@&;ZLpNVrmJGrrP+tfs(sUE&*aN+GJZDoWS z{43i==>75+$^cykOjCQHpK7Qt$sZpxdQC6c_e!eXzU&s#)>XF1tg znlg!X3%;HQdO1S?ODVlW%@lb;ZX*U<=jK>_sD}sEj-q8k38p|3Gp-+V~G_5iRxpK@U+o>PP3p3NrH%gI;%tZfoLeNxe2T1y)8W zZTDVuZ&WAo2MToQde}2zVZw;-bn?K@`y1V0;(nHqc<%STz5L8ymRs9yeBU<8^K<<;Dx#Sj3H|xiOy`4{_rGZrsO>S=^}RMim*pXw)-R z7f08>&zY2jya5Pc*QnmRmLYmIlfh{VZpWXAU_o6G^9rt^9`muPw_;h!Mz=A zKOWFw57A588jkkTG(LsE4M(G0P8~Hw3t;1^dh36qBpYLE35y$7AnlH9nALyaS(?UM zkV#s}e|Sy>L;=f9{Xb}9x58vPF@G7c9XJHnxmf5 z9gBT|a%8;^guRiFAQx;|W=QLIzVm@+9^We|&(^e0Vhqh!_=sy+@TT}c#!tOx3JG>( zEG)jr;?X+UUhgHou6RuQ{uz(Oa^kU} zxnLt^f#v!`Yq3$B%~*>)=ND|ot{>F{s1HtO%r>|eFlO^x)ln~k^D#)B59h^Mw3a2v zrI6!3s_uW#ZK1o2YyE+@KWsl8_BgSnmu5<=s13M}D2v1>{=gdXfbop3B+xaD(FJu2 zd(2hUgYEamd^rg-+iwztKT*by^C3WltHu*MCv%w|Yt*BVLIeeN_v0z}KpcAlI$1nsB6Jk z_L>&$+d~Jh&b_=p4(X9-sOg~&#BWCvjx9K>70)-|@_D+x?cP1LC^Nd0*TWYbuq4Cg zwqC`D(fuGF9uQgdLle%&2i^w{@;3ZUxHhbgO#~9?oUFaTYoBXdFH`iKmYj_uMP=H3 z!#dD@^gQRaxX=56`B4W}wyeWk}>DNRE5p2a;?!0CjbM{Q*&P}_xvu7W3 zUQh*RO}}UBx$gpjo6oYv<9W*Jt@2SQjQ~(E>Uh)U5G#PdATxj%y6f7v#Ek;W!UF zz2WaS&0VO0i`4`4Na`$CI`@aBLqi6H7rZ@rk}eM}-P&$! zw(P>wyI$NSybn+I9^H%rucu(F1&lAH7Es?je`6kEw>8njjjX4Mio=)SI;VbA1X_Tz zC>V7#3n&qGhu1u&Pq!}g_a`VHCKUSS1;i4ppT$rz=<(pwLUn@ARN#0;6JeJL+-pS)OkCVG5TUE& z(DQicrbO5^{XEN=v8G=3UBnVuu$H^dlU+q-eRdl&mh582vVF{0!3%y3FZd=Zcp^TN zd3s0yywjjkP{-6X12%Agc0cspP8?W44AeKTA&l5U>BUXQG^jZTJ%KX{t6B7B^Q3Lz z3Qpf#ff~EzHc8cA1nT1oLdX_dSdFBsios{nNLd9uN{R+mz;PHIgIc*DekH;wS1=b) zwqQO>`O3vXwHQ?CZQN~%oXKUBI|!TsPlOLd*cF-Fe@z}tloSQmdlt~t9(`P0tPA#W>wk@vX!?t7*vo50-+2OlvIkT>yjoOs%T4r672`e=Z z%f^e+ejH`&*E4yW1Q{k+j*B4PngpbPT z08J#GX&JHpS1BJV6QgIvHc(B^IV@v^#mi`KesBRTK{rCYqae8M8=qkdNaiwz!3Ysl zJaRD*mokwaOu2NFa$v4@_uncNSD`lzGbF60 zyi~}pHz&<)H(l`Eydby~069YS5px%SD4Ch%xg$pryXA~N}gG>D7gAIAVdKW3VY%%+D+5QD36)J0U z(LtWEtg-PK*T1mg6P+@;ml)om1or2v`*PCT)%`i!2Ljcfa>jdbWClI>v(q4jbYPS# zMZ^PdB(h8K<)O?13}w`cJ|E>^*ts)H`kMMY(k{5xU(dS(ng*ToJ!PJri06Z!)dMCY z#j{-Jp&vVnG!as0eU{~m^;7ewDg6{t)YfzjLi2tq9batQ$8-MO7`>84lKPDC(KS6U!dU^ozMFNcv1qfwjiv2u zkFj@;tVufeMz*lcPde(|DX}>j>t>a-&gT7puE!Y}orB{gec9t0m?A>k6B$cKZ>4Q) z>{SFmaLC{@X!QS{;7Qq{$5sFYq07gc)1+-pYwMEeZp-HLJ;r$Kg}4A`Y_l>xnSH6T z=o5X>I*+vnR+=LWo=YNgGJc=+u=|tNRnU8(3gePAC3AuM!TEUE4sFdp#$)HBu?=01 zw=LKvdyGg>mio_Hu>rA`o+1KY+~4Z3ZJtis(vvt|+KT{Rhc}1bxXpqxZYbJ`@$GEP z^45cM=w=GOhhD0S$#QR}{aO@@jz6;ZS90Km*xr8vOVf9Az6d2Y!0vfCHetZ+z3#6u zFP-PS8Al~(aKtxO|K&~;uxG$+AJc4T(8lUaq<;a9MzDR){oThJeyFNHMth&P;<9?$ zpDP-0sG7z~de2z(W@`*^xEw%mlprksnzspG&(?p)`D5rKTmPmnBKOGF$CZ3*-sb_E zINz|4AGALjlgn&_bguhfS(wo`unh#p-kc<1X-vYL4%XwiE1RzhBi0WAovK-<6$q#eXTOw1k8RDj=3ylSEDC8GRJ)qPr&55HyScN zbQWU_>ZQ4LRMXKcGmW@wMsRPWrH=cM6iz3M68U?Xnz_%xVN{~al8Y@xFby<{?1II&TCjQBKBD=UG|x##j*>8tAQAPkuBe+DQlT-VG%+v;L&y zoay%RwUnj{kUiuPvrd=ei~566d77przz5E>J_dQCd4IyM=W^-ar_bj7x8Clb_s?o; znWkx41BccPgeOz;)>kEidmUZ3JEHftk}Nlf_R*06yjVaRP9ZFOyh@ph_FWAhSstk@ zU_;A~4@j?kR*%hk`3tJ`2j4^_<;%st;PR&S-#>wfhG|a>cFKsHJ4Z)JPABdAsj5E? z?%s=RRom*1C%SIO@G3@5-*XEZQS5O0#Y_8IHE-V|5)Y}Hqz%v|>-I(p6mrv zxudxxmO2{H8$+#jpuHxczXEq3x4yvfzXUEVybWAx<#wbT-TD`w8&3ZIi~6H>y=QhL zD*ItJ9gS@0i^fIjhqQQ4P{N)`(VDlA9ZloQ$OQI4QTvE2ZGufRcM<;AA4}9U-H#6g zNsX#LyMOSOktPh;)O%(!lrJ%q`5dM5#sE5sUu^*@S0Y10{StA(do^L8_gll~9^vYb z<+*N!41KE9TiC~H+kCT7v?L$Iho>e7_&|0y*+1rdq4c8J6%s0Y>%Be;!uY1)pNyC4 zx4i$A?h28)6{i$BvB(Nd!M$GdmRBiwJsdQ1KSGT|;cJ>+#)q-l7Q^`8j7C$UM&d=} zo$|}-FqRTw&1xGbVq-hiN2BK^tOu{l#re8MI){yCcIkoLXzvtohV70YB|))3vW>3* zyN(!Bz<+~&%dT=%DV_owMLSWD(cLcA%!o1$(O}AU{}fY#N4`@{)h+cBOoeM><=5TW(=T zgQ0Jrb3}=*h8@|{X@94ejYOgqm5I?sG~x1-9T?GpqyQmJH3$VV&?eR4YgC@|J)a9` z{OO>9S`J!)(>DPviR@1DGakWOf93K5#$ppJF}Cq#gbHOv&I1J~EE5t(hl5Yw0fs7* z$v0~?wQcWH%gjm@X?c?omK7}ChID`G`(6$Y!HM?KISiQ&1YJY%d~d)_yOv$p;9D^X zLc1LQpuei+^-Gf1gJ`6JM?3eLUYUf7CywAzVPJe}g3OeVwFdbGhG)2(3G)okRPtVe6V<+dny<^8Xp|Dp1p9R>%^k;`@9 zbE*Th3xLUgO&IwvBKiN^H=Ve%Y9i!+1^ru&f2t0fkLR;))w_?;eOYXakJ5%uZk`yY zZ_dJsRSz6~#3QO5*etB0B5IH>(#*Yz6_%{Hp@Y@Dee=K)YPjhR8ZeuwcAx9C-{H}g zuc#!m*if35<30U9gr;`|EBAXl@_u#}^KCB;c)~=J^C2|Jbb735RC6Nkxp953$Md4b z=03(An{W=>4v8v@)Au-R$nY68V}A#<ZmPCWlvK<_XQzMt-iaNin7w_d=$%jnL;Kx;A<>hz+~ooIBIMd#9?x1GpF zZbWtrw%23j6VD;v$=I=BGV6v_!V+k&AxD#0qptELxzsn`Eb6Zt;4&lS=DXuGjn4qL z-aVk096SS38AYkTJWRIN>yeC{FMZ3{ZNyEO+nMQ}h#}qjM4an({fLNL5Cf&5Z;48K zgtmb&q%Xp;B|DDU6kXeQ6C|Sq;4fB<_5+43j4?&*>1$&7R##Q+w)CQh6R?&FFkLGNyB=KcgXrb%ER3vN1~Nub}r9UW-eyeIY{ z+FO&b(MQ7C?>!OMX&QYj7`3D9(yv*uA}O{aT)|cx^N3{r=TifV8h}?SaH1ofY>D1A zY}zbaM3bv&>5H=9!}2bE~Y&T@}#fNJOgpkS=!%k=S}R^_W8^ z?3K{UQe*3#2twHqhwlIM;f)sP0cg8=fOpW_=*$DfI5r+_*4_YrjF>}?_RYc20vez5 z4d1u$=kn!s=(?S$lBor*!0reO%M8$6NG`p>*ZPwaX_ z5pGuN@rOR61Dn3VVWTG#r)hK6Eqm@^4Lg2kKfr|KhHgkr5-SabjUr3K)mc# ze+;_Pm#}H(zKj2C`w5M@o1TUZ^BTlU5qr_JZ5ZN7e?T^gEc8mEp$A^tTdU8Aa6}s2 z(^0R%b@Z^7oBpP?<3OcDdJxdvHlpwaif8h?V0oC18L)C=KnDs*2jc=&oM;rMtO_Z#y4GWk$mCga4c*tWihv#0^vxA8QMriu0i zVx+1QOJ1h+llOsE-+WWFwrw8W-;sKT^L zsK$D#@SM*6n$Jj{(46~L!!f71M$B6GN1q&eLWOoPpj~Xb5K$X;_tZDr25K5Rm{4Ii zR#ThnQs1?R!{yP1(d0%HHeS@kr8FWo{n9M;4w5)L=;Hdf-V@d99gxtX6OZK%&E^p#`So3tW-Oxg>11}*TG~K{1 zE2Om-RB4*GiA~3ChemfR?En&U-R%Z?eHNwMdMV~VBG4e{AT6Q4hM>uPGLnL zu6`CN)AKi6A22r01ii>2HOhMTC9z;U-FFyGN1}32C`6ATV}s_t>p_pvUyO69byWC+#kr}R$SY!D4kSKHFM9$e^NSInXC|F(CyOv zk1;mA;YW@44cgWOOQw4#&&l)TKsh058j8VQ@QvM6MsJ};qUv!C6@{y5yqxGe0-g%O zE?7&^#Ae-V5hWBfog&0?NE6+clAB?{nPpl%#H7h2(a>Bm5Q42~x(Y53FiqnpkThHv zCkt08oRxmDS(Yynt_g6LpBnEAm5KD@owUUfeVfs}Pt_Bb%p-j=1=K*i`ymVSsLF3g ztDuxe+XrZL-3GJ<-*f&W$HbawAKlZ&TIhYCNxRwiC=#U>dI|;JtHdV`K|vh05jjWW zu-AKH%^!?0nXC)xgEaB>0h|3I-|uB#J<%Mk_~hbtx2!gu2nHNy!hHejKM&|>{uVcH z(m0uBi1!*AHbr}_XftV=9B-KWDEUk(2Q=?!0|_f0(<7BXLyr~dV!TK$Qv#{|C8rbHpZ$UueHlaSLXT>DCjp%^5)8EJI5B=hDqmo18`jZ5=9?t6|6v z!@71%&*#MU%x#WsF|5oTEHh89-g>(+L4pR8ooU@0nsKd<_SUJE$$Ies(wl#VxkUq_x9*5et2TJc=S}>XO z8GqRd7u4;Dp~YUXtJNdRKlBZnoP=7A4CT^uN&=Zdwf3H~8qyB8OhfY| zh#)lQT#?SB4)oy)QdBaUYet>i&G`|inZ5$jhNy$_ZKNL7{fF;*L}1d+R#DJG|KXj3 zR?T-2>K&TZM+q zJ>!+@9`&WBk!C^}JN2H)c!nLB1z*?s_Mo!ox{s60_y*$JSFJ;@d^i57MpM+!vGp%% zzZ+17InBMW-O)KynPvcc;v2?8NoY9>$sm6;*Et^g1eX5O3*r&Sl zJ>p)}a(wIEm%hx5?6~Hrhw%lxLn-hD;2=7&(fM$@W2&$3`&f>k@daG5=r9kfG4-HC zXoo!GR)XXj> zdQQ!3HCNkT|Xm=nl3-TTcQ#Wg3*Tyk^Jl1 zoTsF1Mtd{fCdQVb&d0xX6D5iBN3`uB(2=!dQf~(_&lJ_fF24`N_Tj|tz&D8fiWx-g zyZ8dJ!-?2IG85;(4aBB1V&(QZL_S)gW+M=zccVftTWz8`_$i3M^?mLW)IY5!ikjmi zh-A4`FGp1GjCWb7-h^-J9>-(5>KJ^tY8ZbEPG;|mw|J+o$% zD(g2maO8ayc$7=HRpYbf!9MuX#6to4tncyNdLgxY*In)`qFya7mwF`fPccw$l+~6K zEB0{h)MuP1soMS^Yn*8z_T1zYb4%&GDflZHL%%~8MAQ-Qi>(`DJ7 z(eu$%8{HTID)SHYAxjCg6D}^uIeowbI|3vbtp~J zt!O7EKG5o8BWJ?~?BrAL4>mT(_cIXxd9xZ1qP!2hLnVIc&G^Rf#dVSIMIIGj}W8*tms8wKN*%%F6QQFjy>OPTXs zhSD=apP3UygCe;;G++7%?2P0^3_&)AqC~OY9aRG#??;%GKo3i_H%ConVb`LDHTP+y zc@pRlaZIFB33`|I}b@>$mIJwNq}ecAG3k*Wt0kA88;N&5NYtt zVFUG_Kq!V5ECOl4cU(_18*E+{O0x5i??yNvJvJ7jn_hu!5n;Q7u+a)M8!OX&v;pBo zcrIVKOJnHjNP(7`zLs}hWZ`mbXsJ#(=NpI6#huY!+e;|ebtfZm+vRt1dGak6IqqMx zr2aeEa(Kq~uHQ(Q1ImVaPYK4@ z1N5>q{d5y2PMA1StgzTiEoGKkvBYdGw-k#dHoIu96kV0mD{VEEqTOP4*eVmmiLOe~ zS!NL(<_e2gWUHt!R~C!rQnR&k7=jlE@D zRwtrYI<1v1i$iqUSh5K!dd6`w;A1W?w-uS47LZtBv)75XO0mx7vQz3+E~mwwAda(J zK#>g;$w7!Hr@fBQDf!E)6s?uj=5i~@wU@doER{~N#_SNQ?6zuav86acoaC^G@$qGr z@+zKrvE1r#inbDw#ZvH0sI-X4fx}X5v75{NxE%OG@>Yk#T3H%|3poJukZPgL){7~Cai#s^3wa)_1yjWyOHiwa)>gd>n2f3PZx9THU`R@y`xz8M)^vq@EM zBy1tY7Mv3~ACxW=Ur4V*#WW_@#UhHO$U@u)f2pJ(dnL%Vld*!5Q}}V4%_WwZt1U!n zjok{d1G%hRA$L|T{3W*XVvAj@Vc3X3Igt{iEm|E6oq`YL19mwe^;B?q<)}v%(FHK0 zRDnQb!i_>u}EQ1XdSgdrFm$SHBl6ijP|GPgyj4uS`k6cxTbvdYuZ*+A zZmVFZMC8y?N!%pT#P|xLi_6|9mXxKk7(#Nr7;H;ONbn~(P7zsfhgTLw%mja!a39n< zqP0c4Z(*c3#0r_m4p$YLEz~K0xrd9dxP_LC$QU0Vj{+oysW~sk+bDmsPjHq*Lxs7N zQ-Vg_L7bC0&oUKO0u&O$nlc%3Mdsb9oTCDgY)1upKhaECMGH;x3`evc=-zCck)o5c z$XQ06Ahq!5BCUQh1MOP^Bz>5eU}c7-yaeCoTKuQJG6C^;QS-9ry&19CW=Frk%1T#j zuBbx$hSXKs0)&A?Kug%!S5g9Sv#(^rPuv76$(z*%L6G~iB6NyqTv3Tej;w~%p_I$f zZ=gX$uU9Enm}^ZA>kLcW5TzkyN=Aa;rgWK|TtYfJY8$W>nKcFitJDJHw!jNmnB+i- zjug2gWkL=MC(a8Y&y2{GrKsad-2zil6$Mm90o78-wzx!Paf~q4{{R2}o(FoK z3!&-t5PKW!6)*lF%?Df#co#4Zup2<4GG414%cPmrxgd)!jDI3A+GMfYZFc4z8b67b zW*|f;{wfr+8bOGE5?3vi_`{*u6b*Mk)`weaEkbZ-iTa8rQE=E~k!QwT<<`pSW_yLH z(q3Y!vDwS5h4{J)cuI@Q%M%>KZB@?U`MMi!&`lhEqtRM9snSwgg^Gc?4rJ8M*e#`y zPiP&LqQy~Uu7U`mW}Y$}X`Uo$q-xu3qDn;-gI(eDJVdZU>LDtqCV1gBzcGy6{ z_?cefPo1vrNx)s3L(ZaEes%LJ)IS5nYIvAlw-{CE?nkW8#L~F?HrWvxI~@ro;__edeq? zW65$YH~emA%Z{=-C5(4f6rxpz{EZ)%h4vb)wgbczSuDj443R3V&LFkcQAS;cT^3fZ zJ`STkoOE8+oxwAdXDmR4dAdb3-C#6~&7M5jG*NehZn7!AAge%UG8%FX1#>8r8*B2@bMf zNPLzYbb9KDWf6uYIDUel3^|EHutcU%SbWJoDfZHRQUPE!VCiN1q%D9$fccm2lbrBh z4U>fv;RpNjxP4OQkbTkvfL(xX*Y1Yi~@l*1L#=@MEA1jQXWEAoz=!N_Os5%4_3IyHwn}w|Gn*^{D zO+QJsqYBNXP-&?__hunQ%Lz@jJl<(8WcpKl3EBzBpxthTo`p*4blEF`R>(I9IYyn3 zldT0L0g?eJ!uYJ4g#6paBf+skb{5QBA%D_XL6@H`81hp9$$%t)RzTe?H)CvsMm-+6 zm=5jEhSte%tz->Xyu(^rDHM}n*!efc^F`new?LGxy!*(u|b4TRtF4~0=zS?xuxijs0@@R(izw~Ejj z2#}p>OT4*=SSj4a@uC$iuk)kz%L0=O&cfgjPAle7gdCj_@`TdD|Ee;xP*`rRoGuhW zVJW9ns>+0N8|KA?D(K8kp~_WR8q0?(|Ggpz;{Tt)-%S?&BmAdP1phI9Mt_Y^(?uIf z`_u^XEv0NR3{zJa5J6kSEESt=AjMUfP*UQ+;FCK$uuz7TFBU#z$^!!*Xip)I>RAzi zO#!m$M}ejY1)3ccXyQ?(Zvym%a?G5NVk)QM5c!NW238n`n2U>P3@^^ShYc78J4T8o z^xzILuBOad1l`#o4xZr}B3_RfM5`nIdOm#^;wuQ_Fi%uTtC!czyyqIR*oM(8>Bnr% z2LrjlT(>x>(p-qCJPd@03@id+>5on4IqRx0zn-s5kIEC~e9}~=4(mzEq&ZK>Kby|d zo_P;je58c!mLgkeC8j!&Nlf@ENV~<~B?@x@iA~h*FFw!U@*}w`o6mx$h4B=3ZAjAqCVdBeCXy(9=Nl7#i zUp3`c%$I3Q^2B0}u0WSvfI(L&h`>^1jkVZWCb0ihG9*<{l`&gr4}|d-1oUX7NJ7F2 zLf?e_((>W^rNw|*03+-hWRv{5gN5qjM*>kfghP4XYZF*0W>-Lr4E?C19kwe z0K@<;LHL`~_e-_FQx4DpKE57yiVJfU>@NdE;L`v)@clbr2jF8s3gEMp{ZbY16az*B zB-kTma|qHH2VC^AcC(0UPCY;v0exEw&&-wQ$}`(IE0*|`cq zI1it6tvaeE`;kc%l6IP4O4|}>ZfSM|lNWqtAImNYs#O#=6YpQl#~dRfqRlSFQYi*x ze6~o&Crhxr2qY z<(-weT)1F5*oRqWRcWeqR8jT|?*F@10{;8`Kg|@97A7w(%k%`g zOX^o?>8l2TNJ!b<6D2fj7AQ*0-TS5XS^K4ZfX#qQ>d+U;<~6hTOBVp50Eh0`FZ~Gk z9Iy_s9Iz7M=G*s6Tj0MI@D$*~nZPBRYv!O|1iV_mUwRtg2Gjyd0k;4iK)7W{|0m$t z4tNbvg!s|GO=c_1e*uOg++~1s0PV1E2CM`uLio{@=;x7!0QeUE(_w#7HcfCF57-EJ z6YzJyqkww>Re%o>E-^7to0ycCoS2fBnwXY2A~8KNLz}3@w3Rklo1#tCrfElL)3q5% ziAma|q@?7el%&+8w4@P9=}8&MiOJgJq~zq}l;qUpwB!-V>B$)>i7DEYq?F{8l$6wz zw3HDk=_whhiK*Juq}1fpl+@JJwA2x)>8TlMiD}xjq_pI;l(f{ew6qav>1i1w5=Ur9 zB#lTOkuoB6MB0cEBhp7?q$j3p)05JZ(^Jw@)6>#Nq^GB6WPrpBB%cA)8HknvCm~Ur zl$?^9HX=PEYixFoZk)=&Tv!B^Ob}+xgPuh282ao-I5a*A{Q)p$;i;i`KIGyb=yzX( zz5o~ncz-$iYyg?$*BuxUW)H&lN8EOpbL6;Wl3#Z)|0T%EtB4DTS_)kT<|VR8e%-?J zJgyOOQUFU}?=PG4@!cJigT^O8>w|!$fSvz@{v?~^*ByNMBJ?xRybxg<0hxd)vPpj3 z!JcK%iI84jz%YOb>F)xNNq*hI{O6GWS2&$HNOuO})XFCLbq8`2!;JCCB^A!3>hv@| z?VDEUD#3E0!P?b4lM-H=!H3!M{sbkOu_84wk>-Vgpv!4grO{QJc(_9%d#Je(?xe?s zngiP<4o-gHPb8` zdLz8hok?L-KV`kUSa$PLrtpiohMSA#axP_#<=Suk<8(Veem@+h>q7e zHi7PArTG+jH<((%C%uq)kSdWNBw&rE^D55i=?5~=VT?bkA1J8Cr(%DXVS+XhIWU!B zAB{!cSR@CK{YN;Un_|teQymNVv-z^F{I#h8{3a`Q*kSp_q)pV7m!zebbY;c%uBxv> zUzhQdlTIsslAM7~iRYgpaqvJ%KYV;7e){nlgF2<3ciQQPiI4O{;^*?y1OBN+w$+|g zI?}YQr7oLG*^$EwSeuT`!T~=W?JN^8={UG}Bqr);>k~>{J}og)9PAL3nKhTQBwg8c z!FQ0$%Ca!?o|*S3;w5w^-xz53kSD?7hl>7a{*ON^-)wLs3fSL>8;VvPkVdUMAYB4@ z6EGj(1QY=F0JZ@7z5{ssfRx^HK#B$o1c-obn+`}`0GZ_19rzVx;yK%?E(mXKIUqFx z<^vW2jDTXo9edh9`I3*Zub?}0fACdKIsb35Wa zX9y3=Z#XDr0`dTh09Ams0E#mYX5SkRN?+xMho5dbD3t>m0bc?Z0}cTw&IXuAZ{aX) z>OpDWBo5Iq3Hp|t8e(ocC@C|$*I@P>V_Jp1Y}87^SypyXda3-NR0cQ-hy!e&eo%T6 z;Jxdh^daCSKs{hGAPx`>$V5CoFvadIn!dy_A)1pdFUPh6eh5iPi*^LkY__n)2A}~SKOGD<XY`^W9Sv3kS^p46~Y6;^THZoyKq1_r^hut#`c)fqo&8BJ(l)p>G4C4_8u4X)b=#?Ea`b~ z&u4nR)pJ|V)}CiYh!NLCOp2(AXpUGCu{Ppg5r-o*k=OcH9RkdLpywsgi@tjJc=h|& zKR@S(f2^urIw?^+aY6HMsavPs=pOrN{B@Q|uPmSb^iJKN(Gi~x`sJfdPq$pyQT6JC z9jo7Kf2~I9`}Op!y^q}T-l+CD^Ojw{&C~GoByHT3o4;7G`GsW5nxo zDZD4PeCc;>|1zC3x#ZQqU%mf>e?N9~_raC*(km}5Td|_~##!Z2ro#L46W66olU8q@ zboHu79&8%__?p>6s$y%7?R_1?1j!C{t*c2BATYwRz^& zC)QR?`EBObq}dOb)%#vuoc{S&x+|Z)@ak(O{Oy_(8@|*&U-bJ+%RYQC-SY3{-&tNA z^iXt5!_$}EJ@(k8Q#VZh_2L(XS#ux#%~Lg~_>Ug{y0K>O(@*`q;`yfO_q;i?w)cUW zf#26X_fx@}>o-1g$D?!am^*sv;~#F!PyO(XMNb@`^5(S*el#t5YR%uq{d@3(8Q-O> ze`d*)zdiYP`_r4+w!Y^p$bWyw+q<)_JaFN`_6L^KPWj@Qt>TuQ`B%(5c>4uUj!eA# zi5)8z?SA}?AE)Gh_U%ifa$a2g?W|``#N;e~(P*rGchJJjxAs2tYV)whTVIITd-=8@ z+DCjpFOGTU*}e;(JMm1+uR{)9SNN?Mx3uZg7iZjgQ%-&S_e&!(f4buRhozi5hc7IB zC~M_|3!l9(`OB9t{_)L6zq{zK-`4D0Rr&tot<(S5_sn%Y@BgPF!OHkDWIT%PMm&V# zukEz6KG;7beod$NVaKmE{_!g!bkdzE1%LWs;}`kk)BY%R_z-&T3Xi=z{C62El9On7 zjrhUjDdVS5{Vgz^q|6?1K6Ul~|1W5lVA7;X{pcEP`sE3@ zhAC3$QP3k(h{}P_q)7!?H%CPl=qBY1=s#)F%>z*7g?=%@0D*2A5B~L!(nZE(W$AP` zPnwjMS&%oWN92Iatf+qd2lUG;=&$RS6_v>%if77$l*)+1k6`fT&56 zfE_;taTK!&!bP&FXz+KlLB1fQ(t;O$y+?C1Udv-D(*l-HE@d9adM;q*_viXp%$slY zoJ$T19P9OD`m(l6r4MRZO#5jvRz;bt&J9bU$Fk+sN1go&xO*|f2=OP`^aCvcxmqB-p_m=`}MNxsvkV-qCfuS`S!$<(Z~M!=x0BF`rG*8 zysOsybA8dF%Z`uneDv_bCpNyi_ps-Js7qt+I(zJvHLvV=_WpUd{e0K;cX-bIDf;ME zxnFqs#>I8#3%`E9?CB@3sV;hHK}ON{=QVGN&3|p!kyZ7==KTuY+|2uco8rD_S5yss zY1zhS-~1~7hHYsFdPd*%!QiSsKX=Tv-MQlGp2pv={`A$}cb@#^lS>B7eS2KPca1t} z`umAb<-hRy%eqyMUiFtgO8Xu8ule;iKR5K^#m}Aw{5IyFuWANFEq?SW?^i!%7e02~<*vI%UwHQN zUkfkz*UArDv-@6FKSJ|y-<>@t&X~vxUzLf&?b$aCdt>XpN$vgbJYpLA{Fv*WPCb0& z^N*B%&oFz}BX57^{OfnmPOct&)_I#IZv5kmf8780k^JjiIiK`@@9DU|Ji0)5x?eqXb-H+jE~ra&&|*h9=+nRF9ZzsKxx)Bj+mT)8se z&R#`!Wy+Y&$#gI ztH0SU%v)NSR6F;6;mupm9&I_s_|u^K-k3;7NDDeW7kb=glT zAFRHx-;gN}uRk0&NMeW}g^Ywe^9|U+;VO(&q2V zgiC+D%^Txta2igSHe z-qfqKWuSS(r3bGSgo=d;BgbyN;i2j0ABuVc6T61XzrOyQwihSNeD>rgZ-ZD@#v^^L z#eZmiZjuh)ik!T5ecq=(>?%x)zxSyp&>RYD#$>l08#ZHc@7$G*XeNc*UdYs1Yy%5O zwkhMfD>AEYxFEe|w5eAt*|QdXJ1gt6#Xl`snnKO3aE`d~=WmA;v=r>EVyv;AweI*M z*VU}6*=!(hVZhegEP3|VuKsBqYqo{Y*8h9i%RjomoPUsa1XDf3-0x2F&b#yp7F?*C zV7vJJx`ez8dLtgcpEW;Dzir^xJNn3*BPbDKJn@|vPW+~tLVQ;EtMFCfr^3hgzvlc? z_@?lS_!RmJo!=D$0qO&vj27D75&ElF9JrK7{xGs#>hQbp{BZZZ%#}DJNpt3;PGp-2 z87lIp4|ejm&|GX{rwM7@8;YFY2K`H$$Tqy23$4{!Ep2|s5e0{dc3)the2Goby8N5^ zaX69gDBwrAiYz9aQJl_?YqE5^4Cks03CV&Bs^bDlDP3V!h~QCz{;T7s1;tgJfb@kfVx%VE(0=Oqe|>!Z`(3Wev8d=|cF6vk~yeIh4u( zLY=VT;e(QK-a)B9AQnLOR~G*f1dVVX1sEp#Dq<^|@DXTV|#qUV}$jFC>&m`d<3u+Btn6S^6UGiWd&2qIt% zK>1<+bsEQ&$|CB7Z00W_0EJiL5+0@5#cc&b9PBVU{ZL;DOOO32F3 zHW-EvFPNA$KHq34;C7-H%^Eg+1?7e)<-f50H9`K`a$70xm|-gtgfFQW+iI<7f!JD$ zf=Go=UScsRYYFNg6rb<=>oR^4s-MYLVq!-))p6+?@ssU1?u%*Gun6FIPzqwfFmk| z$w^$r0WmqSA)I$8dW1g(e(S06hw(l${Ei$~Xa<7l@9ceM_^q80sPTvKrt(K8sPLN> z@f2QjnFYT{A(6`i{t$n5<}b$)5NZ{b2#-!z6+Yc`%1B+NZ|yF9Ie;o{`s^nCPLaAw zU#YTP=3fbLM(HEc-gn=3;m9jC6|%Oy7^gYRm38usQ-ZMar9;xTZeYKmW`(FU9WZ4=%ru=% zr}E>v!k;fcu1lPD{Lu0X&O!J2m*e}(?@Z%|lwWXkI-eP&-$9unA@|p@?&(WrxC!LC`3_0~CUO)PjhvI^96xpikLQeA0A~a6K zhqyvD=gnP+JMMSH4vb)=Dm~onstxg!uM!H5A*<~nK`{qF7dnInrNe%_Ug4cP`i)`# z@lRc&mmrt9IuYn;th(w zJQ(O9ME1pDm>7&NqA|$mDbRa(nQWLL;|+A%( z>#!tNAC|l@Z-G7XL4<2QEENED`~_iQubO{Y5&&x-J1pq|PvU!U!nMW{VQ|Ip!NtP| z*9n95BM0a5|04(Ig9^={HYxJzHfhg=ZPND3+N9zE0Z6;NO}g~rfSvp{huF!@aY>u> z8DPex!C|+BWI<(vySRq}@pGAu$k^+|^;}d*Kyr(oJ39Yr7yg zd^z$%=~Magj)a#lV?O>-@9S^iRbDh-Kw|)v6N`fOLb-tfiZ<(5JN2mwZZcKjwJAzZ zT*yU*x^k6&y3*0B5vu&PsY(Eo3V}MYFyHF^K5 zq0$r-3cI_YK!sl$KK`i>V5{P1_!R|15sEbf_x9p~lnQKxHsJzSTsCX7GY>6o`wF@@ zBMjdZr_T7%5pn#s|1$n`r6c(-lCPF8ZK{%hUw-~`HmUfdO;rTMj~@cwgHMZO*0f2J zyMee<_{XUHj#dY7Jqh>a-9Y^*{L55+d8%)v{7<9*_t(n*>F1pXDBbffRKE)z;B+59 z(0uL&`5W`kCv`!Qyk~@#XYm7Pm=9Uu=_hz0fAT z1emv^P1^Bxo3!EGHfiaqHpvN?@=lvnwXIEx0c`seZ4%%~eDB!aCd~qj0&MsOy4AOB zl5pn{=|h4^N2K3ON2ECg0r=_GBhmwt19tM;6JjT~dAA*rEYpri(dOW=kHSuPqYH!G z)oH}venhIj<%kqld_>xJ#}VoADS@!$t`1Az!>1mRz6ON4lYJcGtKHqOQ~K0qs`>-J zeiTxqO4G_rRrpT&5yeya2lOKqLY04K{YVuqC{dL~9bc^hZPGtQkgspz7YW-B3j>U4T&E%-7EHcrtYiPFN6KW=Y_6MkV z8CGIc1s?K=_$fTTwS?E_GeZ!FZ~L?H75e{7@@#w`od0lQ7m{g}H9)^V|7V0C5Z|Bw zGmRgT|FF?%3rGpwiHXx_SW?Dm8Tp6wM|Ad-OVs8VIkE_Ekky=Zw(U}PKYndhdkX8KDw|^drbNe@DktwKy=bE$(VjjiUmXhej0I1Dux*|`Zt4+>7%^l{T1@G>#3q4d>Azy+2UkVeGBi;x9@~W|4&a# z%Ji$$YBsGIPOT2tFe~d8Ty6fd0)qVVX+t3JPwT-kCqoje`5OBD<#5;o7L?$~ zAZr|3Ys4cDc$5cy61F#9jh&FLO8>2txc3QH{WE?9MI3oLcz7P!^@QeX+-yy^YYG)8 zv5e#qA#_2XRqpP>i&3N&%Y~Jh$uGa|yhRM$N6VbfD#ys-!%K^b5^#NZg3Vq!93dRz z1M5NBRIXNWmUS^W!&xyXO#y*Y$Cr<=k>rBsvNjN=YO8UCiBE#|r{brp=|8>XgU8S6 z_>})J`W|SfDFwM4gXW8rD{O-E-wlp#^M3~M!{xu5=v2Q0#m-lo&PYuT7e7pzx{#%A z8vmg_IJ;h7#}0Cm0;L8k3|H2@OD&aj%cWmn><{lk5S!=c1gn-o_Gt9I}1TS-$1r{GcBl`vhI6gJdPiLb~D>Q}Pq zmLzQoYij*Ful*Gm@|(nEDBSK>0rT&{+u4$mWXa>fJ0nyQmd#G_wd&M@qt9P;LMjIs z0mA@`0rS?KkjemhKpbEZprvQK^m;_Qbm-U#=~!gDwD0H%Kg1L@e7TAsM!mvwuNgC6#-O@e^`9# z{6ZJ~PaQwp_$NRiXbKwt1bn!F!e2f9;mZap8Sd=gdHfTKQx*M``^idE#xC-VHk+SqR)!L93*Z(5F!M2FjXNS#ANd$s`rON-Vf5U z2Qhhj6 zPdzqo71Pbo(-|j%{rt&^j=BmKCfGm3mEN@A2SuHDcoLWAE1~IrCH}~R>d8387gd$} zvE8O}6mp~lX~>HAsZ_4C+#^yGqBv5jog5(*I7Xxd!MknPOB%3IN_^c&jhMZ6&mLY= z=w?HLfIuk-*nLr=l|RT!Q|jzOX2qB2!8=;=>*fv&2^j0Bh@38m5{kA1`?*R(ajZjf z78m5^ivZpBuPXS;&Sg=k>QXL5!) z*XTNCHJSeJV0Kt7INZh_J!Fdvc&yGOzYyp!nVlwFSB`?~+Mk}eQ!q0UL4&Q5p1I>R z@`}0O>#Mze5_*hP4~0$DR!a>AV*GIw9_|$Hme3hi6nF4@CIV%f*JHj)h@1PwJ8)mR zeBOjD{DGhTH#?N2&5-sY)C&DRTpOWH3#7+2bw%L{L2!E)2vVq|Q%u>_(Cc)l^VlQK zNz~=tR6~!HrJ5$elj}EU)_!%SE!9M)JWsPV8LrB~(J_JZ=XSff&O}1N7nS8uX#Wz~ zf%H&sf5alQ1BWWnk5e#a@q5vJax0&+A~sV1#c9oj9a3!wkeeD-!cIWpl<(6u3D14q zKv#GvE~P{9?*ULaawAj0N&e(V?gV64fWn0W`6+J7ceuEUTR5DQHsMfcxb&h9DMtk< z_$D`kSQ*s*XZjtA|5WjvNRL1X6E1FlmA?{>Ood*x+v$E&TqP~SuLi~aRJb0xxI=m} z1XjXM?k~#_>VGEoaQII*ez>^d+z6jS@9E-JhoiWmcojFbyW+O`$`0vtVBr-VII9pI zZX3+q-;3>#?gdb|DwsO?J2c*}2v2Dag8$yDc=!!4>i{R{H-(IzZt= z!znn_ep=8M8jkFDz`aU5bBO#C@kU?G(>Z~-Gq358PQw14>^2AHcX6HR7%980RQZiU zTuQ$VZmaNpO=5@iG~hA7bASf{O@KY4JEQ@lI;2NslfGxm-`io{1sFVrhatbNpdZ2< zxt{xf4|B8p-BtKd_t{~>j|t-z8ZVq(K)mP5JESisaCqqU4r$A69a3LQhtyb%@1hQA z^3)E=2)8YhVFI??3KOv97MOr7lVAe26u<;*$%hHpG7<6!JUZamlN$ghzPo~j;}Hj- z_{UasNarH{*LR{mfR0h{Yd3K-7BmxVwIV&hhBCCrfKkBTFdc4yNaStDH11|8;U@W) z=W&QY9xs9Wj=~O{y+Rz&yya%pQKYfuE*{B~Ymh0c-pbx1Zq z1Ypa(9nxZ$qdef@U;g{B7&v2_kp_YK`$3c;AQI_*`3Ukt=>sAkf=LiUOXS1cZLw^I z`v3pR9y?E_17Q^$x-m1-=zD(tMM>4Mul`TT!^<;#tTd>#C1m8$!{b2LYzw2Wy>O)SWzy;ahBnH zIX%XMRI1H*V;gS|@i(?{-c#|q3#+YSHr<}YF_z->XWXkp!Tq!p81u2Gk*$F8y<|Kn zIoIF~W{eWCHmdgVPwa>^(6iaim2;egX*Ve50B}}U5LFpAIm{*SsI>9R ze&9zJ2MJeSEr_OUwy(4nUxo^EskIV36h@A`7IqVV{4Y*WE(8$b5)$xILP7$`CRXR= zU2nLOULJGMPCcRr4-YaI^|w6nDz79eHWo~t%#^(p8}m}Or76)APxE-;>d}HZUoe{m ztjnXUODl2lkzlTY5Sq+2c$FHK8A4GJ7kxf7D#Ab=#S154worVFFnqL7Y(~-1zS=vc zq7aLOV%nvHY_OqJak=aXFNctDtx$|1dbKcIuuKr{94%OE!kvQUZejFjp~NVZOcYAW zg%Z0^ieh&P<@v&>QKN-&t6zk!yiyd(9dH#Y3_|>9p~5I!i~m-kqFkt`5aQ!;eLTt5 z9aDuXMhjO6l{I7&Y!ii9qXnBym^DkNG73XS%=nXb!R~;+;K;+%?=vj65-L*1?Scb~vGj1goO1{0 z9F0&ch$uK_;PH4!G^9op3T?J>_RoUb?r9@4-bSY&_Ak-R$SJUoTPlE zr6^xSQJEP}zf$aU6Xwcb;uaPDk(`7N{HQrWb)xwnJL(-8V9{217bco{qtRL3M-iG~ zB9mE87ke0;IbSck`>P9g6|eW-KgV{sqOxG==#+>k3j48i_#}^9BhEOUQnOAkqMUB1 z5p=&BZB44K2zvoq(8VMCLIE~AW-6i^@^Hl#>kHYg9RFThN~?3catJ7OP=T1mt|}Qv zU_Z|3#6#T*if7C=Wf$C*rxWloep0S(q9L0;3k_~6=Y4kjl6Sp z`T1El=Yg(HV7ldPL-rvhpWQ)aB~N7m(GEgAc0?UoAN(=s#*9lp!QWvy?d|dQssVKzr z6%(M8kU1U;0L&rBQp7)il`sN^B(yv7HA!q=23V^WCcN zI(#cX@}n{x37~H(E9IMbru>N4%3W~|d=ox1K*2?Kuv%pIO8GlnIKoo~AY63ZAY2$Y zv+^SRPJj|NG))ReWlP~GO$tZfgjb+_i8{_IN&AZ$o_<@t8iKHqw=61)hXqh%7yYlc@E_Xg`xDr`4KND zA9REuG@cqKyjfZb9-cTsg%8%Hu6`}BVN-_ zu`4vI(df%MRK9ANKA)%#L(k6#dF{qp@c65Tj9OG=f5m%uG;- z(TGt9n(3hsrj5ozwjDIP5Cp+O5Cmnk5oEK_2!di_#7s~KvPU*$%O*y!Bt1zd=_Ezn zPo2X#`<~~X|L%RxKX;y|o=@I-e|_KY`&M;NC*A#D&q!1L$0rK^{V#r6Py74t!TFyb zY@0@Z|L=+ZB0~HB_PsP0UE!bC`q`=%UvT-%%mW|z=zp~Nul}$9zUqM&`3}SX&A;_( z`uTed{~o`Y;qQb0*TMdKz3(_w-&Ft4AJh9kTKzx8*910sc3lshQ`Z|f=W5C?-+K7} zcI|X;*0uTX^_BLkwP~&eKhdZ0Y3J7Uqg@xc?%_Jmbu(Afwz+~^*Yy)ze;%&u{jP7i z-sig9^?dFAG1d;_{jXOuM|1t-{(t@RKkltG&OiSAzj|+V+w}iGc}!YsiuI4%HZaMtluIv2yR(~(w zf%kANcRlp)_a4K`TpiaRo#)E+GkkiD`faW`*P~n?yj@-YyZbliD}%Z|v!C~t`}X;^yja=@9_U8R}=Gf#=o6;nwR#@6?MJp0`F$mh^r~z$K3z*nsI-* zYxM8+|Knx<_dhJT(9ka4%a(avS>W}a6PiQ)w=UJhwGX5 zwOU^|_i(+)OKyF*-o3@|Sia5Sdd>S=txvJf-M4jCKG15Nd*0!CnV+@)aW3%s5&f@h zwH|)^!}Y#T_}I!-+k9TcU3?egPqtd0XZ8iZfA$WC>-}H!c?aWbeExRF!*%{$zmJ70 zcKh9g%=mMz{GQ)$dna*R>+?TuVUN*ut=1jxe7FvN&}!ZHE{E&EAGTU|zx&}j;VQO^ zR_g{%usdcvo_`PisMWfdtA5;SJ%tDNii2B!+G@RrGy7VtFWvKSz32K?Yv%rk>(O7d zS|4Q2m!5yPp4{JRU3GzVGhQj5ziqYt%6&JsT7P-S;dQ|!OIphxYyR77$Ibj9lRGT&KO@%53%G?Z zVsNJ=t(S3%>p9O?bMu{-wBE#$4|?3;dg)!3v>wLoqf1)T?A~=r>jNzL>BhS+X`O$G z{N8g(>%zwy_g+g{7jrwG!llcWv<@-l<*{~6nXB%-q_xQ9_gT_9=LzEHN^ZIDlGYYR z;gZ%jxX7rAHu+PmLS!I3P%Q=QmTGCo`nf0;t4DoQ7V^3Yux+m8& z;sH)@ncp1M;a0w}xzDZ5{mYiLzQh?844<>4wJbSY&#twfoPMr6ap-b+;#$6vtEQH; z-onlN0K?}mX?=<*zslAXOIp`*4X@`u-oUXJENPwKcHZ<^&Iiw9IxTJ%ypYo`T+(_B zck=0sUL>#V@|7I+o1ospwfq2kA2u&XKVn`cyq+a*;Ev3^EUq-~vpvrrGatKr4EJBX zq?K@dmvhkE=i6EGDz5#`lGaXc=U&e92ClzmNvq<4AIi^Kc_}<+T;vSP^Ui90t|{}k zTzb2+TDNa`g!MAhe?aylM zVtBW+T7Tl~>(25&SmNb*TzLIitt+_h>a$vJV7BY5*6J(N-)x|DJy#D6v<|*Nd^aCx z?V7fKw-{)>=0&{aKx+^8aP^C=vpvvyJ&Uskd?D0xdCoxV4cyJMUedh(23jcxhX-1J z7pMB)NgQ0{)N7r)y9~5G&2=1moqZb} zXzk?K-3D4$zg`@?bc6NXeW3LPX8aWwc(XTnj>ZOBm$BjpIdzYL)@~lW&p>M*m*0P& zb>NNi&FoFq`+$MgA!gjL(YamjYm;wwj``KM`1tq0f!2?Ch&OP{`2(%LvEun}HU5L- zlkFAaf~ zwJyet;(=DejZ9gv%cV~kX!V$~V6tYQweFq9<9~AXlLuNe?{W?}`flrg%0TNq+`_9k z`qY8emw15Jurnckjy-Ll^;@o=9B3Wo=radeLz}HL8EAcn%lY2-*k=yDSKgjA(0U~g z@I4%S&Oqw}jQA1m;U_t<*1oai4sLnwKo{YcW{)+Oy-?imGak?3+7}J9Zo|!;fmYDy z^TOQc`NKXhtQc%IN;4|cw4pWf^K*X#@9o$8r>-8p3YYVS4cinyv--}meXJJ(s4&wIg0>+ zZ+@g+`4#cs;z&J{yU#t}vA(58>T&stImr$?>~aG$ZefqxSu$t)wnyr{jChb8E;42N zL;7=+8CS5+2?pmKsi&DRZR)w1CAYDCyCd~Z#w^(70Tx_n>PL>$L-sjlz%G}w;1-6r z*RQ$Hwe~sZCiXekl<#SZ4_KPMR7NgOP>m+764)WiNiE4%BFI%9DU>$4BR zJ;mSb17{iD%Y03FnS9%i{C-F3DftiXf27{Za=CavC7uT!saLV!TE^$AXYe5Xn=%iv zT46n(HqJ%r89vy3CJ)nZyZet22ZKl2w|~|CVtHipDDkuZX#2{1wRk>b-pAQ@R+k*9 z*D-j4ePsM3`^NSfdHk&PKUp4FvCHtON9x^8c|yKeTzaIAd)9NAd@_6Pk-B8>dGho* z<6VBFUd`eq^2Pp3<&o*Dj?`nH*M7$NV)CXVb&u&r`^r9dIH&2GkJN*6=6$O;7`#oK zOgA5?L+7{RJUj0{Qb%9XE;~~1VvqAIJ}w_$wvJDVkG)UHYvXo#*dZTZa;_QgaK0M9 zBCjlV9jVuQF3RtSgZ*oqv!?uA^L|yo-S(5&_pFQQwMXiGOs;dzzb1}7=4Jc)_JMuw zVDW<^b)VS}t$(NZ3;AdIQ+Z|Q7xMOXLg5N&ClQ(ffdjztauBrTtCj>kW+0p0D>c-g>@X_HFUqcD`QE z;*Rt69wv96uY;@A-+SKYm*#)Ke7(EzqWOAcm->gz*BwR=pRczzvvC*xP>=j$7NcG!KT_58@VGuFd`^Ne3JUr+v6 ze4PG?`{{f=v)4K{%-0qBZ#3^u)pPh~=6#1e%U8txOxS12mb~>Cu;hC2=H2;vlX$xC zG_N>m z4|g-WPI(`HFkf$G{G<7L{CfR;;w#&4`Q9kqX}Z>(1=nEyG( z(=OyzM(i=>E+*W^4i7P7#U6)CadC_VSF&WxKG(A1dWLJw%ZM3c&N1O`cDSD@`|Psy zYx8j_dtAnx5eu$i$tm_Z!-`$DpL=6H%YZu=at|Yxj5*H^2mix-9AS?kbFN~+36`8@ zpDEkVyRqKPklPq@Cp#?I7m*yGrLYR{O_ z7514aGZxGlyg!|kw=!XmDR(jBKIS~ck`*fsAJqTF*2#z~nJ{L`wamDlIXAIn#)@+cI?gvE z?q|Y2Q?`DuKbJD+GM0>3aSel)INyvo!-QR?oMpxx%(;gpOIDm`@KWdd2K_n0gdtO| zV#W#PoMy?C6*n_@ne)wvJDIRx$^*=}z??&W(4PS-E@!aL{xaeu6Ly$#12b-6&h0Fj zGyEs}&i2d2eaQJ{%<7-zm%)1ZWyIY~xSuKe%-H&)ak-Qwm$72R;1%-Ah*L~B!<1cS zoMp}(EV+jjO9ro$Uq&4Kll~lG%8(gXG3NwJPP1al;8pU=h})QOCsP*e@c;`hFqo0o zKYOpd+Bs(R8t0W+>fHC$zs@;lzQKL=-{`sci*ep8{>HaD&xg(THhE;wb-yXUTe~Bk z@Ars@o%dNE(=GBgZ=Cl#=L|loJ-b)RtB)h?t2`ISxXp9Me$PHI`kc5~?(lx{@g@AK zxQ~mMt66?cew#99+0E_83GrR+xjt#V9A&o4^U3Nvo=0}Bk>5peF=Uskm~(=CPBZ+j z{Ib1U|EA1+jCqJ9<5Svy&pOT9zScf6;)c`qfm@hzj?s16G2UbTGwQ!@K4#p)&JXMt zgCAN~rF`5u`>VKX^$c1^{W}F;$6j)@-gGNpPaiy5ulDyU!A*|VyV&RWxym;^T2HdN z#nE~n!?Tapg*ZzNnZJ9Ec1=9DI$9qvUo?EQ4$Rj*_h`M_Jkfba>-OKocaNj>R(9B9 z#)8E?kJf{=`gj)^=1YS5+D03j@Ho<@n3MX zUc>fO5-qkuzAk%b(!dBJ;8jHc^F-6JXVi7S|4QZ3C0^R?wX_Z zEW@W*2ZM>D^(QGoX=Trs zFQzY0&+3Io>;3HfvvF^x%o)b%(RvU2TsoxR>yOrJ8NI=L>~E6Sn~U#lN9$!Q-+r`S z&u&+|EIy>)EyQu<(R!NcRY&W*DbF3Phi_>fu3-8V`_J&ZN9(e2_tDxHFIwH7$`jM; z?Hl{QlpiL)Ia)72TO2nWtv9lF()!qG9jjM3Pwk;&b;k5;zXRAgDmdxy<)T~p9l-1j zAFF2>+}iJVW^tQi^*qzt9jixgD`XiJD70~bC&FLp6$CIs|S}F zpCjyZEsL>Z_131$9>aSat9LQtKE^!6gcVZ`-`2W0#*8bOGiJ%P>~lRUZeshM*2|D{ z>~MGEy^PC@OV6`zE@Q!neI`toStm1YVb1L=xtrm=t&=^*w=?d2%*T{F*k!?t2btg3 z@5UZ64_C3|1S?K62<-!7Ze_~7%=4X$)*nWU<8MEcj~WaR=MW?F&=( z89dN>?4f7L3_lb*#>tGWRlgq`WiYA`>pXtMM4J%T>%c!IIn9 zXU_J;;%3C*yIB`QcDaf@CafN1pP7zp&ywSJHx4IRvBUPG?H5C4>~IIO$JigHk2TMj z@j1qfD;ci#yS|$;b5>kn`*FwWp?g>-19mvhl#?vEnb9TA7n8?Z|2>V*h#A*3#`e2$ zLL7{qCa?FB?@R3~+t0M_W$r)Qd0_Tj?bze+z0Jc(R_ri+o_%DGv&^}J;T6Z~)%P*~ z3!G0DJiuVub8%nwT*}}@&KnEvZ^|#Wf2=z8DYTB4IHwF=ZvOjOHzW2q&3wJ_nZ8;6 z?r$8fVe}T~jNx0I3&yNiZnBRLF#bEm!~T1Z)l>eSzj&WGSaE^n7V|t%KHhIX*!!^e z3gcP*&lk_fojb-Hd64o|#$n7Jd)&i57n}Q^u-+B&!EyGvmf<%0*4$^01xu!%5-+pQ zI!70%pYyz3$S<0oIkz=_NjvsAev$f}-U|%B?VPOS)!x5Mm^bbc$Ah(F!r~hH#pt`n zVTa=nG5`0RTlRU7!L`oCL*3_U=A2=0opZv3yBU4o_>p!$bUqjq?lWflVcPvzo>(zw z_!H}TxPBaA$%qvv8SFJqQ_oFIm@(x}W-OTV5KC69IPwVfKQ$h6PO@Z&6*n>XneiBL zCleM-d5AfeuhNe(D^4@`xpTpYvrKu283!M!A4gd-Vz|$_WXh@LK4%#Ho9BlaXIXJa z<9_Fd;eR*}Ot`=fhb}e_19rKb8OPb~9axWtuWWq&u*nX7p zIm(PHm~%A?ChT(^D{f?Pz{g33>@nspCfvuAhZz0VKC$|p=XzYfgWiLTxRMEDrd-R6 z>zQ*COJ=M%$KdzQ86)mz!Ud)rezg7!nR7KuPO;(!1~(Xw5qC1-KBk;!#=*zv&rz0K z!HR1b{K0sPxPkE@`EJU8ly6qdnf}T8+5WTVu12=<_q;WGp=jOw^*pNrv8=-_3#so+cqvUPBS`t zq29vsoQ1k%exCmReNuTR^D!M=sF$wMpUc?eY8ISkpPSge>q5PqA@?w1$%>;-cK>b* z^(sc3V8Us3n6k@^J?1P}vd@a`yIbE=tcS~4ay{E);&1MAJ0s>z`5xB!RP(dT?4Aqt zBBOhWW5T$cW46qF2KTnkrzvwe`-~agN1V-lZe+z-CigWDbM9vlF4PN5IsA0-F=TW< z`C`T?w(q~-_m^qMjD7B8@&NnKg7XZQFVyWz_2V+OA7~t=oMxY!n4E9jELbplkp9d$ zJgL0GdYE%fQ@+5tXv*B&lrNNrrp&!f`6B(70j~6G?C)v-$xN8>bgwd1bgZWby>V8w6uz%0;{BaEv zPO-xortC6&+CsgHB^R3dOBd=D&$dsK&Ih~Cus*gE<2JrP+|O~JYnd};$&Br3?HRIQ z!b40sv{w8KSa4VO zWQPl^IR1S5{7;@c=IpWL9(G>7P>)<;oPQQ4LvCQqj3xU_*W2G07>5(gxsLHG%*#H9 zr;YPU`D4g&=G?;MRo;J0Sux|t3)OQu;~Dd^&%JEFT7DUF@I~5jg2`)~SEkIFaX-U< zG4G4zi8JhTGux^4GT<(T+{cKA7_(x+;f}m>j5$}bWX$$!oj-FnGQ5z>u?yxPvkGu)~rm=h@}pOO4MF_82nf zDi)kz$!WGXc%B$=Gb3(ek9%0MWW_}WZxH{>#KUEb7%}FW=KdSyqq)yHc33j!;5zr; zBo4-$V9E{5xuvP!XkVIoR!u#Z{gZVuV*AbV&VU(X?qR}`1(&^C+>F?Mi*+()%A7k` za1SdkFnX)^#Xrj%mowbtJ;y#bF?pNw!-}o-;(5EgGUF=tIKiCLESR$7X7;&_?RR*d z8L(i^KI5+adWC#(1-o3sj8p7!hUL4QFGlZ{Cnl_za^#iTaTNRc+{2vn zP5pbkA75o0u4KlwEV+rD_j+E~!8#eS{~6B@E6y?gtaHVT6?+_hgK;>@s7AK7-GD9^YhKE@g+ym@#6(HLN(r=nKvV zQ+AniwyEb1hI8`9h$R!wGv(k$<8p*OhRnH&B`4VDG%KcTf6=}$u11>%UN)oB_~<2!_JqC&y3rca~DgN>~o$K2j3!|FN>djPO;()!yWoFWx@7W z#PL@7Wx$xL*=53tb8LUrzA)lEV-9W-FW0c-6x&}DCj)L{m-Eax_%`jiob8>~$&@L( z+{~OgEAD0TbbD!Ip7e3Cg;vsf_B<}Yb z@5kN~%-CW46YZP(%o*-AZ{ttBSKcR2jM?FOrrg9H=a~G=`kFEax0shB41X?8X57R+ zGj{fQo>=f8^MA9x_bYRZ>Gjsd;1}An!=fqgcg{W_9izKgdT@=1^wc4A|jvW*leENtRsC?jdoo`lGxu_>*y%aP*_*#6SQ;CD|Up)_>w64F&H`}%O*ynB*t>bm;Q~EDCUPsK%I$qDP;&vtj$LsyfIrM4$ z7%&(-?%#Lo$Ar;Mj@O%5a0io{9d+2!GW5iwTa33qS z{?#})KVF9nZgISxWRDwJax2@n)SnS|F>W8P7nz(b&d(U{oa6O0(_0;{XPI#abM9fu zk`?C}3?HutKWjXWuswFX?y$Vb_^ehQ_wUKg^U&k<%AR#U%K90{^2P8;$Lsdz%+FEg zT*F|^@p=PO&aubcEV-YZC!6>4#^-W&pCZ4FPd#35X`DD-7ft=;#{GhRFF#(dXYUQx z!F03y&dKw~j@Rp$f8O{kxt|sLY=1#szbGCqWyocW7%}D=CY);Se_6cj?a=;9=K1FF zdYth!=4ZCs`0QS%|Cf#bTl?`9{eEZPziM3vjl=8)aWej+{$CT{(c^W_l6zV4Ad_R} z*(tt-~SY^7A$yxeJ-#%e!O1&b#a`KKL%XK9($};^zux zT+Pm+bH?bDeQ)Y{fF)bs6xV6{z?7?4a4mx~_L&{dGUqO~EAukpB70n#i-*e@|J8HB zjMMBhWAHcmZ|b?53HLMQA~TMB%RF4kl9Q}B!*+eV?y}(C=04|}`>hl8;J2-VBa9d_ zVa${rX6!O&k0lHCd4RnoC+e}Q-RC&_oMihf{aJ99y}=XpJd>N8sFPjlZ+fEM#_r8d z)C)|8PWb&_;<&|$dWL=OVs^_D_0To)**;N6jL#MiGj3;}yPNyxh=)B^Y~RYdzN;Ts zu;3bo!{TC>o7m?zCg+-uIZKAOK2a|+&6yUmGuIa9{$bDHte6ZJ;s+{W;>;$g;v zY@a93-_wuF*k{bn?ZnZP*=@=r^4pYIH09f$@cjeIY+tK<2m8Z5V|IfRb=G)id1c1I z>#Uz6?BB(DoAT(1dIO8Qov8OV_s34uqkFW!*NJ*P2Zk1>Y} z^KgE&b&W0K9{k})l4sOe%X1v^Uox=j|8bNW{tTS)M0G&$iD@STN-QW?W#-q5Z~Vz>>?Ezg)hVy~X%V`K|Ky@8Wu! z=at2KtiLILSiYEN_TiWE&6SKl>in_Ct!!WEJTqd+4(C}h_?0|=R8Xe|G|1V#&G4ydNm^^Y(My9y_F^RHT4fM4^u8ZBrdLC@KEb!hwGVh z3)|7jdIuBkV~_K!*#4t<9%h})IL@m97I+}X+nRBpj{f|0XhfF!ag6rAm zW=7*D>p3PYnDS6_|Iz0Ai}AUc?Z=#~w=v*OhAi0Q0xOOlw%*5{^zY}nT0bV-#+17l zJ{d`MJ&~gDKAgJ3Ppoi;S)?&w}>T_LIenPS!a~ z?rrYBSbo^!@Nx0HUc3x#1RvbFX8S^rE zjl41X7x`k$1I>Ldu*0E6wCTS4By~(w^3 zjJw(M$LhW6nZM6IH22?coWC0H1MR_zA@luBJC3l=kQG-o+7=Z9TRvUiodH}#xj{t5YD zvh8HOe92j@^poC)%s%Bjv-fH1XZv4I)+^7_?=#LZ%g>&yXPNix1JlombKoq0|Dc{J zXIOA6gD-eqn|khN&PBH8^cyrkS2F*ieP-}w=b=F+X?qtUOthm^ezhj=88}Ay=FH7!a z_q+1m+~4hdvd^jJ{`bt^+`ra3ZXqtNX6HKdG2G+1VxLQIDWBgzS!YfC51boDKNPR~ z?ZWz5vdiR0K8`W{u{^M#|M_ZleKQ%r(KXYEr*8b<_XMdk{u)N+rGXI6V zG28DPon!oeH!tH~s&C5N!yXT@;?S+s|H?UH#?|a|no()|=KinkKdb+6euniw;9N5K zt-P}Mop{gXK_BlJ-QfMw_=l7Anp^9C$Ud<9M<1tdWBfmP-?03%co_7>!-PXiwdXQc zT-}uaVjf0^Pu3ll9KEgajyUJa;k@~p``p3qjn0kw=%{tD;8u2ynUCRu_oJVu)aMj? z$GxAM`V-Efa&%I>Y%f|rOSb%cr0}$J!H7eCPEx{vDJPh5nmJSUxs|~gaWUi`Ml2a~ zo?Q;!L4S@gXUKx9SaO1WPP1alc4hqxxQ!uqGG@Vq2iRrB;IGzqN9$#W!QY%yrrgJp z^Xzjl(607gVfU=XdIQse#d*}mCgoipHG#_TiW@LkN$)eMFf>x2>4vBxfR z&N99EV!fZ$EyXix{I+=+pKZRT%-u}RF@96#$X%6hC05d4K!D-UFSWmINLOr_|$S2DS<%!Ws(Toe=MnPAe3ksL zdZcy?AGKJQ?2a$iOYd*oN81;Mk9FP{uU@P(rjIi(^GoFW0s23Fv5we|J*Nzxuvl+q z=ZW@*Dfh9;D?#vHTb3nC;ifKjYUq2kgGyyv*2sh3w7`(;)GT|zwoM6UjmTwg|`VjFE!*#LJ{WL2llRIOJDg|lefH}F=kxJ9%B|<%Rbk$;wH8~ATJC#$B4Vx;eK}6XOFE_#^F--xs2@( zdafCA4P#ER!x?tjWzOyFb2o#n-ZzX{G3Cf3&BGNexrP-x3_m1ZCfvp@cQI$lJ}br_ z7T3k*=Qwk&W63Tn&NBRn{bbC&Oxb77(MQQc=6tfl8TPo9eePuXQRj#4E9HG$z8Nw6 znDfS*TNuxZlO_A?eB3%8Ee?*edzJVYe8N63{-k!z{ZAY3G45~ozF?Og>4}@c=fu6*ellXkH4HzmKNHR{=XM5Pa2}X)=yB#@ zz>>?^o%8X8(HHF#``p3oOZJ%s7g%xV67zgne?~hzr;NWMP9|S zQ|@Dzhgh)vRP%C_y~2Jm{gM4)!JW+a%HM=}_c`xuUoYQGc!)g?J2QPL1uy$-8vF}W{nLW<2V!?P`Jj^&a zY5g2!bff2%T~4y(dWJ`h!<0Q1+{56Q`PpIXGV?QFbliTh&sl~iv}aby&ojg~aH^hW za??|F#xCdByZI^KzoH)}*t>;x?A-E{?`JW8`&7M`#jQ@&twelW%J%T7dKs%*pQDX4#t<9st-Qb{l}lGS3S@AV)3zjqV-%Z z?kAtBr`WsfRK17E3yeRd{|l{)>5EU*TiAVxJTQFqse0`B^39bjU#p(M>rU0%*?!xp zx@yWCzQTAMW3=T|J;Rt?b~(%NWAf6}bLa)e;~ECD;$r^UQ}s?3EZFYJCwpH#Rj-&< z&(*A$FuPXX8C@?AFEr0Dtee3vPt_ZlaIPu;+PsW8@gnUw#DZJd{tt08;xtpPWX_Zo zcQE*kys==#K8Ihdo?{FSn4b|7X57rqe_9ul--@HD|DC*dv_EKH8F7+*cG>>Dd@*It ziU*te8&1_DFA@JA%-Lgf_*A{0G5bu| zdYSPVv3Y*aGc?B{n%xXeI97;FP^HG|C2a4 z&JHJ;vBUDTb+gaCtay;^GpFiB#(%Z`my4STv)cIVaTohbPS?Z#tRKf151y{qGvOw7 zm@&WU>3Tm4_SwGq={j0(U$}-5r`YFKwr_E|?ltw?)zq_O!bRo`UtztsJY7#PZJ(|; zGdcToy_3;7r|SbvnG0;+>U6#AmGZ%eJx($jK3#8MeD3Lb2m3t8?yarsRo2CEc5ZXJ zPT9Wg={jfcywkq_!gwRbn=ua8FlC2bZeYeOY~TKLT`=SU##~^RL$5X-0~TD~c&F3# zM)sL8zVqpNFLN$196jy(EqFKUX2fmma3?bsjbo?lrT=1lE@RG!1=lp*Q@&ZU*SO61 z>~kpPeY9i6sm4${w(n98z25~>wI$1tM+>9gnVTU^zKFm2} zpQCS(pNBgSEI7l8UB-_%UC%ODWqfvcfCU%Wex!5qM(r4~%T+8m!Qf(XGhxaex3c06 zb{}Q^8?_s^zsecs-Xy+9i?3*Ix&f~3v71z6;#i#2%jGo}!zS(%(tlWK~=YZjpJjd>r>^1k-cpj9aC)@v~JzLD4 zBJYf!D$lG~GM(_evi&r1zeQY}X33Pn)6K{9QtM`CQorW@W!k^hJY2z)6U@1eooAY# z)w7)MP3oU*{S2R@9lKn|{PNTF?xuW&eR`WXr?q4LLeD3|7prI7u@7%||0SL)w%6IG zru=gGW%SSbzeD?1$}f{w%Lk*^sAupm_M@wwD_L*@gYq9{r9VXkNkh|biJ0vht1FKN4%feyHeiYtKY}%6N{_tCwrf8?wNCe$u{TeeeQFL z;U}$^Ikz+Zlz5o3YVLD*i+0=Phrz$<$CBGwF=zA{`_Gh%414zD{r2ti_JhF}oL5#X z*_qRh{T-+MyMBI6J4WBoj>$JYHy^Z)Ts`~Wk~bz-%Ljv9^14;L-w_WBc3EDdp3!dg zAJXo7^2v%_wy%|UW<0V!1Ko9ht~fQ>nfa2Wfa%Zd&qs~N)r|LfJ{eqZz07_gjw{Xk@9Nq8r8rpq%6gcW^3{}o zZT~)Iyx({ZnH=z5Wb~i*mobNC&Ck^gf9rk0h?^KQW5PLhxSJ{Wv&%j+wm$Bha4B;x zW5I|e*RaniR-9q`cj9KiS%%!fh>ji}mdqIb-Z^XPS+Tgm zdHjTae=skjL-N3c``G27rk)l19Ns3bKYHF7b0wocdEc_&4BLMeKLgIP!yU}Ir>XCY zzp3YZQ_sOq${$DAWyp-H*y98XPP1gnJ~y-CHn#sFeugZV@gRF#WX|@dv^y+MOc*gd z;(f^uyX>=Id*1pPv1;l${AuHIj0IP+eWT}#6+7%6bxxXkW-K|!;Fxp54)?RiK6AFV z8)v~eVZdb!88PA-#++h@GfdfKm$S^cgFWtH!IIH&=bABx{?)n}u*c=B7_&IxJ;wG) zaWmi?L+)n8{fyaX!q#WR!=+5Qj9o_TbArL5ePhU!Ip4HlDHnJ>&n?elh1(mh7?OE(U+|9I(SfELb)5 z9R8g8+Bs#PldRZbyLHC*BdF&VhTP7WIXm3Tln2@6A~Uu>Z(lgdf-6{ZHTz6haUI)B z&eR(jax3Gr&eSC{R?Ip41>~S~4!83JhPMHx4 zPBOcRI2hdYOx;$ETdbU@p}UFbacZdE#NlY38>(Q>QGrnI*Te&z;Tvku&w+*WBj_+qc)B2|LYw zZfBo4gFBq54>k3yntHC;sh(2|?r0u{+{PZ~nRD>#+HpB6jy$BN6osr{%tFubehkP){tX3mNp533gwX2g|DIKd95 znKEV0y)0R=&*ASFhhuDq`ZHk6kZT!nJ!5WS!i*ixG39P%+|QhS7HnN(J}za&Wo+Ni z^UH{9m~e_IXPB|eoU<&sgBABMxWD~i#Cawh{H{E6lsO~zImzGw;%CgwOxa_Pdsy%w zE4Fr9_j37U!jmU5h&>K|&v+bR#T5+B_kLi^DfT(r+<%aBz=Q{w zv30HSR*0YJ1@ghph1SoCt?SfZ(8YOA8CKsTGS;{isG@?QRdc3jD9-1-)g@EKcT6upd8? zmnS-J>~o6kC&@2Eb{TV)33sr=JuF!=T4TLGHa;U(>@a+?&li|*3;W!~>?xiD#!of> zPdH)z#;3_EJIt7Jj$Q6%#{KNE&z!Bj;^0zNT*mg(#le7U7;=gkw>0&a8jlr+eyZK1 zbIpj$nQ)vPPO{4mOKxCvnQ>TfJCkQP?~RG~2vZ(p#zp3A|4e_5vf>K1pJksIFk#4b zjJT08w=!XmDR(jBK2{w3`Ts@R`M^b1)%|~%xx1o+BPJy!)o7ShWTNKNBj6Ai1xLX+ zI0g39Q$NSZPcRG)f%Rbc67nCM0LQ`7OUb976CNx9V_*e11lEHiU^Ccr8RZ2=8z>)f z2lIY`ypNIpVCfaOgF{zRUaz3%RpbL00c*hluo(6@_I z^804=l;5Ai-pTJzW4C`v`oJ=90;~b^+VKZQz#(t|oB$JG0t|nKdiW~wfvdo2um-Hy zLb-!+umhX``@quAQVw7YoB&6_C9tT2bp49-gJs|l7zXohr@sLQ?w}okkvqvB`3)9K z;P3O~4>)o!?F)?ckZy1QOn~vP(jI?}JJ<{M+=o9f+Dkrxv9D2oe}jH~#0O4;^$+Lo}gY& z!h@^8$PnoT2f#Qu^fd8;;b)0g_+9AvJMekx16c7J;-4b?Z^>tHVv_nP_~1b!SgZ1_rZkn{2BRR0XPkofUyk; zzVkr3z)o-k>=XXNgjxbiuS%%!U-%tOs1C67nuHnwqu>%)aUJna6F*o3M!*Iz3bueT zFb>ASUa$w;0S;=Q%4ln}l0;Avr7z5|P9?+Oa53mp%0!zUWuo9dAYrzEA2sZo zd%)ZUaZuZ{8t!(bB_2fM)$Z~&YJhryzD@&$~5#@|Q>SO^Y) zrQpzK$zL$9gZu?c!Co*7?f~Q91ULfDfzx2#-|=@l`hZce8XN*6U;=CcBX=ZJ4>$sj zgGF~H)HE0aJ^z3Q3&3!k@&*UM1~6|c`Unrkg$H|u--bS592}M3cOegqf`v=`?xY;R zBCrlD1*2dLYy}6vE-(QOgW=B+Ufe;?KXC^Oz@pDn|G|m7DGzWO>;w~FADGug{g>Zh z;lKF(1@aNB0PDaw*a{YXF`Os;_mEz&6l?(_U>_I-2f=C3NDvQL z2$pt}KCl9;0|&r9a0na(r@<+(^j_=`*aMdB#UB^~C%`7K=u6lMFa{2Qd0(b{z!A{c zhx{JeAvgiX!01;JsvnGjLtq>n1uMQveksC%wP5T%>>(Hjd%%ib{DBd03M~B^>G1HK zUa%C5fR*3~*b4UCPx*oq;4ZNA0qPwX1LwpYG;;VZFjxqVfTdtjAMt}RunCNV?O+es z0}g=O!69%bI0BA?6W}yB4SKvjzQ>qQK`;!i0(-z(Fz+Gk9#{%?h&$K=M#1f19Na0` zPk#G|2MmD|U>(@=2>O5(Unl>-FgOZEz$q{WE`dE@o`HT~5G?uzdVm#RH5dgWU>s}$ z!vp96PJ?4$0^AMeeUo|ymV)^!@CO!yF|ZsQ0mI-lSPw?OOTL2>;F$2>ZgAv#gjKo zQ{G?9t6YKy- zen+{36~CuH$fvyi8@<6e*bSCW;STnI1xJE^puU57f5e`E)8G&o`4jH1BVMo;4DY60 zg9G3=SoA;WdlccpCNS^M{SzBo_8{Sh51=s>6zyYvl%U(4O4uOkc>Fwmt3H%0Iz{nlM1NMO9VCkKE)e=|% z=9SLmwNOM1mXoqCS9O&py=*mgekJ+rd2VKD85! z82i+2FtK8vDmk5U%HOB@!09951z)#M6}%t)kJ_igU|zvK)dUv3ai1Cl2j03*l~LvP`~u#fLV5Z^uf z_$~x;!2z%b+zF0=6JV@+pPB=QK%*Om~G(h-G zga^yPFc=1-U_BTEo548P0SlnPkA<@@3(OWi@rm=U>NKHBj4SpM!+~Y1rC5q-~^a|7Wn`cgQefw zrz*fOSOdnuMz9Brfkoe^{J|(V3C6)iZ~)A!0iPgVFz+dNaOj8R!`bl9?o+$Kyq}=o zIm8RrgR$rF4-S9>U~~kzV9^WY=egu7SPKrlNcn-$m(UxW{weuUi(W5NufQR&7t9+Y zeexTuIFEGwg7N}OUm?H1IJgTO04Km{a8BIEsZSq5AFvc00V~1qFG)8T1v|kZun)|8 zmGTE8;0QPXPJ+{5?)mV)B7QIi)_@~m1DH3lPsPC~*b5GUJHU!xqX!rPjXHR+5G?u) z`hYR85}W{Q!MxuhN8Bfg9}NGF{J#KyUz-h1o%=;VqgQZ{;jDdaN0JsyJ2B*O2-zl$)h<6FS!0b7!&j<)d%(%N{xXMB5iu?kr!B`FX z0G6JuIKPhnbMOa7!Q3eEfI%=(OZkA&^Az7R@OcV6=9P2vIi8%B{G4O*4$1Az@o2sX zr`|(n)O*BB=#YGYV*Xa~S8~lBm7mK^Ab)+JaN`mF8*^JdXT0h3cb-yw9IOr>0rPLb zpAgn1@ip_83-6Ke)+K)8{IwoCqYkk+9Y6PZhs~%>!mSSEZ}EE992Ur3?Oz|rErS~7 zZ|K%NY7OXF6UdKyR|g8W_(Fl;xrYS`39u%RTkStDdFv^`+aiCt$oxb`nCr|i>jJqO z{qikUk0(f8MDTmQmmg{Q>jObEA1ZO52+pWmMb>(Wf0M+&IuL9#ydlI@X%#m3&rYep zSr(6{g>c2BwaqQuS%eD(@~Z;5Vbt)H^Vg66Re3Y&XW}0{wtCkD3gf~gC7y6){Dd|mO3IuCu!JlADz z=J~(Pyd(8heyIy)70}^WmiDwBZ3ZM2tF1yK|e&o08fOVa=4S9SWg zO8Vnc&Q|_Q(r<9&Kl;`XzJYLqZ=X@0SwZ+~%cweBeJ{7jkaoHARn4TO`+R@R?7ELGNl zR$tp8TUN$bY&Ev|?vm;*ZB^p>>dkx9=X}KT#DvhAE9b6V?NRrN9=>1eJh{tzuB3^! zvDH|=JpNFim3RM0U@lwyIrjK-vc&%=?fc7wGoCTyFXVpE@Ob(>GwNg!SRKeepSmoU z*pV^Z#@{)^dxOkN%7CpE&m!F8E0J>-awz|dGN2A`q3-E2==Az7GAIK$M;WY>GH^-D zsfVWXveTO-EuSPUCrh5)W~N2jMLT(0c+!lzO87QYw{22CT-sNYcb99sNT$`6w-4r~ z^=WEbxn)J%*y`IxK1jKW?JWM}9`#PpC^mJGe99;966kVe9{kbCe4?Ff6I+u}S2qT> z`+UDXBzs+T$*03@dTq~E=e|uoy#-y3wWe;h=r(|EqaT=2j|#sjsoQ?q(O@tf7(Le4 zkmFj8SS8nTy!w!IzKtH6r5wv{+oR5uyqm&~aY^2VY2TA)%&31!TY1H_Zy9wg-Oe`# zTD`vOy{>tO<#yHWrz_LCwPvehzoT3`32(HSy5)1fn@%;fc19h>y2CQH4d&9E(%B0(wFGG1FjLyuFEdC1{)`1mkGFfxD68WOc|TdH&c4m*h-O;z`YZ9 zyI%QJkO4RubI2wBis8l`TsfR^>vDf#xH34qyn48>!(TI8i-YTc>vM2DaH9@xJ6r

d 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

guyN)-&D4*RZyzGw7}F7F7xLMB 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

;hP?-a_*c@MfW;siN=Mr7&&B&U!y||w zxXp%Uo>Sygp=>ZS*`SR(O$XvADeLRBP8w%%LMJblzX2jwZ#uNDLwgSkhnL0l<(-Tk z%5?#(izW_ov91_|Ts-wU@B<29B0=YfZZ&gUCn2+ogZHz==vqr0dNk_R0dpSFUdvT=DN=EHHpb7C&05Wqu%TgZ%kA)#I5$6f6q!BB5PC{!iH1<=> zP5plV{Ls9r+9_^gX*RyQQgh>%0-<1*IlEoHj#!sP$>IThdB|i;Vj?_R9nN^>$vCX$ zi1s8>(ntt{uZa{#9+$n9|0zBVR>|wF>{4oBrjwCQyhpXj7F$qcX^KV(q1@@EO;?l~ z<6cp3$9fMfx~4oUdQo8CsdpeRyDvCuMa7I|Np-gB_B7RHYI+e$@OK z4SZV^9+oi}bKKw#p&|?F12Et%RE)y^G&6y1!c$c;UXds0MKNlYsrDv8k`(a5ievf9 z2?&;}!pbB@(4JFYzz1giqanb3#Lk0T4a&WR9u}n>8Z%2EZp_@-z$!>)ZBQgSI=J7Q{=mZxU z-8uA6WL9k!7n3gKOnHXuac>qP<)yNDRS(QE4ey zlxNCjO%Lqu4(E@^_@F*$5J@%|rGq9SxF}Pih}Se)1>}OEx{~dB@AMhtC{Tx%HjB`} zXjppT-8?&rdeZm#BJkK@0t@_^yRauW^*p9i*y>@?B@488V2@AM;Y3;^DwQ)usAkE^ z$&%$=;hxtw5Q75d5JkY-!Ni4=mMrEle=QIRD29tZmD$k411X976|^B-M3wnZSS?Fw zVqZI-6*BzVOErm_Yd+fI?2M+&8Wl=;7vFVGJpF})*?15ntI77gsw;TM2zG192QNCO zWo_ZFUJ=y8DkIdggFmo6@~A&81*TcLBHtri7lw_17@^wCzE_>*hiCO0j*;53Dr61E zaWA@%REl6(#x@k(-*-xOW$k9U}>+xp;*qMvS<-ud{ z+nX`EnqUWUy8cVrDyM&6Y~O$UQ9gM+-Ygd1o+c}7jGCYu{BLyHgzx>c8LEm}_mWi; zyrgK326Y6a@&|dZo6`IUR3qkxS2dpZ(bz(nRI9+kX2+~g(qx$kZ*2k8MT`!fv@IOP z(>U`g;5e4tk;~5z(^~-A!Z}|&fByCT3PZU*lkKD%@b4Tx;L4(&NXg|Vsbd1dgr3Q7 zH~%puBa;vw{^U*+PKrJ0i7*m~(|)|kwYD$9MYk5HrD``@?PhNqfRJ=S3KC_v9qq;V za}+U!csqr7VL*TIxp9=m7=`ZTW+J`wvULeKW`^b2;EO2lZ@ARv`~hOyX-s1}kXieK z_`7v1^Q9=-`;G`%<5@FP=lv+0SOnV5qje>S!v`}2H@VL=TQF(PrwA$)*ltX_K{C)- zEEGc|vv8An&t@wkJUV&5en6$`?urAbpN|Q`eWcjLrKZ3?2B}`zG@vo6B)Jr^v*HB_l7(#Uo7QhyGhA{ z;C*f2bKU{LW5V_d0?I{Ve=5ywW-F@DtK~zk&Zn23rXMeVX|l#O23wxWpgab4!tDY5 zB5|K#Sr(VwK>(i$uN>F=Lp|<6%++HMRVUq1v}isolcsucqYjO>)#Yw*`uQr^L99|G zXPq?m#fszJfQ^a&j?D^HPXg?-*5>g7VMXml-{z)&Vri z=+x-r&;Fj-sAFYP&qYXLzCalV1(I*Nka}O!&INqfdGJY={?lu;9jDPdR!W)*gYY(S zf`fgx8y>@aabQRaj-`aYk)}LCc(HFSPG0sm7}wpO-BD@V*f)05Df{h>IA62FdyP zC?Stl%S;SuwS2&EM*E`CvC2yrKOpePw4l+s!*MX7^yAqSUCDV6;!MA+*0-2~2!gKW zKACap`LKDg!}Ess4a)+p_aoRfj4ly1Gs~nKuafZI^t;;61=(RJB*F|(O=d3Bgi2u~ zowvXjv6aC&83+)Vpro%|iTf(IKvm%feY%yDhOcSuR=KYD>OPjh>ipDuOeu0K;EG0O zTiUK)QzSMx*f&5XmB}6R8b|S5x4y$}7U4!qdr_k9{&sUm`;V9I6|aW{>XD&H21>`; z7A&RD+M)?A1_5*Q7<`}nBQ(CnJkuyLMB;<4z)4Ti z!Hvy_R0O@t9$=0QLtWg37Qo|p*%0;W>Zp~LotbQK$} zvc^1b)mu9UXM(~eWtm_Kg76Zz4()eT1C{p3>Ja_KY*8JMn4zP6IYt@!iKcN{wUT_M z);n5cD{SbFhvj$HM?*9LE~J_+FpKa@2&vN2{ca2)C}FOjp$DA7A_v^zs+@DcCyY*n zDxzZ7kmN*fn9TNQjP_s{bu#_^cyt;7EKnT2te@WiX#MkLiRFXn3=K$ua0!iyb^cf` z#7!SSqz}DBH2qbYQpDcMyK}P@wsc;t{L7OJ5rFtC=aH!HFFC3D=P>tSG61R01TC6W=REN7Oo#X6iJoXlX;m!% zD>_lifW)Wv!Vm=`d|w8lp2G>Lf{%bBcGeW4SNjKETUHf9mtC%i z6L0kC^tX>c=3Ji9aorK444m;^0URn+hR{A9CY<6_=>~$3xMcIXj(cdVl6AF74|Zp8 zVzSF+*j-q2NMM0~PM4akce%hICCN|NpY{gFY*dh-^J+#4g>yJVqwc3U=VA8h;t_v^ zkR`$ZWbZV88dK3FO@4V4rNmmigc2CnS}O}ES#g0KP_Q&#&ZP>_#_{yW6-ouuuS+mb zU{9{nc-7o^mLKN?ON!9eo(;Z9L{|dW=qE^~Qy7zOId@S1hIH603C&`ild`$rS%(Q( zk)bCEhp|U|CwS?#OUKZy)fA1+Rv2Qyeyg{T`J3rIm_33$ z5je6_3Le@FPj9&51}L^z!d7e18@&)I5UGeIY4#phfxt4BtpWDL7D4`{IC@m^4eaA3 zbcd^Yx6>$`qFWW}tSvgX;ck@?U7Lq#maoThzxK$_Vb?T#M{gLq#i#K1m#~<>Ai+Fl zTvCsRsp88&|7kuv{&0`Abu$q=Ejge#a&*1AobY)13u;UH+D0>P?zgvd0@)#4=8Jsvy6p|~Yx6y4f=Ny69_=8^siH9^Xa(SW| zYH)J+12^G;L9UawLqXNDRKp=bYj)N2>uK#pSUAS>4G3IrMQ?VMEX4Sl6Mo*^Y!^>Y zV4?n#uPc+Og>~d3rLCsoY<>$KYg2LFa}$2u6AJ`%1>TfRq0DA)!v8`OsPYDcKoetP z?Bb7)Zv(o;Qxmn|>VNG;*V5c?H%mwif|3bNA=eydEtti1JHjzJ+aS+>elx#RaT!PB z<>r(0j$9%AA|fC)mdrID>{PP$chwPwZNfi!tPa6h&SR+K!(1N;Zy8NT%+h#p`j=>u zcRRGDGb%pe$;xR*cpI42OB87FA42v0y z9ZgpECsuoH%-7EFn?vMaNXTYz_keLZiW6d%yPP?vUG)Y~ZFwH8#_pM7sdJ{zV_=bR z88N}>7HI65<;cx|%9NZJ0l#nrKFLGEE9QOLd3B-Dqs>cj80im3LdFxnJRt#>(e@AX z{M=(?<;7H57V)TtRl>(O25|!K@bq^7AW)q-y@-_~NL;OFuyc!*Hdl64MIhN=#arN- zIJod!Tq0}G413tXR@He*ogrPu>e4z-t~sLFoveIt0^{Dpiz%-gJBOm61XsvR02X;*{6X^V5BC@j zSoeDJ3L;KRM4}LCD-7S-ER}^Y&dRy8pDbrTDX|*IyiJbptpa$88@F*Adbq1qj24T4 zTzXXDJKoJspheFqwcW?^#^YOALEBKIZve`WnF2_Us(q`eMc^^f!o7v2@jbiPe~BT? zyhqXB;gotVORFPtLXLngir7NrtLlf;o8#>>{69p{y>YKP{cz;QjYitjtqjP+N(JFeW;KY>SR?^<&k)8? z89&)ca|v4e!DTp`V-E1+dUT}t)*5~R1s-Hp5U~KFjCvdh{b;B>ou1#lKw$%7oR?_S z9m~I7{<1yrVrRX}MYbWnT2~Q^nC)rYJc`5ETejM>*008`#^*NaT{|K#N~!@lsN#VZ z=})#%MIKZqLb<}_zP^&E!{!f{i`V6XVJjpr7T;qumo3rgVv9=W6wTwJJMe}{VB4=D zf{Ll4tz#-8a;^Hq0;3aHBkDe2HYLhe@pEHx^)5)xhA&Ry+F4TWK!|upCAEztD-ZoS zB4Ca|z0tTMHzHCG=8W;>ilmfwEy;PI^Wci%eLncpaob&;~3K#`m+}G~Y@JUhO!A`=kahkY5)HM%5Rw!&KaH)ToUf)T;;z=GI z@hAr=IO}OVED^#J*$Re`ugG89a<7=B3=gFQJauMxzlBw?l}*oq%Jd03c9##Bgr#E` zCA1_h1hfh=1jDTnXVyVzQ&b`Af6{pGqMf*OlzsAydTQS5dy5om+8F!(X4^Q)6Fn7J}>9@zsebPu@3NgxKzDNNkw{G1Q^2=U~SZK{=5CxXi# zQXty@s*zu^WbpB4&(aKv8^(xfILd0!F~6cL_z<)SRjK&d!)~5^Hl0BQ`p~V+paua> z6~YnOsnJhR(tUore3*S%9G~jQ3(dVbO%5X4>u1O!3lQUHg93E$ql$`vs};Zv{Mu=P$Sx!OxP zq86tQeYjW+!J}0XYCs~qc@l%pzX3(~f|3TnugtPqd-OgLDehElZimHaX*KO@tL<#H z*MJo01}2;}g(C*cZTtNZ(f($$4jnYpIsXL=Zv1trLsB^@fRED#ix*^K$>ju)3E~zjWWVZPvz)2uH7yVOlg+qg%PL8SM_zL* zUa(K0e;YbDzfJ)Jgb_9}8g_$>mg!nLG6Tb32-T`&CLUNgTb@Ut^FN)we?`i~^`IWS z3^o;-&M9>|m4X0iQ|a6@j?JHBm>EcH;aGfSKR3XW2S@R zp$*E(_HkG^+KgxOl9K@6_w%n1d7W)j9pIFw8EepB?Td-`Vk_6grb5I$vuD#hUQi9o>v;~gCt)}#x$Yfk; zIr8S=A~;HFsQJ?82Sw2@UkXaeKt$xzW_2t&?w_tgaKM>vKsa07cPACenshfmPE*Xtx2v|0kSYobQMAksJ&xKumtNcyho?!w$N!8{6_v*#M?L0XddXRp@K#@ zYKes#(vf|IBcd}N@!#rkS}(pORajr!kmA&-hnCjG#zZMR)*p9d-EL)+$sN+TV?oQQ zX*NH58F87`T2Mz1IZ$d=4f;7W0CZp-~Eh>Zyv=yuwf=r*6m|Q_%@;v^{BcxWv zK3<0wqL$UxJC4wzNh%PBuh9cBxd>f_3-Y-@_RR#~9QUYxPLQABD2CG<&psHDJUrRS zI5dVI2~7^M2FWQC)@M^40(YRHJ@qwZl3(HNze;xZaf*w{C&?s-Z~i`ourU7b^-856j?Z*W z!y`OVY@Lbl7P!*ooP+&FCn{xP`&#quZHu2VRB=)8YyJl*+fNgm^hJeRCfW<3vAz>76=&c z*Q{Z{%R~*1qPXN}cA&H&2sA#V)o<;KgL3t75lZsna~|i43>8Zf_$!=!k~1=)Bq6M~ zHCJ)9GILSZC_4huz2{nGdU0UkEq-K7VH~^UA&oFrMv(_QVylOjUKrm@JQql)uq*Js z2xt|dM^FE9u3-~vY14)}>7sJ(a3@ZMgJfpjjc7H-8u^|2_8Xbk!?WRB}-GfdE^I54&}OMRyRX?p`*3lEVR>$0a&_+Res&LhAqM# zy&i;)s~QfFMSpQkc5LBPejnaaQSz4X{51Z>PJ5+2-3sG5@hN*HZvW zRPV$_w0l9Dcxo%>9cD3#P0mKEgVgdza;yox)5gjMtJh8$)~Fy)n9->U$IgAzz(?LZ zqK9ixqO}pV9NL94qZ8=Dp~E7d zZYh0U$C}8if9B`F8m5%kF$pF!p2suQ_u(cbv-Bsj55#5Sbmz(<$50kI^^`?$idzz9 z3R8K|27aTk31Q_<5uY~FWg7rMyJo~HL`W^l~bsW|%dGr;+Q-|Bb9TiyOJm{RNls`$mtxTR+TzL71FFHxSlV;-%UB zSuM)DAXW3Ey#IntP#C9xB!^e?0%_|4?YJs21du5w!nUDPNN&_VBjJkWsd4;+hKxpI zju^KtzFfEXXD8?Y;Gf)VpCE{XEhsAB#?(h*DVaA(_YmoX(#g+3=cr3oA~Vemr3Be+ zkBi}4_gM4KFy?rL!d2*Ls?C$<3=!YjJI|qJN7gSDjZi4P+I6jhKtv3v@W?eLrf|mO z=BEHJN94Q&wfAqqSVS zRu#YxA9io?fzrr=>&bOIiTgNv01+=gH4DtvdWT>JI%!kPRVm|yvC=S4Xy*59Qa3v>@WsXKHg15#NiP+ zf?;}w;65U!d;u9G>zloLwUtSm*FZ;vzJs5mqm|lvD)w_(1_juBuN;6Kd01bkGHeWP z*)f3KT(OFf0OS)cUUpdfk`mML&+-ReCinH6TL$Z3Vp>^FLJTlYg(9O-r$XhI#f>(d z^QLYH2L%t+gc=Hb$NB9E?uzh@ML3Y3Q6%f!+MJz-RgU#Yu4s0-`&&FbE0D1`ub9=r zCHvGuQQ;=d6#nbgO*UZ!nv*f9w5-{%-tP|Acpht`#=VkL1XB|U*XD{D5>i~Z-d9~35SY0o2ADu@? zD|RnEJ;m2cMyI1eKF#fExEUU{Mtkm|W=&}KO%q%)VvO`i4OM9{xqO|B(DJ)OVz)se zx4cKH2r0K1a%a_UlLeG`C+Y5W`o-fJy6Aq`&A02@jL(AKAW}bz=H) zqY*=3@TWJBq_U$G4Sx9=&IQ5|M~0N_(sa4Oa+C6sEsoK={ZlRwt}2U{jjVZ06x!pL z+oiw{QQ+HQo?+7v-9g?p(A;7L`VO!u24&73=Zo7Gz8eTq*MepvbV!^egKmlZh&}fJ zHD_^f#c!F-1U&(=1*T}uJaFq~f3{M{2q)4e^0ap(BX5Ph?o3D?}_cS`F>c1+V} z?_<$gAlK8uhk|gdY@0hAW>Vd1O;{IO$G(;Qp4dRtK+xUt%yM>M!NWwW?kg(a2exka zCUPds0xfxVH2P#@mKtK?dO!%{&0_KGOAE&zOCq#_RLB^%o#r7sqbgV?Z88081pVT% zL1Jjs?wsge_`lNpIT=LEKadLIrYj?@tSTVj?_$Ts=jneH5!_C{g9$}K6q1BZLSTxr ziPm)a_1Jok<)uHsvlP0hR?Ax?W)BM?;lM$red;1T24`*Ip$?{D%mc%_ML?zuHi;pp zJOKbDiGwBHGs>8Aym+OPJB2C!ir*vYj(=MP73WG+4XoA8(_+54T#~JNJfdgB zHbcIy2bC4s>gW0DZhQYU4UTAXjd_v$#$+-NE&^otFl}{5>qo<)AIfIVW_9f^P}{67 zoZn#IKp5+3V%Wu&9}vN(8vaoy-48HHDxKe$p7@NJfYbIh!nf~ zfwG%ENr3j!Dh%_)!S-aOtzL<0*foE+{h`GaLNs??>kW>*pN)gZ!DwBYlL}tr)z6^# zlAR9C!+F;9l&t+42p5i-S9GMlAv4P=*vZ06Cw^%xn-}=(tuq~EjS_s;N}eXaag~E_ zwZbU~#cyxq2|zmSjuu)!jCg$L1qz>lF^NyJJGZYD^JMvV?46IfC@?MfgjF>sBm|D` zX0TPx6pNx)$nkc?MnzQ#eRv3kbA}U5=AK}Mt1O8Z#Ct)h#YCK|-(XS0s3TrUn%#jA zdKimKx(XI*y2TuN!PM{Wvd*&Z?8rGlnpS{Zf|v4ox$&@)n0an3gOIm<53A`*!xtSN z-NN=@X#EV+y`Xfgr+}-oFQ-cE6+}@eE8H$)UiCGsZbm3^j@|^LDgtc|dsQ&Mvk{rn zl_H9%Oub-~FC-a-AzfUsVMWDMv2Z>U+=p}ceA2DSVa4ebBOeOxz2#guZxLc5wmriz zg`h~PY!)I!-;alHwq)@mU4Ys7uAr@*$&nd_OFqTR)7(#K!wXSFi+s_1T^d+dEVB(> zCt>=5i5^!fhn(wx4x1PDV^pviOE;BAQ+q9ORYr_r400k;quB%0h!nNUY{X!gp5%k3 zE=9XcStK9nEezzNM60&cTEj^TvBZsfd+%792_sclta$M<7Q=Y+gyxGD<^s-c-0Kw3 zg*4hZWO^+cvAfAk!C_rug{8YiG+C|a#oGXzjE=nd>vozZlp-Xs_pJmJkI(QvA3>+z zet3CW0Z~J_@5kpaFBEK#uNhLuPC4mPRa_j5wtw+yj-f((KYLk)dED$1yMs>(AQBlE z9X%48iWV-1ErI58c|+h*$W}V*np4^Lm{-B+wVl}I?ah%h$o0ajcD5KSi*}MKAX7#= zi8~EN7L^epYc0egvW5Lb4uLmO zKkXJY!6UcC5H&rH^9KQfpacsfXaXdqdHQdyyzEO=R-p<~`#UGvXSyX4sM(n;0h6L4=a?zI&^$spE+lfdk1fH$=K?F&ge zgF#+5l!?xtaS*c8E87gO^k4$2NwN8*u&WD}%Rwh2*07gb`n&FX5U*s3q^b7)(?Rcb`zR3swQBR z8BIQQ)If!Blu{f_e%ij;UVF8`FNxQot{tX=Z=nuLEi_)aXviL{Ru$})JJK5yym+8L zq22{_TvhMtc;~<-sClFa=u#UNKgDBF1U$u&(};X)@PQ!rW{|7NOlf5B?{(MylVT01 ziDd@Lt-3z&M?xxa=O9>p#&5@ICf+?j4bV@>Hj@FZ2nw@K3ZN|bFEMMqLYr)1a|-`z z3$KmXTD2oxLJR7dCgbQ$>;cV&hXotOY?7+g!Io0klsWq-yx~zdKDL;%7tR4XFH_<{ z_PYg`*~$PAZWQHr&>n+35l}y?DWo_5#ok$4X2Kc%`RhFdh3Dt_Mc)B>Pmx0HWv8;> zWm9RbrB(QNq(n-IR08+pit$o%iCs_Qcttv%L08;H-RXh00_r%0$qa%$-9J<__YBUbrTM0&j>y2BEp5wE!rzoT8fbb z6z?p5XCd>g>y6gH63IX*qSHcnnVhJ*6rg z)HqRX*5F33;seYqWw`^)y%7rB-jE0_BY6z0(l=@ZrGh`kF&e#dwh7s2@558zGiV2T z`W`vqSQOLxqxIu>`xT^0-#F2JyGqyG*(#X0_L59`c`vA-^rpDnz;a@i?dkE6qyg8P zwaZaaiizyZ$sNdKBVx>x*@t(3t4g3p*cQP)pf0tca$yuB5la}U1TB5tu!P=7hF8@| z@rORn*r+HTHWo$Y#Gy37HrO@*qLNFlN;365s-`EsfQjQoFTda%c)kGB9b^~f4ga9VTGjMc03(mF;zu%FirD$CpRu7I)O;Gm31k%VpqUnp13MxY)5NERQsS z*m^sZqX%MVp+ejOGjD~rl=c>TV@3mZ`3_xu74)-bSr`Z$I8GQG*5xDC;X|iKpQ4Q| zEYz>bLTw;)Tw@UfjdM-)e14S*wv|l6Z+zQWA!rg2<1F9)&tD&xw|}J_YA{Y0l|enX z8@NwK>GcqFC*0l+yW<%Hd#f?1PbyE&-(eu;>+j3E&Et?)Ju=as&;9}q4@{G`!KLG$!I>7i)wb-1CshTT43HQJk))6>3d~`lri|QG zn+$He=Lq3UCCeAxWFS)_Kq6G_AoPTgbTM^AOi3X+yb#P)Q~E#cGv=Y8qgPl3`UI3P zKnJ8ht}t`8*tUkH(56=FFnP_Qq5EkJ@U7QH4j6?N0hbHYw;X5n6gPc3*6U(PT~4fs zmP{pwsN>dThsl?us>#SD;qE5YKNDm>EQF?z&e#wp0@J$wv0Gw+<0F_KxwOD)xk(Cq zbT(PVy5UfAZcN_D;2UC#-RjHJ=4ne#F)gF)^+vd_D1l+D^5y;s*ROkIJoj-mokpru;|gdZOJwo!+AJ=6agSl%Pf`hF&E@%7iaZJ~sew z^3C3t!vk?2kLWf|SOAqh-|nVs<0e?Z^lqh8kM9F3Bzu5Q*RyXJQ$$vQlmcsg0GuF} zOBgp%ce9T`Ah$)oRdlKFP={u0iRF~yjG! zt=p`1;E{DK$T<%4u=VFFhIO4!J8VaZ)k!<&s!%F5o}CH%MtAeYS8Nb9t}~38J<@he zZAdG7)-odvTVVM|3ky9K5}}a@@Qly`Q8fr0oEwNWQR|CKWnVTMt#Y!I0)Z5)#KqeP zWkAJAKd@@R5E8}`xTg+erMAouE5YYRd33-1JPp9YebjnG7Z%k@9@PuBXfOpmIA6ca ze{8{$!pzgNo&@b3&hIEyX4zHNTvL>_?wPD6-+A$}Q8$ki z>TD~kA?OgS6^5f|#uRv{&aIs`aNaO9u|>k?m=kWGCL6_y2{3P)Z%>%&rP(LAUQs?` z+A(az(#G%P83d^8b9?u})9scB(o%%~A}~9zW=Y*^a)#ok8_1kvQ%H8)cF(+!JFeR_J(97cW1i zt4rw&As$e!b14(PyW7c-v5gvq_?BuMJ3$gq7C4-;s7yoJ`LcBjUH*EvJC6^s`36mA z8r@0*sa6GNi1eQCS|}?9fQZgA8@Dn?HKH>F6r@H6@i~$%{n;W4tJ5BrO(Xztd71`9 z?n-mAoX=PrYe%5*WZ0bip0@l zI3TN*a%%lplBio^DM=kdQ{f&dcsen@Iw+GKcyQ5+_K{s9O52&vGV%BX=6>wLAz8j& zZb}M|R*LB8i5e$w9#DzGl`iREF$^VaH~#6ZP+Gxk_`E-Z^2o~zieEWk?O>TM)TbLr zw<_Df*-wX=`4*CnOYHm_UVS0$`1K|c9VqO`Jk=nv|L^-3lGMCo(0xyA1?@ zJ8$Mu3XU+wfg;ar@@l%ig|;cQ=;(;$U&a`|CKezo#P><+D+N(j#mOs><<{C!voqc- z_16cO)Kry_5L>BIV9aWW5<;^wI_s#+zp0DzIp`k0O(zB2tDK)53@Nf#glgcP6@Z`t zpO{M~Zm0U+(vhCu@3!8L5Nw`?=+f`)DdK^_oT~XpAxm-fO@EAfpLr54Gy+f?!DuqC zUcviwCHIO^f4kqAXZwCt0-*3GK1ogh0%%;KQPIAFI!;~irnYvgm=;!On60kCENGw> zNtJ;fct8sK4N@;~7Z9O-A^vj*=2-0Qz^x_WOT;G1jpPgX1=h2P}Cmn?)uWUH8PAF0@w9{ zeM&&p(=c(L-_0KGJixOn=yk^_oUHjb@T=@bNjidg=S)*4eaC*+#X}FC4{Z}uM>#Q- zB-hD{&%e(;{r9;j2VQM}HPmnE@lz*K)vl&0_6Gw}#!+rJ>BjLr8esryiY*9KM#B1| zcUJ`5BFm6$s>9+sv4?#iy#li;FS`11myhYuelr)w+d%hHw+k)V#aFhGp|4O)p(#w= zydt$Zu6d~g<3x*S;ggO1zD7*80r!$QxRk#V%q3{BPYHf-unKWGuR)hM4CD&5TCMJS z%UE_~Uc%|$IFk4*-VVzb27#xRXFkf$gUBb($66mePl6o1iS zE+%`v^Z^4CZ<%1&lG=@j;&tUpfmAZ-A6R2UX?YI57CaYNS?M5nGg<%pJn9*~1$^Lm z=WgK55jIc*^P=DdkF<(P&g6(tM)VQD=Kw&ML~8!dxwP&r`-zP4pc0Pl?B1&nVgo-u znvTKl;B@)#r#V^EHCz7txh#8(yFPnQe-E4BDWGCh-|)dAy|&#hjf>gzSU1L#FOMs% z(gYr|i7AiUE6A*1KcYZ6cqEI1IS4V zt`XT^bd(7dyCIgsii(A-4s=nLN=#Wru(9|L1@KO=<^-wGGL(uOfxo zXbL+nz7sLM0)SiXMy$m^M4@-%-0Z_V}Qarc)85LLJI7%xTi z9l=QMky5`X<^S?Vkgz{Dn_N6!t8FkQx5*n|)bZeek!^QNVBa1e!N$L`bfvhB1c1x5 z;=uvS%Clx&yHhecJqpg?Z_?}j3jh8HDZ5;Jbj{v}ut~+li7^*T;j>~cuE-afZvhAB zh3h)uE-`+VZ_BomL6sj7$*tqnA@GSG%Uk`9+g@MIO6+#Ai(sD(f3J(8Yk}@OV_*jW zIGA5ty+vC@{^h^$FQRlUq`?{w{Ek2N`~jMJaf$uaR~Pv2j4D{cQ8sI~`C!atbw10R zCtywX&9g&}Xir7wCiaw-s1?WEJg8ffzQ3uGBa5l0OowHA;v$yb~_!|4M3v9jm1Ua}A zSwK)FEfahc|M@R5r`195oNFwlV~HF5kjFxr19XJ|rJ=_RF9<~@rc6DOZdM0^(Tuj| z>^=CsnpoQ}z0zZwUyXXuyehA-J4FaxydY6Z58vE>+4k>sbw7m$&0nPbYGqjNhq}iP z%Z05hFx_3tvV<9vGx|#$*yrC0sUPX;)54IfH$%(C)m}nvT4ujCoI#8pmE;?EAIVK{ z_?}*MlmXm(u@+VYNeqQU-m)M@RzW);VE52S1I*qbMdnX&9pc0=Wc%0rw#C$SEZ1JmurQ zHNZ=(%*hUQ%o0{g`$#DkEz*btN-e(wBIFj;*~t~zVhI0hntK9@*>xCqw$jkrKRmS1 z;UP*>P3l30whSHMnn9*HtN<&CW)HsysuBUeM;C*_=h;6IE4X`2CGH`^zBZXbv?&KA zmfs&he7*bv&{H$g8#g!7juglKeq5f~Gj~!{5nLxE4x5}I1zLk{P?kMP_a~cgwz}b; z@CVZ8rs^?63Q|1(%%KKnc+WNM%!3p`JAG2-akfTe3(z9@yjjley+ZmDk+vvQa3k9K#$@l`%i<48IUUji)QxV-}5Z#DEY zAJ1#+$5Uz-WduVUpbkBO%hg}~~(qC}gSW-}IsHXE%sC|!YLUka#M+^f2UZB`llJt9{(-214zAxc?b_h$bl77i&c&&B=UJz)W$gj8hUs$Uf^t7!P!3|_zGcMHf=1{5qV0bSbP4g*;3y87hI3L`B z;ztvWqUe2TILh1cmqJx@-XMPO6MaEWLg=n$%e#l&4^n}k;<0(0e_2wnE05h;Ejl^( z*(Ke3$e_fhm)a!GuqgEEUII!y(gM4oMMbV6m|%X44cw$aa4_Ulz-f#DQG){4@C+8_ z4n;2CqkD~EjT26A+H#7k9nfA={2>Q88Vf66&Ho8bFbzx(RrAT~VnV01$j%W2gL#|DJ&PlU^Z;23OKZp%nM&0;hcTE;Nn_P#z7_yWvFlr_>84&USel& ze*eP?-xg`RC=^$}ufY%ZOG3ksVsK&I%Z*h0)E?N;rV3>P4U{z3OE#EDTdeM>AfOL+?2GxJ(sbLS~Z+^C6m*DI^fnM{yN zEM_;WFRR^F9SDCRpXwWM#NBU+BW1M&5-(O2#gmImw059ZXfWkbfzNmm8$#aP_PA2Y zGJke}*EJz6jjwA~|8zfD_k>*sAq@sUbKMppe8-adu2f>1e1ErzlSBcTvf6)EOe5bddy zy%_4(z9A57^)Gw`-Yzo}txcjw{EVn=ECXW}yo1|;9(2B{E`qSZZ-@Lab`DLQnuaSte2(^bsvO% zaW8So5d4rnfh%DTUYO^rMdQ8# zs6ZaSw09{qzGk3KKr&JQ#-qxEQjBt%3Bwxy3}plX!0F=LJa)VtGHuV}W(Bc_j$ zTW$;kLacERAHaL0Ap&>Ry(5KX393i@1@-EzaDK*Kn2(-A`fS!TFR7ZWj0nPU=@mC^ z+PH?2E=-g2TJ>KlL-^cHAYlYoc!V1@XBQI$Wuh795Bmj&1}o0P`*!z5iita)J0@bZ4~bNVbG^2T6X z5q%@g6Pld?bNaxO`Nm%QPvQy6PCU-2l(-Y4ld3xQZbxvd z-T6E2qO7~+KyF+iK{z#jEayn)TL;~eHlJyx?o~^Oy75X{z3ag%!N>+x(jj=ILfjge zWv6a7d85iPqKrrHp)Ni{lWx1!;=1A)n}{|gIjCDjW#8yjC+kO(GP0)>d`qD7^R?WIe~m2SLe{(LiX%7B7vSje@6j+iBQfR25IH$XC!#2KZ-^A2 z;CI75SW6iW(Dkwh>K0g6stcSeq51&rBgmY5JZ!%CbPv9j<{aT7F+H(Snc$}a>x<(IfAqFqGz?XHb)f;Ww>+} zOriT$qCmOls~a(A1^Wj=z2*1C@_}pVsS$;HKQxgMu|Y&Ld*RCB`HvC#jE5toq0I)^ zFFp{}Bs*JGIU~EHAmly&{9!er}yw#?K#@Ye6yg z;E?LyNQcwn|J6|IjqpDTiW$E+u#3sy>ebB9PkT6D12tD4Fc_w0^AlKfX&oSefTA%} z6Nli2MGg0uoxq^d9#`#EhTsVuq4{DTN)NI`x_H~9d2vaI(g|79PTBOEz{ecD0=D9X zATpoXHFC`wBvWd-x<2}~4+sJ|8Zy6LJx`cqY+Ib%F6SOFjGqXRfZ@yI288>V;|8Xk z(#bV^Al`j5lVWe_?ju*#dDAdgkgfK{#>TYqE6saZD!l;zD7lY>&z0KR%Kf8je6#(! zc|pzp2h)Fy+dl3#FN+{=PZe0L<9tARaJzom`Wm~Q5u7z4(l2JdLyl6a`H^sl>+VeCv^UnudjAX?i1B^-z%S~ z?ohknRn$>Ap;6lEv!_=T4iS$paUBnW@hW|x!FVN0O5ZdJ1miS_$WC054$WSpfe%Qv z4}3_cIkHKG+-x*czDP|_+970VoU@gxiOP-Fe}n~EBfM8atk7R2LE~6?-w9V&Shwwq z^TvAzyxrX_RHR8{i$y63AeU|c&%Bu5-vinKPEls$*uZ#i5e|D;fow|_DjtkBvy416qmHP6BtLI&BGk+97jZa9^qptlxA0i^ z3@(h$uKH$;dAz`f#~S4JPam#9B4?U!#i;QCP$;#!qh*`19w<3WDGo+HC)NfebIEn1I`j!-Ms2XaCcbb1WEji? zQ1%Sl4dD2*aSGD-tlUoNw9xNHa72(#y}b!1wtsii0>M8%_~B#XG&5y)`xYttdONi} zMee9_KeDVu4~p5w;2?Fsh~gj*j@g7L1O_nUFpL)=mGTfZ?lH3nL;A{3?Zq2Nu=?O5 z7#w;96-&(i#HD05o{|M zDRNdX5#=U{I7w(e#&d3x_KRK(Ybi`l=q-!Vkvk9n_EJo}ZQd?WcB?o8XY=Tmm<@Zd zBW!mGx3`#6cjQIytb#r;z87Y&ovGr<{4E>x*3Q?lRgico<$8kH57OANS(XQYQw3%` zZ@wv{;SCYcnyZ~A)sgwT1X9dvojot%|3MEQQ8+~Tqjb0&X<9aGmu9j&avB3kv zN--WA_?ugc;3B)N(O?d4e*p2rcenPU{yb6ITPBf(hc_7x$_ zH?A(cMNmY42OwZCJbabl;VXxSZ&B=MGHv2?Jv1%N)+qHjeY^o&)n238`Ie)kAwpe% z#g>}3SR~YQG)}S!wP~~ESTVMYAcCuuf-ZhPFnBh9l#9g6e`7NLrLVjzw32jWkbx%g zvL>k0tKV2$5IRxl-3^%Zi{44!XBWqbm#x>Pz#<&X0RzQ)+JX^@*ol&kv`V+Eb&7BK z%tEz0Uoi$-!}3TVmQU*#r6C>8h#^F-FFp5rvR(b}GKrRh@s7VPzfb>iyZ8zmQwv-& zEDn%tUVyd-AKM2Sp>k9EYpB5tL$ov}G^?Y*6h8<5;8pC6Nn1@mrQa(eHEr_c5T;?n z*uz9B1%>Hw0QdomG%Y?;R&6U%9*F)hmoi9Fkv!lTU_siFN*i|=xIN1Fm9!q8S!35x zzM&~YA8!ky=<7#hw3y$;+Ib69@$=1o;yDv-=yWbUMny_&b#|B*hgU+(Dn#H{5~xUN;uHQ6oWylUk%^{#l_-VJ(R%K!ld`88EUUoGYQ|K-F)`310p*#5GhPtHuhhlO(Oru8T5FU!CmD{ zeu7LOp**U)UbtC=<8LndvC$#Uzu0~FBzz=Mc5?%SJ0GtzOJjuw50vS-b}sX;hB{R=9zFN>BzDzcw}mBFDKY86GG7m=|oNh>NS z5tjaLzJtq)3`m`PFZt&CaDr9o{!U}yPZ|W%f=Oc^oR1DtM+(xh*J>4-ZHt6FwoxD+#O<8!RDm1(-C|XweQ=n*keHV2u=*yh7~g zg<5r>NO$VYCxtfr(a=FhpW&rs-(;rfDn(H>odUv|$#KL@Hmq7Sw!Z6h zU;C>?-dmFtBB%cV{j46VjAEdka%9vG24y9e{GsKvc1abVm;2;()@3fb3N0mEa2A=4 zK(cLKqxkC-O=VxvQ$-=$hUPdkp&-|3f0U1KTk;X^&TnmmK>!y36Y_AgwH{jzbc6jY zo3g15=HEM8Nhy7p$i_ay2&RP_7WgMG*VBe~ighhx<7k?p6Gr>FvF?8NwG~Di5%uJ# z+)(9im&sn6xMDTf&v9Fxre%!_!9}BW1iN zTIc)ie3$*(89$=1_zk%aK1%CR)yUB44fj4!KqBC);qfq5Kw38`WEsQt{OLP>>1cND z=rg2J?Dw@6N#JMLTfXEc0KfKk>E+=E&u5>m!B4ov&WU@#obhtlVo?40J;sk@_>b?| zYp&0XhDgser7p-oEpASKbd3DK>Ucd7Uqn>pV`JU3wFSJ62ch*@MI9jJ4>@g4zvMo1 zDwdpzeMGd5;9t0>`|mk$7uIAvF6a<9x6;@Y)x$9tvzp?Etc=XkgkNYhhdY%-5pfog z|J9T#`LLBpa_bGHK};qJz|7U45Z4`u@)Qv%A_4UMeT!YE{OV#V8v|l3R!IGY`x
7Ov6uBteNHFm#fRHf_C`)PF>J*BL@cbQ}1;OZYSC_b~vxhXeeTH0g%#^<}x{p6sF3Q8k(DYw_8_=O76 z$R-a7Kv~M;C;icL1JT{OVgyM#Tv@mQwF&_XjmuRp0y)}c#cIV^`NOWCbmg8gy=?}5 zZ3JNDhz>?<`2p0Ew1A$eXx1rW8=>aEZfew*wz7aExBUmSxcy1g9{h!Ukg0g+G+Au& zf|#48j_p7v0uKt|zApsQ;7e@~Bx;qUN^G)(WtCeC$k3_wCMUC@jdVC?(h38U8EtNr%le^uC^%T?p9x(Hc#6rcV774 zQF5*9FmgP&%8h$$Qdy=gzHFcq9U75H^^mCKpiP*UY8=)YU`kRP zb8lSPhE}>#WrbKV>e)&~Q$JL<4C0b5v?24TD7(R;9vce5E0ui`RNPxz{X3%uWPCM$ zltvleJql2YC2lsoMJ*}8W2#=Li_EJ>F*dmTf>MyMTX__R%jj751Ox}~xlP5D@s~gr z1-q<}G3Q-YfO{n$ESne7X2>$eJtN^O6fr0#vS-s+TV5P~eH1}lVsRX15E<1g6?HOJ z%uBwkH`myQ4ar6OlCD#@^{Otl$2F}qDEPkV8PHY)2V4q-m%(5WzT#UN0m7jLj9>Ff z4rkAy-VtKbvUmM-Ul3q;h_{l_bl%LMBT;}AtB!IB4!;OgE;>+%v95m*)-ufa05Q2+ zkY23_Sc1A?pEmk<73z;o+gygCsF8 z%&}i(?)X!G^Hz%L8$IYI?&&8?+>QITTMeTLr@_*G5JdRJ0ZLx{!r{p1wpK$j%I zzJj@RxUcg(s#!zu=3Ex3z!@L=VoCq$0uJFzuZ@|V22*yyH5{(kUE2b_09WSYQf+UL z_*6BQ@&@?XIOz7Wu@?`1{AwDN-@wYLOK*2P@bK8^D{`EVB(N|z64f&8zp-hLr7y{Z zrMVNSi|jD+iy1i~udNEy4Ly`b6~d*)cJQO4k5}(dkJ-Khh4zQX+kc^T`sM9BA{;i8Wf&?j;Ch&fM^b@Rt|;H7DsvgGXSAAC(VjX1?B9mRenCIRcr5<8%ooPYdG#0Ak$-zZFyZArww*=$vW{3i49=6=D#a}>kiVNHq&zK#Zp6DWU z4q+jNwI6-ntZt-*2L3VmSwoy(fakz|V=9ZzQxjH40F2&Y#RczN#mS#XlXW^hwZ-iC z8vQ~zeka99pHYp168on0==<3f?I&Q(|df)>7{)`wB+##aaa17Vh*}KtsG(uE7 zduvq3BPHE8<=cn1e{jYiVW#Kw36d97z2y5!oGZ=bM6h@4eX90 zy45La%bEQpgv zT@uemPMKLE^GRN&7+WlyQ-?`J4H{0#%wB#I0l2y`Y#e`N63nsDK4SI&wo|tR*Y&to zD_SmXShYZy#wB8II?$o&bF$D7@p*gyfV^RMoAGZ)e?8@+6vY`{Xb3|h9>tUHZb|Zj3!5k1=DLLrpg=IG!)@EGP zcwBGekVYV02}L1w89p-7fPC3K)hMDC(!tDby>9O(n!NJ1zKQf@`WlA}I*G5)R)^`O zp?EEPf^~SiTi$7xpH-q)v$LD!4vzW^ktp}5;SoVZ#HOrIU}S-c#^3{Qs{jK(5!~Uy zfqcJ)BL;Dk<+qMFS&&p=2xrUx`msQ3Xe*c#nN3Two0o8`3MJQpO&i%M<;5txxQH7;50*yL%DkGmX@!c5Y&Nc*F2D&gK$ zC5i@saZ;+K;lHVNU3Rhy67V9W4}f0^L_le*8#Ytp-cG`mB zZ}MScCXsSS-&#wR#kCF%ae1o>vfH~@&0+KDxz^p^x4x8|IbV|N0 zcOxd3VS&sRm~(45zJqx}swQ;1kQ-QM?dcEmP7iZ17T_1e5ebw0{qkjojxFb|Fgdql z{|NvKEgq2C{$tvO=aCd<*OBqGEUDKUhL};a2hd3rRyG=f`WQ!KKl(gfF~%`&#n}8I}Lzsd_>@A^f*t6Q4=t^NY-!tlfe76y5mUJiaS3X9Hf0LNkn{70H~ywR5T zXRhsaJ7(r7ltmnbn}0+QUu>Var(LyB9N9+h3PL`4^-&g~e8&1ZJTh?Bc=r@A3=Mf4 z3CpTJma4;^qK+V>ea#T0^o?2t5+{(&V9|LCY`oRE;sX`aCoG`O^MmAzw*Y~HIdm8! zb+q#x1LLpx@<1*Q<`D+h+MMo|>-7T_TTpmPqJJ}cUOn!f=2rA9=7s{#ItBdv;m7SA z0f+FI^5n_K+{s~Fe8$-M@^10)1whxNLloG8Vun#8fAt+O(iDk&U%C2P;oe4%pc~9)lLEKRbwXiF10cU)hYtw zo=vUi4^P+a4ZJsNv-8W@1N?vFbcR&C$Bd;aCyFu52|5xxWaeME$^$`KqS1xs0>nk& z!|(dn#H2oA8(NuC%QM?V$}Ah(>SYs52_JS6zWZAh>>lZy6B6Rp4((H9;gT+Z zV5Pt3Yg&Cp^n7sF5qv%kVk38CsftZIGoTLJUNq{+DP&9%=>unx^wy*y@HuW3OaA&q z2{D<>Z~pbP#Ucpl8)`YF(dqe_dSx%y9og~Lt2@xOCVg*ID@O6^$NlG^P*L*gTf~2a zVOflnVZaj*DMJL?;wHJBEju@J7(I-xTrLt3L1`C{m~JDXoH5-rguEMfO@_u-AQ2sz z2{!s5%#B9`U`e8+$5*4TK_BS=FA_zY+>A9&5n%K%l@3x z%UF3Le|0{`h{F91rxa-G^e9cjPVP6@@1uX@=XWsh)Kll2V)l(!6hYE}HYiG&zt6BB zO3#~&MVv5}aP5zZE|0TT&v&gIZ~Bg_*Z3`2BQE`|3eat4z)++Zy^hFY7oe_ZB zxaP2&fXaPi`cI0blnUJ9^2?(Tv#N`{xR%&1n9@@Uxr!R8U9MYRwp#~OAPPx}(O^rl zZed_)x?Hr6vJL;!UwDticp{(B^H7Ib-xjk8m0`b#0FoL z?(eML21TjP_Su6TtrfLeySfHjg)mO^^*Jty*%5xvRi43r$&cm{W~d9NZ)qvsEg zCkP1~@ghCPe(U{d2}we|qKbPd^J^qW8QANw!7H6{XOeq5Uju{1zo-Rql%-cTP7#&G z8UljJxcjH3Y79(1^t#D*f?HRf57ZLEw-lNkyf`pgo^RQs9;1i}D*tcfn+wc_KU!vrpXQ`37HpEH*mn8V^je6TB+U%XcjOGlEU@?_){<${ zVTf4hDAkYLljN<5XEk3qt2w)dM?g*O(HcZ;OBlV&DTz&OSz6^}pu?zSES5LeJNN=_ zgdCFjkr!XEH`qVG6yeMYl?WWb6ux7&Q%UpE9Y^~8+MNYwrZL2b2~nw_q5Axq z|InP2oIwb=(Er0Rlg7!Be^AvNd5sG##9R@wQO;h`Zv;v+qGi9Qm`4z(*d zLDEhyi|JNDltR^qL6DYzU4CuS1lIT7siVLN@U;{i4aN!dJ$y{NJ0o=+WQnf3dT46a zO4NgA0plErxAR8ILKBZpKuf?DNQQ}Qf84FHSuaX&Eo|;vF?8llllR6*-yzw-a~^8f zL=ku%jHoCQ4(+A1oF%SbtP>oFRY!IU;I!FV+@1|k^rs<96fpSp}^*P^dl+rlLKk#Msk zWh9_XOku0|U29b5;hkdCz`N*FkRiDaw~_A~iU z0KhyYz~|f>Q3IfX(hK*s^B^9n*3Nf)W9OSof=7#AWUu+L%ie)jHzvVep$}Ipqit$;ty+{RCYF*jNN?_XsJ3+kY!!FggBha|c|&%_U2ej}x+BDk|&} z_S{0}nV5j3V<>aiH@EXOJ{P<;O|PA81mAFY)a}hJiqY&XH%Ta~Oh<5IdgALO ze1E&8v3K(aZz#AB_wHBDb*c2W#Yh!TXgJ;_aXvNZ5p;Q;dLn9oR!<@_}?f!(z<#< z-(=FZA)wqPtGm(fM3(Y{Pd#kDt@8!!Qdl1=(Xf*W1u3V4`w6=4s?&~VW1gN6VJOz% zZ}oV#CVBV}R7eq%Cic*my8-N>IJT;rr1qiF*v8K^=Np^26xxh~kehzVjp#c#*6Ew= z*Ubye#1D;DbTX(3SCI5s2F3ytRf2HnklAIz00A_f}FbaE@D$IhR&npT8a{$k_nJNK5L z8{t=qD^+m(>s@K1uea5k8Yj!I_2hhm(bSw*<=OvSN7`4z>D!c{NO8s;QD5+`DsCKW z1Yw_q&ZO&;@LAeUm1!8F@q9&@p7d+(LAcmp?(ET1FX9y>i?VU-e?Gt>N6r&)b}U@G;5 zw8y2e~9tEq~ ze{KPt^Z=BS*iut(fEu{`|+Q+x%)>_1An9{as74ZcBxh}Owu7D7O9}SiM&fiCfU9+{!;*3;pPrau@4;v#c8Dj8NNcD zR0MEo+GzC>TC1WOm{p&O?xpY)E<9A1;GWKCxnxq-+7r!XWjT&Z=Nkil@ahbs_TKJ%HeWpCY6>_z%1$KV| zEiPt9n6TrXwZ+EUY48QL@@e_;l>N7EDEPu@1IJs+{pi+<@sDNMJ3xh4oq^#cKR!Tt z(p*j(%9mRf&OVA+W#Z&$lP8# zCXC1g`=-8;pkKZNDx~NTi$YNj_$BY*kn*4aMZX42QM$p@B*8t9GHak6w~veI8nbY^ z2ZqB=?4~ci!90CKC3UsVf$9mqqS~+*)OXApH=?h)#surs4y*Qt9!X4oo$JwiNfx43 zydV&T#^Kq=x4^mAR;~yBqDU2FSO(l)0IjTNLTAp%6`i{;kO34rZy!-c=I`}p_b4{# zTB~4m{y!3_%67Fzz;v#VU>geAJ}ej8i@&{|0pdBC9ZeRSy9cC!7-1rA*hfa>FDJ*^ z-ua4}{Th=a{C{shFV;7^+lQHLsGEL*w%XnKAX1A#GXpnLf9T`_AR$;w^SNX1T?&y^ zD+JaSACiiv31));7u^Uflm1_Xh8h^=G8s2n=`t_iTfls_TC6zEwZ)_+#(6M#l$LCi zv5wZd(yYS=uR&p1QBd(oGEtL*Hng&+A5KzE{~4$&sdG=Yye%p1O;|?t+IC1Pfkr$RSHn z*_(^YuI6G6D)vF7@ZkL7*#$};A2BU<2eL!E@}GpJngKvahXS@M9CkjeZe|!>d(vg- zR+;y+Z)3YUy}&t$Js)q^n-`r5ZZ;aRr9!Q^b{nS)X?ilVvBp*hf%5Ce8@OLv4^crA zv*&;hqIf^Qn%(2wcyS()`^0YW)VX@yhoflq%$r#AgKY*bS}M&~Y3{IQf7F-i3&FAY zF__&bm9r&w!8xc8N76a_4$?^?tR65|tuZt>@?hUh`~pxzKXB~m^k%i4bI%B42*`b0-riuKMSl%KlTegmJ2#qlRhZvE;eog3s3L3+ zBF6O1i?r9bv_-A}VthF9$c_(&&mdc`%W5AOK9(<0QB=ZDN}|nyC-|(TC!TMl=Qt)v z*i5p2d!ri?ypvkjlYBS>L!(o&3K>bv79-8t;-ojoGSf42bh<1@CrVAk1-56lB-q1e z7b5hAa2V_)#8(fp_6=8!imZ^pUNp10*cGP(ZG;fa<30WXKBlz_0nWg-U{Hk~vFr{U zpQf2$Kh*SvflJz9OXy+e|WKkG;PE8(z7qTsT;itE5Tbd%jo)LBXK{eWz?U(8XOp4on z3^Gbt*NLo^sww@o*TN>}?@+b)`a9NqJ^r}T^af^$v*4)$O3Pi^HZ28*gX{Rwl$pFi z@xz8RUnKN1_p#rcNI?;PcX8LA?HHdPq!PlN4TlT1p#j9PIK=v<=JX>t;S}BtBTv&c z4n;W&ukhc1*4CfU7aWSQHl~|g({7i`N|6s|E2RRLtz8>(K`Rhue}Q@M+NKDQkO!2j z!tr+SQiE^MBa}g=;dG182^=i%Wm`7h+H<46Lkvm|MIG8bc)L=O2L+0N;Y`=uMbUy@ zYYGY8t{O}}{u~S(r5re!w5)vxDB^5!jl9M7CKplTF{nH|TH7-KChJKD(Dn07>s=2v zaxGm**i$al-bx$v4n3kNYX4B+ z*h^X-#N7?JvIudDGi{tssNCnf&EY6u36zZk?)~-RvAB4CfOohhX%3o1)`v3;H;VEZ zBBCoMfx3~|?=(|v!OXLVXvEqmczJ~x0{0&tfy#Uj>D=E&1C0Gx__8b|6)8i!m!cen zSb-2~ig*lPoh4$V6+DqVjq;QVmj_~2wrIRF0^${x)kti1wLGlq*tDh()ipF&K780D z<=D9O(4_{agL1lwQ!{=-Za6u{yfjFgv58eE$jo%6?9HndzL@(^WG+r5GK`}m*#3G9 zPWJ8UQM*|}v^Ru%m&P*}jbEm^dX-nmhc*q>+Z?O!98nw`>6 z{sZkJ$X{4NiMHf!{#}a?dii~hv;k)Kz-QCb?3X%|JxnT9iBq%Rs!COXLCj@|qOTEf zc!4HbSETp$H7d#0#z|Zz=@qz?@&3AgqZH3kB!rfw@sPaoBz@rol{CABDXn+`@ z%1nz00YDo{1{v4H7Q!LQn8$%*HUMGz966Pth?gW3h;B5rGhTeGm_9(lEXL3PDR6;x zMc%3tqvKW&?wiAF(UUoMhNe5cj4Q>c$N>225xp`Br)UhwtOSY+GRDh>lxb>(T+Ycs zvp?<~G?uBq+&`s(U?}6$?QDS-sgg+HQ>9RsLfW9T@8M|^V?n( zbSn7Rs8W}HH#i9;pYr@rK0v4CFg3rr+Y%m^*yBljYYN1h&4M5S;*Wc( zCmuUW^`d9TI3BE>b%JT2EGWGA4!0!hG#ZU3Cd1W6jZdWS5Ik_p4Gg}6RPH|#7C0Ym zfxQ60GDY!)MwPK0Qn$9ukuiafwGT?gxE=W?-0gx}@2DTxGk}A*-CSNi%jAB>d`yON ze3IM4M55O*$#`PPE{X5YaQEVUqgW^ihWbGR<>%G4>VzejA`XFX*EwZZofw>wc6}U8 zz`>@gK5%ZnEJoq`nV!}MLV4I5>;^@xvN9gGRO1Z4Xe_4MfZotx( z0CUqD(%H!h8!Ehk6((m-yW4Xe;>Ucd`anPU@?t#;D2~+viuz(ZZznT7HL`@UTiFb= z&1coU?}^rqCFjl7<%b$t39m>E^^wynZbVeZoU5pxm6(nDRe8OwvHKs zw^U;ifX}S7Uc58-Jcu0zpKSRBt*ZXZDAke@AY+1S_rOj*hi4XyiWbiwaX ze=Cms|qTqCU7u5vc?Ds>afh z96r+=280s1Z8Qq03X_3@?7+}58WfA-R3Ab)Bj$ll)EiJiXu)t`zJ8hiK%}%`tw@3; zoy%ij2g`x#JF6crm}H&JCnBuiGOw(jdkZ6b!Q5p**ue7z0}X+QtJ{lzZXfm25o@Di zbOVOZ`C@^=8ClqK0VF*?`xNFAOK}iN+jbhjN>Eiyf6A(&Yyg?!t5LFhS~B%NohcuU z|JVgMi#}bw1&Z=5iju^+BPE*RqxjE%G25f}$cd6#L4TPn-HWNYzJ?y9+VZ$7Z0VX% zIJq-+|J7)s%d@SdV(W0{9pTQal(zO(k4qorFZiq56&_ub=Bs0_m9~y=1nKN+--8}K z7SN&+%&2>u9Vl4Ns$y_E02XL6fM}8jsC4{t)9-`{V*2GkI5Va2N=9ZNPGynn;_Y^N z3S|Wt;uAG0F$i-+14v!`?-HE0n6b?G`2xN%?9O$=R2ukbMXZroO%dw@>Gh_pdlFTU zsyLz>Q57dNZzdFnMnnL6G#c<%H%PKRUP&tB`SPzz!!<+NvfV*Li8Q#K8%<7O>6Q1^ zbz6Xgtt4tFC`RLd=k6ZZVIMLcxOl$yTzSyg_?T@K&S6f?$2L|T*dgoDQbu@iAINj= z?8&pRjg!@1_enu!RfcF)nOqW{D#tXPN#01TVH8kA>dTD_zt3d76Ku;)a{HIEEP#cy zZ)TrXYW>`d#2J0?`D!{X2pC4w$X5RKi9NSis5*AD& z83xz>Yv3jPuQwb|(8!*(=1*4}p@F{nfshvStd1E&pwZ{)H1Vzu2&q-7y~~wGMl?9` zIL?Lbi^^*a+#SkYCtomtlAtPO{x80G_jU8MMcf9G>!mJSMdZ5MfSe}}<{tg^lwRNp zN9zKUgDHH4%95uso^3|{;6!%Q2=0T%+p9rs<-jOTb8uCni#;8WYP^ZgH~b1sktQc_ zznFntc*VB~M>#_e@EU9V?Dg6YnHyb2NZyF^l3aDd%3(p_0hmTm)P0t$*cAg8q>tb) zQ)Eoz^vk}7DiXYnX+UGt_C)I8YEe*YQwk!^*-l<5(-47V(*wZ(cpzIJ#b-J~ybtLE zLp4~1k(l6Qa2`f6cflmZPhhBPh3-5TL`t}(^%?;MULu)jo6Xu1*=fTm@+=jWTzHpQ zq~kROWZZBa>6W}1n>L?>iU4wQM1H-*g8vp>csA+VjzGj;olF8;LI!9OP}~y zqLJ?I+t1OkM-@5R`#fB=7mLGsLb;7nvf~uH9|R=#oCWN$*oV1!%&pR#UpJK5g+{k6 zWcAM=nXT$hUw>W z&kEefesaIIJAF5@J6+seVVop}EAY1|3n^5lZ!BN-scGfSoEo#bg40mU6>XXH$Ai35 zWcFnC+cT1JhWCUP3h;;}NMgc1oX-9mf9t)S@urzXLW|}IyAEL#0tZXYi|YLNAYRfC z)fwAi0DYf8uem|LQK5fF=qm40{SqF}TF5eoEy4N#sFn#APhA(V|Lk5@Y4B2QdRVMB zr(Ps(PL*WAZ`fl5Z$M?Se`s=YVA5gA4plp!eY!@GZ%L>EFiJ88U;XhtN+D7K(R1*GIu)vw+|m32GS8bbV?9>ZoSr* za*u!XxoMYx3KKl!jodEePAZ{S56~3=3BVMN$Q#EXixOBwi<|?gFxSiN4=}RasZUj2 zXL)HLfcgpV60r4(%e(On6%#x<46K2fyt)u9z(<7FxSZofq;u%~`h2G_{uwf4yRPyai*h{vuCk64&stm{-jaNGV#ABP2Fb z>=(2T941r(P0OP*`NNF@)R0RfG(RHa~e%|zlzUl{!4`sr|i8( zKE-fer7rN9E>qJ(nw;p4Ddu_W`2!f+-(QK#>%|Kej2VRtjGCx|NuaNan0o5D?o1k7 zd{u63>=WI_l1j-Vny~)pa?3=*Ocq?FB@)GxlvY|58*es%RUpev5ZNb8f8wgifj z9or{`Ye|*};4piF0e=Gv1{wvXq2(1HF)Z~Ya-ZyIO{aJKmMCwFEI{5upUl%ZtPk{+ zT(4~#@`3?gar=B4cD7QwzkT~uwc_YEB)v|BhW|G)G17i%?;9>-lz|lnHonAW(g{}u z-zv&cx$e)*f=jj9gN?D^evr8;+h^tR>!@Axb z=YcwldMNrEmwTbU0}l$N36FVOJYwSMOu_a8K=7D&Nae7g>#xu&i>Y{837eJd5Dc9- zF`URAioRqqbbqAPza5MyQPcRyyxm!Oz;Btu?Gni|T*#Xi8`GhYqA#XlBT1bh7 zM-~YXS^SI#jh_j%#^9OQgsYV7;06&ss5VqM-M`)c_?^=O`><@Rv-|(1HFbM{NA++$ zOcS#{6&7auwH1h zCE0A=?M?ARn)LL*h8`~mMzoLG7HZc_Ovd@6Y%!AV1(}UlgSOA=G^Pn}-n7q0*?t1jmMG0ur54^}%oA^J5y@x8}!svQo+__?;0W82##cU!kuN+h4wC zr4RD5NApitch|sO;){Nchroja;}0lO=%G_;*^PKFHBCVThLGSZkHs3L&fo&4r@Q5P zoftE{IO=B>{RTw0Z$Err11|VDm7vD*n!Pkrxxh4`A-IFFA{DW44>D>*%%bpR)+b=a zIthkH*w-e9sdSSwhbg}H=oKr$^T)^ekJciFq0SsUtJM6+GxeVm@x&TWH{bbWyz!`Cyt`g-h&zRS2gRR= z+==*L82G&Trl#l(<5@XM{Lh7a_c(h3Mwukl-&KTC9@OOUI-ZGCQqR>&BKR9W^FL2e#bCv}!v_DvO z9zU(rMc7fGB?kF|!tULySzc|T*m}?sof0&8EgLOv*97A8qjt#Pv@nE#`hf&P1Itf}fh)>)vEOR{Js5{H})sdmDrengtBQd=|zOlyLp znkv}bey1m(@yiWt^QiVowp~SFMKsrBdrJhmoo>;wxt#?sX zAkLUC(3}15du)EbnZ4UQE|xd?ANUYdVA1Dw4}2iHs+e8qcUdwL^ha)FjA%*O0JVgk zaO@nxKOkU*`~pcs`!}aWpwK{EkByc>W>Jg_6o$&}Cb)@QN*?$A!NgUMQ5B6f%D~wcJO|1fXyva& zMIi+$4@N6q^KtbXGp5eu4S{@^uV8T`abqtwhWW_f3;_86a7{Q+0{IjctPFCktE)1I zjHe(gh`8d5sKgCof1>y%A?F0XRizbz*KDrfYZB2yWuf#&i{5j49*KFRN3n663Ns$g zU=(LkTlGMj)Es(~I2%KJPqSPN%N&5FZsOYlxHaCG(M#0CO5$2L|0-i>W`1}`ZRge(0OVG7Aqxk8VZsTW%&Laz%aXod4!>>mH1+pzu_;n-C{izE zmXx-BqJ)o z8Z&%ag`knd0Dm~9#f!Fcb%gkgB|E`Um$^8UgT40zMusqPA_k@dN}-oWyQT>_xE`ya zlT=`&EWS8}AfPa}8qLA)2cu+xO|rIuLy?F(Dlj*s zDHWUTGnkeOS7W~ZEdMb1e-pdX1-GgsPtPuweQl5fd1*Fe+uFQEpcQHLD9DGeq=tgic z6y~RuJx^o{w<4)UWITglFm+9H;lRri`}lF|Is?l`4;xS*3rHOci=VN2c`_@?4=ZBI zR?eHz69B_Yk=I%VG&oLz^Ydj1lg6Z@JGSwmmehM2tlVX(5=Bg|W(_KpZGZOpLi}&! z3b`1hZ(vL3wZ!li!5g>506rZ<(nO?di!MT8X*os_IxO|hzCBk+8Que zHki?~7WVdk{)%zpze?y-A#$3l3(QKThx=K)IZaz+wQIb2ar@%{1J=p&sx4;B`bJ(S z6Z&vRhl}4raInYVI&x=WeKPihf6ee2E+?%S_iF1EWGS8@09ac%S}_z6xGyvm zDt8e)C+BPM4W1qJ^|I7sLbUMnEo^y{1oq9%T!m4EwDR}H+8QH<1T$}nPXL;kwCb+-o^(Aj9F*JI zC}&O_7D}a7nb7Y+J$9E{BftN7_D`^dDaT_8%WhUTURa$CFBM$BO1Y0|^mqm!VO1S+jJ4*JlyFE`<_FKzur;e5v>k=`6AlZ>*~ z!OCt*uV=gO_jA~n z&5OaWXKyF?ue-a|&fvG($?^6pnpxjwI|wY4%d)z3*AB}@0n=r^Ps7T<8RZ(YE3Z)P zn&}ju1sW-lJllR-J-jHO60w=cD%q4AI3~7c3{kqnx7Efk%s^LQX2gRFyD`^ zmGNcLBuL+(eoU_T2Uorf=&E=*qR{KypML@P9~g` z^<+ct|7!Ib^0Fqv^fGZt#QR=~EYJmXJRPI75pDJZ=5fBeSfVi7YQnx?T2Y;{i^)*! zMlK|)li@L2*J=*U^Q)?-^YfRHGWTH_3}ZKU1I@^i*Spgp{LQL;jz6u;fS? z+e&zBBELNXYS`;n2U@zp-FxQ`Z6wJsDiw?@$ypamM?XD>)R&kxcCxmx3R;GzWdVda zTeZQ~0@9-T<4~#}cTm=E!)i!)MW>aXUEDpaJ!3~;P-HWaHLn9=PrIX^EP}{xvysrv z%&QW`6d-^w@9j<}+=UBA6#%1^C$moUagUp)2hQvr90PFFLLK|9giI|9ngf%3YaJBh zd|H_=cBjpQ3V|rm2{P<#aHdGuFt~^!+z)7sVvxV}76*8!cneIQI|Ls**Cf$bqwA%z zlk~|Y4F-7tFs%%MGKHTQbu?%1w;YYFxqAJldhP~#kZlo%12LXpvxD+|M36q;ZkvaP zB%vGHD9Hj&HwVk(F8#1zxu?Q?R_;dZbt1zz2!vWF!fE%!k){)&k%Y8 zgOez_e|5jBqG|3Qt>|pXsfDc-I8}UeMV6P&vl<`%h5cIDh?UK4O9(sKsa{0Fp?bqA zY5DPHkyiN~7+{P^rEc}e&VK_54JILls#x1})`$D$F`C~tg7UqCG`OxVz|*#qrvGZQ z1_6O|(xrL~B$^ParlyZoOBhz=BF2N)ElBQ6cUvpcC9g)?B^^lIQOdf6z@-q2>ZhM93(J68(Zm^UL=J zhbin%%Vz{)q)9w6Pv3!npP^I==D)26)`}>*8Z}Dzb8}x}czX0E)#(MHel%0q08Zzq zBqD@+qSwt_aICp>M+Gf)(Nl4Ypx#?xbSV4Jungu-il|~o+IbGu%Q|S4fJ8JF zt=Mq^DIP(xkb^(KLNq=^^27L0JW}2#imP@Gre?JfDeY$lNS?Clkx15_HyA1`iGM{6 z?plE~*|gnC$1iu< zQsgO%Z=S~|Xk1^{cHD$S15$)J_AQn>uzGs&JUxE^24(eq=~Kh$;e%R+B8kiOf$>nh zJA*Ve6@#B%(sFPNGV$P%Ztm$a1!tJTnxg3-dT;r91#}JMGp{A9fSii|rH-{zu?S0D zdW+!bv~_90A>4NAHX=ETI`igFR8xDroBFM2w$w8%ja_Rhdp95DtLfziJUWG;2rC)E zo#@l+v$Zm2$-UY$Xfh}yi1c`elnxSQEJV<11s3A+>&+v^E8dVe;(7JBdqRiR%l&eg zdju>Jkk{kXtvIhvLC88(*H?~|_)IZr$+k7!hwgQN(u58pWqYCpQ4KA6$r9f-2u#)A zwE|8EY}TX%fNAS5979a#^oW3aSdryG*IYn{3-wGxCM3G!*@TTfnSFTow{ir6ZBi44uYI zq?lUP+e_Z6v}9^)vx?ya+;9QE9SJ`I|L=>Xaz!UcJelc6Mwsg5#Tr+)wvoF6QFAwc zXyN4jyQ(+rG?MXcr}t|0VoWY;S2;BKA7(vI(3QMFe7=f#SJip+_#|m|EwM*kn_abq zD`|@-r@}P>Ozv*=-`<3U8^6PY;GiSjW^7Osi`n!@=k6Y)3c zml{@Joa({xSo17pYsW0FH9mA;tabuWxruy29VHw1L5hh>{bW*sVDIaSY*JsIxHUpt zU~$)j<3oHPloVgQ4keeM`YuR{K8v4N$6$-H6bL+67hs92ww9`XLe(48IpHX{vz&7@ zDUj}dq~nCq-{Ux`1VD8zznz`5I$2e*G{Of)ib7EkB}{G}2l96%>>S89szW#_NjWe$ z6OA<<9RLY-*1Nm-mqSMYASsJ8y!d*ApVgY#`a2ta&9i~vwM)X$aY!Icdl5SZ3R|l^ zmUICeAkk3o<@?>W$VLR$fpxIDa7Ut<%w8#lR)!gYc)y7e??)3wyaQ~-{ON~=NQoudpg(+v+Aqx5?J%%ObD z+==c(cREM}4ZKA6G6y~dVyxtk2O7*Xt57uo4DC>kf`bQ$fb<&cnQ@6G{JfoxyunCu zSp1fk`lGbCovE6+gP;t6$CA$}y>#jo8Z(TYc_#)sa~;}B`GUEK`A!zJxQ4PwH54Wo zDi2MQAF1-`?HY7K?*D|?12Z4@%ST!JX$#7EGt9`nlb)C%n0ery;_?( z96WtMbqk&L^V!A6*}IE>fG_qHaQkJ|ALZ%g3r&~`M9MG*57|pQAB|McVYxkc2Wa2m z4>&H`yzG>L`2`Jq)#6|qfqjpAggZzO8pFW#aI9R`1Hv%~pBr|~;cxbnP~C|Ki72RQ z?;c2tS_lU~K_sFU2v1gSk!I?1CbqKgt}Zj!htieutE{dLZmBg1JT^?7g^Y$ zJU8v#%JAePl9QuDVPbj$&bY zsP?;^kfU>6SJ+v^@%j(#XXWdnRIO7Ds$O31w^%Q) zFkORl)#4e|=%lkAcmx7;W4X&t(&FyCr@4sAt_Z!oTK>DN_Vo04qXo{~!OP9Mc~vt7 z@nGDFzH_R$ysqauU}t^`!#D(;KenQwb9Fyg(TM7hhOUv>al6BGb3+>QZdzeLhkhe_rh#!hV$o^h-n05eZN@e-hn0B&tKk24C@SdE%U2Th2{Nv;1(F2mo z)2^DHHg-pQI*X@|H$dh|T|b8sDFVy1c^%l5L@V9yr3$+it{J8C!IfNzLng023Iycy zkB6ndc@gmp^eG8%zOM?Jcws~s#F(#qj*yhFE1}2BO`Bkd|JccYCb}~1_7+CTOSeft z{3fc5v|l>gwaBzdmZ?*-%cr>ZYWa~GjP1#y=!!EZC?;h%5oWUreGwoaFfhKTEv9`W z%>Af4n1CtnrIB49zL$hXzRZ)1f3*_j}>l{;RYp`@sK`!EBuW#xdozer+< zazyA`at=z0n&4x~#8iUVM$`!pqtBijrn;P=g^)Hsnxtr~_}fANHF6nsi2w?b_;v~g zTjYeOiM6{i%9=3+T@oL)R{>xiuLSXV&L~b8vP+Q|_{?@Bt|uK>h?x8b0@AWyfo=h3 z{d65Kog>TK$Ez)@Kqi^XU>~_1yNh6R0~jw^eI`PKPNg0l=(xM!@znDUHeE^?0ZJ=q zB47nusdj=!`|GzXwa0%w;q{eqeJP6uH>U3ZqM*uv@D|TPZ&HWaW$`o;ebXTP9|^KM z3X>Lq?=#N$F~}dvQV$<}&ZQ8K-~^|XK#d(C5*7C1FBr`Oq$wZG(O*wh2|Hq0D5*s6 zMr*&%i@^&_753cKL#B|*US;4B()c3&Fy!Tqtcqz!hcia}XZ})5PHYX6<$1G%f0Z7h zm#y$5CDIke7NK~Mg<|nuBjQ`i;i2o@=4H`5U~78}8o;26AZ7xPF8n9WjIk zxF4=;WYjD_}h9Yw# zqCdKo^wm{TkMa=2Ld+my4Q%17I=2a-*g?kA)Slc~p#>XW51w%Job3!WNu71<1w9uo9>99UUVZ6XvsG>P&BVxId?{L2~u-~gnvQd z(Q6am?Q6%8#g$xff9vClLu%eV_d);L6)CDPQ$|VyQol_gf*Sl!j&iMFb2~K>t!zX3 z3TzW$p>56#im$Ko5VK|U`M4=73Uoe^g&N784t$YB4+rfjLSz3JiAOMVjEpa_>2PST z923{tilEp1*BlH`KYOQa*t7raIK0lE=?q61id!6BT=T)55C*tVOE#(NAzrO9)QA3p zqOt~>_JWPF)RC2?Xt-#x0gAa>-J=sA4ynfZOzL6k$(!}^79%y7IE8G0k$!c%YYkR6 zpQaTv>ccs9{21DrNKv(GjK_sl)nhKkXi~P*T=Ia>5FZWKFx%eu*y;|W%?}&G%se_T`R&amSPtBn z8?druE@0L&861+@S5cVa@d|~N6SqXD8o3WXY%1-dNMYsF+vD+RF@*?1PY^5l&I`Bi zCA-)jMoJ~M7-{t~wQxsTN3FVv1bxwq26ohot;qmqov?5^I2}D|DPO6Nk>ez{K6SBK zdjFut;B^K+OVChUQkM*c6@k**>?ho8xaqQx@){<2^8haR$OL!3b+d*!RFh66v<3kr zhIE8yB>C;~h0-;&rfMnJUM^BBfX@0rQL+JTM7Ys?KVp{BCzc?zqiB$RHF#I12C7{= z5Q@T?i^f{GK1^eA$n41CpUTU&hs|^_pEBr~u4qm4Wzi{)TTClUzFH^<^X=)%2U@u1 z{6p(=oi)>-S~-!yzY#Er`H5tY%c@$2C_sx*_{cbPTjs1kV3q#doheaa?INxm>tJJ) zi(Gyz34E3-V6JkVWs^LzbVRMIa+VMN+p+6I#YG7^`Zhicys5J-HU(pqvh#TvDAwZw zjxDu1cdbyX>Cl?ClGW1_Sh8EdA%PM8vO+iq(*lkPUBdcp`D3QM49(&*)0Z5N{5j&! z4Fb9WsWkWX`33r=@#X3D^2^G=>&34h`phUuXWZz^%^cM9k6P?-=;-Q_eOnldq*E=! z0V^!6WayF=(q>P)+vXhtS#RliLtwjyX$$5dH!i2~m+ z;TD@5U=rXY$@OANaEVig3Ml2UtqobeS{{XIVhhF02Y`M6bU$Abb`vafp zP>)aBJ4=3>uy>cqXt$Rb2wFIgt=pNVUZEUE*V<}2<5%zga?7}(J;HrZLEyC%1a4Q4 z89g8g7458uT8_wi3fKJMy0O5%b#vZ{cjxx6(|YEjv&1aiy@JtV*2UCq{0E#Sxmsg@ z>$s4BACr1fIhXKUt}2iO60By(OIL*nYT!RRHPH4ti_9=V-1_u_(*nJEx?lbKX(^0C z$RDFnu;}cZ3PU`Qf5$V1*0|mF1D^(ANr%Evae&lfO63gY-{1|sQZs2jEgLvhX@TH&W zMQfKZ=p|*`5h&wMLdv*&F`;h?v|4L0RwirLqtN^1{5oE#U5|lg9-L&00^0DE1Yd(2 zypnNiChT*dKw|&x{>Sec&s8mq7Bd~!is=8?K8IcQTF3?}vALZ|J=v8VFIX0Oe8x=> zY>q#JnZl<)_(u2XM)3W#3mjJ~OaJ;?-RuQ6Af>Q&poZ3Go|JV|6*Y?}l7iPcLSPg$ zxB+y2=8GO*och+&Qu>W96lYeNlq@yJI|w2#ZBG42oifeamBOZjSNhnw>^$n$k^x}; z7>LZ|7d8<02Udmf!Zj+N@pd1iVRBqV|L6xY|NIM}{ENGXX1b0iCUS6;&2t^^kphGG72MjHxFqb2!(H zISjB-W_g)E-X!|P*>3)Yr<7ChLFOerGJ}_DRE^R(W^4?_QF6by&)2>z{s@mv1HQEo>t?D^FC# zlHz~{_fR-sk?zLz<*;^43wQ|C*FF&b|K5V`CkM|*Xll>ESTl)OatZ}615VlCf&s{= zvDg`jN!TMjf!37L7#bEI$@WkF9DJ@`4UJ&V{wf$pWutqvhh>A=!*N9 zXfH378a#y-joaxAh6|YFoh2+O-affNeF(+As~Nc;U@l%(yRW#+o7G0VId3MTRssQ- z8Zx8JXQV-dzg5u?Ia_XSuhHnIx?Z7XJ^l29|5{qF{cE0B4M@C0ILtal^&F?p#eY3L z2aQjipPwKC%oE9ZKP++b zr5N352T);2p4qor)t)3k>g$rbuQ%834L-S(ev1lbLA4T6oqyj# zIPYO!k=3l>6J>uL`&FI6=iBBazqp;Amq=Dm3MuqaqUhB~w-+rct+Pmg!AZroDD5&p zXu++4;f<9ns^({w>7bV#`wBhfgUL(el%uD}21n^n>vvE+wdMN6e>69+#h4?*1`SH~ zgMdM6hRAN>$hIfh_bLxiH+?JtC)@cmWbbOz!QXvmou`9=E0YNkK`&rn2LQxUgwoEn z$}>c;;KHOiG$2Xz+`nPRO3evOQzz$Ja0kU8V3LWjSQGrN-Jh1nnoWaV{sb!00I*UL z*zVDaH}^YGPD+X!hOiwCTSLUVZN^8OFAt)lEMSeqt5ZqfzDi0wIIWkD zs3q__J=DTIYo{@a1%eMIQm+vUd>>h+Xlu&&hZt3yZr60H;gltJ^zlr_A292*1*utA zDgP&$Nad7anW4hg1VA{{gV|uSB-`zg*U&bok>p{j;BwWpdMJQ^D`?^Av==Pt5azO@ z*>C8ajA)LsG5Rw^>_hCkrzMcX9Ee&`r;3}PBt2nT)b^49)m7_&EQYEjk1zuW0d$}& zoiC8igUjXh>=Q>0Vj#u1yh3GNtu!B!k`Sizfrylwhg`lAyg3m&R4^28eMXx$<&=HGt^ur`vg}=C?bxn4B#(PpDcJBw;%1z(wgks(Mt7PyC`* zVXrpKzAP5&)iq#OsH~!n`vsdz7T}}iIJyc{uj`CZfj>7a>>U=zg2qvK3Tcjx(D1b# zl?9!%?vlFV$aN&245b@D=rnTu$y_OIVKHZ5fGJJJ(nEIomLT8OvXi8-Uzb?y$WD;VezV=&EfM1@h@cY7H|WLwkabfXaw##g{Lsc0bOw@21LUtYP*#e4ec8c= zfXql39BQ8Qw$*!&&Z1y8VYsxXe8pKyzcrH{9wtN^oUtUv6l3;M8nf-0uaLJS zqCE{K>dah1M>!HwA_N>LnOAo(wZKuSzcWHj)YIkPu6FCaF4-PJiEIhwxXflKH4?^o zO4B-)0&+)KL_`{e7Jnrz2-wStetZAD$fxdtmB~_@w57`JuDx)wR;9V(bPp}POoM`+ zqf@I;^QThTY&{}36{vEm^*M$5cmt&HRYTib$aA18Zm5nQrsJW`!)PX zxBi8uS&S;1>b|Tim_nm1MNshcumE8$&XSuCF0Cu;$Dixv<#ciMw~kSG-;))}EUzeWl7ZU0KzYgyc3W_}m|1 z4grsMP+|uB3aPMcMTZ~w(4uKVs}wRv322qu5s6 zJDw{DgY-CPeNvoV!Vw!Co#^sYNiQd60c8plSLenjGIDNRE*rG3MN={!)w&?XJ=6;c zu8KzEhqSOognH%28(YMZ%XZBZp&vzI!gg!&sQ0L{pA9anX^Nwx)Ikifo(;^8T&qM0 z<|R_Q02`zh^LwoQ1a^$Z2&VT~wj-TBF24W^DX`V~{celE_{aSYJ4ZAKmlg}8sNMwa z6tg4IB!$ZvATg552)3gXwIK&ooTq(HpIJgpOQt?dFgpSCnGQiY*ip;5UQHPQOV@_h zdIPBV^NyqJXkZHN6O6gNx)$88MjS+Yh~v6Udwv|UP{3$(pwY`Hb~e59sJMJ}5EBUNZb36lB=M|F5=diIMC&%aw-{NPrj!2?7=^l0~E_ zt*PqnarcVE?i!~xj@@#1;z&U%S65Yc7q056R8@CPBZMNsA`yy+kPun0felD(jKqc& z-XKDno-w@!X0~&!BR)axX$^QKEJTQVbFSvL{^3O1tt&x6@h$kD8klqoXlo#+)|+>&J*F3V9;Qf zI{4I`gf21`zCy|o`;QYDl$knOR<{JHx|5boI|Gcy7(M*piC^C6e~Dg)>SeA+$89L+@}#7}nVf%)*ynee~LF@y2M;eKM-H z4PEZJdYu_os-A0PDq?60tbkz4sdhnFN6qbaXMBP5P7hbzk{d)5)(b%3bdp&^FPQ1NK9j z>~UQcG?-rXFSN2kv@aFWms>44Rl6P3zhqAC>XAi`1jYB!;$(99h_Tfw4zqvdD=g%_ z9lhhRwNff`k8O?2%K67IolXL6oAggXKJwh(n`D8c2(!fqRvN?>5u=-EAv2lQ#$C>+ zWGL=BI45^CfeZDU=TzntYb#hT3x5o(P9u^BR!@*^2^p}aY#S=QdfYarN3`T{al?1S zwW_H6hc?dj*UWQYCaVf=Dm(}97T&uX`J}fP$_s#I?wS*6GK6}D9s-ne*(EX7p?pE> zBLfol1~196EXT?TI7uW@FWIO8k`ts?!Zb4bRZJS$p%O?5m=P)Q%XNPa9>(HllO5)y zkD2{RrQSWRB!-k}Hp6hy4K2Be+q0*w-41l!qcGY=#;QyMDZ#vLuSZK>OEOL3BL z_jDj}u_atkVWudr=_x`gxQwnUWy+M~fnw$(3&IpMOsRQTGb)JZa9WVGe3__A(SEO@ zjcYYTG3N(_+7FRIs3Yl?DoLWB{H07^A1p*>_7?s zWkY^p)9!F~o2^e%WsV}f;2`V+Iw|xi=DS~VdI)j6t405U=$Kfz=x(&H{VuI2Qb*B+ zW&aZ8&MuG;+SORQ?`50YfKjy-3u;uO3lFLDu&c34cNc(65ToVZ7QBCK>p6&tu2iRY zEK#ps|5j3zfO>!mhLxM$pPaT2AEDXb_18GB`b;WlBYz2OP!0ESpsta^t@$TxJ&r^riip~v}JqOZX7 zisustJt(ud;FCf^c@Y5cQ`~Og<~52k+%Q3RJZ`vjg-s&}I9hGTOow)5raoqvUq{$r&acC6aJSfq z%Vj1gUYX2NiuP37Q=gVS&Vzf7-wc_Dr16W|vu!Wgh z=uk#$Np zNqm4>UNvaWQc=sxPIP*3$K!G+bmRdSllHWW6;e2GzjHL-3k>dlVb zkTJ)MwNz-(jce^T=wlM$*--NgCaB;`Xk*i6joh^^2Z6tdT~wGD3>i*N@5F@=$dUMV zOD8B`Lqb|Hmn?V_q2%-KWIp2+{ib!IC|wQWFHTphRv=L@^=3#qt}D3bwBxiKjv1_A zvj?N;d?n5(aCY!TQ0e&c-sKbb#wgfJ^aa4nwlo&^!ooC)+KC`}mD#=2ePdEU*Zu>6 z2$QC<2_n3;+3086y9@}F1)gi^9ga{U-~i{GKLv2Wm_gtKB|2}M`NQetZ9y(D+(MVa zzyUKARhdmhetreARWka+`D~65zK?_3z1QW3PEvSoNT#UjM^T~+8Jer>+3gZ3y-QT+ zkuH-gdvlIb@omZ@+xf7wq}$x^Rs*?$LICW6E}7l;6^+kxO>(y2?(5BqZ}XN5D8 z2!qt|OHhSAFcDddfrdI}9*zL3x)p;aZ*Ou{+epyX+529*ar~{eeaHnlv4qgIsE9vz zi_@|z#H=r%lkHPId9A#B#+nd2017@eaL{i8KQG}9o*&{2rJf^>2lOZF{yln!&4ARp zW9^=qpz7vT3{O@YfFu-m)IQe|aB;0*Fni!5iJT=7>o&XZGaA@CSx6#RgoMNwDk0m( zSk%_G0oQ@UDDO$03*S9HHNp-sgLs2D6dY=J-2*y*+d0Ey_u}H%?c9oe3?&? zGYNB|zROQ9xJFu(Vu z4cq&U_ni3-X^e}kF8dBe8|X*Pn6SAs4Tk}&Izw(RG>(3&JrlUD>iJ+AG;gbZ#>7#x z!LiDe%xs&o4f=pffH#{j53`ItV$OET;5xt?YKSt1D~lZ6r5+_BR&cVt-YNcx74#ef zq|Vxh$79q_1%mSG7OH8NNMDyTaR}wMp4YNXOa&SyPGhBdhQV%fL9h=lOf!m~Kp9Ck z@0z6!(_SFMl3kH`a`j@w{fV(w`)aHbDBtqhVt^`k5`JfK=ES3b`6S!~b|-nqxC*GD zFofX}H^LaI`Xpnf#&M$XRv2FgmkVqw^U&HOB&1d9 zu5xzeCQS?w|9xy}lxRk>xH!i^B)LcF>zyV%!GX!P^ovH-q94V*Aw?t>t zizO+zy;aw8J1PI@@$oIL$tj)3O9US*K^@oCdai@+A&lMi7*%meZjhqLyP?vSa0{~8 zoJ&ZheJD-)(9#cG>A?uc=-QZ}9AXQ&Nv~%#V?o=NLrd<~NTFKBFrOeyix53~iS6;w zj8Ai?iCYx1{8_~L-r=6%K;Ty8nwgXY0*S}4wn}-Su;FvHxKJ_(kq#A(9`FW@l zo7AosN2_B%PC23^en@!5Qm!viU=$^e1kP;#D3Hl^f>=V`aoyzfu~Br{pc zhB9@T=<=eM#ew@#7`H#8uHm+}i6W7?7`f}J&5*X`>VX{N3dl4SiVd@HWL(32{L=K` z!2=RB<8F5!%e+=ux(R~jfPI`2i7?*6+f@ah8SR*mW@0~o=9y!`S0I+m2=s^~D9Awk z0^f-8&GNA(^E%MCnY1N}5m9pK4R^Lr6ZZ)YXQgMbchcwwxB}%a!CTS4xLBYM8w3U1 zM%ieEb4fTWrgW3!o;$7zL$hpNl(buzv9OB04mVEw0mA*%=MvVQQK_cBJ*Q}8`50c% zL*yLw2V;#@&>jkv6x)E+yd0n%__ypzMKnn6nGdcQ_G8Y#8h#67n6yK*l6i%L9F-bR zABE6$QX^Dv4zw_PK$b!_yJUvIa9g1`<53UT|G_OAAAzeE!wPAvj|bcA52!YM*fj^e zqvh>|v@<;cvIZ(6eOO2!;l5Xb0YbmP9@4i*z#yZ7^vh>o?SX{3L>xXDjto&{PZ;st zs=SSWwgP8YGez2g&g%HPMzSn+qs86}Q7AG2IYD~3!rat|l>km-kVqcjgw2ud0m4o~ zLB|>%8aeq@KKV9TR$K@sMwb-|S>WbHR3s73lxIkU6C{*k8#`q7I)dEFML>z<4%^sy z_{!M}R1fQPF&n@Qe6l>Jl02xkG#a9~>6l!z2-nY+Bku$0>>ebG)Ce!+HrCAA07INe zTO7c07|%{&yQWYHEpr+WtXF-T(JN;+l1*yepE2W52|4=}OavO|3Etr!nG2dM-RWqm z(2JuLibr&TkG>(Fx|UUjc7Tpo>&a}5_QaEPD!28v67mvNO-WriTo03&OkIwEsG=6!#SWtLlF2e_4%t>s{NSlbz z;LjxQ8ssie(AwO)Qmzu32`eWRMEEKPFr#w8K|Gr80MuHqw2+Yv>>Y)W-~qDeNx{pe z#0<_>siFSCOVhm$$vITJr>Tu0#+kD2go__7rsEszHr2A-c04p>8=Xl5kQr?igu@&w zY}+y<6<%9_Rl%dmDo$`Dl$f!x26!B#(H9l2&+DL?I`4@o6J>Osfuf3|Ynb)zDK9nO zBi5{j7KJS0tX{+p&f=cpIrMgAp(I^1HVdQ4th=iDXLvc3nKS4^3f`vsVBOR+A~dg} z9MssbjeEWUWEL*@ESRc-oJJf`(~{o@dEyFip!h)(nF8W6UOKKS_bQx`R-6UXD^Pq$ z=abb6_y8|Yjt}G*v?Zuv4y|4scdi4$J1}Fj^)|*5&Zy}8g@qWA;hrM713@^CULnJJ0$Lz<{xSe74q3(ef)Dc zY79k3v-yQ@d~4Am=%c_Bj|Jgfw!w==-Zw1U5M8FIWYdK6(!l%3e0hVQa#F7^?sShv>Ll1mmh>@^VUV%CSA-+cHAzf2uPJTZA-L(-2a?%R5P6_0 zWGBIEz^O&jAdwA?C{DihmSvKnSQ%J<5}TqH-#I@y4~hDJhl-yh_6sH8w8>ZGTp-(y z(g~>U18g5{YJiJne!LH1J)x69qWe}p!NPC<;P6MCQ=VZEKID5Kh`hj!jJT?u7rL&z z9iCFWDf?CDL`nZTW38^=lR48;gRew8gz6}zVpidZF@?jN%see^uDi)p)_gzJjvcweV%T>0%iPUh&O1cb9L`~r z7qOz_*LGne?SfTfU*WE`AO?*NStFGMxtoqtV7mz(GTMy*qm3b2OVtL;b?~7DQd3F2 znyZxuSGQ@3U5#o2Q3aQPZ8kIYjP9JR z+DzeSFzM3D8f2T3K@5#iJ|m^j&!WvmK_U3BsgLC?r`Pd)ZwhF@j*^NlN2HrcK!a`k zxaM9*<0pcHdZ23z+t(pO%`s4jT4ZE=cOMtKLN#MC+QBABlsFH5zH8Z#EFtWy!UbqG z)568dx16Wspcr`e+yNCysQJZBA4r!qr^e~?RfO`*>W4J7st~x1P6*nC!GVv0P%PQk z(>D;YEo^uCU0|gN>W>VTvPd5WV0%GRunzGjgK2ks%KZUYndBdk1Mbmu#cnTY!IZsF zwx6;zC$%&+hg+jsU{Gc(nuGpq403)b4#1>BFe@vl=a7 zuWC^aP>`vqyhCRhUrvq~5rD?(YXT^y^u#q43S%K_$vy_9ME&0(Kez!rHU@W*wP#Ig zvx7_w-=hu(W2QOkF{2~9dHFD3tTGiC^yW=7%TLLJySaG$%9x`OkL0GFH(k%KfT zU3H?mZtO3iZxE@2aMwHz^?DWR233jl0$X99s<`98d&Ajox6zXn2rTB0OauN2>nAx- zf{I2|usS$H5THGjvXanb_OSmFxCG6R*Ui|!W+45|R=H{OILDSEE+!5OxyPy7nVn~* zp5Ss4{DCX}fSD*LQ<3iN94*b1A*;^V$k*h3k{JiLOFrpvozVI9JrsQuEwYNqCL+sX zsVs$-^T`+uc#sOG8#U00Q=PMfK%+AHq>*pQ7h9K?liTHWf$4yCxHC3WrD}0nX_ZSF zL3v}-G{~P&V9klb?NB_Mxb?U8S$=T>TB*AksEd)%G${&Tw+LN6*p@D zUSV*J>b{hu$%&e-PC-#q%Iv`|XA2q9XpE=;nEGb*r-41`E4r#ZxgBTp4bL%k;(0Km z+m-!O;Tv*7D2=x5Oz^7VofEwHwF$?-_RjrsaEGcS8fP)*swy1Wz=N-842k1|A(U1{ z&m(5Dm0HNH6A=s~T7YA-umCKJj z0+1Hcr=gnxVgWcPie!&(E+u9)-k+ndv*T*!8LMJzIIqj8c7CF&N7r^UqHYW$od)MHC6V#Yv zu3oO)o3}Cy2e_*VA}R7a{{+|`GPF^CM?vn$A;&fp3UrGT&sFIenX}R+)^1R2yQT#Ts_}Ag$!RN$2hhcO zv&&0Z{%%)h%6y0rRyD`naA6io*YLR|wmmM>oq(qZZ0n2~ypI=nU$nhSQYxich8tq=)-0sd7Ku|7L_rXUOx8uq1OXHz_^p)pNzO?FJwfN_Nab34|5!b~f zp)0NW}NF{xs)rRWEJXb$$9NHotthAm*L0g zPsg~vT#*ODLC96EWTx~cTJOi7-^NKkgnu8_lbwD^m9AVZ^J*I!<&!epN*gE zcsuTdKgR1{NZvoh`*8dZbi5rupZxx#$@`OJ{6FbT2l7trIoza#_c8ENip{BO#~tuc;tNgMy}v+{)<|Lht4p&rut z|2956cK>!AJN_|#{G)MC^l8k@n-+qn1vg0q?5A~SN-@od3TmRPEGTx4_|80DNo%n6* zN6Glt7r)NGu%oV~89YUaydje_cPf zgN?W2XEFX$_|nGzRImS2y}tdfZ2adi9)I2V)}JZ^S;_HDVlcs>lg94J-dvQ|G)6$xA?{P c{vw`0yKnm~ai`q)fBeJ_|KwZAfaGoK=W~j6VE_OC literal 0 HcmV?d00001 diff --git a/bin/s140_nrf52_7.3.0_softdevice.hex b/bin/s140_nrf52_7.3.0_softdevice.hex new file mode 100644 index 0000000000..639927f503 --- /dev/null +++ b/bin/s140_nrf52_7.3.0_softdevice.hex @@ -0,0 +1,9726 @@ +:020000040000FA +:1000000000040020810A000015070000610A0000BA +:100010001F07000029070000330700000000000050 +:10002000000000000000000000000000A50A000021 +:100030003D070000000000004707000051070000D6 +:100040005B070000650700006F07000079070000EC +:10005000830700008D07000097070000A10700003C +:10006000AB070000B5070000BF070000C90700008C +:10007000D3070000DD070000E7070000F1070000DC +:10008000FB070000050800000F0800001908000029 +:10009000230800002D080000370800004108000078 +:1000A0004B080000550800005F08000069080000C8 +:1000B000730800007D080000870800009108000018 +:1000C0009B080000A5080000AF080000B908000068 +:1000D000C3080000CD080000D7080000E1080000B8 +:1000E000EB080000F5080000FF0800000909000007 +:1000F000130900001D090000270900003109000054 +:100100003B0900001FB500F003F88DE80F001FBD8C +:1001100000F0ACBC40F6FC7108684FF01022401CA7 +:1001200008D00868401C09D00868401C04D0086842 +:1001300000F037BA9069F5E79069F9E7704770B554 +:100140000B46010B184400F6FF70040B4FF0805073 +:100150000022090303692403406943431D1B104621 +:1001600000F048FA29462046BDE8704000F042BA47 +:10017000F0B54FF6FF734FF4B4751A466E1E11E0DA +:10018000A94201D3344600E00C46091B30F8027B3B +:10019000641E3B441A44F9D19CB204EB134394B25D +:1001A00004EB12420029EBD198B200EB134002EBB2 +:1001B000124140EA0140F0BDF34992B00446D1E952 +:1001C0000001CDE91001FF224021684600F0F4FB58 +:1001D00094E80F008DE80F00684610A902E004C8FB +:1001E00041F8042D8842FAD110216846FFF7C0FF7C +:1001F0001090AA208DF8440000F099F9FFF78AFFCB +:1002000040F6FC7420684FF01025401C0FD0206889 +:1002100010226946803000F078F92068401C08D030 +:100220002068082210A900F070F900F061F9A869AF +:10023000EEE7A869F5E74FF080500369406940F6A2 +:10024000FC71434308684FF01022401C06D0086838 +:1002500000F58050834203D2092070479069F7E788 +:100260000868401C04D00868401C03D00020704778 +:100270009069F9E70420704770B504460068C34DE3 +:10028000072876D2DFE800F033041929631E250021 +:10029000D4E9026564682946304600F062F92A46CE +:1002A0002146304600F031F9AA002146304600F0E0 +:1002B00057FB002800D0032070BD00F009FC4FF46C +:1002C000805007E0201D00F040F90028F4D100F034 +:1002D000FFFB60682860002070BD241D94E80700C3 +:1002E000920000F03DFB0028F6D00E2070BDFFF715 +:1002F000A2FF0028FAD1D4E901034FF0805100EBAE +:10030000830208694D69684382420ED840F6F8704E +:1003100005684FF010226D1C09D0056805EB8305B8 +:100320000B6949694B439D4203D9092070BD55694A +:10033000F4E70168491C03D00068401C02D003E0C8 +:100340005069FAE70F2070BD2046FFF735FFFFF731 +:1003500072FF0028F7D1201D00F0F7F80028F2D135 +:1003600060680028F0D100F0E2F8FFF7D3FE00F05B +:10037000BFF8072070BD10B50C46182802D0012028 +:10038000086010BD2068FFF777FF206010BD41684E +:10039000054609B1012700E0002740F6F8742068FF +:1003A0004FF01026401C2BD02068AA68920000F065 +:1003B000D7FA38B3A86881002068401C27D020688D +:1003C000FFF7BDFED7B12068401C22D026684FF051 +:1003D0008050AC686D68016942695143A9420DD9EA +:1003E000016940694143A14208D92146304600F0E5 +:1003F000B8F822462946304600F087F800F078F831 +:100400007069D2E700F093F8FFF784FEF6E77069B1 +:10041000D6E77669DBE740F6FC7420684FF01026DB +:10042000401C23D02068401C0CD02068401C1FD0EA +:100430002568206805F18005401C1BD027683879A5 +:10044000AA2819D040F6F8700168491C42D001680A +:10045000491C45D00168491C3ED001680968491C07 +:100460003ED00168491C39D000683EE0B069DAE747 +:10047000B569DEE7B769E2E710212846FFF778FEA5 +:100480003968814222D12068401C05D0D4F8001080 +:1004900001F18002C03107E0B169F9E730B108CA63 +:1004A00051F8040D984201D1012000E000208A4259 +:1004B000F4D158B1286810B1042803D0FEE72846CB +:1004C000FFF765FF3149686808600EE0FFF722FE1C +:1004D00000F00EF87169BBE77169BFE7706904E06D +:1004E0004FF480500168491C01D000F0CBFAFEE7C0 +:1004F000BFF34F8F26480168264A01F4E06111439B +:100500000160BFF34F8F00BFFDE72DE9F0411746B3 +:100510000D460646002406E03046296800F054F8EF +:10052000641C2D1D361DBC42F6D3BDE8F08140F69B +:10053000FC700168491C04D0D0F800004FF48051D1 +:10054000FDE54FF010208069F8E74FF080510A690F +:10055000496900684A43824201D810207047002050 +:10056000704770B50C4605464FF4806608E0284693 +:1005700000F017F8B44205D3A4F5806405F5805562 +:10058000002CF4D170BD0000F40A0000000000202F +:100590000CED00E00400FA05144801680029FCD0C5 +:1005A0007047134A0221116010490B68002BFCD0E0 +:1005B0000F4B1B1D186008680028FCD0002010603D +:1005C00008680028FCD07047094B10B501221A605A +:1005D000064A1468002CFCD0016010680028FCD08A +:1005E0000020186010680028FCD010BD00E4014015 +:1005F00004E5014070B50C46054600F073F810B9EB +:1006000000F07EF828B121462846BDE8704000F091 +:1006100007B821462846BDE8704000F037B8000012 +:100620007FB5002200920192029203920A0B000B06 +:100630006946012302440AE0440900F01F0651F80C +:10064000245003FA06F6354341F82450401C8242F8 +:10065000F2D80D490868009A10430860081D016827 +:10066000019A1143016000F03DF800280AD00649C4 +:1006700010310868029A10430860091D0868039A3F +:10068000104308607FBD00000006004030B50F4CED +:10069000002200BF04EB0213D3F800582DB9D3F8A1 +:1006A000045815B9D3F808581DB1521C082AF1D3C3 +:1006B00030BD082AFCD204EB0212C2F80008C3F8CD +:1006C00004180220C3F8080830BD000000E0014013 +:1006D0004FF08050D0F83001082801D0002070473A +:1006E000012070474FF08050D0F83011062905D016 +:1006F000D0F83001401C01D0002070470120704725 +:100700004FF08050D0F830010A2801D00020704707 +:100710000120704708208F490968095808471020B0 +:100720008C4909680958084714208A4909680958FA +:100730000847182087490968095808473020854923 +:100740000968095808473820824909680958084744 +:100750003C20804909680958084740207D490968BC +:100760000958084744207B49096809580847482028 +:1007700078490968095808474C207649096809589A +:10078000084750207349096809580847542071499F +:1007900009680958084758206E49096809580847E8 +:1007A0005C206C4909680958084760206949096854 +:1007B00009580847642067490968095808476820AC +:1007C00064490968095808476C2062490968095852 +:1007D000084770205F4909680958084774205D4937 +:1007E00009680958084778205A490968095808478C +:1007F0007C205849096809580847802055490968EC +:10080000095808478420534909680958084788202F +:1008100050490968095808478C204E490968095809 +:10082000084790204B4909680958084794204949CE +:10083000096809580847982046490968095808472F +:100840009C204449096809580847A0204149096883 +:1008500009580847A4203F49096809580847A820B3 +:100860003C49096809580847AC203A4909680958C1 +:100870000847B0203749096809580847B420354966 +:10088000096809580847B8203249096809580847D3 +:10089000BC203049096809580847C0202D4909681B +:1008A00009580847C4202B49096809580847C82037 +:1008B0002849096809580847CC2026490968095879 +:1008C0000847D0202349096809580847D4202149FE +:1008D000096809580847D8201E4909680958084777 +:1008E000DC201C49096809580847E02019490968B3 +:1008F00009580847E4201749096809580847E820BB +:100900001449096809580847EC2012490968095830 +:100910000847F0200F49096809580847F4200D4995 +:10092000096809580847F8200A490968095808471A +:10093000FC2008490968095808475FF48070054998 +:10094000096809580847000003480449024A034B54 +:100950007047000000000020000B0000000B0000AA +:1009600040EA010310B59B070FD1042A0DD310C82C +:1009700008C9121F9C42F8D020BA19BA884201D97E +:10098000012010BD4FF0FF3010BD1AB1D30703D0C6 +:10099000521C07E0002010BD10F8013B11F8014B7C +:1009A0001B1B07D110F8013B11F8014B1B1B01D198 +:1009B000921EF1D1184610BD02F0FF0343EA032254 +:1009C00042EA024200F005B87047704770474FF0A6 +:1009D00000020429C0F0128010F0030C00F01B800C +:1009E000CCF1040CBCF1020F18BF00F8012BA8BF1A +:1009F00020F8022BA1EB0C0100F00DB85FEAC17CDE +:100A000024BF00F8012B00F8012B48BF00F8012B90 +:100A100070474FF0000200B51346944696462039C1 +:100A200022BFA0E80C50A0E80C50B1F12001BFF4A7 +:100A3000F7AF090728BFA0E80C5048BF0CC05DF80D +:100A400004EB890028BF40F8042B08BF704748BF5B +:100A500020F8022B11F0804F18BF00F8012B7047CF +:100A6000014B1B68DB6818470000002009480A4951 +:100A70007047FFF7FBFFFFF745FB00BD20BFFDE719 +:100A8000064B1847064A1060016881F308884068E1 +:100A900000470000000B0000000B000017040000DE +:100AA000000000201EF0040F0CBFEFF30881EFF3ED +:100AB0000981886902380078182803D100E0000015 +:100AC000074A1047074A12682C3212681047000084 +:100AD00000B5054B1B68054A9B58984700BD0000B0 +:100AE0007703000000000020F00A0000040000006E +:100AF000001000000000000000FFFFFF0090D00386 +:10100000C8130020395E020085C100009F5D020008 +:1010100085C1000085C1000085C1000000000000FE +:10102000000000000000000000000000C55E02009B +:1010300085C100000000000085C1000085C10000DE +:101040002D5F0200335F020085C1000085C10000F2 +:1010500085C1000085C1000085C1000085C1000078 +:10106000395F020085C1000085C100003F5F0200BA +:1010700085C10000455F02004B5F0200515F020026 +:1010800085C1000085C1000085C1000085C1000048 +:1010900085C1000085C1000085C1000085C1000038 +:1010A00085C10000575F020085C1000085C10000B6 +:1010B00085C1000085C1000085C1000085C1000018 +:1010C0005D5F020085C1000085C1000085C1000090 +:1010D00085C1000085C1000085C1000085C10000F8 +:1010E00085C1000085C1000085C1000085C10000E8 +:1010F00085C1000085C1000085C1000085C10000D8 +:1011000085C1000085C1000000F002F824F083FED4 +:101110000AA090E8000C82448344AAF10107DA4552 +:1011200001D124F078FEAFF2090EBAE80F0013F0F7 +:10113000010F18BFFB1A43F00103184718530200B0 +:10114000385302000A444FF0000C10F8013B13F032 +:10115000070408BF10F8014B1D1108BF10F8015B10 +:10116000641E05D010F8016B641E01F8016BF9D103 +:1011700013F0080F1EBF10F8014BAD1C0C1B09D15A +:101180006D1E58BF01F801CBFAD505E014F8016BCC +:1011900001F8016B6D1EF9D59142D6D3704700005E +:1011A0000023002400250026103A28BF78C1FBD870 +:1011B000520728BF30C148BF0B6070471FB500F011 +:1011C00003F88DE80F001FBD24F022BE70B51A4C45 +:1011D00005460A202070A01C00F0D5F85920A080F8 +:1011E00029462046BDE8704008F082B908F08BB966 +:1011F00070B50C461149097829B1A0F160015E294A +:1012000008D3012013E0602804D0692802D043F2FB +:1012100001000CE020CC0A4E94E80E0006EB8000A2 +:10122000A0F58050241FD0F8806E2846B04720607B +:1012300070BD012070470000080000201C00002045 +:10124000A05F02003249884201D20120704700208D +:10125000704770B50446A0F500002E4EB0F1786FCF +:1012600002D23444A4F500042948844201D2012565 +:1012700000E0002500F043F848B125B9B44204D39A +:101280002548006808E0012070BD002070BD002DD9 +:10129000F9D1B442F9D321488442F6D2F3E710B52C +:1012A0000446A0F50000B0F1786F03D21948044459 +:1012B000A4F5000400F023F84FF0804130B1164847 +:1012C000006804E08C4204D2012003E01348844209 +:1012D000F8D2002080F0010010BD10B520B1FFF75A +:1012E000DEFF08B1012010BD002010BD10B520B1F7 +:1012F000FFF7AFFF08B1012010BD002010BD084866 +:1013000008490068884201D10120704700207047D9 +:1013100000700200000000202000002008000020D3 +:101320005C000020BEBAFECA10B5044600210120B0 +:1013300000F042F800210B2000F03EF800210820C8 +:1013400000F03AF80421192000F036F804210D20AD +:1013500000F032F804210E2000F02EF804210F20B6 +:1013600000F02AF80421C84300F026F806211620D0 +:1013700000F022F80621152000F01EF82046FFF7A5 +:1013800025FF002010BD40F2231101807047FFF7B8 +:101390002DBF1148704710487047104A10B51468A7 +:1013A0000E4B0F4A08331A60FFF722FF0B48001D4F +:1013B000046010BD704770474907090E002804DB20 +:1013C00000F1E02080F80014704700F00F0000F1F9 +:1013D000E02080F8141D704703F900421005024018 +:1013E00001000001FD48002101604160018170475A +:1013F0002DE9FF4F93B09B46209F160004460DD069 +:101400001046FFF726FF18B1102017B0BDE8F08F87 +:101410003146012001F0D3FE0028F6D101258DF8D8 +:1014200042504FF4C050ADF84000002210A92846A9 +:1014300006F0C5FC0028E8D18DF84250A8464FF4CC +:1014400028500025ADF840001C2229466846079523 +:101450000DF01DF89DF81C000DF11C0A20F00F0086 +:10146000401C20F0F00010308DF81C0020788DF822 +:101470001D0061789DF81E000DF1400961F34200E6 +:1014800040F001008DF81E009DF8000008AA40F011 +:1014900002008DF800002089ADF83000ADF8325020 +:1014A0006089ADF83400CDF82CA060680E900AA9D0 +:1014B000CDF82890684606F090FA0028A5D160681B +:1014C000FFF70BFF40B16068FFF710FF20B96078AD +:1014D00000F00300022801D0012000E00020BF4CF2 +:1014E00008AA0AA92072BDF8200020808DF8428049 +:1014F00042F60120ADF840009DF81E0020F00600E5 +:10150000801C20F001008DF81E000220ADF8300094 +:10151000ADF8340014A80E90684606F05EFA002874 +:1015200089D1BDF82000608036B1211D304600F021 +:101530005FF90028C2D109E0BBF1000F05D00CF023 +:1015400021FDE8BB0CF01EFDD0BBA58017B1012F1B +:1015500043D04AE08DF8428042F6A620ADF8400024 +:1015600046461C220021684607950CF090FF9DF826 +:101570001C00ADF8346020F00F00401C20F0F0009B +:1015800010308DF81C009DF81D0020F0FF008DF834 +:101590001D009DF81E0020F0060040F00100801C98 +:1015A0008DF81E009DF800008DF8446040F00200A8 +:1015B0008DF80000CDE90A9AADF8306011A800E07E +:1015C00011E00E9008AA0AA9684606F006FA00285B +:1015D000A6D1BDF82000E08008E00CF0D3FC10B9E3 +:1015E0000CF0D0FC08B103200FE7E58000200CE7E9 +:1015F0003EB50446794D0820ADF80000A88828B112 +:101600002046FFF726FE18B110203EBD06203EBD45 +:101610002146012001F0D3FD0028F8D12088ADF843 +:1016200004006088ADF80600A088ADF80800E088E6 +:10163000ADF80A00A88801AB6A46002106F0AAFDB1 +:10164000BDF800100829E2D003203EBD7FB5634DF0 +:101650000446A88868B1002002900820ADF8080070 +:10166000CDF80CD02046FFF7F4FD20B1102004B0D7 +:1016700070BD0620FBE7A98802AA4FF6FF7006F0AE +:10168000CCFF0028F3D1BDF80810082901D00320B1 +:10169000EDE7BDF800102180BDF802106180BDF8B3 +:1016A0000410A180BDF80610E180E0E701B582B02A +:1016B0000220ADF80000494802AB6A46408800218C +:1016C00006F068FDBDF80010022900D003200EBD11 +:1016D0001CB5002100910221ADF800100190FFF728 +:1016E000DEFD08B110201CBD3C486A4641884FF61B +:1016F000FF7006F092FFBDF800100229F3D003201E +:101700001CBDFEB5354C06461546207A0F46C0076F +:1017100005D00846FFF79DFD18B11020FEBD0F2033 +:10172000FEBDF82D01D90C20FEBD3046FFF791FD1E +:1017300018BB208801A905F03AFE0028F4D13078C2 +:101740008DF80500208801A906F003FD0028EBD1E3 +:1017500000909DF800009DF8051040F002008DF803 +:101760000000090703D040F008008DF80000208831 +:10177000694606F08BFC0028D6D1ADF808502088C9 +:101780003B4602AA002106F005FDBDF80810A9425B +:10179000CAD00320FEBD7CB5054600200090019014 +:1017A0000888ADF800000C4628460195FFF795FD26 +:1017B00018B92046FFF773FD08B110207CBD15B1A4 +:1017C000BDF8000060B105486A4601884FF6FF7019 +:1017D00006F023FFBDF8001021807CBD240200200C +:1017E0000C20FAE72F48C088002800D0012070475D +:1017F00030B5044693B000200D46014600901422F7 +:1018000001A80CF044FE1C22002108A80CF03FFEA9 +:101810009DF80000CDF808D020F00F00401C20F00B +:10182000F00010308DF800009DF8010006AA20F0AD +:10183000FF008DF801009DF8200001A940F0020092 +:101840008DF8200001208DF8460042F60420ADF806 +:10185000440011A801902088ADF83C006088ADF8E4 +:101860003E00A088ADF84000E088ADF842009DF849 +:10187000020020F00600801C20F001008DF802001C +:101880000820ADF80C00ADF810000FA8059008A8CE +:1018900006F0A3F8002803D1BDF818002880002026 +:1018A00013B030BD24020020F0B5007B059F1E461A +:1018B00014460D46012800D0FFDF0C2030803A206E +:1018C0003880002C08D0287A032806D0287B0128ED +:1018D00000D0FFDF17206081F0BDA889FBE72DE96C +:1018E000F0470D4686B095F80C900E991446B9F164 +:1018F000010F0BD01022007B2E8A9046052807D0BE +:10190000062839D0FFDF06B0BDE8F0870222F2E7F3 +:10191000E8890C2200EB400002EB400018803320E5 +:101920000880002CEFD0E8896081002720E0009635 +:10193000688808F1020301AA696900F097FF06EBC5 +:101940000800801C07EB470186B204EB4102BDF89A +:1019500004009081F848007808B1012300E00023DA +:101960000DF1060140460E3214F029F87F1CBFB27B +:101970006089B842DBD8C6E734200880E889B9F12D +:10198000010F11D0122148430E301880002CBAD01C +:10199000E88960814846B9F1010F00D00220207328 +:1019A00000270DF1040A1FE00621ECE70096688885 +:1019B00008F1020301AA696900F058FF06EB08006C +:1019C000801C86B2B9F1010F12D007EBC70004EBFF +:1019D0004000BDF80410C18110220AF1020110304C +:1019E0000CF02BFD7F1CBFB26089B842DED88AE7BD +:1019F00007EB470104EB4102BDF80400D0810AF176 +:101A000002014046103213F0FCFFEBE72DE9F047EE +:101A10000E4688B090F80CC096F80C80378AF5898D +:101A20000C20DFF81493109902F10C04BCF1030FA1 +:101A300008D0BCF1040F3DD0BCF1070F75D0FFDF1B +:101A400008B061E705EB850C00EB4C0018803120F5 +:101A50000880002AF4D0A8F1060000F0FF0A5581A2 +:101A600024E01622002101A80CF011FD00977088D7 +:101A7000434601AA716900F0F9FEBDF80400208018 +:101A8000BDF80600E080BDF80800208199F800004C +:101A900008B1012300E00023A21C0DF10A01504609 +:101AA00013F08DFF07EB080087B20A346D1EADB24C +:101AB000D7D2C5E705EB850C00EB4C00188032202F +:101AC0000880002ABCD0A8F1050000F0FF0A55816B +:101AD00037E000977088434601AA716900F0C6FE9E +:101AE0009DF80600BDF80410E1802179420860F3FA +:101AF000000162F34101820862F38201C20862F3CD +:101B0000C301020962F30411420962F3451182091B +:101B100062F386112171C0096071BDF80700208150 +:101B200099F8000010B1012301E00EE000232246E5 +:101B30000DF10901504613F042FF07EB080087B290 +:101B40000A346D1EADB2C4D27AE7A8F1020084B2A5 +:101B500005FB08FC0CF10E00188035200880002AD7 +:101B6000A7D05581948100971FFA8CF370880E32AC +:101B7000716900F07BFE63E72DE9F84F1E460A9D70 +:101B80000C4681462AB1607A00F58070D080E089E9 +:101B9000108199F80C000C274FF000084FF00E0A46 +:101BA0000D2872D2DFE800F09D070E1B272F374566 +:101BB000546972727200214648460095FFF774FE20 +:101BC000BDE8F88F207B9146082802D0032800D07A +:101BD000FFDF3780302009E0A9F80A80F0E7207B9A +:101BE0009146042800D0FFDF378031202880B9F1EA +:101BF000000FF1D1E4E7207B9146042800D0FFDFFD +:101C000037803220F2E7207B9146022800D0FFDFA8 +:101C100037803320EAE7207B1746022800D0FFDF19 +:101C20003420A6F800A02880002FC9D0A7F80A8089 +:101C3000C6E7207B1746042800D0FFDF3520A6F832 +:101C400000A02880002FBBD04046A7F80A8012E0F1 +:101C5000207B1746052802D0062800D0FFDF102081 +:101C6000308036202880002FAAD0E0897881A7F81C +:101C70000E80B9F80E00B881A2E7207B91460728B4 +:101C800000D0FFDF37803720B0E72AE04FF01200A6 +:101C900018804FF038001700288091D0E0897881B3 +:101CA000A7F80E80A7F8108099F80C000A2805D034 +:101CB0000B2809D00C280DD0FFDF81E7207B0A28F4 +:101CC00000D0FFDF01200AE0207B0B2800D0FFDFDF +:101CD000042004E0207B0C2800D0FFDF05203873AF +:101CE0006EE7FFDF6CE770B50C46054601F0AAFB16 +:101CF00020B10078222804D2082070BD43F20200EF +:101D000070BD0521284612F0D1F8206008B10020EE +:101D100070BD032070BD30B44880087820F00F00FB +:101D2000C01C20F0F000903001F8080B1DCA81E8BB +:101D30001D0030BC07F05DBC100000202DE9FF47FE +:101D400084B0002782460297079890468946123051 +:101D50000AF069FA401D20F00306079828B907A980 +:101D60005046FFF7C0FF002854D1B9F1000F05D04D +:101D70000798017B19BB052504681BE098F8000053 +:101D8000092803D00D2812D0FFDF46E0079903256C +:101D90004868B0B3497B42887143914239D98AB2CD +:101DA000B3B2011D11F0F5FE0446078002E0079C66 +:101DB000042508340CB1208810B1032D29D02CE063 +:101DC0000798012112300AF060FAADF80C000246C3 +:101DD00002AB2946504608F0B8FA070001D1A01C12 +:101DE000029007983A461230C8F80400A8F802A0FA +:101DF00003A94046029B0AF055FAD8B10A2817D227 +:101E000000E006E0DFE800F007091414100B0D14E1 +:101E10001412132014E6002012E6112010E6082008 +:101E20000EE643F203000BE6072009E60D2007E665 +:101E3000032005E6BDF80C002346CDE900702A46D4 +:101E40005046079900F022FD57B9032D08D1079895 +:101E5000B3B2417B406871438AB2011D11F0ADFEFF +:101E6000B9F1000FD7D0079981F80C90D3E72DE98D +:101E7000FE4F91461A881C468A468046FAB102AB4C +:101E8000494608F062FA050019D04046A61C27888A +:101E900012F04FF93246072629463B46009611F0CC +:101EA0005EFD20882346CDE900504A465146404613 +:101EB00000F0ECFC002020800120BDE8FE8F002017 +:101EC000FBE710B586B01C46AAB104238DF800309C +:101ED0001388ADF808305288ADF80A208A788DF85A +:101EE0000E200988ADF80C1000236A462146FFF742 +:101EF00025FF06B010BD1020FBE770B50D4605218B +:101F000011F0D4FF040000D1FFDF294604F11200D4 +:101F1000BDE870400AF0A2B92DE9F8430D468046AD +:101F2000002607F063FB04462878102878D2DFE803 +:101F300000F0773B345331311231313108313131D6 +:101F400031312879001FC0B2022801D0102810D1E9 +:101F500014BBFFDF35E004B9FFDF0521404611F077 +:101F6000A5FF007B032806D004280BD0072828D023 +:101F7000FFDF072655E02879801FC0B2022820D055 +:101F800050B1F6E72879401FC0B2022819D01028B6 +:101F900017D0EEE704B9FFDF13E004B9FFDF2879BB +:101FA00001280ED1172137E00521404611F07EFFB0 +:101FB000070000D1FFDF07F1120140460AF02BF9BC +:101FC0002CB12A4621464046FFF7A5FE29E0132101 +:101FD000404602F01FFD24E004B9FFDF0521404622 +:101FE00011F064FF060000D1FFDF694606F1120020 +:101FF0000AF01BF9060000D0FFDFA988172901D2DB +:10200000172200E00A46BDF80000824202D90146CC +:1020100002E005E01729C5D3404600F047FCD0E7B1 +:10202000FFDF3046BDE8F883401D20F0030219B100 +:1020300002FB01F0001D00E000201044704713B5C2 +:10204000009858B10024684611F04DFD002C04D1D1 +:10205000F749009A4A6000220A701CBD0124002042 +:10206000F2E72DE9F0470C461546242200212046D0 +:102070000CF00DFA05B9FFDFA87860732888DFF847 +:10208000B0A3401D20F00301AF788946DAF80400C0 +:1020900011F047FD060000D1FFDF4FF00008266079 +:1020A000A6F8008077B109FB07F1091D0AD0DAF81C +:1020B000040011F036FD060000D1FFDF6660C6F8AF +:1020C000008001E0C4F80480298804F11200BDE812 +:1020D000F0470AF091B82DE9F047804601F112006F +:1020E0000D4681460AF09FF8401DD14F20F00302B3 +:1020F0006E7B14462968786811F03EFD3EB104FB02 +:1021000006F2121D03D06968786811F035FD0520CC +:1021100011F074FE0446052011F078FE201A012803 +:1021200002D1786811F0F2FC49464046BDE8F0471C +:102130000AF078B870B50546052111F0B7FE040025 +:1021400000D1FFDF04F112012846BDE870400AF01B +:1021500062B82DE9F04F91B04FF0000BADF828B008 +:10216000ADF804B047880C4605469246052138462E +:1021700011F09CFE060000D1FFDF24B1A780A4F877 +:1021800006B0A4F808B0297809220B20B2EB111F81 +:1021900073D12A7A04F1100138274FF00C084FF060 +:1021A00012090291102A69D2DFE802F068F2F1F018 +:1021B0008008D3898EA03DDCF3EEB7B7307B0228D0 +:1021C00000D0FFDFA88908EBC001ADF80410302172 +:1021D000ADF82810002C25D06081B5F80E800027BE +:1021E0001DE004EBC709317C89F80E10F189A9F8CC +:1021F0000C10CDF800806888042305AA296900F036 +:1022000035FBBDF81410A9F8101008F10400BDF852 +:1022100016107F1C1FFA80F8A9F81210BFB260894F +:10222000B842DED80CE1307B022800D0FFDFE9891C +:1022300008EBC100ADF804003020ADF8280095F897 +:102240000C90002CA9F10400C0B20F90EAD061817B +:10225000B5F81080002725E0CDF8008068884B464F +:1022600003AA696900F002FB08EB09001FFA80F875 +:102270006F48007818B1012302E0DDE0DAE00023C6 +:1022800004EBC702009204A90C320F9813F097FBDD +:10229000009ABDF80C007F1C1082009ABDF80E0059 +:1022A000BFB250826089B842D6D8C9E00AA800906F +:1022B00001AB224629463046FFF711FBC0E0307BD8 +:1022C000082805D0FFDF03E0307B082800D0FFDFBF +:1022D000E8891030ADF804003620ADF82800002C55 +:1022E0003FD0A9896181F189A18127E0307B09284C +:1022F00000D0FFDFA88901460C30ADF8040037207C +:10230000ADF82800002C2CD06181E8890090AB89C1 +:10231000688804F10C02296955E0E88939211030F8 +:1023200080B2ADF80400ADF82810002C72D0A98955 +:102330006181287A0E280AD002212173E989E1817E +:10234000288A0090EB8968886969029A3BE001213C +:10235000F3E70AA8009001AB224629463046FFF772 +:1023600055FB6DE0307B0A2800D0FFDFADF804900C +:10237000ADF828704CB3A9896181A4F810B0A4F815 +:102380000EB0012020735BE020E002E030E038E096 +:1023900041E0307B0B2800D0FFDF288AADF82870A1 +:1023A0001230ADF8040084B104212173A989618140 +:1023B000E989E181298A2182688A00902B8A6888CC +:1023C00004F11202696900F051FA39E0307B0C28FF +:1023D00000D0FFDFADF80490ADF828703CB30521C4 +:1023E0002173A4F80AB0A4F80EB0A4F810B027E046 +:1023F0000AA8009001AB224629463046FFF754FA5E +:102400001EE00AA8009001AB224629463046FFF79D +:10241000B3FB15E034E03B21ADF80400ADF8281023 +:1024200074B30120E080A4F808B084F80AB007E093 +:1024300010000020FFDF03E0297A012917D0FFDF19 +:10244000BDF80400AAF800006CB1BDF82800208097 +:10245000BDF804006080BDF82800392803D03C286E +:1024600001D086F80CB011B00020BDE8F08F3C21FF +:10247000ADF80400ADF8281014B1697AA172DFE755 +:10248000AAF80000EFE72DE9F84356880F4680468A +:1024900015460521304611F009FD040000D1FFDF8B +:1024A000123400943B46414630466A680AF02EF8E2 +:1024B000B8E570B50D46052111F0F8FC040000D117 +:1024C000FFDF294604F11200BDE8704009F0B8BEF4 +:1024D00070B50D46052111F0E9FC040000D1FFDFC5 +:1024E000294604F11200BDE8704009F0D6BE70B56F +:1024F0000546052111F0DAFC040000D1FFDF04F1EC +:10250000080321462846BDE870400422AFE470B5B8 +:102510000546052111F0CAFC040000D1FFDF214669 +:1025200028462368BDE870400522A0E470B5064641 +:10253000052111F0BBFC040000D1FFDF04F1120003 +:1025400009F071FE401D20F0030511E0011D008817 +:102550000322431821463046FFF789FC00280BD0A0 +:10256000607BABB2684382B26068011D11F05BFB17 +:10257000606841880029E9D170BD70B50E460546F6 +:1025800007F034F8040000D1FFDF012020726672EA +:102590006580207820F00F00C01C20F0F000303063 +:1025A0002070BDE8704007F024B8602801D00720F3 +:1025B00070470878C54900F0010008700020704796 +:1025C0002DE9F0438BB00D461446814606A9FFF76E +:1025D0008AFB002814D14FF6FF7601274FF42058CC +:1025E0008CB103208DF800001020ADF8100007A872 +:1025F000059007AA204604A913F005FA78B1072030 +:102600000BB0BDE8F0830820ADF808508DF80E70CF +:102610008DF80000ADF80A60ADF80C800CE006986B +:10262000A17801742188C1818DF80E70ADF8085031 +:10263000ADF80C80ADF80A606A4602214846069B58 +:10264000FFF77CFBDCE708B501228DF8022042F69B +:102650000202ADF800200A4603236946FFF731FC69 +:1026600008BD08B501228DF8022042F60302ADF83C +:1026700000200A4604236946FFF723FC08BD00B585 +:1026800087B079B102228DF800200A88ADF80820C1 +:102690004988ADF80A1000236A460521FFF74EFB72 +:1026A00007B000BD1020FBE709B1072309E40720AC +:1026B000704770B588B00D461446064606A9FFF768 +:1026C00012FB00280ED17CB10620ADF808508DF821 +:1026D0000000ADF80A40069B6A460821DC813046BE +:1026E000FFF72CFB08B070BD05208DF80000ADF899 +:1026F0000850F0E700B587B059B107238DF80030D6 +:10270000ADF80820039100236A460921FFF716FB64 +:10271000C6E71020C4E770B588B00C460646002511 +:1027200006A9FFF7E0FA0028DCD106980121123053 +:1027300009F0ABFD9CB12178062921D2DFE801F038 +:10274000200505160318801E80B2C01EE28880B2E4 +:102750000AB1A3681BB1824203D90C20C2E7102042 +:10276000C0E7042904D0A08850B901E00620B9E7E9 +:10277000012913D0022905D004291CD005292AD00B +:102780000720AFE709208DF800006088ADF8080049 +:10279000E088ADF80A00A068039023E00A208DF8D5 +:1027A00000006088ADF80800E088ADF80A00A06875 +:1027B0000A25039016E00B208DF800006088ADF824 +:1027C0000800A088ADF80A00E088ADF80C00A06809 +:1027D0000B25049006E00C208DF8000060788DF841 +:1027E00008000C256A4629463046069BFFF7A6FAE4 +:1027F00078E700B587B00D228DF80020ADF80810FD +:1028000000236A461946FFF799FA49E700B587B0F1 +:1028100071B102228DF800200A88ADF8082049889D +:10282000ADF80A1000236A460621FFF787FA37E75A +:10283000102035E770B586B0064601200D46ADF88C +:1028400008108DF80000014600236A463046FFF765 +:1028500075FA040008D12946304605F0B5FC002180 +:10286000304605F0CFFC204606B070BDF8B51C46DA +:1028700015460E46069F11F04AFC2346FF1DBCB2CA +:1028800031462A46009411F036F8F8BD30B41146AE +:10289000DDE902423CB1032903D0002330BC08F03B +:1028A00032BE0123FAE71A8030BC704770B50C467F +:1028B0000546FFF722FB2146284605F094FC2846F2 +:1028C000BDE87040012105F09DBC00001000002013 +:1028D0004FF0E0224FF400400021C2F88001BFF326 +:1028E0004F8FBFF36F8F1748016001601649900248 +:1028F00008607047134900B500220A600A60124B55 +:102900004FF060721A60002808BF00BD0F4A104BDC +:10291000DFF840C001280CD002281CBFFFDF00BD3B +:10292000032008601A604FF4000000BFCCF80000DC +:1029300000BD022008601A604FF04070F6E700B555 +:10294000FFDF00BD00F5004008F50140A4020020B3 +:1029500014F5004004F5014070B50B2000F0BDF9FE +:10296000082000F0BAF900210B2000F0D4F9002172 +:10297000082000F0D0F9F44C01256560A560002026 +:10298000C4F84001C4F84401C4F848010B2000F029 +:10299000B5F9082000F0B2F90B2000F091F925609C +:1029A00070BD10B50B2000F098F9082000F095F9E3 +:1029B000E548012141608160E4490A68002AFCD1B0 +:1029C0000021C0F84011C0F84411C0F848110B2094 +:1029D00000F094F9BDE81040082000F08FB910B560 +:1029E0000B2000F08BF9BDE81040082000F086B9FC +:1029F00000B530B1012806D0022806D0FFDF002044 +:102A000000BDD34800BDD34800BDD248001D00BD65 +:102A100070B5D1494FF000400860D04DC00BC5F8EB +:102A20000803CF4800240460C5F840410820C4359D +:102A300000F053F9C5F83C41CA48047070BD08B5B0 +:102A4000C14A002128B1012811D002281CD0FFDF83 +:102A500008BD4FF48030C2F80803C2F84803BB48F1 +:102A60003C300160C2F84011BDE80840D0E74FF4A7 +:102A70000030C2F80803C2F84803B448403001608F +:102A8000C2F84411B3480CE04FF48020C2F80803A8 +:102A9000C2F84803AD4844300160C2F84811AD485F +:102AA000001D0068009008BD70B516460D4604462E +:102AB000022800D9FFDF0022A348012304F11001FE +:102AC0008B4000EB8401C1F8405526B1C1F840218C +:102AD000C0F8043303E0C0F80833C1F84021C0F85F +:102AE000443370BD2DE9F0411D46144630B1012834 +:102AF00033D0022838D0FFDFBDE8F081891E0022E4 +:102B000021F07F411046FFF7CFFF012D23D0002099 +:102B1000944D924F012668703E61914900203C39E6 +:102B200008600220091D08608D49042030390860C2 +:102B30008B483D34046008206C6000F0DFF83004FE +:102B4000C7F80403082000F0BBF88349F007091F09 +:102B500008602E70D0E70120DAE7012B02D00022B6 +:102B6000012005E00122FBE7012B04D00022022016 +:102B7000BDE8F04198E70122F9E774480068704722 +:102B800070B500F0D8F8704C0546D4F84001002626 +:102B9000012809D1D4F80803C00305D54FF48030CB +:102BA000C4F80803C4F84061D4F8440101280CD1EA +:102BB000D4F80803800308D54FF40030C4F80803A4 +:102BC000C4F84461012013F0EEFED4F84801012856 +:102BD0000CD1D4F80803400308D54FF48020C4F882 +:102BE0000803C4F84861022013F0DDFE5E4805606A +:102BF00070BD70B500F09FF85A4D0446287850B16A +:102C0000FFF706FF687818B10020687013F0CBFE5C +:102C10005548046070BD0320F8E74FF0E0214FF401 +:102C20000010C1F800027047152000F067B84B494A +:102C300001200861082000F061B848494FF47C1079 +:102C4000C1F808030020024601EB8003C3F84025C9 +:102C5000C3F84021401CC0B20628F5D37047410A92 +:102C600043F609525143C0F3080010FB02F000F58F +:102C7000807001EB5020704710B5430B48F2376469 +:102C800063431B0C5C020C60384C03FB0400384BA4 +:102C90004CF2F72443435B0D13FB04F404EB402098 +:102CA00000F580704012107008681844086010BD6C +:102CB0002C484068704729490120C1F8000270473C +:102CC000002809DB00F01F0201219140400980002B +:102CD00000F1E020C0F80011704700280DDB00F083 +:102CE0001F02012191404009800000F1E020C0F85E +:102CF0008011BFF34F8FBFF36F8F7047002809DB40 +:102D000000F01F02012191404009800000F1E02005 +:102D1000C0F8801270474907090E002804DB00F153 +:102D2000E02080F80014704700F00F0000F1E02070 +:102D300080F8141D70470C48001F00680A4A0D49AE +:102D4000121D11607047000000B0004004B5004043 +:102D50004081004044B1004008F50140008000403F +:102D6000408500403C00002014050240F7C2FFFFF0 +:102D70006F0C0100010000010A4810B50468094900 +:102D800009480831086013F0A2FE0648001D0460DF +:102D900010BD0649002008604FF0E0210220C1F874 +:102DA000800270471005024001000001FC1F004036 +:102DB000374901200860704770B50D2000F049F8D0 +:102DC000344C0020C4F800010125C4F804530D2040 +:102DD00000F050F825604FF0E0216014C1F80001C8 +:102DE00070BD10B50D2000F034F82A480121416073 +:102DF0000021C0F80011BDE810400D2000F03AB8E5 +:102E0000254810B504682449244808310860214940 +:102E1000D1F80001012804D0FFDF1F48001D046025 +:102E200010BD1B48001D00680022C0B2C1F800217F +:102E300014F07FFBF1E710B5164800BFD0F8001181 +:102E40000029FBD0FFF7DCFFBDE810400D2000F0AB +:102E500011B800280DDB00F01F020121914040094C +:102E6000800000F1E020C0F88011BFF34F8FBFF366 +:102E70006F8F7047002809DB00F01F02012191408D +:102E80004009800000F1E020C0F880127047000087 +:102E900004D5004000D000401005024001000001B0 +:102EA0004FF0E0214FF00070C1F8800101F5C071D2 +:102EB000BFF34F8FBFF36F8FC1F80001394B8022F2 +:102EC00083F8002441F8800C704700B502460420C6 +:102ED000354903E001EBC0031B792BB1401EC0B2A2 +:102EE000F8D2FFDFFF2000BD41F8302001EBC00128 +:102EF00000224A718A7101220A7100BD2A4A00210A +:102F000002EBC0000171704710B50446042800D3DD +:102F1000FFDF254800EBC4042079012800D0FFDF43 +:102F20006079A179401CC0B2814200D060714FF03D +:102F3000E0214FF00070C1F8000210BD70B504250B +:102F4000194E1A4C16E0217806EBC1000279012ACD +:102F500008D1427983799A4204D04279827156F835 +:102F6000310080472078401CC0B22070042801D373 +:102F7000002020706D1EEDB2E5D270BD0C4810B57A +:102F800004680B490B4808310860064890F80004B3 +:102F90004009042800D0FFDFFFF7D0FF0448001DE0 +:102FA000046010BD19E000E0E0050020580000209A +:102FB00010050240010000010548064A01689142DF +:102FC00001D1002101600449012008607047000020 +:102FD0005C000020BEBAFECA40E5014070B50C4658 +:102FE000054609F02FFC21462846BDE870400AF04E +:102FF00010BD7047704770470021016081807047A5 +:103000002CFFFFFFDBE5B151007002002301FFFF41 +:103010008C00000078DB6A007A2E9AC67DB66CFAC6 +:10302000F35721CCC310D5E51471FB3C30B5FC4DF2 +:103030000446062CA9780ED2DFE804F0030E0E0E2B +:103040000509FFDF08E0022906D0FFDF04E00329BD +:1030500002D0FFDF00E0FFDFAC7030BD30B50446CA +:103060001038EF4D07280CD2DFE800F0040C060CF6 +:103070000C0C0C00FFDF05E0287E112802D0FFDFDA +:1030800000E0FFDF2C7630BD2DE9F04112F026FE86 +:10309000044614F063F8201AC5B2062010F0AEFE04 +:1030A0000446062010F0B2FE211ADD4C207E1228C4 +:1030B00018D000200F18072010F0A0FE06460720A9 +:1030C00010F0A4FE301A3918207E13280CD00020EE +:1030D0000144A078042809D000200844281AC0B26E +:1030E000BDE8F0810120E5E70120F1E70120F4E7E8 +:1030F000CB4810B590F825004108C94800F12600DA +:1031000005D00EF0F5FEBDE8104006F08CB80EF0CC +:10311000D0FEF8E730B50446A1F120000D460A289C +:103120004AD2DFE800F005070C1C2328353A3F445B +:10313000FFDF42E0207820283FD1FFDF3DE0B848A4 +:103140008178052939D0007E122836D020782428AD +:1031500033D0252831D023282FD0FFDF2DE0207851 +:1031600022282AD0232828D8FFDF26E0207822280A +:1031700023D0FFDF21E0207822281ED024281CD075 +:1031800026281AD0272818D0292816D0FFDF14E0C7 +:103190002078252811D0FFDF0FE0207825280CD0DB +:1031A000FFDF0AE02078252807D0FFDF05E0207840 +:1031B000282802D0FFDF00E0FFDF257030BD1FB5FB +:1031C00004466A46002001F0A5FEB4B1BDF8022015 +:1031D0004FF6FF700621824201D1ADF80210BDF812 +:1031E0000420824201D1ADF80410BDF808108142DC +:1031F00003D14FF44860ADF8080068460FF0E2FADA +:1032000006F011F804B010BD70B516460C46054620 +:10321000FEF71FF848B90CB1B44208D90C2070BDB4 +:1032200055F82400FEF715F808B1102070BD2046AF +:10323000641EE4B2F4D270BD2DE9F04105461F468C +:1032400090460E4600240068FEF750F830B9A98871 +:1032500028680844401EFEF749F808B110203FE7EF +:1032600028680028A88802D0B84202D850E0002878 +:10327000F5D0092034E72968085DB8B1671CCA5D3C +:10328000152A2ED03CDC152A3AD2DFE802F039129A +:10329000222228282A2A313139393939393939391C +:1032A00039392200085D30BB641CA4B2A242F9D8AF +:1032B00033E00228DDD1A01C085C88F80000072854 +:1032C00001D2400701D40A200AE7307840F001001B +:1032D00015E0C143C90707E0012807D010E0062028 +:1032E000FEE60107A1F180510029F5D01846F7E666 +:1032F0003078810701D50B20F2E640F002003070F3 +:103300002868005D384484B2A888A04202D2B0E7A1 +:103310004FF4485382B2A242ADD80020E0E610B587 +:10332000027843F2022354080122022C12D003DC5B +:103330003CB1012C16D106E0032C10D07F2C11D10A +:1033400012E0002011E080790324B4EB901F09D132 +:103350000A700BE08079B2EB901F03D1F8E7807917 +:103360008009F5D0184610BDFF200870002010BD60 +:1033700008B500208DF80000294890F82E1051B1B2 +:1033800090F82F0002280FD003280FD0FFDF00BFD6 +:103390009DF8000008BD22486946253001F009FE6D +:1033A0000028F5D0FFDFF3E7032000E001208DF8CF +:1033B0000000EDE738B50C460546694601F0F9FD19 +:1033C00000280DD19DF80010207861F3470020708F +:1033D00055F8010FC4F80100A888A4F805000020E2 +:1033E00038BD38B5137888B102280FD0FF281BD01C +:1033F0000CA46D46246800944C7905EB9414247851 +:1034000064F347031370032805D010E023F0FE0394 +:1034100013700228F7D1D8B240F001000AE0000092 +:10342000F00100200302FF0143F0FE00107010784D +:1034300020F0010010700868C2F801008888A2F826 +:10344000050038BD022110F031BD38B50C460978B1 +:10345000222901D2082038BDADF800008DF80220E5 +:1034600068460EF087FD05F0DEFE050003D1212140 +:103470002046FFF74FFE284638BD1CB500208DF8CA +:103480000000CDF80100ADF80500FB4890F82E00D3 +:10349000022801D0012000E000208DF807006846D6 +:1034A0000EF0F0FD002800D0FFDF1CBD00220A80D6 +:1034B000437892B263F3451222F040020A8000780A +:1034C0000C282BD2DFE800F02A06090E1116191C71 +:1034D0001F220C2742F0110009E042F01D00088075 +:1034E0000020704742F0110012E042F0100040F05E +:1034F0000200F4E742F01000F1E742F00100EEE7CD +:1035000042F0010004E042F00200E8E742F002006D +:1035100040F00400E3E742F00400E0E707207047D2 +:103520002DE9FF478AB00025BDF82C6082461C4675 +:1035300091468DF81C50700703D56068FDF789FE31 +:1035400068B9CD4F4FF0010897F82E0058B197F8A1 +:103550002F00022807D16068FDF7C8FE18B11020BF +:103560000EB0BDE8F087300702D5A08980283DD88D +:10357000700705D4B9F1000F02D097F8240098B372 +:10358000E07DC0F300108DF81B00627D0720032151 +:103590005AB3012A2CD0022AE2D0042AE0D18DF8B5 +:1035A0001710F00627D4A27D072022B3012A22D0CB +:1035B000022A23D0042AD3D18DF819108DF8159042 +:1035C000606810B307A9FFF7AAFE0028C8D19DF8CC +:1035D0001C00FF2816D0606850F8011FCDF80F10AE +:1035E0008088ADF8130014E000E001E00720B7E7A1 +:1035F0008DF81780D5E78DF81980DFE702208DF868 +:103600001900DBE743F20220AAE7CDF80F50ADF82E +:103610001350E07B40B9207C30B9607C20B9A07C9D +:1036200010B9E07CC00601D0062099E78DF800A013 +:10363000BDF82C00ADF80200A0680190A0680290CF +:1036400004F10F0001F0A9FC8DF80C00FFF790FECB +:103650008DF80D009DF81C008DF80E008DF81650A9 +:103660008DF81850E07D08A900F00F008DF81A00C1 +:1036700068460FF0E3F905F0D6FD71E7F0B58FB0BD +:1036800000258DF830508DF814508DF834500646D2 +:103690008DF82850019502950395049519B10FC92D +:1036A00001AC84E80F00744CA078052801D00428F0 +:1036B0000CD101986168884200D120B90398E16873 +:1036C000884203D110B108200FB0F0BD207DC006A4 +:1036D00001D51F2700E0FF273B460DAA05A903A837 +:1036E000FFF7AAFD0028EFD1A08AC10702D0C006CB +:1036F00000D4EE273B460AAA0CA901A8FFF79CFDBF +:103700000028E1D19DF81400C00701D00A20DBE7B2 +:10371000A08A410708D4A17D31B19DF828108907FE +:1037200002D043F20120CFE79DF82810C90709D045 +:10373000400707D4208818B144F25061884201D96B +:103740000720C1E78DF818508DF81960BDF8080002 +:10375000ADF81A000198079006A80FF07BF905F064 +:1037600062FD0028B0D18DF820508DF82160BDF8A1 +:103770001000ADF822000398099008A80FF08CF90A +:1037800005F051FD00289FD101AD241D95E80F00E3 +:1037900084E80F00002097E770B586B00D4604005E +:1037A00005D0FDF7A3FD20B1102006B070BD0820A4 +:1037B000FBE72078C107A98802D0FF2902D303E0E4 +:1037C0001F2901D20920F0E7800763D4FFF75CFCD2 +:1037D00038B12178C1F3C100012804D0032802D0F8 +:1037E00005E01320E1E7244890F82400C8B1C80799 +:1037F0004FF001064FF0000502D08DF80F6001E098 +:103800008DF80F50FFF7B4FD8DF800002078694661 +:10381000C0F3C1008DF8010060788DF80250C20835 +:1038200001D00720C1E730B3C20701D08DF8026094 +:10383000820705D59DF8022042F002028DF8022091 +:10384000400705D59DF8020040F004008DF8020005 +:10385000002022780B18C2F38002DA7001EB4002DC +:103860006388D380401CA388C0B253810228F0D360 +:10387000207A78B905E001E0F00100208DF80260BF +:10388000E6E7607A30B9A07A20B9E07A10B9207BF7 +:10389000C00601D0062088E704F1080001F07DFB96 +:1038A0008DF80E0068460EF0F6FC05F0BCFC002812 +:1038B00089D18DF810608DF81150E088ADF81200B4 +:1038C000ADF8145004A80EF039FD05F0ACFC00284A +:1038D00088D12078C00701D0152000E01320FFF721 +:1038E000BDFB002061E72DE9FF470220FD4E8DF86A +:1038F00004000027708EADF80600B84643F20209B6 +:103900004CE001A810F039FA050006D0708EA8B37B +:10391000A6F83280ADF806803EE0039CA07F010748 +:103920002DD504F124000090A28EBDF80800214698 +:1039300004F1360301F0BCFC050005D04D452AD04A +:10394000112D3CD0FFDF3AE0A07F20F00801E07F9E +:10395000420862F3C711A177810861F30000E077A4 +:1039600094F8210000F01F0084F820002078282817 +:1039700026D129212046FFF7CDFB21E014E04007A6 +:103980000AD5BDF8080004F10E0101F01CFB05008A +:103990000DD04D4510D100257F1CFFB2022010F044 +:1039A0002DFA401CB842ACD8052D11D008E0A07FFC +:1039B00020F00400A07703E0112D00D0FFDF0025E8 +:1039C000BDF806007086052D04D0284604B0C8E571 +:1039D000A6F832800020F9E770B50646FFF732FD01 +:1039E000054605F003FE040000D1FFDF6680207865 +:1039F00020F00F00801C20F0F00020302070032009 +:103A0000207295F83E006072BDE8704005F0F1BD8F +:103A10002DE9F04786B0040000D1FFDF2078B14DDA +:103A200020F00F00801C20F0F000703020706068E3 +:103A30000178491F1B2933D2DFE801F0FE32323210 +:103A400055FD320EFDFD42FC32323278FCFCFBFAB1 +:103A500032FCFCF9F8FCFC00C6883046FFF7F2FCAB +:103A60000546304607F045FCE0B16068007A85F80D +:103A70003E0021212846FFF74DFB3046FEF75AFB5A +:103A8000304603F0D7FE3146012014F017F8A87F26 +:103A900020F01000A877FFF726FF002800D0FFDFF6 +:103AA00006B05EE5207820F0F00020302070032082 +:103AB000207266806068007A607205F09AFDD8E72F +:103AC000C5882846FFF7BEFC00B9FFDF60680079B3 +:103AD000012800D0FFDF6068017A06B02846BDE803 +:103AE000F04707F0EBBDC6883046FFF7ABFC05009A +:103AF00000D1FFDF05F07DFD606831460089288137 +:103B000060684089688160688089A881012013F01D +:103B1000D5FF0020A875A87F00F003000228BFD1C0 +:103B2000FFF7E1FE0028BBD0FFDFB9E7007928B13D +:103B30000228B5D03C28B3D0FFDFB1E705F059FD2E +:103B40006668B6F806A0307A361D012806D0687E71 +:103B5000814605F0D4FA070003D101E0E878F7E7E1 +:103B6000FFDF00220221504610F097F9040000D137 +:103B7000FFDF22212046FFF7CDFA3079012800D05F +:103B80000220A17F804668F30101A177308B20815C +:103B9000708B6081B08BA08184F822908DF80880B2 +:103BA000B8680090F86801906A460321504610F00A +:103BB00074F900B9FFDFB888ADF81000B8788DF857 +:103BC000120004AA0521504610F067F900B9FFDF82 +:103BD000B888ADF80C00F8788DF80E0003AA04211F +:103BE000504610F05AF900B9FFDF062106F1120025 +:103BF0000DF00EF940B37079800700D5FFDF7179C1 +:103C0000E07D61F34700E075D6F80600A061708999 +:103C1000A083062106F10C000DF0FAF8F0B195F83A +:103C200025004108607861F3470006E041E039E093 +:103C300071E059E04EE02FE043E06070D5F82600D7 +:103C4000C4F80200688D12E0E07D20F0FE00801CC8 +:103C5000E075D6F81200A061F08AD9E7607820F00C +:103C6000FE00801C6070F068C4F80200308AE080BA +:103C7000B8F1010F04D0B8F1020F05D0FFDF0FE754 +:103C80000320FFF7D3F90BE7287E122800D0FFDFCF +:103C90001120FFF7E3F903E706B02046BDE8F0473F +:103CA00001F092BD05F0A5FC15F8300F40F00200C0 +:103CB00005E005F09EFC15F8300F40F00400287078 +:103CC000EEE6287E13280AD01528D8D15FF016001A +:103CD000FFF7C4F906B0BDE8F04705F08ABC142030 +:103CE000F6E70000F0010020A978052909D0042991 +:103CF000C5D105F07EFC022006B0BDE8F047FFF715 +:103D000095B900790028BAD0E87801F02DF905F0CE +:103D100070FC0320F0E7287E122802D1687E01F0B3 +:103D200023F91120D4E72DE9F05F054600784FF024 +:103D300000080009DFF8B8A891460C46464601285D +:103D40006ED002286DD007280BD00A286AD0FFDF7A +:103D5000A9F8006014B1A4F8008066800020BDE8D6 +:103D6000F09F6968012704F108000B784FF0020BFF +:103D70005B1F4FF6FF721B2B7ED2DFE803F0647DE2 +:103D80007D7D0E7D7D7D7D7D7D217D7D7D2BFDFC81 +:103D9000FBFA7D14D2F9E7F8F700C8884FF0120853 +:103DA000102621469AE14FF01C080A26BCB38888E9 +:103DB000A0806868807920726868C0796072C7E7FF +:103DC0004FF01B08142654B30320207268688088C3 +:103DD000A080BDE70A793C2ABAD00D1D4FF010082B +:103DE0002C26E4B16988A180298B6182298B2182EC +:103DF000698BA182A98BE1826B790246A91D1846C5 +:103E0000FFF7EFFA2979002001290CD084F80FB0D0 +:103E1000FF212176E06120626062A06298E70FE0F6 +:103E20003BE15EE199E1E77320760AF1040090E856 +:103E30000E00DAF81000C4E90930C4E9071287E778 +:103E4000A9F800608AE72C264FF01D08002CF7D057 +:103E5000A28005460F1D897B008861F30000288041 +:103E6000B97A490861F341002880B97A890861F379 +:103E700082002880B97A00E00CE1C90861F3C30030 +:103E80002880B97AAA1C0911491C61F3041000F0BA +:103E90007F0028807878B91CFFF7A3FA387D05F1F8 +:103EA000090207F11501FFF79CFA387B01F0A9F828 +:103EB0002874787B01F0A5F86874F87EA874787A85 +:103EC000E874387F2875B87B6875388AE882DAF834 +:103ED0001C10A961B97A504697F808A0C1F34111A6 +:103EE000012904D0008C504503D2824609E0FFDF4F +:103EF00010E0022903D0288820F0600009E0504536 +:103F000004D1288820F06000403002E0288840F08A +:103F100060002880A4F824A0524607F11D01A8697A +:103F20009BE011264FF02008002C89D0A280686801 +:103F300004F10A02007920726868007B6072696887 +:103F40008B1D48791946FFF74CFA01E70A264FF016 +:103F50002108002CE9D08888A080686880792072C8 +:103F60006868C07960729AF8301006E078E06BE01B +:103F700052E07FE019E003E03AE021F00401A6E01E +:103F80000B264FF02208002CCFD0C888A08068688C +:103F9000007920726868007A01F033F8607268680E +:103FA000407A01F02EF8A072D2E61C264FF02608C7 +:103FB000002CBAD0A2806868407960726868007A84 +:103FC000A0720AF1040090E80E00DAF81000C4E9CB +:103FD0000530C4E90312686800793C2803D04328FF +:103FE00003D0FFDFB4E62772B2E684F808B0AFE68C +:103FF00010264FF02408002C97D08888A08068688D +:10400000807920816868807A608168680089A081F1 +:1040100068688089E0819BE610264FF02308002C19 +:1040200098D08888A0806868C088208168680089E6 +:10403000608168684089A08168688089E0819AF819 +:10404000301021F0020142E030264FF02508002C0C +:104050009AD0A2806968282249680AF0EEF977E6CA +:104060002A264FF02F08002C8ED0A28069682222C9 +:10407000091DF2E714264FF01B08002C84D0A28003 +:10408000686800790128B0D02772DAE90710C4E91E +:1040900003105DE64A46214660E0287A012803D0F5 +:1040A000022817D0FFDF53E610264FF01F08002C20 +:1040B000A2D06888A080A8892081E8896081288AA8 +:1040C000A081688AE0819AF8301021F001018AF815 +:1040D00030103DE64FF012081026688800F07EFF91 +:1040E00036E6287AC8B3012838D0022836D003280B +:1040F00001D0FFDF2CE609264FF01108002C8FD0ED +:104100006F883846FFF79EF990F822A0A780687A5A +:104110002072042138460FF0DBFE052138460FF0EF +:10412000D7FE002138460FF0D3FE012138460FF0AC +:10413000CFFE032138460FF0CBFE022138460FF0A8 +:10414000C7FE062138460FF0C3FE072138460FF0A0 +:10415000BFFE504600F008FFFAE5FFE72846BDE83D +:10416000F05F01F0BBBC70B5012803D0052800D07A +:10417000FFDF70BD8DB22846FFF764F9040000D15F +:10418000FFDF20782128F4D005F030FA80B10178E3 +:1041900021F00F01891C21F0F00110310170022182 +:1041A000017245800020A075BDE8704005F021BA7D +:1041B00021462846BDE870401322FFF746B92DE995 +:1041C000F04116460C00804600D1FFDF307820F029 +:1041D0000F00801C20F0F000103030702078012893 +:1041E00004D0022818D0FFDFBDE8F0814046FFF779 +:1041F00029F9050000D1FFDF0320A87505F0F9F9C2 +:1042000094E80F00083686E80F00F94810F8301FD0 +:1042100041F001010170E7E74046FFF713F905009F +:1042200000D1FFDFA1884FF6FF700027814202D145 +:10423000E288824203D0814201D1E08840B105F09A +:10424000D8F994E80F00083686E80F00AF75CBE781 +:10425000A87D0128C8D178230022414613F084FBB1 +:104260000220A875C0E738B50C4624285CD008DCCD +:1042700020280FD0212825D022284BD0232806D152 +:104280004CE0252841D0262832D03F2851D00725A0 +:10429000284638BD0021052013F0E6FB08B11120A7 +:1042A00038BDA01C0EF0E1FA04F0BDFF0500EFD10F +:1042B000002208231146052013F056FB0528E7D0FD +:1042C000FFDFE5E76068FDF708F808B1102038BDAA +:1042D000618820886A460EF071FD04F0A4FF050095 +:1042E000D6D160680028D3D0BDF800100180CFE798 +:1042F000206820B1FCF7FAFF08B11025C8E7204676 +:104300000EF03BFE1DE00546C2E7A17820880EF0C6 +:1043100086FD16E0086801F08DFEF4E7087800F0ED +:1043200001000DF0B9FD0CE0618820880EF0C1FCA1 +:1043300007E0087800F001008DF8000068460EF0F4 +:10434000DFF804F070FFDEE770B505460C4608465E +:10435000FCF7A5FF08B1102070BD202D07D0212D3E +:104360000DD0222D0BD0252D09D0072070BD20881F +:10437000A11C0DF065FEBDE8704004F054BF06209E +:1043800070BD9B482530704708B5342200219848FD +:104390000AF07DF80120FEF749FE1120FEF75EFECF +:1043A00093496846263105F0B7F891489DF80020FA +:1043B00010F8251F62F3470121F00101017000216F +:1043C00041724FF46171A0F8071002218172FEF76B +:1043D0008FFE00B1FFDFFDF705F801F0BEF908BD63 +:1043E00010B50C464022002120460AF050F8A07F6C +:1043F00020F00300A077202020700020A07584F812 +:10440000230010BD70472DE9FC410746FCF721FF52 +:1044100010B11020BDE8FC81754E06F12501D6F8DB +:1044200025000090B6F82950ADF8045096F82B40BE +:104430008DF806403846FEF7BDFF0028EAD1FEF7AA +:1044400057FE0028E6D0009946F8251FB580B471C4 +:10445000E0E710B50446FCF722FF08B1102010BDBC +:1044600063486349224690F8250026314008FEF74C +:10447000B8FF002010BD3EB504460D460846FCF7C7 +:104480000EFF08B110203EBD14B143F204003EBD42 +:1044900057488078052803D0042801D008203EBD65 +:1044A000694602A80AF012FC2A4669469DF80800EF +:1044B000FEF797FF00203EBDFEB50D4604004FF00D +:1044C000000712D00822FEF79FFE002812D1002616 +:1044D00009E000BF54F826006946FEF720FF0028D7 +:1044E00008D1761CF6B2AE42F4D30DF01CFC10B12C +:1044F00043F20320FEBD3E4E86F824700CB3002725 +:104500001BE000BF54F8270002A9FEF708FF00B126 +:10451000FFDF9DF808008DF8000054F8270050F8E0 +:10452000011FCDF801108088ADF8050068460DF038 +:104530001FFC00B1FFDF7F1CFFB2AF42E2D386F861 +:1045400024500020FEBD2DE9F0418AB01546884672 +:1045500004001ED00F4608222946FEF755FE00280B +:1045600011D1002613E000BF54F826006946103030 +:1045700000F01FFD002806D13FB157F82600FCF7D8 +:1045800068FE10B110200AB02EE6761CF6B2AE42DC +:10459000EAD3681EC6B217E0701CC7B212E000BFB3 +:1045A00054F82600017C4A0854F827100B7CB2EB23 +:1045B000530F05D106221130113109F011FF50B10E +:1045C0007F1CFFB2AF42EBD3761EF6B2E4D2464672 +:1045D00024B1012003E043F20520D4E700200DF0D0 +:1045E000ECFB10B90DF0F5FB20B143F20420CAE753 +:1045F000F001002064B300270DF1170826E000BF8A +:1046000054F827006946103000F0D3FC00B1FFDFFA +:1046100054F82700102250F8111FCDF8011080889F +:10462000ADF8050054F827100DF1070009F005FF5B +:1046300096B156F827101022404609F0FEFE684653 +:104640000DF07BFB00B1FFDF7F1CFFB2AF42D7D381 +:10465000FEF713FF002096E7404601F0DFFCEEE78F +:1046600030B585B00446FDF7BDF830B906200FF02F +:10467000C5FB10B1062005B030BD2046FCF7E9FDB2 +:1046800018B96068FCF732FE08B11020F3E76088C3 +:104690004AF2B811884206D82078F94D28B101288D +:1046A00006D0022804D00720E5E7FEF721FD18E038 +:1046B0006078022804D0032802D043F20220DAE70F +:1046C00085F82F00C1B200200090ADF80400022947 +:1046D0002CD0032927D0FFDF68460DF009FC04F039 +:1046E000A2FD0028C7D1606801F08BFC207858B18A +:1046F00001208DF800000DF1010001F08FFC6846EB +:104700000EF0FDFB00B1FFDF207885F82E00FEF7EC +:10471000B4FE608860B1A88580B20DF046FB00B1A0 +:10472000FFDF0020A7E78DF80500D5E74020FAE776 +:104730004FF46170EFE710B50446FCF7B0FD20B907 +:10474000606838B1FCF7C9FD08B1102010BD606881 +:1047500001F064FCCA4830F82C1F6180C178617098 +:1047600080782070002010BD2DE9F843144689465A +:104770000646FCF794FDA0B94846FCF7B7FD80B9A2 +:104780002046FCF7B3FD60B9BD4DA878012800D1E3 +:104790003CB13178FF2906D049B143F20400BDE8AD +:1047A000F8831020FBE7012801D00420F7E7CCB301 +:1047B000052811D004280FD069462046FEF776FE62 +:1047C0000028ECD1217D49B1012909D0022909D065 +:1047D000032909D00720E2E70820E0E7024604E0C9 +:1047E000012202E0022200E003228046234617460F +:1047F00000200099FEF794FE0028D0D1A0892880DF +:10480000A07BE875BDF80000A882AF75BDF8001068 +:10481000090701D5A18931B1A1892980C00704D038 +:10482000032003E006E08021F7E70220FEF7FEFB0D +:1048300086F800804946BDE8F8430020FEF71EBF19 +:104840007CB58F4C05460E46A078022803D003287D +:1048500001D008207CBD15B143F204007CBD0720C7 +:104860000FF0D4FA10B9A078032806D0FEF70CFC9C +:1048700028B1A078032804D009E012207CBD1320C1 +:104880007CBD304600F053FB0028F9D1E670FEF7FE +:104890006FFD0AF058F901208DF800008DF8010035 +:1048A0008DF802502088ADF80400E07D8DF80600F8 +:1048B00068460EF0C1F904F0B6FC0028E0D1A078FB +:1048C000032805D05FF00400FEF7B0FB00207CBD9C +:1048D000E07800F03CFB0520F6E71CB510B143F290 +:1048E00004001CBD664CA078042803D0052801D024 +:1048F00008201CBD00208DF8000001218DF801105A +:104900008DF8020068460EF097F904F08CFC002840 +:10491000EFD1A078052805D05FF00200FEF786FBF6 +:1049200000201CBDE07800F01FFB0320F6E72DE916 +:10493000FC4180460E4603250846FCF7D7FC0028BC +:1049400066D14046FEF77EFD040004D02078222880 +:1049500004D208205EE543F202005BE5A07F00F090 +:1049600003073EB1012F0CD000203146FEF727FC93 +:104970000500EFD1012F06D0022F1AD0FFDF284605 +:1049800048E50120F1E7A07D3146022801D011B1B0 +:1049900007E011203EE56846FCF758FE0028D9D113 +:1049A0006946404606F04DFE0500E8D10120A0759D +:1049B000E5E7A07D032804D1314890F83000C00716 +:1049C00001D02EB30EE026B1A07F40071ED40021F7 +:1049D00000E00121404606F054FE0500CFD1A0754D +:1049E000002ECCD03146404600F0EDFA05461128A5 +:1049F000C5D1A07F4107C2D4316844F80E1F716849 +:104A0000616040F0040020740025B8E71125B6E786 +:104A10001020FFE470B50C460546FEF713FD0100BB +:104A200005D022462846BDE87040FEF70EBD43F291 +:104A3000020070BD10B5012807D1114B9B78012BE6 +:104A400000D011B143F2040010BD0DF0E0F9BDE853 +:104A5000104004F0E8BB012300F090BA00231A468E +:104A6000194600F08BBA70B506460C460846FCF7AE +:104A7000F0FB18B92068FCF712FC18B1102070BDCB +:104A8000F0010020F84D2A7E112A04D0132A00D309 +:104A90003EB10820F3E721463046FEF77DFE60B1C7 +:104AA000EDE70920132A0DD0142A0BD0A188FF2985 +:104AB000E5D31520FEF7D2FA0020D4E90012C5E9AB +:104AC0000712DCE7A1881F29D9D31320F2E71CB510 +:104AD000E548007E132801D208201CBD00208DF877 +:104AE000000068460DF02AFC04F09DFB0028F4D17C +:104AF0001120FEF7B3FA00201CBD2DE9F04FDFF8BE +:104B000068A3814691B09AF818009B4615460C465A +:104B1000132803D3FFF7DBFF00281FD12046FCF743 +:104B200098FBE8BB2846FCF794FBC8BB20784FF005 +:104B30000107C0074FF0000102D08DF83A7001E084 +:104B40008DF83A1020788846C0F3C1008DF8000037 +:104B500060788DF80910C10803D0072011B0BDE8B6 +:104B6000F08FB0B3C10701D08DF80970810705D56A +:104B70009DF8091041F002018DF80910400705D594 +:104B80009DF8090040F004008DF809009DF8090027 +:104B9000810703D540F001008DF80900002000E0F6 +:104BA00015E06E4606EB400162884A81401CA288EF +:104BB000C0B20A820328F5D32078C0F3C1000128CF +:104BC00025D0032823D04846FCF743FB28B110200A +:104BD000C4E7FFE78DF80970D8E799F800004008AE +:104BE00008D0012809D0022807D0032805D043F2B5 +:104BF0000220B3E78DF8028001E08DF8027048468C +:104C000050F8011FCDF803108088ADF80700FEF7BB +:104C1000AFFB8DF801000021424606EB41002B88D6 +:104C2000C3826B888383AB884384EB880385491CEC +:104C3000C285C9B282860329EFD3E088ADF83C0073 +:104C400068460DF053FC002887D19AF818005546A5 +:104C5000112801D0082081E706200FF0D7F838B1DD +:104C60002078C0F3C100012804D0032802D006E058 +:104C7000122073E795F8240000283FF46EAFFEF78A +:104C800003FA022801D2132068E7584600F04FF9D2 +:104C900000289DD185F819B068460DF06DFD04F02F +:104CA000C2FA040094D1687E00F051F91220FEF798 +:104CB000D5F9204652E770B56B4D287E122801D0F9 +:104CC0000820DCE60DF05BFD04F0ADFA040005D130 +:104CD000687E00F049F91120FEF7C0F92046CEE6C3 +:104CE00070B5064615460C460846FCF7D8FA18B9C2 +:104CF0002846FCF7D4FA08B11020C0E62A4621461F +:104D000030460EF03BF804F08EFA0028F5D12178F9 +:104D10007F29F2D10520B2E67CB505460C4608464F +:104D2000FCF797FA08B110207CBD2846FEF78AFBF5 +:104D300020B10078222804D208207CBD43F2020072 +:104D40007CBD494890F83000400701D511207CBD5A +:104D50002078C00802D16078C00801D007207CBD4F +:104D6000ADF8005020788DF8020060788DF80300CF +:104D70000220ADF8040068460CF03BFE04F053FA44 +:104D80007CBD70B586B014460D460646FEF75AFB4C +:104D900028B10078222805D2082006B06FE643F239 +:104DA0000200FAE72846FCF7A1FA20B944B12046F0 +:104DB000FCF793FA08B11020EFE700202060A080F4 +:104DC000294890F83000800701D51120E5E703A9B4 +:104DD00030460CF05EFE10B104F025FADDE7ADF8C8 +:104DE0000060BDF81400ADF80200BDF81600ADF883 +:104DF0000400BDF81000BDF81210ADF80600ADF8C3 +:104E000008107DB1298809B1ADF80610698809B18B +:104E1000ADF80210A98809B1ADF80810E98809B108 +:104E2000ADF80410DCB1BDF80610814201D9081AB2 +:104E30002080BDF80210BDF81400814201D9081A83 +:104E40006080BDF80800BDF80410BDF816200144CC +:104E5000BDF812001044814201D9081AA0806846AA +:104E60000CF0D5FEB8E70000F00100201CB56C493D +:104E70000968CDE9001068460DF03AFB04F0D3F95B +:104E80001CBD1CB500200090019068460DF030FB61 +:104E900004F0C9F91CBD70B505460C460846FCF780 +:104EA000FEF908B11020EAE5214628460DF012F976 +:104EB000BDE8704004F0B7B93EB505460C4608465B +:104EC000FCF7EDF908B110203EBD002000900190E4 +:104ED0000290ADF800502089ADF8080020788DF8D8 +:104EE0000200606801902089ADF808006089ADF883 +:104EF0000A0068460DF000F904F095F93EBD0EB5C4 +:104F0000ADF800000020019068460DF0F5F804F0BF +:104F10008AF90EBD10800888508048889080C88823 +:104F200010818888D080002050819081704710B512 +:104F3000044604F0E4F830B1407830B1204604F083 +:104F4000FCFB002010BD052010BD122010BD10B5C7 +:104F500004F0D5F8040000D1FFDF607800B9FFDF6E +:104F60006078401E607010BD10B504F0C8F80400F1 +:104F700000D1FFDF6078401C607010BD1CB5ADF83B +:104F800000008DF802308DF803108DF8042068467B +:104F90000DF0B7FE04F047F91CBD0CB521A2D2E913 +:104FA0000012CDE900120079694601EB501000783B +:104FB0000CBD0278520804D0012A02D043F202202C +:104FC0007047FEF7ACB91FB56A46FFF7A3FF684606 +:104FD0000DF008FC04F027F904B010BD70B50C000A +:104FE00006460DD0FEF72EFA050000D1FFDFA680A1 +:104FF00028892081288960816889A081A889E08129 +:105000003DE500B540B1012805D0022803D00328B2 +:1050100004D0FFDF002000BDFF2000BD042000BD44 +:1050200014610200070605040302010010B50446DE +:10503000FCF70FF908B1102010BD2078C0F3021062 +:10504000042807D86078072804D3A178102901D84C +:10505000814201D2072010BDE078410706D42179B2 +:105060004A0703D4000701D4080701D5062010BD64 +:10507000002010BD10B513785C08837F64F3C7135C +:10508000837713789C08C37F64F30003C377107899 +:10509000C309487863F34100487013781C090B7802 +:1050A00064F347130B701378DB0863F30000487058 +:1050B0005078487110BD10B5C4780B7864F30003C4 +:1050C0000B70C478640864F341030B70C478A408BF +:1050D00064F382030B70C478E40864F3C3030B70B9 +:1050E0000379117863F30001117003795B0863F3AE +:1050F0004101117003799B0863F3820111700079FB +:10510000C00860F3C301117010BD70B514460D46A0 +:10511000064604F06BFA80B10178182221F00F01E5 +:10512000891C21F0F001A03100F8081B214609F08C +:1051300084F9BDE8704004F05CBA29463046BDE809 +:1051400070401322FEF781B92DE9F047064608A802 +:10515000904690E8300489461F46142200212846D4 +:1051600009F095F90021CAF80010B8F1000F03D03A +:10517000B9F1000F03D114E03878C00711D02068CE +:10518000FCF78DF8C0BBB8F1000F07D120681230D2 +:1051900028602068143068602068A8602168CAF818 +:1051A00000103878800724D56068FCF796F818BBA3 +:1051B000B9F1000F21D0FFF7E4F80168C6F86811D3 +:1051C0008188A6F86C11807986F86E0101F013FDD4 +:1051D000F94FEF60626862B196F8680106F26911F2 +:1051E00040081032FEF7FDF810223946606809F0D9 +:1051F00024F90020BDE8F08706E0606820B1E8608F +:105200006068C6F86401F4E71020F3E730B505469E +:1052100008780C4620F00F00401C20F0F0011031FF +:1052200021700020607095F8230030B104280FD061 +:10523000052811D0062814D0FFDF20780121B1EB1A +:10524000101F04D295F8200000F01F00607030BDE0 +:1052500021F0F000203002E021F0F000303020702A +:10526000EBE721F0F0004030F9E7F0B591B002270C +:1052700015460C4606463A46ADF80870092103ABC0 +:1052800005F063F80490002810D004208DF8040085 +:105290008DF80170E034099605948DF818500AA92C +:1052A000684610F0FCFA00B1FFDF012011B0F0BD3C +:1052B00010B588B00C460A99ADF80000CBB118685B +:1052C000CDF80200D3F80400CDF80600ADF80A20AE +:1052D000102203A809F0B1F868460DF0F3FA03F0C4 +:1052E000A2FF002803D1A17F41F01001A17708B0EF +:1052F00010BD0020CDF80200E6E72DE9F84F064684 +:10530000808A0D4680B28246FEF79CF804463078CB +:10531000DFF8A48200274FF00209A8F120080F2827 +:1053200070D2DFE800F06FF23708387D8CC8F1F0FA +:10533000EFF35FF3F300A07F00F00300022809D031 +:105340005FF0000080F0010150460EF0AFFD050057 +:1053500003D101E00120F5E7FFDF98F85C10C907F1 +:1053600002D0D8F860000BE0032105F11D0012F017 +:10537000BEF8D5F81D009149B0FBF1F201FB120017 +:10538000C5F81D0070686867B068A8672078252890 +:1053900000D0FFDFCAE0A07F00F00300022809D0A0 +:1053A0005FF0000080F0010150460EF07FFD060026 +:1053B00003D101E00120F5E7FFDF3078810702D556 +:1053C0002178252904D040F001003070BDE8F88F25 +:1053D00085F80090307F287106F11D002D36C5E953 +:1053E0000206F3E7A07F00F00300022808D00020A7 +:1053F00080F0010150460EF059FD040004D102E096 +:105400000120F5E7A7E1FFDF2078C10604D50720DA +:1054100028703D346C60D9E740F008002070D5E773 +:10542000E07F000700D5FFDF307CB28800F0010389 +:1054300001B05046BDE8F04F092106F064B804B948 +:10544000FFDF716821B1102204F1240008F0F5FF9C +:1054500028212046FDF75EFEA07F00F00300022811 +:105460000ED104F12400002300901A462146504634 +:10547000FFF71EFF112807D029212046FDF74AFE1D +:10548000307A84F82000A1E7A07F000700D5FFDF75 +:1054900014F81E0F40F008002070E782A761E76152 +:1054A000C109607861F34100014660F382016170D7 +:1054B000307AE0708AE7A07F00F00300022809D06C +:1054C0005FF0000080F0010150460EF0EFFC040098 +:1054D00003D101E00120F5E7FFDF022104F185009F +:1054E00012F005F80420287004F5B4706860B4F870 +:1054F00085002882304810387C346C61C5E9028010 +:1055000064E703E024E15BE02DE015E0A07F00F01C +:105510000300022807D0002080F0010150460EF061 +:10552000C5FC18B901E00120F6E7FFDF324621464D +:105530005046BDE8F84FE8E504B9FFDF20782128A0 +:10554000A1D93079012803D1E07F40F00800E0774D +:10555000324621465046FFF7D8FD2046BDE8F84FB9 +:105560002321FDF7D7BD3279AA8005F1080309216F +:10557000504604F0EAFEE86010B10520287025E7E7 +:10558000A07F00F00300022808D0002080F0010175 +:1055900050460EF08BFC040003D101E00120F5E73A +:1055A000FFDF04F1620102231022081F0EF005FB49 +:1055B00007703179417009E75002002040420F0026 +:1055C000A07F00F00300022808D0002080F0010135 +:1055D00050460EF06BFC050003D101E00120F5E719 +:1055E000FFDF95F8840000F0030001287AD1A07F46 +:1055F00000F00307E07F10F0010602D0022F04D173 +:1056000033E095F8A000C0072BD0D5F8601121B386 +:1056100095F88320087C62F387000874A17FCA098B +:10562000D5F8601162F341000874D5F8601166F393 +:1056300000000874AEB1D5F86001102204F1240115 +:10564000883508F0FAFE287E40F001002876287898 +:1056500020F0010005F8880900E016B1022F04D0FF +:105660002DE095F88800C00727D0D5F85C1121B34C +:1056700095F88320087C62F387000874A17FCA092B +:10568000D5F85C1162F341000874D5F85C1166F33B +:10569000000008748EB1D5F85C01102204F12401D9 +:1056A000883508F0CAFE287840F0010005F8180B8C +:1056B000287820F0010005F8A009022F44D000202E +:1056C00000EB400005EBC00090F88800800709D58A +:1056D00095F87C00D5F86421400805F17D01103271 +:1056E000FDF77FFE8DF8009095F884006A4600F083 +:1056F00003008DF8010095F888108DF8021095F8D8 +:10570000A0008DF803002146504601F05DFA207894 +:10571000252805D0212807D0FFDF2078222803D9AB +:1057200022212046FDF7F6FCA07F00F003000228AE +:105730000CD0002080F0010150460EF0C9FB00287B +:105740003FF44FAEFFDF41E60120B9E70120F1E76A +:10575000706847703AE6FFDF38E670B5FE4C00250A +:1057600084F85C50256610F066F804F110012046BC +:1057700003F0F8FE84F8305070BD70B50D46FDF7AB +:1057800061FE040000D1FFDF4FF4B872002128460B +:1057900008F07DFE04F124002861A07F00F00300E2 +:1057A000022809D05FF0010105F1E00010F044F893 +:1057B000002800D0FFDF70BD0221F5E70A46014650 +:1057C00002F1E00010F059B870B50546406886B0A7 +:1057D00001780A2906D00D2933D00E292FD0FFDFFA +:1057E00006B070BD86883046FDF72CFE040000D15F +:1057F000FFDF20782128F3D028281BD168680221F8 +:105800000E3001F0D6F9A8B168680821801D01F0BA +:10581000D0F978B104F1240130460DF00FFA03F00D +:1058200002FD00B1FFDF06B02046BDE8704029212F +:10583000FDF770BC06B0BDE8704003F0DABE012190 +:1058400001726868C6883046FDF7FCFD040000D18F +:10585000FFDFA07F00F00301022902D120F0100039 +:10586000A077207821280AD06868017A09B10079E8 +:1058700080B1A07F00F00300022862D0FFDFA07F8C +:1058800000F003000228ABD1FEF72DF80028A7D0C6 +:10589000FFDFA5E703F0ADFEA17F08062BD5E07F73 +:1058A000C00705D094F8200000F01F00102820D079 +:1058B0005FF0050084F82300207829281DD02428D3 +:1058C000DDD13146042012F0F9F822212046FDF7FF +:1058D00021FCA07F00F00300022830D05FF0000020 +:1058E00080F0010130460EF0F3FA0028C7D0FFDF48 +:1058F000C5E70620DEE70420DCE701F0030002280C +:1059000008D0002080F0010130460EF0CFFA0500EB +:1059100003D101E00120F5E7FFDF25212046FDF757 +:10592000F9FB03208DF80000694605F1E0000FF057 +:105930009BFF0228A3D00028A1D0FFDF9FE7012012 +:10594000CEE703F056FE9AE72DE9F04387B099467B +:10595000164688460746FDF775FD04004BD02078B3 +:10596000222848D3232846D0E07F000743D4A07FD5 +:1059700000F00300022809D05FF0000080F0010170 +:1059800038460EF093FA050002D00CE00120F5E74E +:10599000A07F00F00300022805D001210022384634 +:1059A0000EF07BFA05466946284601F034F9009866 +:1059B00000B9FFDF45B10098E03505612078222865 +:1059C00006D0242804D007E000990020086103E0F5 +:1059D00025212046FDF79EFB00980121417047627A +:1059E000868001A9C0E902890FF059FF022802D080 +:1059F000002800D0FFDF07B0BDE8F08370B586B0A7 +:105A00000546FDF71FFD017822291ED9807F00F091 +:105A10000300022808D0002080F0010128460EF083 +:105A200045FA04002FD101E00120F5E7FFDF2AE06D +:105A3000B4F85E0004F1620630440178427829B17E +:105A400021462846FFF711FCB0B9C9E6ADF804209D +:105A50000921284602AB04F078FC03900028F4D01A +:105A600005208DF80000694604F1E0000FF0FCFE0F +:105A7000022801D000B1FFDF02231022314604F1D9 +:105A80005E000EF0D0F8B4F860000028D0D1A7E690 +:105A900010B586B00446FDF7D5FC017822291BD944 +:105AA000807F00F00300022808D0002080F0010170 +:105AB00020460EF0FBF9040003D101E00120F5E7D8 +:105AC000FFDF06208DF80000694604F1E0000FF0CA +:105AD000CBFE002800D0FFDF06B010BD2DE9F05F3F +:105AE00005460C4600270078904601093E4604F121 +:105AF000080BBA4602297DD0072902D00A2909D10C +:105B000046E0686801780A2905D00D2930D00E29B1 +:105B10002ED0FFDFBBE114271C26002C6BD0808821 +:105B2000A080FDF78FFC5FEA000900D1FFDF99F844 +:105B300017005A46400809F11801FDF752FC686841 +:105B4000C0892082696851F8060FC4F812004868BD +:105B5000C4F81600A07E01E03002002020F006000C +:105B600040F00100A07699F81E0040F020014DE0C1 +:105B70001A270A26002CD1D0C088A080FDF762FC2D +:105B8000050000D1FFDF59462846FFF73FFB7EE1C5 +:105B90000CB1A88BA080287A0B287DD006DC0128C8 +:105BA0007BD0022808D0032804D135E00D2875D019 +:105BB0000E2874D0FFDF6AE11E270926002CADD025 +:105BC000A088FDF73FFC5FEA000900D1FFDF287BDA +:105BD00000F003000128207A1BD020F00100207281 +:105BE000297B890861F341002072297BC90861F390 +:105BF000820001E041E1F2E02072297B090961F3B2 +:105C0000C300207299F81E0040F0400189F81E1070 +:105C10003DE140F00100E2E713270D26002CAAD059 +:105C2000A088FDF70FFC8146807F00F0030002286A +:105C300008D0002080F00101A0880EF037F905009F +:105C400003D101E00120F5E7FFDF99F81E0000F025 +:105C50000302022A50D0686F817801F00301012904 +:105C6000217A4BD021F00101217283789B0863F3E4 +:105C7000410121728378DB0863F38201217283780A +:105C80001B0963F3C3012172037863F306112172C8 +:105C9000437863F3C71103E061E0A9E090E0A1E07D +:105CA000217284F809A0C178A172022A29D0027950 +:105CB000E17A62F30001E1720279520862F3410174 +:105CC000E1720279920862F38201E1720279D208EC +:105CD00062F3C301E1724279217B62F30001217317 +:105CE0004279520862F3410121734279920862F3CA +:105CF00082012173407928E0A86FADE741F00101EE +:105D0000B2E74279E17A62F30001E1724279520826 +:105D100062F34101E1724279920862F38201E17219 +:105D20004279D20862F3C301E1720279217B62F306 +:105D3000000121730279520862F341012173027953 +:105D4000920862F3820121730079C00860F3C301F5 +:105D5000217399F80000232831D9262140E0182723 +:105D60001026E4B3A088FDF76DFB8346807F00F02A +:105D70000300022809D0002080F00101A0880EF065 +:105D800095F85FEA000903D101E00120F4E7FFDFA5 +:105D9000E868A06099F8000040F0040189F800105C +:105DA00099F80100800708D5012020739BF80000B6 +:105DB00023286CD92721584651E084F80CA066E0CE +:105DC00015270F265CB1A088FDF73CFB8146062213 +:105DD0005946E86808F0C7FB0120A073A0E041E045 +:105DE00048463CE016270926E4B3287B20724EE0A3 +:105DF000287B19270E26ACB3C4F808A0A4F80CA081 +:105E0000012807D0022805D0032805D0042803D094 +:105E1000FFDF0DE0207207E0697B042801F00F012D +:105E200041F0800121721ED0607A20F00300607280 +:105E3000A088FDF707FB05460078212827D02328F6 +:105E400000D0FFDFA87F00F00300022813D000205D +:105E500080F00101A0880EF03BF822212846FDF7D2 +:105E600059F914E004E0607A20F00300401CDEE7FA +:105E7000A8F8006010E00120EAE70CB16888A08073 +:105E8000287A68B301280AD002284FD0FFDFA8F88B +:105E900000600CB1278066800020BDE8F09F1527C8 +:105EA0000F26002CE4D0A088FDF7CCFA807F00F00C +:105EB0000300022808D0002080F00101A0880DF026 +:105EC000F5FF050003D101E00120F5E7FFDFD5F87C +:105ED0001D000622594608F046FB84F80EA0D6E7BE +:105EE00017270926002CC3D0A088FDF7ABFA8146FE +:105EF000807F00F00300022808D0002080F001011C +:105F0000A0880DF0D3FF050003D101E00120F5E7E3 +:105F1000FFDF6878800701D5022000E001202072B1 +:105F200099F800002328B2D9272159E719270E260E +:105F3000002C9DD0A088FDF785FA5FEA000900D10A +:105F4000FFDFC4F808A0A4F80CA084F808A0A07A89 +:105F500040F00300A07299F81E10C90961F3820095 +:105F6000A07299F81F2099F81E1012EAD11F05D0CF +:105F700099F8201001F01F0110292BD020F0080003 +:105F8000A07299F81F10607A61F3C3006072697A99 +:105F900001F003010129A2D140F00400607299F8D8 +:105FA0001E0000F003000228E87A16D0217B60F37F +:105FB00000012173AA7A607B62F300006073EA7AC1 +:105FC000520862F341012173A97A490861F3410043 +:105FD00060735CE740F00800D2E7617B60F300018A +:105FE0006173AA7A207B62F300002073EA7A520878 +:105FF00062F341016173A97A490861F3410020739A +:1060000045E710B5FE4C30B10146102204F12000E6 +:1060100008F013FA012084F8300010BD10B50446D2 +:1060200000F0E9FDF64920461022BDE8104020317D +:1060300008F003BA70B5F24D06004FF0000413D01B +:10604000FBF707F908B110240CE00621304608F0F0 +:1060500071FA411C05D028665FF0010085F85C00EC +:1060600000E00724204670BD0020F7E7007810F01C +:106070000F0204D0012A05D0022A0CD110E0000939 +:1060800009D10AE00009012807D0022805D0032819 +:1060900003D0042801D00720704708700020704703 +:1060A0000620704705282AD2DFE800F003070F1703 +:1060B0001F00087820F0FF001EE0087820F00F0095 +:1060C000401C20F0F000103016E0087820F00F009F +:1060D000401C20F0F00020300EE0087820F00F0087 +:1060E000401C20F0F000303006E0087820F00F006F +:1060F000401C20F0F000403008700020704707205E +:1061000070472DE9F041804688B00D4600270846CB +:10611000FBF7ECF8A8B94046FDF794F9040003D06A +:106120002078222815D104E043F2020008B0BDE82F +:10613000F08145B9A07F410603D500F00300022895 +:1061400001D01020F2E7A07FC10601D4010702D5DB +:106150000DB10820EAE7E17F090701D50D20E5E749 +:1061600000F0030002280DD165B12846FEF75EFF5E +:106170000700DBD1FBF736FB20B9E878800701D5B3 +:106180000620D3E7A07F00F00300022808D00020FB +:1061900080F0010140460DF089FE060002D00FE0BC +:1061A0000120F5E7A07F00F0030002280ED00020B8 +:1061B00080F00101002240460DF06FFE060007D07E +:1061C000A07F00F00300022804D009E00120EFE7DF +:1061D0000420ABE725B12A4631462046FEF74AFFA8 +:1061E0006946304600F017FD009800B9FFDF0099BE +:1061F000022006F1E0024870C1F824804A610022C2 +:106200000A81A27F02F00302022A1CD00120087139 +:10621000287800F00102087E62F3010008762A78EF +:10622000520862F3820008762A78920862F3C3006B +:1062300008762A78D20862F30410087624212046D2 +:10624000FCF768FF33E035B30871301D88613078A2 +:10625000400908777078C0F340004877287800F04C +:106260000102887F62F301008877A27FD20962F37E +:1062700082008877E27F62F3C3008877727862F3E6 +:1062800004108877A878C87701F1210228462031C8 +:10629000FEF711FF03E00320087105200876252191 +:1062A0002046FCF737FFA07F20F04000A07701A92F +:1062B00000980FF0F4FA022801D000B1FFDF384651 +:1062C00034E72DE9FF4F8DB09A4693460D460027DF +:1062D0000D98FDF7B7F8060006D03078262806D0CE +:1062E000082011B0BDE8F08F43F20200F9E7B07F5B +:1062F00000F00309B9F1020F11D04DB95846FEF76D +:1063000095FE0028EDD1B07F00F00300022806D0F2 +:10631000BBF1000F11D0FBF765FA20B10DE0BBF126 +:10632000000F50D109E006200DF068FD28B19BF860 +:106330000300800701D50620D3E7B07F00F00300FB +:10634000022809D05FF0000080F001010D980DF0E7 +:10635000ADFD040003D101E00120F5E7FFDF852D4D +:1063600027D007DCEDB1812D1DD0822D1DD0832DCE +:1063700008D11CE0862D1ED0882D1ED0892D1ED060 +:106380008A2D1ED00F2020710F281CD003F02EF96B +:10639000D8B101208DF81400201D06902079B0B1ED +:1063A00056E10020EFE70120EDE70220EBE70320B4 +:1063B000E9E70520E7E70620E5E70820E3E709200D +:1063C000E1E70A20DFE707208BE7112089E7B9F131 +:1063D000020F03D0A56F03D1A06F02E0656FFAE74B +:1063E000606F804631D04FF0010001904FF0020005 +:1063F00000905A4621463046FEF73CFE02E000007F +:10640000300200209BF8000000F00101A87861F341 +:106410000100A870B17FC90961F38200A870F17F03 +:1064200061F3C300A870617861F30410A87020784C +:10643000400928706078C0F3400068709BF8020043 +:10644000E87000206871287103E0022001900120AB +:106450000090A87898F80210C0F3C000C1F3C00102 +:10646000084003902CD05046FAF7F3FEC0BBDAF890 +:106470000C00FAF7EEFE98BBDAF81C00FAF7E9FE1A +:1064800070BBDAF80C00A060DAF81C00E0606078FD +:1064900098F8012042EA500161F34100607098F8D9 +:1064A0000210C0B200EA111161F300006070002018 +:1064B0002077009906F11700022907D0012106E094 +:1064C000607898F8012002EA5001E5E7002104EB2A +:1064D000810148610199701C022902D0012101E06B +:1064E00028E0002104EB81014861A87800F0030056 +:1064F000012857D198F8020000F00300012851D17B +:10650000B9F1020F04D02A1D691D5846FEF7D3FDCC +:10651000287998F8041008408DF82C00697998F8CB +:10652000052011408DF8301008433BD05046FAF753 +:1065300090FE08B11020D4E60AF110018B46B9F1A3 +:10654000020F17D00846002104F18C03CDE90003A7 +:1065500004F5AE7202920BAB2046039AFEF7F4FDEF +:106560000028E8D1B9F1020F08D0504608D14FF009 +:10657000010107E050464FF00101E5E75846F5E715 +:106580004FF0000104F1A403CDE9000304F5B0725B +:10659000029281F001010CAB2046039AFEF7D4FD74 +:1065A0000028C8D16078800733D4A87898F8021002 +:1065B000C0F38000C1F3800108432AD0297898F8FD +:1065C0000000F94AB9F1020F06D032F81120430059 +:1065D000DA4002F003070AE032F810204B00DA40FC +:1065E00012F0030705D0012F0AD0022F0AD0032F83 +:1065F00006D0039A6AB1012906D0042904D008E024 +:106600000227F6E70127F4E7012801D0042800D18A +:106610000427B07F40F08000B077F17F039860F3EB +:106620000001F1776078800705D50320A0710398F9 +:1066300070B9002029E00220022F18D0012F18D0B5 +:10664000042F2AD00020A071B07F20F08000B07706 +:1066500025213046FCF75EFD05A904F1E0000FF0AE +:1066600003F910B1022800D0FFDF002039E6A07145 +:10667000DFE7A0710D22002104F1200007F007FFE1 +:10668000207840F00200207001208DF8100004AA4C +:1066900031460D9800F098FADAE70120A071D7E7AB +:1066A0002DE9F04387B09046894604460025FCF763 +:1066B000C9FE060006D03078272806D0082007B08B +:1066C000BDE8F08343F20200F9E7B07F00F0030079 +:1066D000022809D05FF0000080F0010120460DF093 +:1066E000E5FB040003D101E00120F5E7FFDFA77916 +:1066F0005FEA090005D0012821D0B9F1020F26D1A7 +:1067000010E0B8F1000F22D1012F05D0022F05D0E3 +:10671000032F05D0FFDF2EE00C252CE001252AE019 +:10672000022528E04046FAF794FDB0B9032F0ED1B8 +:106730001022414604F11D0007F07FFE1BE0012FEF +:1067400002D0022F03D104E0B8F1000F13D00720CC +:10675000B5E74046FAF77DFD08B11020AFE71022FB +:10676000002104F11D0007F092FE0621404607F0CB +:10677000E1FEC4F81D002078252140F002002070C1 +:106780003046FCF7C7FC2078C10713D020F0010089 +:10679000207002208DF8000004F11D0002908DF899 +:1067A00004506946C3300FF05FF8022803D010B1DF +:1067B000FFDF00E02577002081E730B587B00D4688 +:1067C0000446FCF73FFE98B1807F00F003000228EA +:1067D00011D0002080F0010120460DF067FB04007D +:1067E0000ED02846FAF735FD38B1102007B030BD7D +:1067F00043F20200FAE70120ECE72078400701D4D9 +:106800000820F3E7294604F13D002022054607F061 +:1068100014FE207840F01000207001070FD520F002 +:106820000800207007208DF80000694604F1E000A0 +:1068300001950FF019F8022801D000B1FFDF002008 +:10684000D4E770B50D460646FCF7FCFD18B101789B +:10685000272921D102E043F2020070BD807F00F0C1 +:106860000300022808D0002080F0010130460DF01E +:106870001DFB040003D101E00120F5E7FFDFA07953 +:10688000022809D16078C00706D02A462146304642 +:10689000FEF7EBFC10B10FE0082070BDB4F860000B +:1068A0000E280BD204F1620102231022081F0DF002 +:1068B00084F9012101704570002070BD112070BD68 +:1068C00070B5064614460D460846FAF7C2FC18B9DC +:1068D0002046FAF7E4FC08B1102070BDA6F57F4011 +:1068E000FF380ED03046FCF7ADFD38B14178224676 +:1068F0004B08811C1846FCF774FD07E043F20200C8 +:1069000070BD2046FDF7A5FD0028F9D11021E01D3E +:1069100010F0EDFDE21D294604F1170000F08BF99F +:10692000002070BD2DE9F04104468AB01546884626 +:1069300000270846FAF7DAFC18B92846FAF7D6FC19 +:1069400018B110200AB0BDE8F0812046FCF77AFDAE +:10695000060003D0307827281BD102E043F2020062 +:10696000F0E7B07F00F00300022809D05FF00000DC +:1069700080F0010120460DF099FA040003D101E0F6 +:106980000120F5E7FFDF2078400702D56078800717 +:1069900001D40820D6E7B07F00F00300022805D01C +:1069A000A06F05D1A16F04E01C610200606FF8E7E1 +:1069B000616F407800B19DB1487810B1B8F1000F17 +:1069C0000ED0ADB1EA1D06A8E16800F034F910223E +:1069D00006A905F1170007F003FD18B1042707E029 +:1069E0000720AFE71022E91D04F12D0007F025FD77 +:1069F000B8F1000F06D0102208F1070104F11D00C4 +:106A000007F01BFD2078252140F002002070304661 +:106A1000FCF780FB2078C10715D020F00100207022 +:106A200002208DF8000004F11D0002901030039048 +:106A30008DF804706946B3300EF016FF022803D0BB +:106A400010B1FFDF00E0277700207BE7F8B515469F +:106A50000E460746FCF7F6FC040004D020782228F6 +:106A600004D00820F8BD43F20200F8BDA07F00F07A +:106A70000300022802D043F20500F8BD3046FAF7C1 +:106A8000E8FB18B92846FAF7E4FB08B11020F8BD76 +:106A900000953288B31C21463846FEF709FC1128C0 +:106AA00015D00028F3D1297C4A08A17F62F3C711D1 +:106AB000A177297CE27F61F30002E277297C8908D3 +:106AC00084F82010A17F21F04001A177F8BDA17FBB +:106AD0000907FBD4D6F80200C4F83600D6F8060041 +:106AE000C4F83A003088A0861022294604F1240018 +:106AF00007F0A3FC287C4108E07F61F34100E077C8 +:106B0000297C61F38200E077287C800884F82100EA +:106B1000A07F40F00800A0770020D3E770B50D46B5 +:106B200006460BB1072070BDFCF78CFC040007D0B3 +:106B30002078222802D3A07F800604D4082070BDCC +:106B400043F2020070BDADB1294630460CF076F834 +:106B500002F069FB297C4A08A17F62F3C711A17783 +:106B6000297CE27F61F30002E277297C890884F8BE +:106B7000201004E030460CF084F802F054FBA17FB2 +:106B800021F02001A17770BD70B50D46FCF75AFCCD +:106B9000040005D02846FAF782FB20B1102070BD12 +:106BA00043F2020070BD29462046FEF72FFB00206D +:106BB00070BD04E010F8012B0AB100207047491E97 +:106BC00089B2F7D20120704770B51546064602F02B +:106BD0000DFD040000D1FFDF207820F00F00801CA5 +:106BE00020F0F0002030207066802868A060BDE8AA +:106BF000704002F0FEBC10B5134C94F83000002831 +:106C000008D104F12001A1F110000EF06FFE012067 +:106C100084F8300010BD10B190F8B9202AB10A48AC +:106C200090F8350018B1002003E0B83001E00648C4 +:106C300034300860704708B50023009313460A46B5 +:106C40000DF031FB08BD00003002002018B1817842 +:106C5000012938D101E010207047018842F6011265 +:106C6000881A914231D018DC42F60102A1EB0200F1 +:106C700091422AD00CDC41B3B1F5C05F25D06FF44E +:106C8000C050081821D0A0F57060FF381BD11CE05F +:106C900001281AD002280AD117E0B0F5807F14D05D +:106CA00008DC012811D002280FD003280DD0FF28BE +:106CB00009D10AE0B0F5817F07D0A0F580700338D4 +:106CC00003D0012801D0002070470F2070470A2808 +:106CD0001FD008DC0A2818D2DFE800F0191B1F1F9C +:106CE000171F231D1F21102815D008DC0B2812D0D8 +:106CF0000C2810D00D2816D00F2806D10DE0112831 +:106D00000BD084280BD087280FD003207047002099 +:106D1000704705207047072070470F2070470420F8 +:106D20007047062070470C20704743F202007047FE +:106D300038B50C46050041D06946FFF797F90028A1 +:106D400019D19DF80010607861F302006070694607 +:106D5000681CFFF78BF900280DD19DF800106078B2 +:106D600061F3C5006070A978C1F34101012903D026 +:106D7000022905D0072038BD217821F0200102E04A +:106D8000217841F020012170410704D0A978C90879 +:106D900061F386106070607810F0380F07D0A97822 +:106DA000090961F3C710607010F0380F02D16078E4 +:106DB000400603D5207840F040002070002038BD08 +:106DC00070B504460020088015466068FFF7B0FFE4 +:106DD000002816D12089A189884211D8606880785E +:106DE000C0070AD0B1F5007F0AD840F20120B1FBFC +:106DF000F0F200FB1210288007E0B1F5FF7F01D907 +:106E00000C2070BD01F201212980002070BD10B559 +:106E10000478137864F3000313700478640864F34F +:106E2000410313700478A40864F382031370047898 +:106E3000E40864F3C30313700478240964F30413AF +:106E400013700478640964F34513137000788009A3 +:106E500060F38613137031B10878C10701D1800740 +:106E600001D5012000E0002060F3C713137010BDAE +:106E70004278530702D002F0070306E012F0380F01 +:106E800002D0C2F3C20300E001234A7863F3020296 +:106E90004A70407810F0380F02D0C0F3C20005E00D +:106EA000430702D000F0070000E0012060F3C502B4 +:106EB0004A7070472DE9F04F95B00D00824613D00F +:106EC00012220021284607F0E2FA4FF6FF7B05AABE +:106ED0000121584607F0A3F80024264637464FF410 +:106EE00020586FF4205972E0102015B0BDE8F08FE3 +:106EF0009DF81E0001280AD1BDF81C1041450BD099 +:106F000011EB09000AD001280CD002280CD0042C67 +:106F10000ED0052C0FD10DE0012400E00224BDF8B5 +:106F20001A6008E0032406E00424BDF81A7002E0A9 +:106F3000052400E00624BDF81A10514547D12C74F1 +:106F4000BEB34FF0000810AA4FF0070ACDE9028245 +:106F5000CDE900A80DF13C091023CDF81090424670 +:106F60003146584607F02BF908BBBDF83C002A46CD +:106F7000C0B210A90EF045FDC8B9AE81CFB1CDE9C0 +:106F800000A80DF1080C0AAE40468CE8410213231C +:106F900000223946584607F012F940B9BDF83C00C6 +:106FA000F11CC01EC0B22A1D0EF02BFD10B1032033 +:106FB0009BE70AE0BDF82900E881062C05D19DF881 +:106FC0001E00A872BDF81C00288100208DE705A8CE +:106FD00007F031F800288BD0FFF779FE85E72DE91F +:106FE000F0471C46DDE90978DDF8209015460E00D3 +:106FF000824600D1FFDF0CB1208818B1D5B1112035 +:10700000BDE8F087022D01D0012100E0002106F14A +:10701000140005F0CDFEA8F8000002463B462946C4 +:10702000504603F092F9C9F8000008B9A41C3C606E +:107030000020E5E71320E3E7F0B41446DDE904524D +:107040008DB1002314B1022C09D101E0012306E027 +:107050000D7CEE0703D025F0010501230D742146B8 +:10706000F0BC04F050BA1A80F0BC70472DE9FE4F16 +:1070700091461A881C468A468046FAB102AB4946B8 +:1070800003F063F9050019D04046A61C27880DF0CF +:1070900050F83246072629463B4600960CF05FFC26 +:1070A00020882346CDE900504A4651464046FFF726 +:1070B000C3FF002020800120BDE8FE8F0020FBE7F9 +:1070C0002DE9F04786B082460EA8904690E8B000C1 +:1070D000894604AA05A903A88DE807001E462A468A +:1070E00021465046FFF77BFF039901B1012139701A +:1070F000002818D1FA4904F1140204AB086003987F +:1071000005998DE8070042464946504606F003FAC5 +:10711000A8B1092811D2DFE800F005080510100A0F +:107120000C0C0E00002006B06AE71120FBE70720D8 +:10713000F9E70820F7E70D20F5E70320F3E7BDF8AE +:1071400010100398CDE9000133462A4621465046E7 +:10715000FFF772FFE6E72DE9F04389B01646DDE957 +:1071600010870D4681461C461422002103A807F013 +:107170008EF9012002218DF810108DF80C008DF889 +:107180001170ADF8146064B1A278D20709D08DF8FF +:107190001600E088ADF81A00A088ADF81800A068C5 +:1071A000079008A80095CDE90110424603A948467A +:1071B0006B68FFF785FF09B0BDE8F083F0B58BB0D1 +:1071C00000240646069407940727089405A8099406 +:1071D000019400970294CDE903400D461023224606 +:1071E000304606F0ECFF78B90AA806A9019400978A +:1071F0000294CDE90310BDF8143000222946304630 +:1072000006F07BFD002801D0FFF761FD0BB0F0BD5B +:1072100006F00CBC2DE9FC410C468046002602F02D +:10722000E5F9054620780D287ED2DFE800F0BC079E +:1072300013B325BD49496383AF959B00A8480068F7 +:1072400020B1417841F010014170ADE0404602F0BC +:10725000FDF9A9E0042140460CF028FE070000D10A +:10726000FFDF07F11401404605F037FDA5BB1321F0 +:107270004046FDF7CFFB97E0042140460CF016FE98 +:10728000070000D1FFDFE088ADF800000020B881E2 +:107290009DF80000010704D5C00602D5A088B8817A +:1072A00005E09DF8010040067ED5A088F88105B96B +:1072B000FFDF22462946404601F0ACFC022673E07F +:1072C000E188ADF800109DF8011009060FD50728D8 +:1072D00003D006280AD00AE024E0042140460CF03E +:1072E000E5FD060000D1FFDFA088F0810226CDB9C0 +:1072F000FFDF17E0042140460CF0D8FD070000D165 +:10730000FFDF07F1140006F0C8FB90F0010F02D177 +:10731000E079000648D5387C022640F00200387437 +:1073200005B9FFDF224600E03DE02946404601F076 +:1073300071FC39E0042140460CF0B8FD017C002DC1 +:1073400001F00206C1F340016171017C21F00201EC +:107350000174E7D1FFDFE5E702260121404602F094 +:10736000A7F921E0042140460CF0A0FD0546606825 +:1073700000902089ADF8040001226946404602F0E1 +:10738000B8F9287C20F0020028740DE0002DC9D146 +:10739000FFDFC7E7022600214046FBF799F8002DE2 +:1073A000C0D1FFDFBEE7FFDF3046BDE8FC813EB560 +:1073B0000C0009D001466B4601AA002006F084FFAC +:1073C00020B1FFF784FC3EBD10203EBD0020208090 +:1073D000A0709DF8050002A900F00700FEF762FE0C +:1073E00050B99DF8080020709DF8050002A9C0F36F +:1073F000C200FEF757FE08B103203EBD9DF808000D +:1074000060709DF80500C109A07861F30410A070B8 +:107410009DF80510890961F3C300A0709DF8041060 +:10742000890601D5022100E0012161F342009DF8A7 +:10743000001061F30000A07000203EBD70B514463E +:1074400006460D4651EA040005D075B10846F9F725 +:1074500044FF78B901E0072070BD2946304606F0A8 +:107460009AFF10B1BDE8704031E454B12046F9F7FD +:1074700034FF08B1102070BD21463046BDE8704091 +:1074800095E7002070BD2DE9FC5F0C46904605464F +:10749000002701780822007A3E46B2EB111F7DD109 +:1074A00004F10A0100910A31821E4FF0020A04F130 +:1074B000080B0191092A72D2DFE802F0EDE005F530 +:1074C00028287BAACE00688804210CF0EFFC060077 +:1074D00000D1FFDFB08928B152270726C3E00000A2 +:1074E0009402002051271026002C7DD06888A080AF +:1074F0000120A071A88900220099FFF79FFF0028B2 +:1075000073D1A8892081288AE081D1E0B5F8129052 +:10751000072824D1E87B000621D5512709F1140062 +:1075200086B2002CE1D0A88900220099FFF786FFDF +:1075300000285AD16888A08084F806A0A8892081F4 +:107540000120A073288A2082A4F81290A88A0090B3 +:1075500068884B46A969019A01F038FBA8E05027DA +:1075600009F1120086B2002C3ED0A88900225946AB +:10757000FFF764FF002838D16888A080A889E080E0 +:10758000287A072813D002202073288AE081E87B1C +:10759000C0096073A4F81090A88A01E085E082E039 +:1075A000009068884B4604F11202A969D4E70120D3 +:1075B000EAE7B5F81290512709F1140086B2002CC1 +:1075C00066D0688804210CF071FC83466888A0802E +:1075D000A88900220099FFF731FF00286ED184F8B6 +:1075E00006A0A889208101E052E067E00420A07392 +:1075F000288A2082A4F81290A88A009068884B46B6 +:10760000A969019A01F0E2FAA989ABF80E104FE0DE +:107610006888FBF717FF0746688804210CF046FCD2 +:10762000064607B9FFDF06B9FFDF687BC00702D057 +:107630005127142601E0502712264CB36888A080F9 +:10764000502F06D084F806A0287B594601F0CEFAC8 +:107650002EE0287BA11DF9E7FE49A88949898142CE +:1076600005D1542706269CB16888A08020E05327C6 +:107670000BE06888A080A889E08019E06888042170 +:107680000CF014FC00B9FFDF55270826002CF0D1C0 +:10769000A8F8006011E056270726002CF8D068886B +:1076A000A080002013E0FFDF02E0012808D0FFDF08 +:1076B000A8F800600CB1278066800020BDE8FC9F20 +:1076C00057270726002CE3D06888A080687AA0712D +:1076D000EEE7401D20F0030009B14143091D01EB15 +:1076E0004000704713B5DB4A00201071009848B184 +:1076F000002468460CF0F7F9002C02D1D64A009914 +:1077000011601CBD01240020F4E770B50D4614463D +:10771000064686B05C220021284606F0B8FE04B971 +:10772000FFDFA0786874A2782188284601F089FAE2 +:107730000020A881E881228805F11401304605F077 +:10774000B0FA6A460121304606F069FC1AE000BF33 +:107750009DF80300000715D5BDF806103046FFF769 +:107760002DFD9DF80300BDF8061040F010008DF8C7 +:107770000300BDF80300ADF81400FF233046059A5E +:1077800006F0D1FD684606F056FC0028E0D006B0B1 +:1077900070BD10B50C4601F1140005F0BAFA0146AF +:1077A000627C2046BDE8104001F080BA30B5044646 +:1077B000A84891B04FF6FF75C18905AA284606F082 +:1077C0002EFC30E09DF81E00A0422AD001282AD1CC +:1077D000BDF81C00B0F5205F03D042F601018842DD +:1077E00021D1002002AB0AAA0CA9019083E807006E +:1077F00007200090BDF81A1010230022284606F03A +:10780000DEFC38B9BDF828000BAAC0B20CA90EF0F6 +:10781000F8F810B1032011B030BD9DF82E00A04241 +:1078200001D10020F7E705A806F005FC0028C9D023 +:107830000520F0E770B5054604210CF037FB040085 +:1078400000D1FFDF04F114010C46284605F045FA8B +:1078500021462846BDE8704005F046BA70B58AB0AA +:107860000C460646FBF7EEFD050014D028782228CA +:1078700027D30CB1A08890B101208DF80C00032013 +:107880008DF8100000208DF8110054B1A088ADF8DB +:107890001800206807E043F202000AB070BD09201A +:1078A000FBE7ADF818000590042130460CF0FEFA15 +:1078B000040000D1FFDF04F1140005F040FA0007D6 +:1078C00001D40820E9E701F091FE60B108A8022187 +:1078D0000094CDE9011095F8232003A93046636890 +:1078E000FFF7EEFBD9E71120D7E72DE9F04FB2F80B +:1078F00002A0834689B0154689465046FBF7A2FD93 +:107900000746042150460CF0D1FA0026044605969D +:107910004FF002080696ADF81C6007B9FFDF04B906 +:10792000FFDF4146504603F055FF50B907AA06A9AC +:1079300005A88DE807004246214650466368FFF7D8 +:107940004EFB444807AB0660DDE9051204F1140064 +:10795000CDF80090CDE90320CDE9013197F823203F +:10796000594650466B6805F033FA06000AD0022EDD +:1079700004D0032E14D0042E00D0FFDF09B030460F +:10798000BDE8F08FBDF81C000028F7D00599CDE9BF +:1079900000104246214650466368FFF74DFBEDE775 +:1079A000687840F008006870E8E710B50C46FFF70B +:1079B000BFF900280BD1607800F00701012905D13B +:1079C00010F0380F02D02078810601D5072010BDB5 +:1079D00040F0C8002070002010BD2DE9F04F99B094 +:1079E00004464FF000081B48ADF81C80ADF820801D +:1079F000ADF82480A0F80880ADF81480ADF81880A8 +:107A0000ADF82880ADF82C80007916460D46474623 +:107A1000012808D0022806D0032804D0042802D068 +:107A2000082019B0ACE72046F9F713FCF0BB284654 +:107A3000F9F70FFCD0BB6068F9F758FCB0BB606881 +:107A400068B160892189884202D8B1F5007F05D9E3 +:107A50000C20E6E7940200201800002080460EAAC1 +:107A600006A92846FFF7ACF90028DAD168688078C3 +:107A7000C0F34100022808D19DF8190010F0380F1A +:107A800003D02869F9F729FC80B905A92069FFF717 +:107A90004FF90028C5D1206950B1607880079DF862 +:107AA000150000F0380002D5F0B301E011E0D8BBBA +:107AB0009DF8140080060ED59DF8150010F0380FC3 +:107AC00003D06068F9F709FC18B96068F9F70EFC93 +:107AD00008B11020A5E70BA906A8FFF7C9F99DF882 +:107AE0002D000BA920F00700401C8DF82D006069C7 +:107AF000FFF75BFF002894D10AA9A069FFF718F9E6 +:107B000000288ED19DF8280080062BD4A06940B1B2 +:107B10009DF8290000F00701012923D110F0380F4A +:107B200020D0E06828B100E01CE00078D0B11C282B +:107B300018D20FAA611C2046FFF769F901213846C7 +:107B400061F30F2082468DF85210B94642F60300C9 +:107B50000F46ADF850000DF13F0218A928680DF04E +:107B600052FF08B107205CE79DF8600015A9CDF829 +:107B70000090C01CCDE9019100F0FF0B00230BF237 +:107B80000122514614A806F075F9E8BBBDF854006F +:107B90000C90FB482A8929690092CDE901106B8974 +:107BA000BDF838202868069906F064F9010077D1FD +:107BB00020784FF0020AC10601D4800616D58DF850 +:107BC000527042F60210ADF85000CDF80C9008A9A2 +:107BD00003AACDF800A0CDE90121002340F2032241 +:107BE00014A80B9906F046F9010059D1E4484D4616 +:107BF00008380089ADF83D000FA8CDE90290CDF816 +:107C00000490CDF8109000E00CE04FF007095B46BF +:107C10000022CDF80090BDF854104FF6FF7006F02A +:107C20006CF810B1FFF753F8FBE69DF83C00000636 +:107C300024D52946012060F30F218DF852704FF4AE +:107C400024500395ADF8500062789DF80C00002395 +:107C500062F300008DF80C006278CDF800A05208A5 +:107C600062F341008DF80C0003AACDE9012540F232 +:107C7000032214A806F0FEF8010011D1606880B359 +:107C80002069A0B905A906A8FFF7F2F86078800777 +:107C900007D49DF8150020F038008DF8150006E097 +:107CA00077E09DF8140040F040008DF814008DF846 +:107CB000527042F60110ADF85000208940F20121C7 +:107CC000B0FBF1F201FB1202606809ABCDF8008055 +:107CD000CDE90103002314A8059906F0CBF80100B3 +:107CE00057D12078C00728D00395A06950B90AA9B8 +:107CF00006A8FFF7BDF89DF8290020F00700401CFA +:107D00008DF829009DF8280007A940F040008DF863 +:107D100028008DF8527042F60310ADF8500003AA07 +:107D2000CDF800A0CDE90121002340F2032214A8E0 +:107D30000A9906F09FF801002BD1E06868B3294644 +:107D4000012060F30F218DF8527042F60410ADF857 +:107D50005000E068002302788DF8582040788DF8B4 +:107D60005900E06816AA4088ADF85A00E06800792A +:107D70008DF85C00E068C088ADF85D00CDF800903B +:107D8000CDE901254FF4027214A806F073F8010042 +:107D900003D00C9800F0B6FF43E679480321083879 +:107DA000017156B100893080BDF824007080BDF8A3 +:107DB0002000B080BDF81C00F080002031E670B5D6 +:107DC00001258AB016460B46012802D0022816D19A +:107DD00004E08DF80E504FF4205003E08DF80E5063 +:107DE00042F60100ADF80C005BB10024601C60F3AA +:107DF0000F2404AA08A918460DF005FE18B10720A3 +:107E00004BE5102049E504A99DF820205C48CDE908 +:107E10000021801E02900023214603A802F20122C5 +:107E200006F028F810B1FEF752FF36E5544808383E +:107E30000EB1C1883180057100202EE5F0B593B0F8 +:107E4000044601268DF83E6041F601000F46ADF86C +:107E50003C0011AA0FA93046FFF7B1FF002837D127 +:107E60002000474C4FF00005A4F1080432D01C223A +:107E7000002102A806F00BFB9DF808008DF83E607B +:107E800040F020008DF8080042F60520ADF83C00D7 +:107E900004200797ADF82C00ADF8300039480A905F +:107EA0000EA80D900E950FA80990ADF82E506A46B9 +:107EB00009A902A8FFF791FD002809D1BDF800002B +:107EC0006081BDF80400A081401CE0812571002084 +:107ED00013B0F0BD6581A581BDF84400F4E72DE93C +:107EE000F74F2749A0B00024083917940A79A14612 +:107EF000012A04D0022A02D0082023B040E5CA8813 +:107F0000824201D00620F8E721988A46824201D1B8 +:107F10000720F2E70120214660F30F21ADF8480069 +:107F20004FF6FF788DF86E000691ADF84A8042F664 +:107F3000020B8DF872401CA9ADF86CB0ADF8704022 +:107F40001391ADF8508012A806F0A4F800252E4633 +:107F50002F460DAB072212A9404606F09EF898B1B5 +:107F60000A2861D1B5B3AEB3ADF86450ADF8666020 +:107F70009DF85E008DF8144019AC012868D06FE0C0 +:107F80009C020020266102009DF83A001FB30128E0 +:107F900059D1BDF8381059451FD118A809A9019425 +:107FA0000294CDE9031007200090BDF8361010238D +:107FB0000022404606F003F9B0BBBDF8600004287B +:107FC00001D006284AD1BDF82410219881423AD127 +:107FD0000F2092E73AE0012835D1BDF83800B0F51E +:107FE000205F03D042F6010188422CD1BAF8060086 +:107FF000BDF83610884201D1012700E0002705B105 +:108000009EB1219881421ED118A809AA0194029418 +:10801000CDE90320072000900D46102300224046A2 +:1080200006F0CDF800B902E02DE04E460BE0BDF8B9 +:108030006000022801D0102810D1C0B217AA09A9E7 +:108040000DF0DFFC50B9BDF8369082E7052054E70B +:1080500005A917A8221D0DF0D6FC08B103204CE796 +:108060009DF814000023001DC2B28DF81420229840 +:108070000092CDE901401BA8069905F0FBFE10B95E +:1080800002228AF80420FEF722FE36E710B50B46DE +:10809000401E88B084B205AA00211846FEF7B7FE3C +:1080A00000200DF1080C06AA05A901908CE8070034 +:1080B000072000900123002221464FF6FF7005F0B3 +:1080C0001CFE0446BDF81800012800D0FFDF204642 +:1080D000FEF7FDFD08B010BDF0B5FF4F044687B0B8 +:1080E00038790E46032804D0042802D0082007B0AF +:1080F000F0BD04AA03A92046FEF762FE0500F6D1F2 +:1081000060688078C0F3410002280AD19DF80D0014 +:1081100010F0380F05D02069F9F7DFF808B110200A +:10812000E5E7208905AA21698DE807006389BDF884 +:1081300010202068039905F09DFE10B1FEF7C7FDE1 +:10814000D5E716B1BDF814003080042038712846F8 +:10815000CDE7F8B50C0006460BD001464FF6FF758B +:1081600000236A46284606F0AFF820B1FEF7AFFDBF +:10817000F8BD1020F8BD69462046FEF7D9FD00285D +:10818000F8D1A078314600F001032846009A06F0A5 +:10819000CAF8EBE730B587B0144600220DF1080CA1 +:1081A00005AD01928CE82C00072200920A46014698 +:1081B00023884FF6FF7005F0A0FDBDF81410218054 +:1081C000FEF785FD07B030BD70B50D4604210BF0FC +:1081D0006DFE040000D1FFDF294604F11400BDE864 +:1081E000704004F0A5BD70B50D4604210BF05EFE95 +:1081F000040000D1FFDF294604F11400BDE87040FF +:1082000004F0B9BD70B50D4604210BF04FFE04001B +:1082100000D1FFDF294604F11400BDE8704004F0EE +:10822000D1BD70B5054604210BF040FE040000D11D +:10823000FFDF214628462368BDE870400122FEF793 +:1082400015BF70B5064604210BF030FE040000D1C6 +:10825000FFDF04F1140004F05CFD401D20F0030575 +:1082600011E0011D00880022431821463046FEF728 +:10827000FDFE00280BD0607CABB2684382B2A068E0 +:10828000011D0BF0D0FCA06841880029E9D170BD28 +:1082900070B5054604210BF009FE040000D1FFDF94 +:1082A000214628466368BDE870400222FEF7DEBE24 +:1082B00070B50E46054601F099F9040000D1FFDFC4 +:1082C0000120207266726580207820F00F00001D6A +:1082D00020F0F00040302070BDE8704001F089B916 +:1082E00010B50446012900D0FFDF2046BDE810404C +:1082F0000121FAF7EDB82DE9F04F97B04FF0000AE1 +:108300000C008346ADF814A0D04619D0E06830B117 +:10831000A068A8B10188ADF81410A0F800A05846D4 +:10832000FBF790F8070043F2020961D03878222861 +:108330005CD3042158460BF0B9FD050005D103E0DC +:10834000102017B0BDE8F08FFFDF05F1140004F036 +:10835000E0FC401D20F00306A078012803D002288D +:1083600001D00720EDE7218807AA584605F057FEFF +:1083700030BB07A805F05FFE10BB07A805F05BFE49 +:1083800048B99DF82600012805D1BDF82400A0F5C4 +:108390002451023902D04FF45050D2E7E068B0B116 +:1083A000CDE902A00720009005AACDF804A0049210 +:1083B000A2882188BDF81430584605F09EFC10B103 +:1083C000FEF785FCBDE7A168BDF8140008809DF8A4 +:1083D0001F00C00602D543F20140B2E70B9838B146 +:1083E000A1780078012905D080071AD40820A8E7D1 +:1083F0004846A6E7C007F9D002208DF83C00A868DF +:108400004FF00009A0B1697C4288714391420FD9B5 +:108410008AB2B3B2011D0BF0BCFB8046A0F800A0ED +:1084200006E003208DF83C00D5F800804FF00109EC +:108430009DF8200010F0380F00D1FFDF9DF82000DC +:108440002649C0F3C200084497F8231010F8010C25 +:10845000884201D90F2074E72088ADF8400014A9A4 +:108460000095CDE90191434607220FA95846FEF732 +:1084700027FE002891D19DF8500050B9A07801281E +:1084800007D1687CB3B2704382B2A868011D0BF0BB +:1084900094FB002055E770B5064615460C46084685 +:1084A000FEF7D4FB002805D12A4621463046BDE818 +:1084B000704084E470BD12E570B51E4614460D0090 +:1084C0000ED06CB1616859B160B10349C98881426D +:1084D00008D0072070BD000094020020296102002E +:1084E0001020F7E72068FEF7B1FB0028F2D13246F2 +:1084F00021462846BDE87040FFF76FBA70B51546B3 +:108500000C0006D038B1FE490989814203D007200A +:10851000E0E71020DEE72068FEF798FB0028D9D1BD +:1085200029462046BDE87040D6E570B5064686B0BF +:108530000D4614461046F8F7B2FED0BB6068F8F757 +:10854000D5FEB0BBA6F57F40FF3803D03046FAF722 +:1085500079FF80B128466946FEF7ACFC00280CD1B3 +:108560009DF810100F2008293DD2DFE801F0080621 +:108570000606060A0A0843F2020006B0AAE703202C +:10858000FBE79DF80210012908D1BDF80010B1F5F4 +:10859000C05FF2D06FF4C052D142EED09DF8061009 +:1085A00001290DD1BDF80410A1F52851062907D2E3 +:1085B00000E029E0DFE801F0030304030303DCE744 +:1085C0009DF80A1001290FD1BDF80810B1F5245FFC +:1085D000D3D0A1F60211B1F50051CED00129CCD0F3 +:1085E000022901D1C9E7FFDF606878B9002305AA35 +:1085F0002946304605F068FE10B1FEF768FBBCE77F +:108600009DF81400800601D41020B6E76188224648 +:1086100028466368FFF7BEFDAFE72DE9F0438146CA +:1086200087B0884614461046F8F739FE18B1102076 +:1086300007B0BDE8F083002306AA4146484605F08E +:1086400043FE10B1FEF743FBF2E79DF81800C006A9 +:1086500002D543F20140EBE70025072705A8019565 +:1086600000970295CDE9035062884FF6FF734146AB +:10867000484605F0A4FD060013D16068F8F70FFE28 +:1086800060B960680195CDE9025000970495238890 +:1086900062884146484605F092FD0646BDF8140042 +:1086A00020803046CEE739B1954B0A889B899A42A3 +:1086B00002D843F2030070471DE610B586B0904C17 +:1086C0000423ADF81430638943B1A4898C4201D2EC +:1086D000914205D943F2030006B010BD0620FBE726 +:1086E000ADF81010002100910191ADF80030022189 +:1086F0008DF8021005A9029104A90391ADF812208A +:108700006946FFF7F8FDE7E72DE9FC4781460D468E +:108710000846F8F79EFD88BB4846FAF793FE5FEAE5 +:1087200000080AD098F80000222829D304214846DE +:108730000BF0BCFB070005D103E043F20200BDE8EB +:10874000FC87FFDF07F1140004F0F9FA06462878E9 +:10875000012803D0022804D00720F0E7B0070FD586 +:1087600002E016F01C0F0BD0A8792C1DC00709D011 +:10877000E08838B1A068F8F76CFD18B11020DEE78A +:108780000820DCE721882A780720B1F5847F35D0DE +:108790001EDC40F20315A1F20313A94226D00EDC21 +:1087A000B1F5807FCBD003DCF9B1012926D1C6E732 +:1087B000A1F58073013BC2D0012B1FD113E0012B27 +:1087C000BDD0022B1AD0032BB9D0042B16D112E046 +:1087D000A1F20912082A11D2DFE802F00B040410FA +:1087E00010101004ABE7022AA9D007E0012AA6D096 +:1087F00004E0320700E0F206002AA0DACDB200F071 +:10880000F5FE50B198F82300CDE90005FA8923461A +:1088100039464846FEF79FFC91E711208FE72DE986 +:10882000F04F8BB01F4615460C4683460026FAF7DC +:1088300009FE28B10078222805D208200BB081E576 +:1088400043F20200FAE7B80801D00720F6E7032F49 +:1088500000D100274FF6FF79CCB1022D71D320460D +:10886000F8F744FD30B904EB0508A8F10100F8F76A +:108870003DFD08B11020E1E7AD1E38F8028CAAB228 +:108880002146484605F081FE40455AD1ADB21C490B +:10889000B80702D58889401C00E001201FFA80F843 +:1088A000F80701D08F8900E04F4605AA4146584697 +:1088B00005F0B5FB4FF0070A4FF00009FCB1204668 +:1088C00008E0408810283CD8361D304486B2AE42BD +:1088D00037D2A01902884245F3D352E09DF8170021 +:1088E00002074ED57CB304EB0608361DB8F80230FB +:1088F000B6B2102B25D89A19AA4222D802E040E03D +:1089000094020020B8F8002091421AD1C0061BD56D +:10891000CDE900A90DF1080C0AAAA11948468CE876 +:108920000700B8F800100022584605F0E6F910B12B +:10893000FEF7CDF982E7B8F80200BDF828108842AA +:1089400002D00B207AE704E0B8F80200304486B287 +:1089500006E0C00604D55846FEF730FC00288AD150 +:108960009DF81700BDF81A1020F010008DF81700C0 +:10897000BDF81700ADF80000FF235846009A05F037 +:10898000D2FC05A805F057FB18B9BDF81A10B9427A +:10899000A4D9042158460BF089FA040000D1FFDF66 +:1089A000A2895AB1CDE900A94D4600232146584677 +:1089B000FEF7D1FB0028BDD1A5813FE700203DE7B0 +:1089C0002DE9FF4F8BB01E4617000D464FF00004F7 +:1089D00012D0B00802D007200FB0B3E4032E00D1AC +:1089E00000265DB10846F8F778FC28B93888691E7A +:1089F0000844F8F772FC08B11020EDE7C74AB00749 +:108A000001D5D18900E00121F0074FF6FF7802D0AF +:108A1000D089401E00E0404686B206AA0B9805F0B9 +:108A2000FEFA4FF000094FF0070B0DF1140A38E081 +:108A30009DF81B00000734D5CDF80490CDF800B0A8 +:108A4000CDF80890CDE9039A434600220B9805F033 +:108A5000B6FB60BB05B3BDF814103A882144281951 +:108A6000091D8A4230D3BDF81E2020F8022BBDF824 +:108A7000142020F8022BCDE900B9CDE90290CDF801 +:108A800010A0BDF81E10BDF8143000220B9805F0A0 +:108A900096FB08B103209FE7BDF814002044001D99 +:108AA00084B206A805F0C7FA20B10A2806D0FEF75E +:108AB0000EF991E7BDF81E10B142B9D934B17DB1BC +:108AC0003888A11C884203D20C2085E7052083E763 +:108AD00022462946404605F058FD014628190180E6 +:108AE000A41C3C80002077E710B50446F8F7D7FBBC +:108AF00008B1102010BD8948C0892080002010BD19 +:108B0000F0B58BB00D4606461422002103A805F0EF +:108B1000BEFC01208DF80C008DF8100000208DF8AF +:108B20001100ADF814503046FAF78CFC48B10078CB +:108B3000222812D3042130460BF0B8F9040005D1E5 +:108B400003E043F202000BB0F0BDFFDF04F11400BC +:108B5000074604F0F4F8800601D40820F3E7207CEF +:108B6000022140F00100207409A80094CDE9011011 +:108B7000072203A930466368FEF7A2FA20B1217CE0 +:108B800021F001012174DEE729463046F9F791FC16 +:108B900008A9384604F0C2F800B1FFDFBDF8204054 +:108BA000172C01D2172000E02046A84201D92C46FC +:108BB00002E0172C00D2172421463046FFF713FBA2 +:108BC00021463046F9F799F90020BCE7F8B51C4674 +:108BD00015460E46069F0BF09AFA2346FF1DBCB2BF +:108BE00031462A4600940AF086FEF8BD70B50C4660 +:108BF00005460E220021204605F049FC0020208079 +:108C00002DB1012D01D0FFDF64E4062000E0052036 +:108C1000A0715FE410B548800878134620F00F007B +:108C2000001D20F0F00080300C4608701422194618 +:108C300004F1080005F001FC00F0DBFC374804609B +:108C400010BD2DE9F047DFF8D890491D064621F008 +:108C5000030117460C46D9F800000AF062FF050030 +:108C600000D1FFDF4FF000083560A5F800802146F5 +:108C7000D9F800000AF055FF050000D1FFDF75604C +:108C8000A5F800807FB104FB07F1091D0BD0D9F8CE +:108C900000000AF046FF040000D1FFDFB460C4F812 +:108CA0000080BDE8F087C6F80880FAE72DE9F041BA +:108CB0001746491D21F00302194D06460168144666 +:108CC00028680AF059FF2246716828680AF054FFA4 +:108CD0003FB104FB07F2121D03D0B16828680AF007 +:108CE0004BFF04200BF08AF8044604200BF08EF8AA +:108CF000201A012804D12868BDE8F0410AF006BF17 +:108D0000BDE8F08110B50C4605F058F900B1FFDF61 +:108D10002046BDE81040FDF7DABF000094020020B5 +:108D20001800002038B50C468288817B19B1418932 +:108D3000914200D90A462280C188121D90B26A462B +:108D40000AF0B2F8BDF80000032800D30320C1B236 +:108D5000208801F020F838BD38B50C468288817B28 +:108D600019B10189914200D90A462280C188121D99 +:108D700090B26A460AF098F8BDF80000022800D3C5 +:108D80000220C1B2208801F006F8401CC0B238BDF4 +:108D90002DE9FF5F82468B46F74814460BF103022C +:108DA000D0E90110CDE9021022F0030201A84FF42E +:108DB000907101920AF097FEF04E002C02D1F0491A +:108DC000019A8A60019901440191B57F05F101057D +:108DD00004D1E8B20CF098FD00B1FFDF019800EB80 +:108DE0000510C01C20F0030101915CB9707AB27AC1 +:108DF0001044C2B200200870B08C80B204F03DFF75 +:108E000000B1FFDF0198716A08440190214601A872 +:108E100000F084FF80460198C01C20F00300019000 +:108E2000B37AF27A717A04B100200AF052FF019904 +:108E300008440190214601A800F0B8FFCF48002760 +:108E40003D4690F801900CE0284600F04AFF0646A7 +:108E500081788088F9F7E8F871786D1C00FB01775C +:108E6000EDB24D45F0D10198C01C20F003000190F7 +:108E700004B100203946F9F7E2F8019900270844C7 +:108E80000190BE483D4690F801900CE0284600F065 +:108E900028FF0646C1788088FEF71BFC71786D1CA0 +:108EA00000FB0177EDB24D45F0D10198C01C20F0D8 +:108EB0000300019004B100203946FEF713FC01992C +:108EC0004FF0000908440190AC484D4647780EE049 +:108ED000284600F006FF0646807B30B106F1080008 +:108EE00002F09CF9727800FB02996D1CEDB2BD4254 +:108EF000EED10198C01C20F00300019004B10020C5 +:108F00009F494A78494602F08DF901990844019039 +:108F1000214601A800F0B8FE0198C01D20F007000E +:108F20000190DAF80010814204D3A0EB0B01B1F5F7 +:108F3000803F04DB4FF00408CAF8000004E0CAF8E0 +:108F40000000B8F1000F03D0404604B0BDE8F09F28 +:108F500084BB8C490020019A0EF044FEFBF714FA02 +:108F6000864C207F0090607F012825D0002328B305 +:108F70000022824800211030F8F73AFA00B1FFDFF2 +:108F80007E49E07F2031FEF759FF00B1FFDF7B48CB +:108F90004FF4F6720021443005F079FA7748042145 +:108FA000443080F8E91180F8EA11062180F8EB11CD +:108FB000032101710020C8E70123D8E702AAD8E7FE +:108FC00070B56E4C06464434207804EB4015E078CA +:108FD000083598B9A01990F8E80100280FD0A078BA +:108FE0000F2800D3FFDF20220021284605F04FFA8A +:108FF000687866F3020068700120E070284670BD52 +:109000002DE9F04105460C460027007805219046E1 +:109010003E46B1EB101F00D0FFDF287A50B1012887 +:109020000ED0FFDFA8F800600CB12780668000201A +:10903000BDE8F0810127092674B16888A08008E0A6 +:109040000227142644B16888A0802869E060A88AB5 +:109050002082287B2072E5E7A8F80060E7E730B5BA +:10906000464C012000212070617020726072032242 +:10907000A272E07261772177217321740521218327 +:109080001F216183607440A161610A21A177E077AB +:1090900039483B4DB0F801102184C07884F8220093 +:1090A0004FF4B06060626868C11C21F00301814226 +:1090B00000D0FFDF6868606030BD30B5304C1568A7 +:1090C000636810339D4202D20420136030BD2B4BE5 +:1090D0005D785A6802EB0512107051700320D08041 +:1090E000172090800120D0709070002090735878E5 +:1090F000401C5870606810306060002030BD70B552 +:1091000006461E480024457807E0204600F0E9FDA9 +:109110000178B14204D0641CE4B2AC42F5D1002025 +:1091200070BDF7B5074608780C4610B3FFF7E7FFA8 +:109130000546A7F12006202F06D0052E19D2DFE81C +:1091400006F00F383815270000F0D6FD0DB169780C +:1091500000E00021401AA17880B20844FF2808D816 +:10916000A07830B1A088022831D202E060881728A8 +:109170002DD20720FEBD000030610200B0030020A8 +:109180001C000020000000206E52463578000000D0 +:10919000207AE0B161881729EBD3A1881729E8D399 +:1091A000A1790029E5D0E1790029E2D0402804D94D +:1091B000DFE7242F0BD1207A48B161884FF6FB708E +:1091C000814202D8A188814201D90420D2E765B941 +:1091D000207802AA0121FFF770FF0028CAD1207869 +:1091E000FFF78DFF050000D1FFDF052E18D2DFE865 +:1091F00006F0030B0E081100A0786870A088E880C4 +:109200000FE06088A8800CE0A078A87009E0A07842 +:10921000E87006E054F8020FA8606068E86000E0BB +:10922000FFDF0020A6E71A2835D00DDC132832D244 +:10923000DFE800F01B31203131272723252D313184 +:1092400029313131312F0F00302802D003DC1E28A4 +:1092500021D1072070473A3809281CD2DFE800F0F6 +:10926000151B0F1B1B1B1B1B07000020704743F225 +:109270000400704743F202007047042070470D203D +:1092800070470F2070470820704711207047132047 +:109290007047062070470320704710B5007800F033 +:1092A000010009F0F3FDBDE81040BCE710B50078FF +:1092B00000F0010009F0F3FDBDE81040B3E70EB582 +:1092C000017801F001018DF80010417801F00101F1 +:1092D0008DF801100178C1F340018DF8021041783A +:1092E000C1F340018DF80310017889088DF804104E +:1092F000417889088DF8051081788DF80610C178BD +:109300008DF8071000798DF80800684608F0FDFD1B +:10931000FFF789FF0EBD2DE9FC5FDFF8F883FE4CF7 +:1093200000264FF490771FE0012000F082FD01201D +:10933000FFF746FE05463946D8F808000AF0F1FB6B +:10934000686000B9FFDF686808F0AAFCB0B1284681 +:10935000FAF75EFB284600F072FD28B93A466968C4 +:10936000D8F808000AF008FC94F9E9010428DBDACF +:1093700002200AF043FD07460025AAE03A46696844 +:10938000D8F808000AF0F8FBF2E7B8F802104046F7 +:10939000491C89B2A8F80210B94201D300214180CA +:1093A0000221B8F802000AF081FD002866D0B8F862 +:1093B0000200694609F0CFFCFFF735FF00B1FFDF7F +:1093C0009DF80000019078B1B8F802000AF0B1FEF3 +:1093D0005FEA000900D1FFDF48460AF020F918B122 +:1093E000B8F8020002F0E4F9B8F802000AF08FFEC3 +:1093F0005FEA000900D1FFDF48460AF008F9E8BB40 +:109400000321B8F802000AF051FD5FEA000B4BD1CE +:10941000FFDF49E0DBF8100010B10078FF284DD0E5 +:10942000022000F006FD0220FFF7CAFD82464846F2 +:109430000AF0F9F9CAF8040000B9FFDFDAF804000D +:109440000AF0C1FA002100900170B8F802105046ED +:10945000AAF8021002F0B2F848460AF0B6FA00B9CB +:10946000FFDF019800B10126504600F0E8FC18B972 +:109470009AF80100000705D5009800E027E0CBF836 +:10948000100011E0DBF8101039B10878401C10F022 +:10949000FF00087008D1FFDF06E0002211464846B1 +:1094A00000F0F0FB00B9FFDF94F9EA01022805DBC8 +:1094B000B8F8020002F049F80028ABD194F9E901AC +:1094C000042804DB48460AF0E4FA00B101266D1CCA +:1094D000EDB2BD4204D294F9EA010228BFF655AFBD +:1094E000002E7FF41DAFBDE8FC5F032000F0A1BC9F +:1094F00010B5884CE06008682061AFF2E510F9F71C +:10950000E4FC607010BD844800214438017081483B +:10951000017082494160704770B505464FF0805038 +:109520000C46D0F8A410491C05D1D0F8A810C943A6 +:109530000904090C0BD050F8A01F01F0010129709B +:10954000416821608068A080287830B970BD06210C +:1095500020460DF0CCFF01202870607940F0C0005B +:10956000607170BD70B54FF080540D46D4F8801016 +:10957000491C0BD1D4F88410491C07D1D4F88810A9 +:10958000491C03D1D4F88C10491C0CD0D4F880109D +:109590000160D4F884104160D4F888108160D4F858 +:1095A0008C10C16002E010210DF0A1FFD4F89000F2 +:1095B000401C0BD1D4F89400401C07D1D4F898007B +:1095C000401C03D1D4F89C00401C09D054F8900FE3 +:1095D000286060686860A068A860E068E86070BDA6 +:1095E0002846BDE8704010210DF081BF4A4800793F +:1095F000E6E470B5484CE07830B3207804EB4010D6 +:10960000407A00F00700204490F9E801002800DCCF +:10961000FFDF2078002504EB4010407A00F00700BF +:10962000011991F8E801401E81F8E8012078401CFA +:10963000C0B220700F2800D12570A078401CA07007 +:109640000DF0D4FDE57070BDFFDF70BD3EB5054681 +:1096500003210AF02BFC044628460AF058FD054673 +:1096600004B9FFDF206918B10078FF2800D1FFDFBF +:1096700001AA6946284600F005FB60B9FFDF0AE051 +:10968000002202A9284600F0FDFA00B9FFDF9DF88C +:10969000080000B1FFDF9DF80000411E8DF80010AA +:1096A000EED220690199884201D1002020613EBD9F +:1096B00070B50546A0F57F400C46FF3800D1FFDFAE +:1096C000012C01D0FFDF70BDFFF790FF040000D137 +:1096D000FFDF207820F00F00401D20F0F000503018 +:1096E000207065800020207201202073BDE870404A +:1096F0007FE72DE9F04116460D460746FFF776FF56 +:10970000040000D1FFDF207820F00F00401D20F082 +:10971000F00005E01C000020F403002048140020A5 +:109720005030207067800120207228682061A8884E +:10973000A0822673BDE8F0415BE77FB5FFF7DFFC51 +:10974000040000D1FFDF02A92046FFF7EBFA05462F +:1097500003A92046FFF700FB8DF800508DF80100AB +:10976000BDF80800001DADF80200BDF80C00001D9A +:10977000ADF80400E088ADF80600684609F070FB1B +:10978000002800D0FFDF7FBD2DE9F05FFC4E814651 +:10979000307810B10820BDE8F09F4846F7F77FFD0C +:1097A00008B11020F7E7F74C207808B9FFF757FC0D +:1097B000A17A607A4D460844C4B200F09DFAA042F6 +:1097C00007D2201AC1B22A460020FFF776FC0028F3 +:1097D000E1D17168EB48C91C002721F003017160D9 +:1097E000B3463E463D46BA463C4690F801800AE004 +:1097F000204600F076FA4178807B0E4410FB01553C +:10980000641CE4B27F1C4445F2D10AEB870000EBF4 +:10981000C600DC4E00EB85005C46F17A012200EBCD +:109820008100DBF80410451829464846FFF7B0FAD6 +:10983000070012D00020FFF762FC05000BD005F1F5 +:109840001300616820F00300884200D0FFDF7078C9 +:10985000401E7070656038469DE7002229464846E4 +:10986000FFF796FA00B1FFDFD9F8000060604FF60D +:10987000FF7060800120207000208CE72DE9F0410E +:109880000446BF4817460D46007810B10820BDE8D1 +:10989000F0810846F7F7DDFC08B11020F7E7B94E74 +:1098A000307808B9FFF7DBFB601E1E2807D8012CB3 +:1098B00023D12878FE2820D8B0770020E7E7A4F14C +:1098C00020001F2805D8E0B23A462946BDE8F041FD +:1098D00027E4A4F140001F2805D829462046BDE80A +:1098E000F04100F0D4BAA4F1A0001F2805D8294601 +:1098F0002046BDE8F04100F006BB0720C7E72DE990 +:10990000F05F81460F460846F7F7C9FC48B948465C +:10991000F7F7E3FC28B909F1030020F003014945FA +:1099200001D0102037E797484FF0000B4430817882 +:1099300069B14178804600EB411408343E883A46CC +:109940000021204600F089FA050004D027E0A7F89E +:1099500000B005201FE7B9F1000F24D03888B042CD +:1099600001D90C251FE0607800F00700824600F066 +:1099700060FA08EB0A063A4696F8E8014946401CA8 +:1099800086F8E801204600F068FA054696F8E801F6 +:10999000401E86F8E801032000F04BFA2DB10C2D93 +:1099A00001D0A7F800B02846F5E6754F5046BAF149 +:1099B000010F25D002280DD0BAF1030F35D0FFDFFB +:1099C00098F801104046491CC9B288F801100F29C7 +:1099D00037D038E0606828B16078000702D460882A +:1099E000FFF734FE98F8EA014446012802D178785E +:1099F000F9F78AFA94F9EA010428E1DBFFDFDFE7EF +:109A0000616821B14FF49072B8680AF0B5F898F81F +:109A1000E9014446032802D17878F9F775FA94F9F8 +:109A2000E9010428CCDBFFDFCAE76078C00602D575 +:109A30006088FFF70BFE98F9EB010628C0DBFFDF1B +:109A4000BEE780F801B08178491E88F8021096F8C8 +:109A5000E801401C86F8E801A5E770B50C4605460C +:109A6000F7F7F7FB18B92046F7F719FC08B11020F3 +:109A700070BD28460BF07FFF207008B1002070BD3C +:109A8000042070BD70B505460BF08EFFC4B22846A9 +:109A9000F7F723FC08B1102070BD35B128782C7081 +:109AA00018B1A04201D0072070BD2046FDF77EFE10 +:109AB000052805D10BF07BFF012801D0002070BDE7 +:109AC0000F2070BD70B5044615460E460846F7F7E0 +:109AD000C0FB18B92846F7F7E2FB08B1102070BDAB +:109AE000022C03D0102C01D0092070BD2A4631462B +:109AF00020460BF086FF0028F7D0052070BD70B51A +:109B000014460D460646F7F7A4FB38B92846F7F782 +:109B1000C6FB18B92046F7F7E0FB08B1102070BD6E +:109B20002246294630460BF06EFF0028F7D007206A +:109B300070BD3EB50446F7F7B2FB08B110203EBD3C +:109B4000684608F053F9FFF76EFB0028F7D19DF83F +:109B500006002070BDF808006080BDF80A00A080F3 +:109B600000203EBD70B505460C460846F7F7B5FB2C +:109B700020B95CB12068F7F792FB28B1102070BDC6 +:109B80001C000020B0030020A08828B121462846F0 +:109B9000BDE87040FDF762BE0920F0E770B50546EC +:109BA0000C460846F7F755FBA0BB681E1E280ED8CA +:109BB000032D01D90720E2E705B9FFDFFE4800EBDE +:109BC000850050F8041C2046BDE870400847A5F108 +:109BD00020001F2805D821462846BDE87040FAF726 +:109BE00042BBA5F160001F2805D821462846BDE8E4 +:109BF0007040F8F7DABCF02D0DD0F12D15D0BF2D47 +:109C0000D8D1A078218800F0010001F08DFB98B137 +:109C10000020B4E703E0A068F7F71BFB08B11020B1 +:109C2000ADE7204609F081F902E0207809F0A0F9BB +:109C3000BDE87040FFF7F7BA0820A0E770B504460A +:109C40000D460846F7F72BFB30B9601E1E280FD8CB +:109C50002846F7F7FEFA08B1102090E7012C03D050 +:109C6000022C01D0032C01D1062088E7072086E7CB +:109C7000A4F120001F28F9D829462046BDE87040ED +:109C8000FAF762BB09F092BC38B50446CB48007BBA +:109C900000F00105F9B904F01DFC0DB1226800E0E7 +:109CA0000022C7484178C06807F06DFDC4481030F5 +:109CB000C0788DF8000010B1012802D004E0012026 +:109CC00000E000208DF80000684608F0FFF8BA4870 +:109CD000243808F0B5FE002D02D02068283020601E +:109CE00038BD30B5B54D04466878A04200D8FFDFD6 +:109CF000686800EB041030BD70B5B04800252C46F4 +:109D0000467807E02046FFF7ECFF4078641C2844C3 +:109D1000C5B2E4B2B442F5D1284630E72DE9F041AE +:109D20000C4607464FF0000800F01FF90646FF28D2 +:109D300001D94FF013083868C01C20F003023A60C4 +:109D400054EA080421D19D48F3B2072128300DF0D0 +:109D5000DBFD09E0072C10D2DFE804F00604080858 +:109D60000A040600974804E0974802E0974800E09C +:109D700097480DF0E9FD054600E0FFDFA54200D061 +:109D8000FFDF641CE4B2072CE4D3386800EB061054 +:109D9000386040467BE5021D5143452900D24521EC +:109DA0000844C01CB0FBF2F0C0B270472DE9FC5F64 +:109DB000064682484FF000088B464746444690F8D6 +:109DC000019022E02046FFF78CFF050000D1FFDF65 +:109DD000687869463844C7B22846FEF7A3FF824632 +:109DE00001A92846FEF7B8FF0346BDF80400524615 +:109DF000001D81B2BDF80000001D80B20AF0D4F849 +:109E00006A78641C00FB0288E4B24C45DAD1306801 +:109E1000C01C20F003003060BBF1000F00D0002018 +:109E2000424639460AF0CEF8316808443060BDE851 +:109E3000FC9F6249443108710020C87070475F4937 +:109E40004431CA782AB10A7801EB421108318142C3 +:109E500001D001207047002070472DE9F0410646EF +:109E60000078154600F00F0400201080601E0F4699 +:109E7000052800D3FFDF50482A46183800EB84003D +:109E8000394650F8043C3046BDE8F04118472DE90A +:109E9000F0414A4E0C46402806D0412823D04228A3 +:109EA0002BD0432806D123E0A07861780D18E17803 +:109EB000814201D90720EAE42078012801D9132042 +:109EC000E5E4FF2D08D80BF009FF07460DF046F931 +:109ED000381A801EA84201DA1220D8E42068B06047 +:109EE000207930730DE0BDE8F041084600F078B805 +:109EF00008780228DED8307703E008780228D9D81D +:109F000070770020C3E4F8B500242C4DA02805D0BC +:109F1000A12815D0A22806D00720F8BD087800F0A7 +:109F20000100E8771FE00E4669463046FDF73DFD2B +:109F30000028F2D130882884B07885F8220012E019 +:109F400008680921F82801D3820701D00846F8BD26 +:109F50006A7C02F00302012A04D16A8BD73293B2E1 +:109F60008342F3D868622046F8BD2DE9F047DFF858 +:109F70004C900026344699F8090099F80A2099F87F +:109F800001700244D5B299F80B20104400F0FF088C +:109F900008E02046FFF7A5FE817B407811FB0066B4 +:109FA000641CE4B2BC42F4D199F8091099F80A0093 +:109FB0002944294441440DE054610200B0030020CB +:109FC0001C0000206741000045B30000DD2F0000A9 +:109FD000FB56010000B1012008443044BDE8F08781 +:109FE00038B50446407800F00300012803D0022869 +:109FF0000BD0072038BD606858B1F7F777F9D0B9B2 +:10A000006068F7F76AF920B915E06068F7F721F999 +:10A0100088B969462046FCF729F80028EAD160781B +:10A0200000F00300022808D19DF8000028B1606804 +:10A03000F7F753F908B1102038BD6189F8290DD818 +:10A04000208988420AD8607800F003020A48012A71 +:10A0500006D1D731426A89B28A4201D2092038BD7D +:10A0600094E80E0000F1100585E80E000AB9002101 +:10A070000183002038BD0000B00300202DE9F0412D +:10A08000074614468846084601F08AFD064608EB56 +:10A0900088001C22796802EBC0000D18688C58B14A +:10A0A0004146384601F08BFD014678680078C200D1 +:10A0B000082305F120000CE0E88CA8B141463846A1 +:10A0C00001F084FD0146786808234078C20005F15C +:10A0D000240009F0A8FD38B1062121726681D0E97B +:10A0E0000010C4E9031009E0287809280BD00520E6 +:10A0F000207266816868E060002028702046BDE814 +:10A10000F04101F02EBD072020726681F4E72DE9B1 +:10A11000F04116460D460746406801EB85011C22BA +:10A1200002EBC1014418204601F072FD40B100214C +:10A13000708865F30F2160F31F4106200DF0BEFC0F +:10A1400009202070324629463846BDE8F04195E79F +:10A150002DE9F0410E46074600241C21F07816E058 +:10A1600004EB8403726801EBC303D25C6AB1FFF7AE +:10A170003DFA050000D1FFDF6F802A4621463046B8 +:10A18000FFF7C5FF0120BDE8F081641CE4B2A042E6 +:10A19000E6D80020F7E770B5064600241C21C078F9 +:10A1A0000AE000BF04EB8403726801EBC303D51817 +:10A1B0002A782AB1641CE4B2A042F3D8402070BDD2 +:10A1C00028220021284604F062F9706880892881DD +:10A1D000204670BD70B5034600201C25DC780CE0DD +:10A1E00000EB80065A6805EBC6063244167816B1B5 +:10A1F000128A8A4204D0401CC0B28442F0D8402067 +:10A2000070BDF0B5044600201C26E5780EE000BFC6 +:10A2100000EB8007636806EBC7073B441F788F425B +:10A2200002D15B78934204D0401CC0B28542EFD883 +:10A230004020F0BD0078032801D0002070470120A5 +:10A2400070470078022801D0002070470120704735 +:10A250000078072801D000207047012070472DE9C1 +:10A26000F041064688461078F1781546884200D3BA +:10A27000FFDF2C781C27641CF078E4B2A04201D8E0 +:10A28000201AC4B204EB8401706807EBC1010844D2 +:10A29000017821B14146884708B12C7073E72878CE +:10A2A000A042E8D1402028706DE770B514460B88B5 +:10A2B0000122A240134207D113430B8001230A223B +:10A2C000011D09F07AFC047070BD2DE9FF4F81B0CB +:10A2D0000878DDE90E7B9A4691460E4640072CD45D +:10A2E000019809F026FF040000D1FFDF07F1040800 +:10A2F00020461FFA88F109F065F8050000D1FFDF5C +:10A30000204629466A4609F0B0FA0098A0F8037082 +:10A31000A0F805A0284609F056FB017869F306016C +:10A320006BF3C711017020461FFA88F109F08DF810 +:10A3300000B9FFDF019807F094F906EB0900017FEF +:10A34000491C017705B0BDE8F08F2DE9F84F0E46A6 +:10A350009A4691460746032109F0A8FD0446008D60 +:10A36000DFF8B885002518B198F80000B0421ED17A +:10A37000384609F0DEFE070000D1FFDF09F10401D5 +:10A38000384689B209F01EF8050010D03846294633 +:10A390006A4609F06AFA009800210A460180817035 +:10A3A00007F01CFA0098C01DCAF8000021E098F8D8 +:10A3B0000000B04216D104F1260734F8341F012002 +:10A3C00000FA06F911EA090F00D0FFDF2088012307 +:10A3D00040EA090020800A22391D384609F008FCAD +:10A3E000067006E0324604F1340104F12600FFF75E +:10A3F0005CFF0A2188F800102846BDE8F88FFEB5FA +:10A4000015460C46064602AB0C220621FFF79DFFBF +:10A41000002827D00299607812220A70801C4870A8 +:10A4200008224A80A07002982988052381806988C3 +:10A43000C180A9880181E988418100250C20CDE9EE +:10A440000005062221463046FFF73FFF294600223D +:10A4500066F31F41F02310460DF086FA6078801CE9 +:10A4600060700120FEBDFEB514460D46062206466C +:10A4700002AB1146FFF769FF002812D0029B1320A0 +:10A4800000211870A8785870022058809C800620FF +:10A49000CDE900010246052329463046FFF715FFA6 +:10A4A0000120FEBD2DE9FE430C46804644E002AB90 +:10A4B0000E2207214046FFF748FF002841D0606880 +:10A4C0001C2267788678BF1C06EB860102EBC1016F +:10A4D000451802981421017047700A214180698A49 +:10A4E0000181E98A4181A9888180A98981813046D9 +:10A4F00001F056FB029905230722C8806F700420E3 +:10A50000287000250E20CDE9000521464046FFF7C2 +:10A51000DCFE294666F30F2168F31F41F023002279 +:10A5200006200DF021FA6078FD49801C6070626899 +:10A530002046921CFFF793FE606880784028B6D1D1 +:10A540000120BDE8FE83FEB50D46064638E002ABAD +:10A550000E2207213046FFF7F8FE002835D0686844 +:10A560001C23C17801EB810203EBC202841802981C +:10A5700015220270627842700A224280A2894281CA +:10A58000A2888281084601F00BFB01460298818077 +:10A59000618AC180E18A0181A088B8B10020207061 +:10A5A00000210E20CDE9000105230722294630466F +:10A5B000FFF78BFE6A68DB492846D21CFFF74FFE87 +:10A5C0006868C0784028C2D10120FEBD0620E6E7B9 +:10A5D0002DE9FE430C46814644E0204601F002FB93 +:10A5E000D0B302AB082207214846FFF7AEFE002891 +:10A5F000A7D060681C2265780679AD1C06EB860141 +:10A6000002EBC10147180298B7F8108006210170CB +:10A61000457004214180304601F0C2FA014602989B +:10A6200005230722C180A0F804807D7008203870BF +:10A630000025CDE9000521464846FFF746FE29469C +:10A6400066F30F2169F31F41F023002206200DF06D +:10A650008BF96078801C60706268B3492046121DD7 +:10A66000FFF7FDFD606801794029B6D1012068E758 +:10A670002DE9F34F83B00D4691E0284601F0B2FA80 +:10A6800000287DD068681C2290F806A00AEB8A0199 +:10A6900002EBC10144185146284601F097FAA1780F +:10A6A000CB0069684978CA00014604F1240009F02A +:10A6B000D6FA07468188E08B4FF00009091A8EB25E +:10A6C00008B1C84607E04FF00108504601F053FAC0 +:10A6D00008B9B61CB6B2208BB04200D80646B346C5 +:10A6E00002AB324607210398FFF72FFE060007D082 +:10A6F000B8F1000F0BD0504601F03DFA10B106E062 +:10A7000000201FE60299B8884FF0020908800196E0 +:10A71000E28B3968ABEB09001FFA80F80A44039812 +:10A720004E46009209F005FDDDE90021F61D434685 +:10A73000009609F014F9E08B404480B2E083B988B8 +:10A74000884201D1012600E00026CDE900B6238A27 +:10A75000072229460398FFF7B8FD504601F00BFA8F +:10A7600010B9E089401EE08156B1A078401CA0706D +:10A770006868E978427811FB02F1CAB2012300E06F +:10A7800007E081690E3009F018FA80F800A0002077 +:10A79000E0836A6865492846921DFFF760FD686896 +:10A7A000817940297FF469AF0120CBE570B5064679 +:10A7B00048680D4614468179402910D104EB840184 +:10A7C0001C2202EBC101084401F043FA002806D024 +:10A7D0006868294684713046BDE8704048E770BD1E +:10A7E000FEB50C460746002645E0204601F0FAF982 +:10A7F000D8B360681C22417901EB810102EBC101F1 +:10A800004518688900B9FFDF02AB082207213846E6 +:10A81000FFF79BFD002833D00299607816220A705A +:10A82000801C4870042048806068407901F0B8F9C5 +:10A83000014602980523072281806989C18008208A +:10A84000CDE9000621463846FFF73FFD6078801CC1 +:10A850006070A88969890844B0F5803F00D3FFDFA4 +:10A86000A88969890844A8816E81626830492046B8 +:10A87000521DFFF7F4FC606841794029B5D10120F1 +:10A88000FEBD30B5438C458BC3F3C704002345B1EF +:10A89000838B641EED1AC38A6D1E1D4495FBF3F372 +:10A8A000E4B22CB1008918B1A04200D8204603447C +:10A8B0004FF6FF70834200D3034613800C7030BD07 +:10A8C0002DE9FC41074616460D46486802EB860115 +:10A8D0001C2202EBC10144186A4601A92046FFF779 +:10A8E000D0FFA089618901448AB2BDF8001091426D +:10A8F00012D0081A00D5002060816868407940288D +:10A900000AD1204601F09BF9002805D06868294645 +:10A9100046713846FFF764FFBDE8FC813000002037 +:10A9200035A2000043A2000051A2000053BC000069 +:10A930003FBC00002DE9FE4F0F468146154650886A +:10A94000032109F0B3FA0190B9F8020001F01BF9F4 +:10A9500082460146019801F045F9002824D001986B +:10A960001C2241680AEB8A0002EBC0000C1820464A +:10A9700001F04EF9002817D1B9F80000E18A8842A9 +:10A980000ED8A18961B1B8420ED100265146019876 +:10A9900001F015F9218C01EB0008608B30B114E057 +:10A9A000504601F0E8F8A0B3BDE8FE8F504601F034 +:10A9B000E2F808B1678308E0022FF5D3B9F8040084 +:10A9C0006083618A884224D80226B81B87B2B8F80F +:10A9D0000400A28B801A002814DD874200DA384672 +:10A9E0001FFA80FB688869680291D8F800100A4451 +:10A9F000009209F08CFBF61D009A5B4602990096C6 +:10AA000008F079FFA08B384480B2A083618B884224 +:10AA100007D96888019903B05246BDE8F04F01F0AC +:10AA200035B91FD14FF009002872B9F802006881CA +:10AA3000D8E90010C5E90410608BA881284601F010 +:10AA400090F85146019801F0BAF8014601980823A0 +:10AA500040680078C20004F1200009F0E4F800200A +:10AA6000A0836083504601F086F810B9A089401E8B +:10AA7000A0816888019903B00AF0FF02BDE8F04F99 +:10AA80001EE72DE9F041064615460F461C461846BE +:10AA9000F6F7DFFB18B92068F6F701FC10B11020BB +:10AAA000BDE8F0817168688C0978B0EBC10F01D303 +:10AAB0001320F5E73946304601F081F80146706809 +:10AAC00008230078C20005F1200009F076F8D4E9E7 +:10AAD0000012C0E900120020E2E710B5044603218D +:10AAE00009F0E4F90146007800F00300022805D0DF +:10AAF0002046BDE8104001F1140280E48A8A204615 +:10AB0000BDE81040AFE470B50446032109F0CEF96A +:10AB1000054601462046FFF75BFD002816D0294672 +:10AB20002046FFF75DFE002810D029462046FFF79B +:10AB30000AFD00280AD029462046FFF7B3FC00286A +:10AB400004D029462046BDE8704091E570BD2DE94E +:10AB5000F0410C4680461EE0E178427811FB02F19C +:10AB6000CAB2816901230E3009F05DF80778606888 +:10AB70001C22C179491EC17107EB8701606802EB95 +:10AB8000C10146183946204601F02CF818B130466C +:10AB900001F037F820B16068C1790029DCD17FE786 +:10ABA000FEF724FD050000D1FFDF0A202872384699 +:10ABB00000F0F6FF68813946204601F007F80146AB +:10ABC000606808234078C20006F1240009F02BF8E1 +:10ABD000D0E90010C5E90310A5F80280284600F06E +:10ABE000C0FFB07800B9FFDFB078401EB07057E703 +:10ABF00070B50C460546032109F058F90146406836 +:10AC0000C2792244C2712846BDE870409FE72DE911 +:10AC1000FE4F8246507814460F464FF00008002839 +:10AC20004FD0012807D0022822D0FFDF2068B8606B +:10AC30006068F860B8E602AB0E2208215046FFF7C4 +:10AC400084FB0028F2D00298152105230170217899 +:10AC500041700A214180C0F80480C0F80880A0F843 +:10AC60000C80628882810E20CDE90008082221E054 +:10AC7000A678304600F094FF054606EB86012C22AC +:10AC8000786802EBC1010822465A02AB11465046D1 +:10AC9000FFF75BFB0028C9D00298072101702178DB +:10ACA00041700421418008218580C680CDE90018CB +:10ACB00005230A4639465046FFF707FB87F8088008 +:10ACC00072E6A678022516B1022E13D0FFDF2A1DE8 +:10ACD000914602AB08215046FFF737FB0028A5D06C +:10ACE00002980121022E01702178417045808680F2 +:10ACF00002D005E00625EAE7A188C180E18801814C +:10AD0000CDE900980523082239465046D4E710B50E +:10AD10000446032109F0CAF8014600F10802204662 +:10AD2000BDE8104073E72DE9F04F0F4605468DB0A2 +:10AD300014465088032109F0B9F84FF000088DF847 +:10AD400014800646ADF81680042F7BD36A78002A5B +:10AD500078D028784FF6FF794FF01C0A132834D0AA +:10AD600008DC012871D006284AD007286ED01228A6 +:10AD70000ED106E014286AD0152869D0162807D10C +:10AD8000AAE10C2F04D1307800F00301022907D08A +:10AD9000CDF80880CDF80C8068788DF808004CE07C +:10ADA00040F0080030706878B07001208DF8140011 +:10ADB000A888ADF81800E888ADF81A002889ADF821 +:10ADC0001C006889ADF81E0011E1B078904239D1BD +:10ADD0003078010736D5062F34D120F008003070C6 +:10ADE0006088414660F31F4100200CF067FE02209E +:10ADF0008DF81400ADF81890A888ADF81A00F6E0A8 +:10AE0000082F1FD1A888EF88814600F0BCFE80463D +:10AE10000146304600F0E6FE18B1404600F0ABFEB9 +:10AE2000B8B1FC48D0E90010CDE902106878ADF85F +:10AE30000C908DF80800ADF80E70608802AA3146BB +:10AE4000FFF7E5FE0DB0BDE8F08FB6E01EE041E093 +:10AE5000ECE0716808EB88002C2202EBC000085A75 +:10AE6000B842EFD1EB4802AAD0E90210CDE90210B6 +:10AE700068788DF8080008F0FF058DF80A506088A2 +:10AE80003146FFF7C4FE224629461FE0082FD9D1DC +:10AE9000B5F80480E88800F076FE074601463046A3 +:10AEA00000F0A0FE0028CDD007EB870271680AEB06 +:10AEB000C2000844028A4245C4D101780829C1D1A0 +:10AEC000407869788842BDD1F9B222463046FFF712 +:10AED0001EF9B7E70E2F7FF45BAFE9886F898B46C9 +:10AEE000B5F808903046FFF775F9ABF140014029FD +:10AEF00001D309204AE0B9F1170F01D3172F01D26E +:10AF00000B2043E040280ED000EB800271680AEB72 +:10AF1000C20008440178012903D140786978884249 +:10AF200090D00A2032E03046FFF735F9014640283C +:10AF30002BD001EB810372680AEBC30002EB00081F +:10AF4000012288F800206A7888F801207068AA88B1 +:10AF50004089B84200D93846AD8903232372A282C2 +:10AF6000E7812082A4F80C906582084600F018FE64 +:10AF70006081A8F81490A8F81870A8F80E50A8F8E6 +:10AF800010B0204600F0EDFD5CE7042005212172A1 +:10AF9000A4F80A80E081012121739E49D1E90421AE +:10AFA000CDE9022169788DF80810ADF80A006088B3 +:10AFB00002AA3146FFF72BFEE3E7062F89D3B078CC +:10AFC00090421AD13078010717D520F00800307070 +:10AFD0006088414660F31F4100200CF06FFD0220A5 +:10AFE0008DF81400A888ADF81800ADF81A906088A4 +:10AFF000224605A9F9F7E3F824E704213046FFF7D4 +:10B0000000F905464028BFD0022083030090224665 +:10B010002946304600F003FE4146608865F30F2163 +:10B0200060F31F4106200CF049FD0BE70E2FABD15A +:10B0300004213046FFF7E5F881464028A4D0414678 +:10B04000608869F30F2160F31F4106200CF036FD84 +:10B05000A8890B906889099070682F894089B84247 +:10B0600000D938468346B5F80680A8880A90484635 +:10B0700000F096FD60810B9818B1022000900B9BA8 +:10B0800024E0B8F1170F1ED3172F1CD30420207211 +:10B0900009986082E781A4F810B0A4F80C8009EB4D +:10B0A000890271680AEBC2000D18DDE90913A5F8E1 +:10B0B0001480A5F818B0E9812B82204600F051FDDC +:10B0C00006202870BEE601200B2300902246494648 +:10B0D000304600F0A4FDB5E6082F8DD1A988304692 +:10B0E000FFF778F80746402886D000F044FD002896 +:10B0F0009BD107EB870271680AEBC20008448046C7 +:10B1000000F086FD002890D1ED88B8F80E002844A4 +:10B11000B0F5803F05D360883A46314600F0B6FD71 +:10B1200090E6002DCED0A8F80E0060883A46314651 +:10B13000FFF73CFB08202072384600F031FD6081AB +:10B14000A5811EE72DE9F05F0C4601281FD09579F7 +:10B1500092F8048092F8056005EB85011F2202EB4E +:10B16000C10121F0030B08EB060111FB05F14FF6BD +:10B17000FF7202EAC10909F1030115FB0611264F0E +:10B1800021F0031ABB6840B101283ED125E0616877 +:10B19000E57891F800804E78DEE75946184608F0C9 +:10B1A000C0FC606000B9FFDF5A460021606803F010 +:10B1B0006EF9E5705146B86808F0B3FC6168486103 +:10B1C00000B9FFDF6068426902EB090181616068D4 +:10B1D00080F800806068467017E0606852464169F8 +:10B1E000184608F0C9FC5A466168B86808F0C4FC03 +:10B1F000032008F003FE0446032008F007FE201A8F +:10B20000012802D1B86808F081FC0BEB0A00BDE808 +:10B21000F09F000060610200300000200246002123 +:10B2200002208FE7F7B5FF4C0A20164620700098E1 +:10B2300060B100254FEA0D0008F055FC0021A17017 +:10B240006670002D01D10099A160FEBD012500208E +:10B25000F2E770B50C46154638220021204603F06F +:10B2600016F9012666700A22002104F11C0003F081 +:10B270000EF905B9FFDF297A207861F3010020700B +:10B28000A87900282DD02A4621460020FFF75AFF32 +:10B2900061684020E34A88706168C870616808711D +:10B2A000616848716168887161682888088161688F +:10B2B00068884881606886819078002811D061682C +:10B2C0000620087761682888C885616828884886CC +:10B2D00060680685606869889288018681864685EF +:10B2E000828570BDC878002802D00022012029E79D +:10B2F000704770B50546002165F31F4100200CF032 +:10B30000DDFB0321284608F0D1FD040000D1FFDF5A +:10B3100021462846FEF71CFF002804D0207840F084 +:10B3200010002070012070BD70B505460C4603204A +:10B3300008F056FD08B1002070BDBA4885708480C1 +:10B34000012070BD2DE9FF4180460E460F0CFEF72F +:10B350004DF9050007D06F800321384608F0A6FD9F +:10B36000040008D106E004B03846BDE8F0411321DE +:10B37000F9F750BBFFDF5FEA080005D0B8F1060F10 +:10B3800018D0FFDFBDE8FF8120782A4620F00800B2 +:10B3900020700020ADF8020002208DF800004FF66A +:10B3A000FF70ADF80400ADF8060069463846F8F7BE +:10B3B00006FFE7E7C6F3072101EB81021C23606863 +:10B3C00003EBC202805C042803D008280AD0FFDF08 +:10B3D000D8E7012000904FF440432A46204600F071 +:10B3E0001EFCCFE704B02A462046BDE8F041FEF738 +:10B3F0008EBE2DE9F05F05464089002790460C4639 +:10B400003E46824600F0BFFB8146287AC01E0828CF +:10B410006BD2DFE800F00D04192058363C47722744 +:10B420001026002C6CD0D5E90301C4E902015CE0D0 +:10B4300070271226002C63D00A2205F10C0104F1BA +:10B44000080002F0FAFF50E071270C26002C57D0BC +:10B45000E868A06049E0742710269CB3D5E9030191 +:10B46000C4E902016888032108F020FD8346FEF745 +:10B47000BDF802466888508049465846FEF7FEFDF2 +:10B4800033E075270A26ECB1A88920812DE07627C4 +:10B490001426BCB105F10C0004F1080307C883E8C9 +:10B4A000070022E07727102664B1D5E90301C4E93B +:10B4B00002016888032108F0F9FC01466888FFF75B +:10B4C00046FB12E01CE073270826CCB168880321F4 +:10B4D00008F0ECFC01460078C00606D56888FEF747 +:10B4E00037FE10B96888F8F777FAA8F800602CB131 +:10B4F0002780A4F806A066806888A080002086E6E1 +:10B50000A8F80060FAE72DE9FC410C461E461746F4 +:10B510008046032108F0CAFC05460A2C0AD2DFE85F +:10B5200004F005050505050509090907042303E0DD +:10B53000062301E0FFDF0023CDE9007622462946FD +:10B540004046FEF7C2FEBDE8FC81F8B50546A0F511 +:10B550007F40FF382BD0284608F0D9FD040000D1E9 +:10B56000FFDF204608F05FF9002821D001466A4637 +:10B57000204608F07AF900980321B0F805602846C3 +:10B5800008F094FC0446052E13D0304600F0FBFA78 +:10B5900005460146204600F025FB40B1606805EBFA +:10B5A00085013E2202EBC101405A002800D0012053 +:10B5B000F8BD007A0028FAD00020F8BDF8B504469E +:10B5C000408808F0A4FD050000D1FFDF6A46284648 +:10B5D000616800F0C4FA01460098091F8BB230F888 +:10B5E000032F0280428842800188994205D1042AB3 +:10B5F00008D0052A20D0062A16D022461946FFF781 +:10B6000099F9F8BD001D0E46054601462246304612 +:10B61000F6F739FF0828F4D1224629463046FCF7D0 +:10B6200064F9F8BD30000020636864880A46011D93 +:10B630002046FAF789F9F4E72246001DFFF773FB6D +:10B64000EFE770B50D460646032108F02FFC040015 +:10B6500004D02078000704D5112070BD43F2020009 +:10B6600070BD2A4621463046FEF7C9FE18B9286843 +:10B6700060616868A061207840F0080020700020B8 +:10B6800070BD70B50D460646032108F00FFC04009E +:10B6900004D02078000704D4082070BD43F20200D3 +:10B6A00070BD2A4621463046FEF7DDFE00B9A58270 +:10B6B000207820F008002070002070BD2DE9F04FA8 +:10B6C0000E4691B08046032108F0F0FB0446404648 +:10B6D00008F02FFD07460020079008900990ADF86C +:10B6E00030000A9002900390049004B9FFDF0DF13E +:10B6F0000809FFB9FFDF1DE038460BA9002207F05B +:10B7000055FF9DF82C0000F07F050A2D00D3FFDFC8 +:10B710006019017F491E01779DF82C00000609D5AC +:10B720002A460CA907A8FEF7C0FD19F80510491C08 +:10B7300009F80510761EF6B2DED204F13400F84D99 +:10B7400004F1260BDFF8DCA304F12A07069010E0D1 +:10B750005846069900F08CFA064628700A2800D34D +:10B76000FFDF5AF8261040468847E08CC05DB042A3 +:10B7700002D0208D0028EBD10A202870E94D4E46DA +:10B7800028350EE00CA907A800F072FA0446375DD0 +:10B7900055F8240000B9FFDF55F82420394640460B +:10B7A0009047BDF81E000028ECD111B0BDE8F08F25 +:10B7B00010B5032108F07AFB040000D1FFDF0A2254 +:10B7C000002104F11C0002F062FE207840F0040029 +:10B7D000207010BD10B50C46032108F067FB204413 +:10B7E000007F002800D0012010BD2DE9F84F8946C8 +:10B7F00015468246032108F059FB070004D028466D +:10B80000F5F727FD40B903E043F20200BDE8F88FE9 +:10B810004846F5F744FD08B11020F7E7786828B1ED +:10B8200069880089814201D90920EFE7B9F8000051 +:10B830001C2488B100F0A7F980460146384600F084 +:10B84000D1F988B108EB8800796804EBC000085C86 +:10B8500001280BD00820D9E73846FEF79CFC80462B +:10B86000402807D11320D1E70520CFE7FDF7BEFE22 +:10B8700006000BD008EB8800796804EBC0000C18B8 +:10B88000B9F8000020B1E88910B113E01120BDE73C +:10B890002888172802D36888172801D20720B5E71F +:10B8A000686838B12B1D224641463846FFF7E9F853 +:10B8B0000028ABD104F10C0269462046FEF7E1FFF7 +:10B8C000288860826888E082B9F8000030B10220E0 +:10B8D0002070E889A080E889A0B12BE003202070C7 +:10B8E000A889A08078688178402905D180F80280F5 +:10B8F00039465046FEF7D6FD404600F051F9A9F80A +:10B90000000021E07868218B4089884200D90846F0 +:10B910002083A6F802A004203072B9F800007081DC +:10B92000E0897082F181208B3082A08AB08130461C +:10B9300000F017F97868C178402905D180F80380B4 +:10B9400039465046FEF7FFFD00205FE770B50D4613 +:10B950000646032108F0AAFA04000ED0284600F09B +:10B9600012F905460146204600F03CF918B1284678 +:10B9700000F001F920B1052070BD43F2020070BD56 +:10B9800005EB85011C22606802EBC101084400F050 +:10B990003FF908B1082070BD2A462146304600F024 +:10B9A00075F9002070BD2DE9F0410C461746804620 +:10B9B000032108F07BFA0546204600F0E4F804462F +:10B9C00095B10146284600F00DF980B104EB8401E1 +:10B9D0001C22686802EBC1014618304600F018F9D5 +:10B9E00038B10820BDE8F08143F20200FAE70520F3 +:10B9F000F8E73B46324621462846FFF742F8002842 +:10BA0000F0D1E2B229464046FEF75AFF708C083862 +:10BA1000082803D242484078F7F776FA0020E1E799 +:10BA20002DE9F0410D4617468046032108F03EFA05 +:10BA30000446284600F0A7F8064624B13846F5F734 +:10BA400008FC38B902E043F20200CBE73868F5F7AA +:10BA500000FC08B11020C5E73146204600F0C2F8CE +:10BA600060B106EB86011C22606802EBC10145183B +:10BA7000284600F0CDF818B10820B3E70520B1E75B +:10BA8000B888A98A884201D90C20ABE76168E88CA4 +:10BA90004978B0EBC10F01D31320A3E7314620460C +:10BAA00000F094F80146606808234078C20005F170 +:10BAB000240008F082F8D7E90012C0E90012F2B2BF +:10BAC00021464046FEF772FE00208BE72DE9F04745 +:10BAD0000D461F4690468146032108F0E7F90446CB +:10BAE000284600F050F806463CB14DB13846F5F70F +:10BAF000F4FB50B11020BDE8F08743F20200FAE7F2 +:10BB0000606858B1A0F80C8027E03146204600F06C +:10BB100069F818B1304600F02EF828B10520EAE7A0 +:10BB2000300000207861020006EB86011C2260686C +:10BB300002EBC1014518284600F06AF808B1082058 +:10BB4000D9E7A5F80880F2B221464846FEF7B8FECC +:10BB50001FB1A8896989084438800020CBE707F025 +:10BB600084BE017821F00F01491C21F0F001103151 +:10BB70000170FDF73EBD20B94E48807808B1012024 +:10BB80007047002070474B498988884201D10020C6 +:10BB90007047402801D2402000E0403880B2704712 +:10BBA00010B50446402800D9FFDF2046FFF7E3FF29 +:10BBB00010B14048808810BD4034A0B210BD40682C +:10BBC00042690078484302EBC0007047C278406881 +:10BBD000037812FB03F24378406901FB032100EB79 +:10BBE000C1007047C2788A4209D9406801EB8101DF +:10BBF0001C2202EBC101405C08B10120704700200B +:10BC000070470078062801D901207047002070474E +:10BC10000078062801D00120704700207047F0B45A +:10BC200001EB81061C27446807EBC6063444049DDB +:10BC300005262670E3802571F0BCFEF71FBA10B50B +:10BC4000418911B1FFF7DDFF08B1002010BD0120CF +:10BC500010BD10B5C18C8278B1EBC20F04D9C18977 +:10BC600011B1FFF7CEFF08B1002010BD012010BDBB +:10BC700010B50C4601230A22011D07F0D4FF0078FD +:10BC80002188012282409143218010BDF0B402EB53 +:10BC900082051C264C6806EBC505072363554B68D7 +:10BCA0001C79402C03D11A71F0BCFEF791BCF0BC9A +:10BCB000704700003000002010B5EFF3108000F056 +:10BCC000010472B6FC484178491C41704078012853 +:10BCD00001D10BF0B3FA002C00D162B610BD70B5E3 +:10BCE000F54CA07848B90125A570FFF7E5FF0BF0EA +:10BCF000B6FA20B100200BF080FA002070BD4FF0A2 +:10BD00008040E570C0F80453F7E770B5EFF310809A +:10BD100000F0010572B6E84C607800B9FFDF60788A +:10BD2000401E6070607808B90BF08CFA002D00D1CD +:10BD300062B670BDE04810B5817821B10021C170B4 +:10BD40008170FFF7E2FF002010BD10B504460BF034 +:10BD500086FAD9498978084000D001202060002067 +:10BD600010BD10B5FFF7A8FF0BF079FA02220123EE +:10BD7000D149540728B1D1480260236103200872D9 +:10BD800002E00A72C4F804330020887110BD2DE966 +:10BD9000F84FDFF824934278817889F80420002650 +:10BDA00089F80510074689F806600078DFF810B3B7 +:10BDB000354620B1012811D0022811D0FFDF0BF049 +:10BDC00060FA4FF0804498B10BF062FAB0420FD1A4 +:10BDD00030460BF061FA0028FAD042E00126EEE787 +:10BDE000FFF76AFF58460168C907FCD00226E6E75C +:10BDF0000120E060C4F80451B2490E600107D1F897 +:10BE00004412B04AC1F3423124321160AD49343199 +:10BE100008604FF0020AC4F804A3A060AA480168B1 +:10BE2000C94341F3001101F10108016841F010011B +:10BE3000016001E019F0A8FFD4F804010028F9D04E +:10BE400030460BF029FA0028FAD0B8F1000F04D1DF +:10BE50009D48016821F010010160C4F808A3C4F8EE +:10BE6000045199F805004E4680B1387870B90BF04E +:10BE7000F6F980460BF006FC6FF00042B8F1000FB7 +:10BE800002D0C6E9032001E0C6E90302DBF80000A6 +:10BE9000C00701D00BF0DFF9387810B13572BDE87A +:10BEA000F88F4FF01808C4F808830127A7614FF4F2 +:10BEB0002070ADF8000000BFBDF80000411EADF8D5 +:10BEC0000010F9D2C4F80C51C4F810517A48C01DC2 +:10BED0000BF06CFA3570FFF744FF676179493079F0 +:10BEE00020310860C4F80483D9E770B5050000D19B +:10BEF000FFDF4FF080424FF0FF30C2F8080300210F +:10BF0000C2F80011C2F80411C2F80C11C2F81011E5 +:10BF1000694C61700BF0AFF910B10120A070607036 +:10BF200067480068C00701D00BF095F92846BDE8C6 +:10BF300070402CE76048007A002800D0012070474C +:10BF40002DE9F04F61484FF0000A85B0D0F800B0FD +:10BF5000D14657465D4A5E49083211608406D4F8DE +:10BF6000080110B14FF0010801E04FF000080BF09C +:10BF7000F0F978B1D4F8240100B101208246D4F858 +:10BF80001C0100B101208146D4F8200108B101272D +:10BF900000E00027D4F8000100B101200490D4F89B +:10BFA000040100B101200390D4F80C0100B101207C +:10BFB0000290D4F8100100B101203F4D0190287883 +:10BFC00000260090B8F1000F04D0C4F808610120E9 +:10BFD0000BF013F9BAF1000F04D0C4F82461092062 +:10BFE0000BF00BF9B9F1000F04D0C4F81C610A2062 +:10BFF0000BF003F927B1C4F820610B200BF0FDF81A +:10C000002D48C01D0BF0DAF900B1FFDFDFF8AC807E +:10C010000498012780B1C4F80873E87818B1EE706D +:10C0200000200BF0EAF8287A022805D103202872B4 +:10C030000221C8F800102761039808B1C4F8046110 +:10C04000029850B1C4F80C61287A032800D0FFDFB1 +:10C05000C8F800602F72FFF758FE019838B1C4F895 +:10C060001061287A012801D100F05CF8676100981E +:10C0700038B12E70287A012801D1FFF772FEFFF740 +:10C0800044FE0D48C01D0BF0AFF91049091DC1F861 +:10C0900000B005B0BDE8F08F074810B5C01D0BF02B +:10C0A0008DF90549B0B1012008704FF0E021C1F8C9 +:10C0B0000002BDE81040FFE544000020340C0040C1 +:10C0C0000C0400401805004010ED00E0100502408F +:10C0D00001000001087A012801D1FFF742FEBDE806 +:10C0E000104024480BF080B970B5224CE41FA078B2 +:10C0F00008B90BF0A7F801208507A861207A00266F +:10C10000032809D1D5F80C0120B900200BF0C4F8A0 +:10C110000028F7D1C5F80C6126724FF0FF30C5F842 +:10C12000080370BD70B5134CE41F6079F0B10128AD +:10C1300003D0A179401E814218DA0BF090F8054631 +:10C140000BF0A0FA6179012902D9A179491CA171EA +:10C150000DB1216900E0E168411A022902DA11F10A +:10C16000020F06DC0DB1206100E0E060BDE8704028 +:10C17000F7E570BD4B0000200F4A12680D498A4256 +:10C180000CD118470C4A12680A4B9A4206D101B5E5 +:10C190000BF04AFA0BF01DFDBDE8014007490968A4 +:10C1A0000958084706480749054A064B70470000EA +:10C1B00000000000BEBAFECA5C000020040000209F +:10C1C000C8130020C8130020F8B51D46DDE9064756 +:10C1D0000E000AD007F0ADFF2346FF1DBCB231466A +:10C1E0002A46009407F0BBFBF8BDD0192246194639 +:10C1F00002F023F92046F8BD70B50D460446102222 +:10C20000002102F044F9258117206081A07B40F0D5 +:10C210000A00A07370BD4FF6FF720A80014602202B +:10C220000BF04CBC704700897047827BD30701D16B +:10C23000920703D48089088000207047052070474A +:10C24000827B920700D581817047014600200988D2 +:10C2500041F6FE52114200D00120704700B503465E +:10C26000807BC00701D0052000BD59811846FFF72B +:10C27000ECFFC00703D0987B40F004009873987BD4 +:10C2800040F001009873002000BD827B520700D56A +:10C2900009B14089704717207047827B61F3C30260 +:10C2A000827370472DE9FC5F0E460446017896467E +:10C2B000012000FA01F14DF6FF5201EA020962681D +:10C2C0004FF6FF7B1188594502D10920BDE8FC9F3C +:10C2D000B9F1000F05D041F6FE55294201D00120E9 +:10C2E000F4E741EA090111801D0014D000232B70EE +:10C2F00094F800C0052103221F464FF0020ABCF14A +:10C300000E0F76D2DFE80CF0F909252F47646B7722 +:10C31000479193B4D1D80420D8E7616820898B7BFA +:10C320009B0767D517284AD30B89834247D389894E +:10C33000172901D3814242D185F800A0A5F8010058 +:10C340003280616888816068817B21F0020181739D +:10C35000C6E0042028702089A5F801006089A5F8AE +:10C3600003003180BCE0208A3188C01D1FFA80F8AC +:10C37000414524D3062028702089A5F80100608952 +:10C38000A5F80300A089A5F805000721208ACDE9BA +:10C390000001636941E00CF0FF00082810D008207C +:10C3A00028702089A5F801006089A5F80300318074 +:10C3B0006A1D694604F10C0009F025FB10B15EE02E +:10C3C0001020EDE730889DF800100844308087E0A9 +:10C3D0000A2028702089A5F80100328044E00C2052 +:10C3E00028702089A5F801006089A5F80300318034 +:10C3F0003AE082E064E02189338800EB41021FFAD1 +:10C4000082F843453BD3B8F1050F38D30E222A708A +:10C410000BEA4101CDE90010E36860882A467146C5 +:10C42000FFF7D2FEA6F800805AE04020287060890D +:10C430003188C01C1FFA80F8414520D32878714606 +:10C4400020F03F00123028702089A5F80100608993 +:10C45000CDE9000260882A46E368FFF7B5FEA6F83A +:10C460000080287840063BD461682089888037E0C6 +:10C47000A0893288401D1FFA80F8424501D2042766 +:10C480003DE0162028702089A5F801006089A5F8F4 +:10C490000300A089CDE9000160882A46714623691E +:10C4A000FFF792FEA6F80080DEE718202870207AB9 +:10C4B0006870A6F800A013E061680A88920401D4AD +:10C4C00005271CE0C9882289914201D0062716E081 +:10C4D0001E21297030806068018821F4005101809C +:10C4E000B9F1000F0BD061887823002202200BF0F5 +:10C4F0003BFA61682078887006E033800327606823 +:10C50000018821EA090101803846DFE62DE9FF4F65 +:10C5100085B01746129C0D001E461CD03078C1070E +:10C5200003D000F03F00192801D9012100E00021CB +:10C530002046FFF7AAFEA8420DD32088A0F57F4130 +:10C54000FF3908D03078410601D4000605D508200F +:10C5500009B0BDE8F08F0720FAE700208DF8000051 +:10C560008DF8010030786B1E00F03F0C0121A81EF1 +:10C570004FF0050A4FF002094FF0030B9AB2BCF1DD +:10C58000200F75D2DFE80CF08B10745E7468748C29 +:10C59000749C74B574BA74C874D474E1747474F10E +:10C5A00074EF74EE74ED748B052D78D18DF80090D6 +:10C5B000A0788DF804007088ADF8060030798DF809 +:10C5C0000100707800F03F000C2829D00ADCA0F1AF +:10C5D0000200092863D2DFE800F0126215621A62D5 +:10C5E0001D622000122824D004DC0E281BD0102845 +:10C5F000DBD11BE016281FD01828D6D11FE02078E9 +:10C60000800701E020784007002848DAEEE0207833 +:10C610000007F9E72078C006F6E720788006F3E700 +:10C6200020784006F0E720780006EDE72088C00576 +:10C63000EAE720884005E7E720880005E4E720884E +:10C64000C004E1E72078800729D5032D27D18DF894 +:10C6500000B0B6F8010081E0217849071FD5062D0A +:10C660001DD381B27078012803D0022817D102E0CF +:10C67000C9E0022000E0102004228DF8002072782A +:10C680008DF80420801CB1FBF0F2ADF8062092B2C8 +:10C6900042438A4203D10397ADF80890A6E079E0BF +:10C6A0002078000776D598B282088DF800A0ADF802 +:10C6B0000420B0EB820F6DD10297ADF8061095E023 +:10C6C0002178C90666D5022D64D381B206208DF883 +:10C6D0000000707802285DD3B1FBF0F28DF8040001 +:10C6E000ADF8062092B242438A4253D1ADF8089089 +:10C6F0007BE0207880064DD5072003E020784006B7 +:10C700007FD508208DF80000A088ADF80400ADF8B2 +:10C710000620ADF8081068E02078000671D50920E1 +:10C72000ADF804208DF80000ADF8061002975DE02A +:10C730002188C90565D5022D63D381B20A208DF801 +:10C740000000707804285CD3C6E72088400558D5DF +:10C75000012D56D10B208DF80000A088ADF8040003 +:10C7600044E021E026E016E0FFE72088000548D5F8 +:10C77000052D46D30C208DF80000A088ADF80400EC +:10C78000B6F803006D1FADF80850ADF80600ADF81F +:10C790000AA02AE035E02088C00432D5012D30D12E +:10C7A0000D208DF8000021E02088800429D4B6F8FF +:10C7B0000100E080A07B000723D5032D21D3307832 +:10C7C00000F03F001B2818D00F208DF800002088B3 +:10C7D00040F40050A4F80000B6F80100ADF80400E1 +:10C7E000ED1EADF80650ADF808B003976946059800 +:10C7F000F5F792FB050008D016E00E208DF800003A +:10C80000EAE7072510E008250EE0307800F03F0049 +:10C810001B2809D01D2807D0022005990BF04EF9DE +:10C82000208800F400502080A07B400708D52046D7 +:10C83000FFF70BFDC00703D1A07B20F00400A0731D +:10C84000284685E61FB5022806D101208DF8000094 +:10C8500088B26946F5F760FB1FBD0000F8B51D46BC +:10C86000DDE906470E000AD007F063FC2346FF1DF2 +:10C87000BCB231462A46009407F071F8F8BDD019D1 +:10C880002246194601F0D9FD2046F8BD2DE9FF4F9B +:10C890008DB09B46DDE91B57DDF87CA00C46082BCC +:10C8A00005D0E06901F0FEF850B11020D2E02888F0 +:10C8B000092140F0100028808AF80010022617E0B5 +:10C8C000E16901208871E2694FF420519180E169AA +:10C8D0008872E06942F601010181E06900218173FB +:10C8E0002888112140F0200028808AF800100426B2 +:10C8F00038780A900A2038704FF0020904F11800C5 +:10C900004D460C9001F0C6FBB04681E0BBF1100F24 +:10C910000ED1022D0CD0A9EB0800801C80B20221A0 +:10C92000CDE9001005AB52461E990D98FFF796FF12 +:10C93000BDF816101A98814203D9F74800790F9074 +:10C9400004E003D10A9808B138702FE04FF00201DB +:10C95000CDE900190DF1160352461E990D98FFF707 +:10C960007DFF1D980088401B801B83B2C6F1FF002D +:10C97000984200D203461E990BA8D9B15FF000027D +:10C98000DDF878C0CDE9032009EB060189B2CDE9D5 +:10C9900001C10F980090BDF8161000220D9801F00B +:10C9A0000EFC387070B1C0B2832807D0BDF81600F5 +:10C9B00020833AE00AEB09018A19E1E7022011B06D +:10C9C000BDE8F08FBDF82C00811901F0FF08022DA1 +:10C9D0000DD09AF80120424506D1BDF820108142C1 +:10C9E00007D0B8F1FF0F04D09AF801801FE08AF851 +:10C9F0000180C94800680178052902D1BDF81610E8 +:10CA0000818009EB08001FFA80F905EB080085B268 +:10CA1000DDE90C1005AB0F9A01F03FFB28B91D981A +:10CA20000088411B4145BFF671AF022D13D0BBF109 +:10CA3000100F0CD1A9EB0800801C81B20220CDE9B7 +:10CA4000000105AB52461E990D98FFF707FF1D9890 +:10CA50000580002038700020B1E72DE9F8439C469E +:10CA6000089E13460027B26B9AB3491F8CB2F18F10 +:10CA7000A1F57F45FF3D05D05518AD882944891D96 +:10CA80008DB200E000252919B6F83C8008314145F7 +:10CA900020D82A44BCF8011022F8021BBCF803106D +:10CAA00022F8021B984622F8024B914607F02FFB12 +:10CAB0004FF00C0C41464A462346CDF800C006F024 +:10CAC0001AFFF587B16B00202944A41D214408807A +:10CAD00003E001E0092700E083273846BDE8F8833A +:10CAE00010B50B88848F9C420CD9846BE0180488A5 +:10CAF00044B1848824F40044A41D23440B801060B6 +:10CB0000002010BD0A2010BD2DE9F0478AB0002595 +:10CB1000904689468246ADF8185007274BE00598A5 +:10CB200006888088000446D4A8F8006007A801950C +:10CB300000970295CDE903504FF40073002231466F +:10CB4000504601F03CFB04003CD1BDF81800ADF8A4 +:10CB50002000059804888188B44216D10A0414D4B0 +:10CB600001950295039521F400410097049541F445 +:10CB7000804342882146504601F0BFF804000BD1A3 +:10CB80000598818841F40041818005AA08A948469A +:10CB9000FFF7A6FF0400DCD00097059802950195E9 +:10CBA000039504950188BDF81C300022504601F021 +:10CBB000A4F80A2C06D105AA06A94846FFF790FF5B +:10CBC0000400ACD0ADF8185004E00598818821F439 +:10CBD0000041818005AA06A94846FFF781FF002889 +:10CBE000F3D00A2C03D020460AB0BDE8F08700201D +:10CBF000FAE710B50C46896B86B051B10C218DF85F +:10CC00000010A18FADF80810A16B01916946FAF7E9 +:10CC100001FB00204FF6FF71A063E187A08706B0FB +:10CC200010BD2DE9F0410D460746896B0020069E98 +:10CC30001446002911D0012B0FD13246294638461F +:10CC4000FFF762FF002808D1002C06D032462946A3 +:10CC50003846BDE8F04100F034BFBDE8F0812DE971 +:10CC6000FC411446DDE9087C0E46DDE90A15521D3B +:10CC7000BCF800E092B2964502D20720BDE8FC81E4 +:10CC8000ACF8002017222A70A5F80160A5F803303F +:10CC90000522CDE900423B462A46FFF7DFFD002092 +:10CCA000ECE770B50C46154648220021204601F0FD +:10CCB000EEFB04F1080044F81C0F00204FF6FF7152 +:10CCC000E06161842084A5841720E08494F82A0020 +:10CCD00040F00A0084F82A0070BD4FF6FF720A8007 +:10CCE000014603200AF0EABE30B585B00C46054681 +:10CCF000FFF77FFFA18E284629B101218DF8001092 +:10CD00006946FAF787FA0020E0622063606305B0A5 +:10CD100030BDB0F8400070476000002090F8462019 +:10CD2000920703D4408808800020F4E70620F2E749 +:10CD300090F846209207EED5A0F84410EBE70146A4 +:10CD4000002009880A0700D5012011F0F00F01D05A +:10CD500040F00200CA0501D540F004008A0501D563 +:10CD600040F008004A0501D540F010000905D2D571 +:10CD700040F02000CFE700B5034690F84600C0071A +:10CD800001D0062000BDA3F842101846FFF7D7FFD8 +:10CD900010F03E0F05D093F8460040F0040083F8F1 +:10CDA000460013F8460F40F001001870002000BD47 +:10CDB00090F84620520700D511B1B0F84200AAE71A +:10CDC0001720A8E710F8462F61F3C3020270A2E70C +:10CDD0002DE9FF4F9BB00E00DDE92B34DDE929780A +:10CDE000289D24D02878C10703D000F03F001928DF +:10CDF00001D9012100E000212046FFF7D9FFB04210 +:10CE000015D32878410600F03F010CD41E290CD020 +:10CE1000218811F47F6F0AD13A8842B1A1F57F428F +:10CE2000FF3A04D001E0122901D1000602D5042006 +:10CE30001FB0C5E5FA491D984FF0000A08718DF83A +:10CE400018A08DF83CA00FAA0A60ADF81CA0ADF8A0 +:10CE500050A02978994601F03F02701F5B1C04F135 +:10CE6000180C4FF0060E4FF0040BCDF858C01F2AD7 +:10CE70007ED2DFE802F07D7D107D267DAC7DF47DE5 +:10CE8000F37DF27DF17DF47DF07D7D7DEF7DEE7DA6 +:10CE90007D7D7D7DED0094F84610B5F80100890791 +:10CEA00001D5032E02D08DF818B01EE34FF40061B7 +:10CEB000ADF85010608003218DF83C10ADF84000B3 +:10CEC000D4E2052EEFD1B5F801002083ADF81C00A7 +:10CED000B5F80310618308B1884201D9012079E1D6 +:10CEE0000020A07220814FF6FF702084169801F078 +:10CEF000D1F8052089F800000220029083460AAB91 +:10CF00001D9A16991B9801F0C8F890BB9DF82E0049 +:10CF1000012804D0022089F80100102003E001203C +:10CF200089F8010002200590002203A90BA808F04F +:10CF30006AFDE8BB9DF80C00059981423DD1398816 +:10CF4000801CA1EB0B01814237DB02990220CDE965 +:10CF500000010DF12A034A4641461B98FFF77EFC6B +:10CF600002980BF1020B801C81B217AA029101E01A +:10CF70009CE228E003A90BA808F045FD02999DF862 +:10CF80000C00CDE9000117AB4A4641461B98FFF75C +:10CF900065FC9DF80C000AAB0BEB00011FFA81FB4E +:10CFA00002991D9A084480B2029016991B9800E0DD +:10CFB00003E001F072F80028B6D0BBF1020F02D0F6 +:10CFC000A7F800B04FE20A208DF818004BE20021CC +:10CFD0000391072EFFF467AFB5F801002083ADF889 +:10CFE0001C00B5F80320628300283FF477AF90421D +:10CFF0003FF674AF0120A072B5F805002081002033 +:10D00000A073E06900F04EFD78B9E16901208871F4 +:10D01000E2694FF420519180E1698872E16942F63A +:10D0200001000881E06900218173F01F20841E98AF +:10D03000606207206084169801F02CF8072089F8B8 +:10D0400000000120049002900020ADF82A0028E0A2 +:10D0500019E29FE135E1E5E012E2A8E080E043E07B +:10D060000298012814D0E0698079012803D1BDF825 +:10D070002800ADF80E00049803ABCDE900B04A4695 +:10D0800041461B98FFF7EAFB0498001D80B204900C +:10D09000BDF82A00ADF80C00ADF80E00059880B27E +:10D0A00002900AAB1D9A16991B9800F0F6FF28B95A +:10D0B00002983988001D05908142D1D2029801283A +:10D0C00081D0E0698079012803D1BDF82800ADF84E +:10D0D0000E00049803ABCDE900B04A4641461B98C8 +:10D0E000FFF7BCFB0298BDE1072E02D0152E7FF49E +:10D0F000DAAEB5F801102183ADF81C10B5F80320A5 +:10D10000628300293FF4EAAE91423FF6E7AE012187 +:10D11000A1724FF0000BA4F808B084F80EB0052EF1 +:10D1200007D0C0B2691DE26908F06BFC00287FF4EB +:10D130004AAF4FF6FF70208401A906AA14A8CDF8C3 +:10D1400000B081E885032878214600F03F031D9A4E +:10D150001B98FFF79BFB8246208BADF81C0082E1F9 +:10D160000120032EC3D14021ADF85010B5F80110B5 +:10D170002183ADF81C100AAAB8F1000F00D00023DB +:10D18000CDE9020304921D98CDF804800090388800 +:10D190000022401E83B21B9801F011F88DF8180090 +:10D1A00090BB0B2089F80000BDF8280035E04FF057 +:10D1B000010C052E9BD18020ADF85000B5F8011070 +:10D1C0002183B5F803002084ADF81C10B0F5007F72 +:10D1D00003D907208DF8180087E140F47C422284AF +:10D1E0000CA8B8F1000F00D00023CDE90330CDE941 +:10D1F000018C1D9800903888401E83B21B9800F067 +:10D20000DEFF8DF8180018B18328A8D10220BFE0F6 +:10D210000D2189F80010BDF83000401C22E100000B +:10D2200060000020032E04D248067FF53CAE0020AB +:10D2300018E1B5F80110ADF81C102878400602D5A9 +:10D240008DF83CE002E007208DF83C004FF000082C +:10D250000320CDE902081E9BCDF810801D98019394 +:10D26000A6F1030B00901FFA8BF342461B9800F0C7 +:10D2700044FD8DF818008DF83C80297849060DD5BD +:10D280002088C00506D5208BBDF81C10884201D12E +:10D29000C4F8248040468DF81880E3E0832801D14B +:10D2A0004FF0020A4FF48070ADF85000BDF81C003A +:10D2B0002083A4F820B01E986062032060841321AC +:10D2C000CDE0052EFFF4EFADB5F80110ADF81C1060 +:10D2D000A28F6AB3A2F57F43FE3B29D008228DF8C6 +:10D2E0003C2000BF4FF0000B0523CDE9023BDDF8E9 +:10D2F00078C0CDF810B01D9A80B2CDF804C040F4CB +:10D3000000430092B5F803201B9800F0F6FC8DF85E +:10D310003CB04FF400718DF81800ADF85010832820 +:10D3200010D0F8B1A18FA1F57F40FE3807D0DCE026 +:10D330000B228DF83C204FF6FE72A287D2E7A4F8AC +:10D340003CB0D2E000942B4631461E9A1B98FFF762 +:10D3500084FB8DF8180008B183284BD1BDF81C0060 +:10D36000208353E700942B4631461E9A1B98FFF703 +:10D3700074FB8DF81800E8BBE18FA06B0844831D97 +:10D380008DE888034388828801881B98FFF767FC33 +:10D39000824668E095F80180022E70D15FEA0800AD +:10D3A00002D0B8F1010F6AD109208DF83C0007A81E +:10D3B00000908DF840804346002221461B98FFF7DD +:10D3C00030FC8DF842004FF0000B8DF843B050B99F +:10D3D000B8F1010F12D0B8F1000F04D1A18FA1F55F +:10D3E0007F40FF380AD0A08F40B18DF83CB04FF499 +:10D3F000806000E037E0ADF850000DE00FA91B9809 +:10D40000F9F708FF82468DF83CB04FF48060ADF824 +:10D410005000BAF1020F06D0FC480068C07928B16C +:10D420008DF8180027E0A4F8188044E0BAF1000F46 +:10D4300003D081208DF818003DE007A800904346F6 +:10D44000012221461B98FFF7ECFB8DF818002146BE +:10D450001B98FFF7CEFB9DF8180020B9192189F819 +:10D460000010012038809DF83C0020B10FA91B98C6 +:10D47000F9F7D0FE8246BAF1000F33D01BE018E076 +:10D480008DF818E031E02078000712D5012E10D178 +:10D490000A208DF83C00E088ADF8400003201B997D +:10D4A0000AF00CFB0820ADF85000C0E648067FF5F6 +:10D4B000FAAC4FF0040A2088BDF8501008432080D1 +:10D4C000BDF8500080050BD5A18FA1F57F40FE3837 +:10D4D00006D11E98E06228982063A6864FF0030AC2 +:10D4E0005046A5E49DF8180078B1012089F80000A5 +:10D4F000297889F80110BDF81C10A9F802109DF8D0 +:10D50000181089F80410052038802088BDF85010C4 +:10D5100088432080E4E72DE9FF4F8846087895B0DE +:10D52000012181404FF20900249C0140ADF82010F8 +:10D530002088DDF88890A0F57F424FF0000AFF3A7E +:10D5400006D039B1000705D5012019B0BDE8F08F2C +:10D550000820FAE7239E4FF0000B0EA886F800B0D3 +:10D5600018995D460988ADF83410A8498DF81CB0AB +:10D57000179A0A718DF838B0086098F800000128F1 +:10D580003BD0022809D003286FD1307820F03F002B +:10D590001D303070B8F80400E08098F800100320C7 +:10D5A000022904D1317821F03F011B31317094F808 +:10D5B0004610090759D505ABB9F1000F13D000216A +:10D5C00002AA82E80B000720CDE90009BDF834006B +:10D5D000B8F80410C01E83B20022159800F0EFFDC9 +:10D5E0000028D1D101E0F11CEAE7B8F80400A6F860 +:10D5F0000100BDF81400C01C04E198F805108DF876 +:10D600001C1098F80400012806D04FF4007A022874 +:10D610002CD00328B8D16CE12188B8F8080011F4A7 +:10D620000061ADF8201020D017281CD3B4F84010AA +:10D63000814218D3B4F84410172901D3814212D182 +:10D64000317821F03F01C91C3170A6F80100032197 +:10D65000ADF83410A4F8440094F8460020F002001D +:10D6600084F8460065E105257EE177E1208808F130 +:10D67000080700F4FE60ADF8200010F0F00F1BD09A +:10D6800010F0C00F03D03888228B9042EBD199B9AB +:10D69000B878C00710D0B9680720CDE902B1CDF83D +:10D6A00004B00090CDF810B0FB88BA88398815987E +:10D6B00000F023FB0028D6D12398BDF82010401C91 +:10D6C00080294ED006DC10290DD020290BD040290E +:10D6D00087D124E0B1F5807F6ED051457ED0B1F581 +:10D6E000806F97D1DEE0C80601D5082000E0102049 +:10D6F00082460DA907AA0520CDE902218DF8380040 +:10D70000ADF83CB0CDE9049608A93888CDE9000110 +:10D710005346072221461598FFF7B8F8A8E09DF870 +:10D720001C2001214FF00A0A002A9BD105ABB9F158 +:10D73000000F00D00020CDE902100720CDE900093C +:10D74000BDF834000493401E83B2218B002215984B +:10D7500000F035FD8DF81C000B203070BDF8140072 +:10D7600020E09DF81C2001214FF00C0A002A22D154 +:10D7700013ABB9F1000F00D00020CDE90210072053 +:10D78000CDE900090493BDF83400228C401E83B219 +:10D79000218B159800F013FD8DF81C000D203070C2 +:10D7A000BDF84C00401CADF8340005208DF8380061 +:10D7B000208BADF83C00BCE03888218B88427FF498 +:10D7C00052AF9DF81C004FF0120A00281CD1606A6D +:10D7D000A8B1B878C0073FF446AF00E018E0BA68D7 +:10D7E0000720CDE902B2CDF804B00090CDF810B01A +:10D7F000FB88BA88159800F080FA8DF81C00132079 +:10D8000030700120ADF8340093E00000600000208B +:10D810003988208B8142D2D19DF81C004FF0160A26 +:10D820000028A06B08D0E0B34FF6FF7000215F46E0 +:10D83000ADF808B0019027E068B1B978C907BED14A +:10D84000E18F0DAB0844821D03968DE80C024388DE +:10D850008288018809E0B878C007BCD0BA680DABEF +:10D8600003968DE80C02BB88FA881598FFF7F7F944 +:10D8700005005ED0072D72D076E0019005AA02A9BE +:10D880002046FFF72DF90146E28FBDF808008242DD +:10D8900001D00029F1D0E08FA16B084407800198E6 +:10D8A000E08746E09DF81C004FF0180A40B1208B3D +:10D8B000C8B13888208321461598FFF79AF938E0D7 +:10D8C00004F118000090237E012221461598FFF7ED +:10D8D000A8F98DF81C000028EDD119203070012026 +:10D8E000ADF83400E7E7052521461598FFF781F9E3 +:10D8F0003AE0208800F40070ADF8200050452DD1AA +:10D90000A08FA0F57F41FE3901D006252CE0D8F884 +:10D9100008004FF0160A48B1A063B8F80C10A187B0 +:10D920004FF6FF71E187A0F800B002E04FF6FF70FC +:10D93000A087BDF8200030F47F611AD07823002240 +:10D94000032015990AF010F898F80000207120883B +:10D95000BDF82010084320800EE000E00725208855 +:10D96000BDF8201088432080208810F47F6F1CD0E1 +:10D970003AE02188814321809DF8380020B10EA92A +:10D980001598F9F747FC05469DF81C000028EBD0D8 +:10D9900086F801A001203070208B70809DF81C005B +:10D9A00030710520ADF83400DEE7A18EE1B11898A2 +:10D9B0000DAB0088ADF834002398CDE90304CDE920 +:10D9C0000139206B0090E36A179A1598FFF700FA67 +:10D9D000054601208DF838000EA91598F9F71AFCB4 +:10D9E00000B10546A4F834B094F8460040070AD5C3 +:10D9F0002046FFF7A4F910F03E0F04D114F8460FAB +:10DA000020F0040020701898BDF8341001802846DA +:10DA10009BE500B585B0032806D102208DF80000F3 +:10DA200088B26946F9F7F6FB05B000BD10B5384C71 +:10DA30000B782268012B02D0022B2AD111E0137837 +:10DA40000BB1052B01D10423137023688A889A80B7 +:10DA50002268CB88D38022680B8913814989518140 +:10DA60000DE08B8893802268CB88D38022680B8955 +:10DA700013814B8953818B899381096911612168D5 +:10DA8000F9F7C8FB226800210228117003D0002892 +:10DA900000D0812010BD832010BD806B002800D0F5 +:10DAA000012070478178012909D10088B0F5205FF5 +:10DAB00003D042F60101884201D1002070470720BF +:10DAC0007047F0B587B0002415460E460746ADF8FE +:10DAD000184011E005980088288005980194811D60 +:10DAE000CDE902410721049400918388428801888E +:10DAF000384600F002F930B905AA06A93046FEF70B +:10DB0000EFFF0028E6D00A2800D1002007B0F0BDC2 +:10DB10006000002010B58B7883B102789A4205D15D +:10DB20000B885BB102E08B79091D4BB18B789A426F +:10DB3000F9D1B0F801300C88A342F4D1002010BD17 +:10DB4000812010BD072826D012B1012A27D103E079 +:10DB5000497801F0070102E04978C1F3C2010529C3 +:10DB60001DD2DFE801F00318080C12000AB10320EF +:10DB700070470220704704280DD250B10DE00528EF +:10DB800009D2801E022808D303E0062803D0032808 +:10DB900003D005207047002070470F207047812078 +:10DBA0007047C0B282060BD4000607D5FA48807AC7 +:10DBB0004143C01D01EBD00080B27047084670475A +:10DBC0000020704770B513880B800B781C0625D594 +:10DBD000F14CA47A844204D843F01000087000206D +:10DBE00070BD956800F0070605EBD0052D78F5406F +:10DBF00065F304130B701378D17803F0030341EA43 +:10DC0000032140F20123B1FBF3F503FB15119268E8 +:10DC1000E41D00FB012000EBD40070BD906870BDD6 +:10DC200037B51446BDF804101180117841F0040195 +:10DC300011709DF804100A061ED5D74AA368C1F3D7 +:10DC40000011927A824208D8FE2811D1D21DD20842 +:10DC50004942184600F01BFC0AE003EBD00200F03A +:10DC60000703012510789D40A84399400843107090 +:10DC7000207820F0100020703EBD2DE9F0410746CD +:10DC8000C81C0E4620F00300B04202D08620BDE83A +:10DC9000F081C14D002034462E60AF802881AA72E9 +:10DCA000E8801AE0E988491CE980810614D4E1780B +:10DCB00000F0030041EA002040F20121B0FBF1F244 +:10DCC00001FB12012068FFF76CFF2989084480B22C +:10DCD0002881381A3044A0600C3420784107E1D400 +:10DCE0000020D4E7AC4801220189C08800EB400045 +:10DCF00002EB8000084480B270472DE9FF4F89B0E5 +:10DD00001646DDE9168A0F46994623F44045084633 +:10DD100000F054FB040002D02078400703D4012017 +:10DD20000DB0BDE8F08F099806F086F802902078D3 +:10DD3000000606D59848817A0298814201D887204A +:10DD4000EEE7224601A90298FFF73CFF8346002038 +:10DD50008DF80C004046B8F1070F1AD00122214679 +:10DD6000FFF7F0FE0028DBD12078400611D5022015 +:10DD70008DF80C00ADF81070BDF80400ADF812007D +:10DD8000ADF814601898ADF81650CDF81CA0ADF899 +:10DD900018005FEA094004D500252E46A846012751 +:10DDA0000CE02178E07801F0030140EA012040F224 +:10DDB0000121B0FBF1F2804601FB12875FEA494086 +:10DDC00009D5B84507D1A178207901F0030140EACF +:10DDD0000120B04201D3BE4201D90720A0E7A81913 +:10DDE0001FFA80F9B94501D90D2099E79DF80C007B +:10DDF00028B103A90998F9F70BFA002890D1B84582 +:10DE000007D1A0784FEA192161F30100A07084F8CE +:10DE100004901A9800B10580199850EA0A0027D09A +:10DE2000199830B10BEB06002A46199900F005FB52 +:10DE30000EE00BEB06085746189E099806F067F9A6 +:10DE40002B46F61DB5B239464246009505F053FD06 +:10DE5000224601A90298FFF7B5FE9DF8040022466C +:10DE600020F010008DF80400DDE90110FFF7D8FE66 +:10DE7000002055E72DE9FF4FDFF81C91824685B061 +:10DE8000B9F80610D9F8000001EB410100EB81045C +:10DE900040F20120B2FBF0F1174600FB1175DDE9FD +:10DEA000138B4E4629460698FFF77BFE0346FFF785 +:10DEB00019FF1844B1880C30884202D9842009B077 +:10DEC0002FE70698C6B2300603D5B00601D5062066 +:10DED000F5E7B9F80620521C92B2A9F80620BBF16A +:10DEE000000F01D0ABF80020B00602D5C4F80880BE +:10DEF0000AE0B9F808201A4492B2A9F80820D9F823 +:10DF00000000891A0844A0602246FE200699FFF707 +:10DF100087FEE77025712078390A61F301002A0A2B +:10DF2000A17840F0040062F30101A17020709AF81A +:10DF300002006071BAF80000E08000252573300609 +:10DF400002D599F80A7000E00127B00601D54FF01C +:10DF500000084E4600244FF007090FE0CDE90258B3 +:10DF60000195CDF800900495F1882046129B089AFF +:10DF7000FFF7C3FE0028A2D1641CE4B2BC42EDD37B +:10DF800000209CE700B5FFF7ADFE03490C308A88FE +:10DF9000904203D9842000BD00060020CA8808688A +:10DFA00002EB420300EB8300521C037823F00403CE +:10DFB0000370CA80002101730846ECE72DE9F047A1 +:10DFC000804600F0FBF9070005D000264446F74DD7 +:10DFD00040F2012916E00120BDE8F087204600F05C +:10DFE000EDF90278C17802F0030241EA0222B2FBA5 +:10DFF000F9F309FB13210068FFF7D3FD3044641CDB +:10E0000086B2A4B2E988601E8142E7DCA8F1010073 +:10E01000E8802889801B288100203870DCE710B553 +:10E02000144631B1491E218005F006FFA070002082 +:10E0300010BD012010BD70B50446DC48C1880368DE +:10E0400001E0401C20802088884207D200EB40027B +:10E0500013EB820202D015786D07F2D580B28842A8 +:10E0600016D2AAB15079A072D08820819178107907 +:10E0700001F0030140EA0120A081A078E11CFFF734 +:10E08000A1FD20612088401C2080E080002070BD20 +:10E090000A2070BD0121018270472DE9FF4F85B034 +:10E0A0004FF6FF798246A3F8009048681E460D4659 +:10E0B00080788DF8060048680088ADF804000020DC +:10E0C0008DF80A00088A0C88A04200D304462C82EE +:10E0D00051E03878400708D4641C288AA4B2401C58 +:10E0E000288208F10100C0B246E0288A401C28823C +:10E0F000781D6968FFF70EFDD8BB3188494501D10D +:10E10000601E30803188A1EB080030806888A04212 +:10E1100038D3B878397900F0030041EA002801A922 +:10E12000781DFFF7F7FC20BB298949452ED0002236 +:10E1300039460798FFF706FDD8B92989414518D116 +:10E14000E9680391B5F80AC0D7F808B05046CDF891 +:10E1500000C005F0DCFFDDF800C05A460CF1070CEA +:10E160001FFA8CFC43460399CDF800C005F08DFBE7 +:10E1700060B1641CA4B200208046204600F01EF965 +:10E180000700A6D1641E2C820A2098E67480787954 +:10E19000B071F888B0803978F87801F0030140EA6E +:10E1A00001207081A6F80C80504605F045FE3A46E5 +:10E1B00006F10801FFF706FD306100207FE62DE93A +:10E1C000FF4F87B081461C469246DDF860B0DDF80F +:10E1D0005480089800F0F2F8050002D02878400733 +:10E1E00002D401200BB09CE5484605F025FE2978B5 +:10E1F000090605D56D49897A814201D88720F1E762 +:10E20000CAF309062A4601A9FFF7DCFC0746149861 +:10E2100007281CD000222946FFF794FC0028E1D1F2 +:10E220002878400613D501208DF808000898ADF82D +:10E230000C00BDF80400ADF80E00ADF81060ADF8AC +:10E24000124002A94846F8F7E3FF0028CAD129780E +:10E25000E87801F0030140EA0121AA78287902F068 +:10E26000030240EA0220564507D0B1F5007F04D9E9 +:10E27000611E814201DD0B20B4E7864201D90720EF +:10E28000B0E7801B85B2A54200D92546BBF1000F3F +:10E2900001D0ABF80050179818B1B9192A4600F010 +:10E2A000CCF8B8F1000F0DD03E4448464446169FC6 +:10E2B00005F03FFF2146FF1DBCB232462B460094BD +:10E2C00005F04DFB00208DE72DE9F04107461D4686 +:10E2D0001646084600F072F8040002D02078400785 +:10E2E00001D40120D3E4384605F0A6FD21780906C3 +:10E2F00005D52E49897A814201D88720C7E4224674 +:10E300003146FFF75FFC65B12178E07801F0030149 +:10E3100040EA0120B0F5007F01D8012000E0002094 +:10E3200028700020B3E42DE9F04107461D4616464B +:10E33000084600F043F8040002D02078400701D4DA +:10E340000120A4E4384605F077FD2178090605D5BB +:10E350001649897A814201D8872098E422463146BD +:10E36000FFF75EFCFF2D14D02178E07801F0030266 +:10E3700040EA022040F20122B0FBF2F302FB13005C +:10E3800015B900F2012080B2E070000A60F30101CB +:10E39000217000207BE410B50C4600F00FF810B19E +:10E3A0000178490704D4012010BD000000060020B8 +:10E3B000C18821804079A0700020F5E70749CA880C +:10E3C000824209D340B1096800EB40006FF00B02B4 +:10E3D00002EB8000084470470020704700060020D0 +:10E3E00070B504460D4621462B460AB9002070BD83 +:10E3F00001E0491C5B1C501E021E03D008781E78E9 +:10E40000B042F6D008781E78801BF0E730B50C4695 +:10E4100001462346051B954206D202E0521E9D5C32 +:10E420008D54002AFAD107E004E01D780D70491CD4 +:10E430005B1C521E002AF8D130BDF0B50E460146D5 +:10E44000334680EA030404F00304B4B906E002B9D9 +:10E45000F0BD13F8017B01F8017B521E01F00307A8 +:10E46000002FF4D10C461D4602E080CD80C4121F5F +:10E47000042AFAD221462B4600BF04E013F8014BD0 +:10E4800001F8014B521E002AF8D100BFE0E7F0B5B9 +:10E490000C460146E6B204E002B9F0BD01F8016B9A +:10E4A000521E01F00307002FF6D10B46E5B245EAF4 +:10E4B000052545EA054501E020C3121F042AFBD2C9 +:10E4C000194602E001F8016B521E002AFAD100BF82 +:10E4D000E3E7000010B509F0A0FDF4F7F9F909F041 +:10E4E000E7FBBDE8104009F0AFBC302834BF012085 +:10E4F00000207047202834BF4FF0A0420C4A01236F +:10E5000000F01F0003FA00F0002914BFC2F80C0548 +:10E51000C2F808057047202834BF4FF0A0410449D5 +:10E5200000F01F00012202FA00F0C1F81805704740 +:10E530000003005070B50346002002466FF02F051F +:10E540000EE09C5CA4F130060A2E02D34FF0FF309F +:10E5500070BD00EB800005EB4000521C2044D2B29D +:10E560008A42EED370BD30B50A230BE0B0FBF3F462 +:10E5700003FB1404B0FBF3F08D183034521E05F881 +:10E58000014CD2B2002AF1D130BD30B500234FF694 +:10E59000FF7510E0040A44EA002084B2C85C6040C1 +:10E5A000C0F30314604005EA00344440E0B25B1C51 +:10E5B00084EA40109BB29342ECD330BD2DE9F04188 +:10E5C000FE4B0026012793F864501C7893F868C02E +:10E5D000B8B183F89140A3F8921083F8902083F8A3 +:10E5E0008E70BCF1000F0CBF83F8946083F89450D8 +:10E5F000F3488068008805F08AFDBDE8F04105F029 +:10E6000021BA4FF6FF7083F89140A3F8920083F887 +:10E61000902083F88E70BCF1000F14BF83F89450E3 +:10E6200083F89460BDE8F0812DE9F041E44D29685C +:10E6300091F89C200024012A23D091F89620012AE9 +:10E6400030D091F86C301422DC4E0127012B32D0EF +:10E6500091F88E30012B4FD091F8A620012A1CBFD3 +:10E660000020BDE8F08144701F2200F8042B222214 +:10E67000A731FFF7E2FE286880F8A6400120BDE838 +:10E68000F08144701B220270D1F89D204260D1F8C5 +:10E69000A120826091F8A520027381F89C4001209E +:10E6A000BDE8F081447007220270D1F898204260E2 +:10E6B00081F89640E2E78046447000F8042B20225F +:10E6C0006E31FFF7BAFE88F80870286880F86C4051 +:10E6D00090F86E000028D1D1B6F87000A6F8980026 +:10E6E000A868417B86F89A1086F89670008805F035 +:10E6F0000EFD05F0B6F9C1E791F86C30012B0BD097 +:10E70000447017220270D1F890204260B1F8942032 +:10E71000028181F88E40B1E78046447000F8042BF6 +:10E7200020226E31FFF789FE88F80870286880F88B +:10E730006C4090F86E000028A0D1CDE7A04800689A +:10E7400090F86C10002914BFB0F870004FF6FF70FD +:10E75000704770B59A4C06462068002808BFFFDF56 +:10E760000025206845706660002808BFFFDF20682C +:10E77000417800291CBFFFDF70BDCC220021FFF7CC +:10E7800086FE2068FF2101707F2180F83810132158 +:10E790004184282180F86910012180F85C1080F8FC +:10E7A00061500AF0C1F9BDE8704009F0AEBA844981 +:10E7B0000968097881420CBF012000207047804819 +:10E7C000006890F82200C0F3400070477C48006861 +:10E7D00090F8220000F0010070477948006890F836 +:10E7E0002200C0F3001070472DE9F0437448002464 +:10E7F000036893F82400B3F822C0C0F38001C0F38B +:10E800004002114400F001000844CCF3001121B390 +:10E81000BCF1100F02BF6B4931F81000BDE8F08366 +:10E82000BCF1120F18BFBCF1130F0ED0BCF1150FC5 +:10E830001EBFFFDF2046BDE8F0830021624A32F8A8 +:10E84000102010FB0120BDE8F083604A002132F85F +:10E85000102010FB0120BDE8F08393F85E2093F8B0 +:10E860005F102E264FF47A774FF014084FF04009CE +:10E87000022A04BF4AF2D745B5FBF7F510D0012AAA +:10E8800004BF4AF22F75B5FBF7F510D04AF62315F1 +:10E89000B5FBF7F5082A08BF4E4613D0042A18D056 +:10E8A0002646082A0ED0042A13D0022A49D004F1A1 +:10E8B0002806042A0FD0082A1CBF4FF01908082286 +:10E8C00004D00AE04FF0140806F5A8764FF0400295 +:10E8D00003E006F5A8764FF0100218FB026212FB67 +:10E8E0000052C0EB00103A4D00EB800005EB8000B9 +:10E8F00010441CF0010F4FF4C8724FF4BF7504BFF1 +:10E90000CCF34006002E65D0CCF3400600F5A57090 +:10E91000EEB1082904BF174640260CD0042904BFD5 +:10E920002F46102607D0022907BF04F11807042636 +:10E9300004F12807082606EB860808EB86163E44F5 +:10E940001BE004F118064FF019080422C5E7082956 +:10E9500004BF164640270CD0042904BF2E461027BA +:10E9600007D0022907BF04F11806042704F128067E +:10E97000082707EB871706EB8706304400F19C0653 +:10E9800093F8690001F00C07002F08BF0020304405 +:10E9900018BF00F5416027D1082904BF164640275B +:10E9A0001BD0042904BF2E46102716D0022906BF0B +:10E9B00004F11806042704F128060CE00C060020D8 +:10E9C00068000020DC610200E4610200D461020002 +:10E9D000D4FEFFFF64E018BF0827C7EBC70707EBAB +:10E9E000470706EB4706304498301CF0010F17D05C +:10E9F000082908BF40210CD0042904BF2A46102151 +:10EA000007D0022907BF04F11802042104F12802EB +:10EA1000082101EB410303EB0111114408443BE0E1 +:10EA2000082904BF944640260CD0042904BFAC46F4 +:10EA3000102607D0022907BF04F1180C042604F1A0 +:10EA4000280C082606EB8616B3F840300CEB860C33 +:10EA50006044EB2B20D944F2552C0B3303FB0CF311 +:10EA60009B0D082907D0042902D0022905D008E00F +:10EA70002A46102108E0402106E004F11802042192 +:10EA800002E004F12802082101EB811102EB81016F +:10EA900001F5A57103FB010000F5B470BDE8F0833A +:10EAA00000F5A570082904BF944640260CD004291F +:10EAB00004BFAC46102607D0022907BF04F1180C8A +:10EAC000042604F1280C082606EB8616B3F8483015 +:10EAD0000CEB860C6044EB2BDED944F2552C0B3347 +:10EAE00003FB0CF39B0D0829C5D00429C0D00229D3 +:10EAF000C7D1C2E7FE4840F271210068806A4843EE +:10EB00007047FB48006890F83700002818BF0120C4 +:10EB1000704710B5F74C207B022818BF032808D196 +:10EB2000207D04F115010EF0E6FE08281CBF01202F +:10EB300010BD207B002816BF022800200120BDE860 +:10EB400010400AF021BDEB4908737047E849096895 +:10EB500081F8300070472DE9F047E54C2168087BCB +:10EB6000002816BF022800200120487301F10E0181 +:10EB70000AF0F4FC2168087B022816BF0328012252 +:10EB8000002281F82F204FF0080081F82D00487BEB +:10EB900001F10E034FF001064FF00007012804BFFA +:10EBA0005B7913F0C00F0AD001F10E03012804D1E4 +:10EBB000587900F0C000402801D0002000E001207A +:10EBC00081F82E00002A04BF91F8220010F0040FF3 +:10EBD00007D0087D01F115010EF08DFE216881F846 +:10EBE0002D002068476007F0BFFA2168C14D4FF043 +:10EBF0000009886095F82D000EF089FE804695F892 +:10EC00002F00002818BFB8F1000F04D095F82D0090 +:10EC10000EF0B1FC68B195F8300000281CBF95F8E3 +:10EC20002E0000281DD0697B05F10E0001290ED0B1 +:10EC300012E06E734A4605F10E0140460AF0E4FC0C +:10EC400095F82D1005F10E000EF063FF09E04079F4 +:10EC500000F0C000402831D0394605F10E000AF01E +:10EC60000BFD2068C77690F8220010F0040F08BF53 +:10EC7000BDE8F087002795F82D000EF017FD050080 +:10EC800008BFBDE8F087102102F0C2F8002818BFC5 +:10EC9000BDE8F08720683A4600F11C01C676284698 +:10ECA0000AF0B2FC206800F11C0160680FF08EF8D9 +:10ECB0006068BDE8F04701210FF0A3B80EF066FFD1 +:10ECC0004A4605F10E010AF09FFCCAE7884A12681D +:10ECD000137B0370D2F80E000860508A888070475A +:10ECE00078B584490446824E407B087332682078A8 +:10ECF00010706088ADF8000080B200F00101C0F330 +:10ED0000400341EA4301C0F3800341EA8301C0F3B9 +:10ED1000C00341EAC301C0F3001341EA0311C0F389 +:10ED2000401341EA4311C0F3801041EA801050843F +:10ED3000E07D012808BF012507D0022808BF022571 +:10ED400003D0032814BFFFDF0825306880F85E5029 +:10ED5000607E012808BF012507D0022808BF0225D0 +:10ED600003D0032814BFFFDF0825316881F85F5006 +:10ED700091F83500012829D0207B81F82400488CA7 +:10ED80001D280CBF002060688862607D81F8370014 +:10ED9000A07B002816BF0228002001200875D4F8A7 +:10EDA0000F00C1F81500B4F81300A1F81900A07EF7 +:10EDB00091F86B2060F3071281F86B20E07E012848 +:10EDC00018BF002081F83400002078BD91F85E2043 +:10EDD0000420082A08BF81F85E00082D08BF81F8CA +:10EDE0005F00C9E742480068408CC0F3001131B1B0 +:10EDF000C0F38000002804BF1F20704702E0C0F36A +:10EE0000400109B10020704710F0010F14BFEE203F +:10EE1000FF20704736480068408CC0F3001119B1DC +:10EE2000C0F3800028B102E0C0F3400008B1002028 +:10EE30007047012070472E49002209684A664B8CB2 +:10EE40001D2B0CBF81F8682081F8680070470023F3 +:10EE5000274A126882F85D30D164A2F85000012080 +:10EE600082F85D007047224A0023126882F85C3005 +:10EE7000A2F858000120516582F85C0070471C49D7 +:10EE8000096881F8360070471949096881F86100FE +:10EE900070471748006890F961007047144800688F +:10EEA00090F82200C0F3401070471148006890F8B5 +:10EEB0002200C0F3C0007047012070470C48006872 +:10EEC00090F85F00704770B509F018FE09F0F7FD83 +:10EED00009F0C0FC09F06CFD054C2068416E491C2E +:10EEE000416690F83300002558B109F01DFE03E09B +:10EEF000680000200C06002008F007FF206880F85A +:10EF000033502068457090F8391021B1BDE8704049 +:10EF100004200AF0AEBF90F86810D9B1406E81426B +:10EF200018D804200AF0A5FF206890F8220010F0FD +:10EF3000010F07D0A06843220188BDE8704001207E +:10EF4000FFF73CBBBDE8704043224FF6FF71002045 +:10EF5000FFF734BBBDE8704000200AF08ABF2DE9FE +:10EF6000F04782B00F468146FE4E4FF000083068F1 +:10EF7000458C15F0030F10D015F0010F05F00200BD +:10EF800005D0002808BF4FF0010806D004E0002893 +:10EF900018BF4FF0020800D1FFDF4FF0000A5446BF +:10EFA00015F0010F05F002000DD080B915F0040F27 +:10EFB0000DD04AF00800002F1CBF40F0010040F0C7 +:10EFC00002044DD09EE010B115F0040F0DD015F0E5 +:10EFD000070F10D015F0010F05F0020043D00028F4 +:10EFE00008BF15F0040F34D04AE0002F18BF4AF0D4 +:10EFF000090444D141E037B14AF00800044615F055 +:10F00000200F1BD07EE0316805F02002B1F84800E7 +:10F01000104308BF4AF0010474D04AF018000446B7 +:10F0200015F0200F6ED191F85E1011F00C0118BF91 +:10F030000121C94361F30000044663E0316891F89F +:10F040005E1011F00C0118BF012161F300000446AD +:10F0500058E04AF00800002F18BF40F0010451D1D9 +:10F0600040F010044EE0002818BF15F0040F07D040 +:10F07000002F18BF4AF00B0444D14AF0180441E0B5 +:10F0800015F0030F3DD115F0040F3AD077B1306879 +:10F090004AF0080490F85E0010F00C0118BF01213E +:10F0A00061F3410415F0200F24D02BE0306805F007 +:10F0B0002002B0F84810114308BF4AF0030421D0E1 +:10F0C0004AF0180415F0200F0AD000BF90F85E0037 +:10F0D00010F00C0018BF0120C04360F3410411E0A0 +:10F0E00090F85E1011F00C0118BF0121C94361F3C3 +:10F0F0000004EBE710F00C0018BF012060F30004DF +:10F1000000E0FFDF15F0400F1CD0CFB93168B1F837 +:10F110004800002804BF488C10F0010F0BD110F0FC +:10F12000020F08BF10F0200F05D115F0010F08BF26 +:10F1300015F0020F04D091F85E0010F00C0F01D111 +:10F1400044F040047068A0F800A0017821F020018C +:10F1500001704FF007010EF005FE414670680EF099 +:10F16000F8FF214670680FF000F814F0010F0CD082 +:10F170004FF006034FF000027B4970680EF0CFFF9E +:10F180003068417B70680EF02FFE14F0020F18D02B +:10F19000D6E90010B9F1000F4FF006034FF001025D +:10F1A00007D01C310EF0BBFF012170680EF029FE64 +:10F1B00007E015310EF0B3FF3068017D70680EF086 +:10F1C00020FE14F0040F18BFFFDF14F0080F19D051 +:10F1D000CDF800A03068BDF800200223B0F86A1016 +:10F1E00061F30B02ADF8002090F86B0003220109D7 +:10F1F0009DF8010061F307108DF801006946706801 +:10F200000EF08DFF012F62D13068B0F84810E1B3E5 +:10F2100090F82200C0F34000B8BB70680EF095FF74 +:10F22000401CC7B23068C7F1FF05B0F84820B0F8FD +:10F230005A10511AA942B8BF0D46AA423BD990F8BC +:10F24000220010F0010F36D144F0100421467068FE +:10F250000EF08BFFF81CC0B2ED1E284482B230685D +:10F26000B0F86A10436EC1F30B0151FA83F190F8C4 +:10F2700060303E4F1944BC460023E1FB07C31B0925 +:10F280006FF0240C03FB0C1100E020E080F860100C +:10F2900090F85F00012101F01FF90090BDF8000017 +:10F2A0009DF80210032340EA01400190042201A9C5 +:10F2B00070680EF034FF3068AAB2416C70680EF0CE +:10F2C00082FF3068B0F85A102944A0F85A1014F0A0 +:10F2D000400F06D0D6E900100123062261310EF05E +:10F2E0001EFF14F0200F18BFFFDF0020002818BFFA +:10F2F000FFDF02B0BDE8F0872DE9F043194C89B07B +:10F300002068002808BFFFDF20684178002944D129 +:10F310000178FF2941D0002680F83160A0F85A60BA +:10F32000867080F83960304609F062FB104802AD03 +:10F3300000F1240191E80E1085E80E10D0E90D10BF +:10F34000CDE9061002A809F041FB08F0BCFF2068D7 +:10F3500090F9610009F090F8064809F093F8064822 +:10F360000CE00000680000201A06002053E4B36E91 +:10F37000C8610200D0610200CD61020009F012FBF9 +:10F38000606809F038FB206890F8240010F0010F45 +:10F3900007D0252009F07EF80AE009B00C20BDE86E +:10F3A000F08310F0020F18BF262069D009F072F820 +:10F3B000206890F85E10252008F043FF206880F850 +:10F3C0002C6009F00FFB206890F85E10002009F017 +:10F3D00028F90F21052008F0F8FF206890F82E107A +:10F3E000002901BF90F82F10002990F8220010F09A +:10F3F000040F74D006F0B8FE0546206829468068E0 +:10F4000007F0AAFBDFF82884074690FBF8F008FB1A +:10F4100010704142284606F08EFB2168886097FBF9 +:10F42000F8F04A68104448600EF062FA014620681D +:10F43000426891426ED8C0E90165FE4D4FF0010867 +:10F4400095F82D000EF063FA814695F82F000127FC +:10F45000002818BFB9F1000F04D095F82D000EF068 +:10F460008AF8A0B195F8300000281CBF95F82E004E +:10F47000002824D0687B05F10E01012815D019E081 +:10F4800010F0040F14BF2720FFDF8FD190E73A461A +:10F490006F7305F10E0148460AF0B6F895F82D1085 +:10F4A00005F10E000EF035FB09E0487900F0C000D0 +:10F4B000402815D0414605F10E000AF0DDF820681D +:10F4C00090F8220010F0040F24D095F82D000EF0D3 +:10F4D000EDF805001ED0102101F09AFC40B119E0B2 +:10F4E0000EF054FB3A4605F10E010AF08DF8E6E7FE +:10F4F00020683A4600F11C01C77628460AF084F8D5 +:10F50000206800F11C0160680EF060FC0121606859 +:10F510000EF077FC2068417B0E3008F038FF206841 +:10F5200090F85C1061B3B0F85810A0F84810416D25 +:10F53000416490F82210C1F30011F1B9B0F86A00EB +:10F540000221C0F30B05ADF80050684607F0B0FF8C +:10F5500028B1BDF80000C0F30B00A84204D1BDF8EB +:10F560000000401CADF800002168BDF80000B1F8B3 +:10F570006A2060F30B02A1F86A20206880F85C60C2 +:10F58000206890F85D1039B1B0F85010A0F8401024 +:10F59000C16CC16380F85D60B0F86A10426EC1F35F +:10F5A0000B0151FA82F190F86020DFF88CC211440F +:10F5B00063460022E1FB0C3212096FF0240302FBC8 +:10F5C000031180F860100EF00CFA032160680EF051 +:10F5D00090FA216881F8330009B00020BDE8F0837B +:10F5E0009649886070472DE9F043944C83B02268B7 +:10F5F00092F831303BB1508C1D2808BFFFDF03B0BB +:10F60000BDE8F0435FE401260027F1B1054692F81A +:10F61000600008F03FFF206890F85F10FF2008F0BE +:10F6200010FE20684FF4A57190F85F20002009F0CB +:10F63000D4F8206890F8221011F0030F00F02C810C +:10F64000002D00F0238100F027B992F822108046A7 +:10F65000D07EC1F30011002956D0054660680780AE +:10F66000017821F020010170518C132937D01FDC63 +:10F67000102908BF022144D0122908BF062140D01A +:10F68000FFDF6C4D606805F10E010EF091FB697BA8 +:10F6900060680EF0A9FB2068418C1D2918BF152950 +:10F6A00063D0B0F84820416C60680EF0B6FB5CE0B7 +:10F6B000152918BF1D29E3D14FF001010EF052FBAF +:10F6C0006068017841F020010170216885B11C312A +:10F6D0000EF07CFB012160680EF093FBD1E7002166 +:10F6E0000EF040FB6068017841F020010170C8E72E +:10F6F00015310EF06BFB2068017D60680EF081FB18 +:10F70000BFE70EF02FFBBCE70021FFF728FC606885 +:10F71000C17811F03F0F28D0017911F0100F24D0DB +:10F720000EF01EFB2368024693F82410C1F38000FC +:10F73000C1F3400C604401F00101084493F82C101F +:10F74000C1F3800CC1F34005AC4401F001016144F8 +:10F75000401AC1B293F85E0000F0BEFE0090032391 +:10F760000422694660680EF0DAFC2068002590F8F3 +:10F77000241090F82C0021EA000212F0010F18BFAB +:10F7800001250ED111F0020F04D010F0020F08BFB6 +:10F79000022506D011F0040F03D010F0040F08BFAB +:10F7A0000425B8F1000F2BD0012D1BD0022D08BF6E +:10F7B00026201BD0042D14BFFFDF272016D0206881 +:10F7C00090F85E10252008F03CFD206890F822108B +:10F7D000C1F3001169B101224FF49671002008F0C5 +:10F7E000FCFF0DE0252008F055FEE8E708F052FE8A +:10F7F000E5E790F85E204FF49671002008F0EDFFE9 +:10F80000206890F82C10294380F82C1090F82420C0 +:10F8100032EA01011CD04670418C13292BD026DC22 +:10F82000102904BF03B0BDE8F083122923D007E0FC +:10F8300040420F000C06002053E4B36E6800002025 +:10F84000C1F30010002818BFFFDF03B0BDE8F0834C +:10F85000418C1D2908BF80F82C70DCD0C1F3001149 +:10F86000002914BF80F8316080F83170D3E7152982 +:10F8700018BF1D29DBD190F85E2003B04FF00101C5 +:10F88000BDE8F043084609F094B900BF90F85F2046 +:10F890000121084609F08DF92168002DC87E7CD031 +:10F8A0004A8C3D46C2F34000002808BF47F00805D7 +:10F8B00012F0400F18BF45F04005002819BFD1F8DD +:10F8C0003C90B1F84080D1F84490B1F8488060682D +:10F8D000072107800EF046FA002160680EF039FC1F +:10F8E000294660680EF041FC15F0080F17D020681B +:10F8F000BDF800100223B0F86A2062F30B01ADF8E6 +:10F90000001090F86B00032201099DF8010061F3DB +:10F9100007108DF80100694660680EF000FC606811 +:10F920000EF0DCFA2168C0F1FE00B1F85A20A8EB15 +:10F9300002018142A8BF0146CFB2D019404544D24E +:10F9400045F0100160680EF010FC60680EF0C6FA19 +:10F950002168C0F1FE00B1F85A10A8EB0101814204 +:10F96000A8BF0146CFB260680EF0EFFB3844421CDE +:10F970002068B0F86A10436EC1F30B0151FA83F1AD +:10F9800090F86030FE4D1944AC460023E1FB05C3FE +:10F990004FEA131C6FF0240300E03CE00CFB031162 +:10F9A00080F8601090F85F00012100F095FD009054 +:10F9B000BDF800009DF80210032340EA01400190C9 +:10F9C000042201A960680EF0AAFB216891F82200C8 +:10F9D00010F0400F05D001230622613160680EF05F +:10F9E0009EFB20683A46B0F85A0000EB09016068B7 +:10F9F0000EF0E9FB2068B0F85A103944A0F85A100C +:10FA000009F0BFFC002818BFFFDF20684670867031 +:10FA100003B0BDE8F0830121FFF7A1FAF0E7D94870 +:10FA200010B50068417841B90078FF2805D0002161 +:10FA30000846FFF7D8FD002010BD09F05FF809F077 +:10FA40003EF808F007FF08F0B3FF0C2010BD2DE9C9 +:10FA5000F041CC4D0446174628680E4690F86C00DD +:10FA6000002818BFFFDF2868002F80F86E7018BFCD +:10FA7000BDE8F0812188A0F870106188A0F8861098 +:10FA8000A188A0F88810E188A0F88A1094F888115D +:10FA900080F88C1090F82F10002749B1427B00F1BC +:10FAA0000E01012A04D1497901F0C001402935D065 +:10FAB00090F8301041B1427B00F10E01012A04BFE1 +:10FAC000497911F0C00F29D000F17A00F3F794FAC8 +:10FAD0006868FF2E0178C1F380116176D0F80310B9 +:10FAE000C4F81A10B0F80700E08328681ED0C0F8E8 +:10FAF0008010E18BA0F8841000F17402511E304692 +:10FB00000DF014FF002808BFFFDF286890F873107D +:10FB100041F0020180F87310BDE8F081D0F80E10BA +:10FB2000C0F87A10418AA0F87E10D1E7C0F8807042 +:10FB3000A0F88470617E80F87310D4F81A104167C1 +:10FB4000E18BA0F87810BDE8F08170B58D4C0125EF +:10FB5000206890F82200C0F3C00038B13C22FF2199 +:10FB6000A068FFF774FF206880F86C50206890F858 +:10FB7000220010F0010F1CBFA06801884FF03C026A +:10FB800012BF01204FF6FF710020FEF717FD20681D +:10FB900080F8395070BD7B49096881F832007047A0 +:10FBA0002DE9F041774C0026206841780127354641 +:10FBB000012906D0022901D003297DD0FFDFBDE84D +:10FBC000F081817802250029418C46D0C1F34002A2 +:10FBD000002A08BF11F0010F6FD090F85F204FF09E +:10FBE00001014FF0000008F0E4FF216891F82200C5 +:10FBF000C0F34000002814BF0C20222091F85F10B1 +:10FC000008F01FFB2068457090F8330058B108F0E9 +:10FC100068F8206890F85F0010F00C0F0CBF4020CF +:10FC2000452008F077FF206890F83400002818BFBE +:10FC300008F08FFF216891F85F0091F8691010F0CB +:10FC40000C0F08BF0021962008F0F6FE09F090FB8B +:10FC5000002818BFFFDFBDE8F081C1F3001282B1B8 +:10FC600010293FD090F8330020B108F03AF8402036 +:10FC700008F050FF206890F8221011F0040F36D0E1 +:10FC800043E090F8242090F82C309A422AD1B0F822 +:10FC90004800002808BF11F0010F05D111F0020F34 +:10FCA00008BF11F0200F6FD04FF001014FF000009E +:10FCB000FFF799FC206801E041E035E0418C11F04C +:10FCC000010F04BFC1F34001002907D1B0F85A1059 +:10FCD000B0F84820914218BFBDE8F08180F831703B +:10FCE000BDE8F081BDE8F041002101207BE490F8FF +:10FCF0003710012914BF0329102646F00E0190F891 +:10FD00005E204FF0000008F054FF206890F83400A7 +:10FD1000002818BF08F01DFF0021962008F08CFE77 +:10FD200020684570BDE8F081B0F85A10B0F848007E +:10FD3000814242D0BDE8F0410121084653E4817878 +:10FD4000D9B1418C11F0010F22D080F86C7090F87D +:10FD50006E20B0F870100120FEF730FC206845706E +:10FD600008F0CCFE08F0ABFE08F074FD08F020FEB1 +:10FD7000BDE8F04103200AF07CB88178012004E05E +:10FD800053E4B36E6800002017E0BDE8F0412AE4B8 +:10FD900011F0020F04BFFFDFBDE8F081B0F85A1088 +:10FDA000B0F84000814208D001210846FFF71BFC53 +:10FDB000216803204870BDE8F081BDE8F041FFF7FD +:10FDC00082B8FFF780B810B5FE4C206890F8341068 +:10FDD00049B1383008F0CCFE18B921687F2081F88D +:10FDE000380008F0ACFE206890F8330018B108F035 +:10FDF0009BFE07F08AFF0AF02EFCA8B1206890F85D +:10FE00002210C1F3001179B14078022818BFFFDF3A +:10FE100000210120FFF7E7FB2068417800291EBF81 +:10FE200040780128FFDF10BDBDE81040FFF74BB858 +:10FE30002DE9F047E34C0F4680462168B8F1030FE7 +:10FE4000488C08BFC0F3400508D000F0010591F8C8 +:10FE50003200002818BF4FF0010901D14FF000090E +:10FE600008F00CFB0646B8F1030F0CBF4FF0020878 +:10FE70004FF0010835EA090008BFBDE8F0872068A7 +:10FE800090F8330068B10DF08FFD38700146FF28FF +:10FE900007D06068C01C0DF060FD38780DF091FD52 +:10FEA000064360680178C1F3801221680B7D9A4295 +:10FEB00008D10622C01C1531FEF792FA002808BFAF +:10FEC000012000D000203978FF2906D0C8B9206869 +:10FED00090F82D00884216D113E0A0B1616811F8A6 +:10FEE000030BC0F380100DF006FD05460DF061FE1A +:10FEF00038B128460DF0DAFB18B1102100F088FF68 +:10FF000008B1012000E00020216891F8221011F0D2 +:10FF1000040F01D0F0B11AE0CEB9AB4890F8370029 +:10FF2000002818BF404515D1616811F8030BC0F3D4 +:10FF300080100DF0E0FC04460DF03BFE38B1204689 +:10FF40000DF0B4FB18B1102100F062FF10B10120D8 +:10FF5000BDE8F0870020BDE8F0872DE9F04F994D0E +:10FF6000044683B0286800264078022818BFFFDFC7 +:10FF700028684FF07F0B90F8341049B1383008F002 +:10FF8000F7FD002804BF286880F838B008F0D7FDD6 +:10FF900068680DF009FF8046002C00F0458208F0EB +:10FFA00010FA002800F04082012400274FF0FF09DA +:10FFB000B8F1050F1ED1686890F8240000F01F000A +:10FFC000102817D9286890F8360098B18DF800905D +:10FFD00069460520FFF72CFF002800F025822868DD +:10FFE00080F8A64069682222A730C91CFEF725FACE +:10FFF00000F01ABA68680EF062F8002800F0148267 +:020000040001F9 +:100000004046DFF8C4814FF0030A062880F02182C1 +:10001000DFE800F0FCFCFC03FCFB8DF80090694677 +:100020000320FFF705FF002800F0F180296891F810 +:10003000340010B191F89C00D8B12868817801296A +:100040004DD06868042107800DF08CFE08F10E0188 +:1000500068680DF0ADFE98F80D1068680DF0C4FEEC +:100060002868B0F84020C16B68680DF0FAFE00F017 +:1000700063B99DF8000081F89C400A7881F89D20C2 +:10008000FF280FD001F19F029E310DF04FFC002898 +:1000900008BFFFDF286890F89E1041F0020180F849 +:1000A0009E100DE068680278C2F3801281F89E20ED +:1000B000D0F80320C1F89F20B0F80700A1F8A300F2 +:1000C000286800F1A50490F838007F2808BFFFDFFA +:1000D000286890F83810217080F838B0ADE790F8B3 +:1000E00022000721C0F3801938480479686869F351 +:1000F000861407800DF036FE002168680EF029F89E +:10010000214668680EF031F80623002208F10E013E +:1001100068680EF004F82868417B68680DF064FE9A +:1001200068680DF0DBFE2968B1F84020C0F1FE01DF +:100130008A42B8BF1146CFB2BA423CD9F81EC7B204 +:1001400044F0100B594668680EF00FF868680DF01F +:10015000FCFF384400F101082868B0F86A10426ECC +:10016000C1F30B0151FA82F190F86020184C0A4457 +:10017000A4460023E2FB04C319096FF0240301FB2A +:10018000032180F8601090F85F004246012100F0E2 +:10019000A3F90190BDF804009DF80610032340EA7E +:1001A00001400290042202A968680DF0B8FF594688 +:1001B00068680DF0DAFFB9F1000F0FD0D5E9001033 +:1001C000012307E0680000200C060020C86102003F +:1001D00053E4B36E062261310DF0A1FF28683A4660 +:1001E000C16B68680DF0EFFF2868A0F85A70B0F88E +:1001F00040108F420CBF0121002180F8311009F01E +:10020000C0F8002818BFFFDF96E007E021E128686A +:100210008078002840F00A8100F006B98DF800903F +:1002200068680178C1F38019D0F803100191B0F823 +:100230000700ADF8080069460520FFF7F9FD002822 +:1002400028687DD0817800297CD090F85FB0D5E90E +:100250000104D0F80F10C4F80E10B0F8131061822A +:10026000417D2175817D6175B0F81710E182B0F88C +:1002700019106180B0F81B10A180B0F81D10E1804A +:1002800000F11F0104F1080015F085FE686890F880 +:10029000241001F01F01217690F82400400984F811 +:1002A000880184F864B084F865B01BF00C0F0CBFB3 +:1002B0000021012104F130000EF0ABF92868002282 +:1002C00090F8691084F8661090F8610084F867006F +:1002D0009DF80010A868FFF7BAFB022009F0C9FDDD +:1002E000B2480DF1040B08210468686807800DF01E +:1002F00039FD002168680DF02CFF214668680DF07B +:1003000034FF0623002208F10E0168680DF007FF94 +:100310002868417B68680DF067FD494668680DF004 +:1003200070FD06230122594668680DF0F8FE09F0B9 +:1003300028F8002818BFFFDF286880F801A077E0C0 +:100340006DE0FFE76868D5F808804FF00109027892 +:1003500098F80D10C2F34012114088F80D10D0F833 +:100360000F10C8F80E10B0F81310A8F81210417D45 +:1003700088F81410817D88F81510B0F81710A8F8C7 +:100380001610B0F81910A8F80210B0F81B10A8F851 +:100390000410B0F81D10A8F8061000F11F0108F1B4 +:1003A000080015F0F8FD686890F8241001F01F01AE +:1003B00088F8181090F824000021400988F8880176 +:1003C00088F8649088F8659008F130000EF021F903 +:1003D0002868002290F8691088F8661090F861008B +:1003E00088F867009DF80010A868FFF730FB2868C0 +:1003F00080F86C4090F86E20B0F870100120FEF785 +:10040000DDF82868477008F079FB08F058FB08F021 +:1004100021FA08F0CDFA012009F02BFD08E090F850 +:100420002200C0F3001008B1012601E0FEF74BFDE9 +:10043000286890F8330018B108F076FB07F065FCE7 +:1004400096B10AF008F960B100210120FFF7CBF85E +:1004500013E0286890F82200C0F300100028E5D0CF +:10046000E2E7FEF730FD08E028688178012904D131 +:1004700090F85F10FF2007F0E4FE2868417800291B +:1004800019BF4178012903B0BDE8F08F40780328F7 +:1004900018BFFFDF03B0BDE8F08F70B5444C0646CF +:1004A0000D462068807858B107F0F2FD21680346B8 +:1004B000304691F85F202946BDE870400AF085BAC1 +:1004C00007F0E6FD21680346304691F85E20294694 +:1004D000BDE870400AF079BA78B50C460021009169 +:1004E000082804BF4FF4C87040210DD0042804BF71 +:1004F0004FF4BF70102107D0022807BF01F1180088 +:10050000042101F128000821521D02FB01062848A0 +:100510009DF80010006890F8602062F3050141F03A +:1005200040058DF8005090F85F00012829D002287E +:100530002ED004281CBF0828FFDF2FD025F0800014 +:100540008DF80000C4EB041000EB80004FF01E019A +:1005500001EB800006FB04041648844228BFFFDF3D +:100560001548A0FB0410BDF80110000960F30C0150 +:10057000ADF80110BDF800009DF8021040EA0140FE +:1005800078BD9DF8020020F0E0008DF80200D5E76C +:100590009DF8020020F0E000203004E09DF8020009 +:1005A00020F0E00040308DF80200C7E7C86102008B +:1005B00068000020C4BF0300898888880023C383A3 +:1005C000428401EBC202521EB2FBF1F1018470477A +:1005D0002DE9F04104460026D9B3552333224FF4C8 +:1005E000FA4501297DD0022900F01481032918BFA2 +:1005F000BDE8F08104F17001207B00F01F00207342 +:1006000084F889605FF0000004EB000C9CF808C0DF +:1006100003EA5C05ACEB050C0CF0FF0C0CF03305A9 +:1006200002EA9C0CAC440D180CEB1C1C0CF00F0CDB +:1006300085F814C04D7E401CAC44C0B281F819C08E +:100640000528E1D30CF0FF00252898BFBDE8F08114 +:10065000DCE0FFE704F17005802200212846FDF769 +:1006600016FFAE71EE712E736E73EE732E746E7193 +:10067000AE76EE76212085F84000492085F84100CD +:10068000FE2085F874002588702200212046FDF7A1 +:10069000FEFE2580012584F8645084F865502820EA +:1006A00084F86600002104F130000DF0B2FF1B2237 +:1006B000A4F84E20A4F85020A4F85220A4F8542006 +:1006C0004FF4A470A4F85600A4F8580065734FF4D2 +:1006D00048606080A4F8F060A4F8F260A4F8F460C8 +:1006E00000E023E0A4F8F660A4F8F86084F8FA606B +:1006F00084F8FD60A4F8066184F80461A4F8186128 +:10070000A4F81A6184F8B66184F8B76184F8C0610E +:1007100084F8C16184F88C6184F88F6184F8A861E1 +:10072000C4F8A061C4F8A461BDE8F081A4F8066132 +:1007300084F8FB606088FE490144B1FBF0F1A4F845 +:1007400090104BF68031A4F89210B4F806C0A4F8CB +:100750009860B4F89C704FEACC0C4743BCFBF0FCAB +:1007600097FBF0F70CF1010CA4F89C701FFA8CFCBD +:100770000CFB00F704F17001A4F89AC0B7F5C84F5C +:10078000C4BFACF1010CA1F82AC0B5FBF0FC0CF120 +:10079000010CA1F830C000F5802C0CF5EE3CACF15A +:1007A0000105B5FBF0FCA1F820C0CD8B05FB00FCDA +:1007B000BCFBF0F0C8830846217B01F01F012173C8 +:1007C0004676002104EB010C9CF808C003EA5C05A6 +:1007D000ACEB050C0CF0FF0C0CF0330502EA9C0CA2 +:1007E000AC4445180CEB1C1C0CF00F0C85F814C025 +:1007F000457E491CAC44C9B280F819C00529E1D333 +:100800000CF0FF00252898BFBDE8F081FFDFBDE8B0 +:10081000F08100BFB4F8B011B4F8B4316288A4F824 +:100820009860B4F89CC0DB000CFB02FCB3FBF1F356 +:100830009CFBF1FC5B1CA4F89CC09BB203FB01FC7D +:1008400004F17000A4F89A30BCF5C84FC4BF5B1E19 +:100850004385B5FBF1F35B1C0386438C01EBC303BB +:100860005B1EB3FBF1F30384C38B5A43B2FBF1F17C +:10087000C183BDE8F0812DE9F04104460025A1B314 +:1008800055234FF4FA464FF0330C01297DD002294D +:1008900000F0E080032918BFBDE8F08104F170008A +:1008A000217B01F01F01217384F889500021621817 +:1008B000127A03EA5205521BD2B202F033050CEA57 +:1008C00092022A44451802EB121202F00F022A7516 +:1008D000457E491C2A44C9B242760529E7D3D0B2E5 +:1008E000252898BFBDE8F081B1E0FFE704F170066C +:1008F000802200213046FDF7CAFDB571F5713573D0 +:100900007573F57335747571B576F576212086F8B3 +:100910004000492086F84100FE2086F874002688B1 +:10092000702200212046FDF7B2FD2680012684F8C2 +:10093000646084F86560282084F86600002104F172 +:1009400030000DF066FE1B22A4F84E20A4F85020C3 +:10095000A4F85220A4F854204FF4A470A4F8560030 +:10096000A4F858006673A4F8F850202084F8FA0020 +:1009700084F8F050C4F8F45084F8245184F82551D8 +:1009800084F82E5184F82F5100E005E084F81451CA +:1009900084F82051BDE8F081618865480844B0FBC7 +:1009A000F1F0A4F890004BF68030A4F89200E288B1 +:1009B000A4F89850B4F89C70D2004F43B2FBF1F207 +:1009C00097FBF1F7521CA4F89C7092B202FB01F75E +:1009D00004F17000A4F89A20B7F5C84FC4BF521EA6 +:1009E0004285B6FBF1F2521C028601F5802202F527 +:1009F000EE32561EB6FBF1F20284C68B06FB01F204 +:100A0000B2FBF1F1C1830146207B00F01F0020738F +:100A10004D7600202218127A03EA5205521BD2B2F8 +:100A200002F033050CEA92022A440D1802EB12126E +:100A300002F00F022A754D7E401C2A44C0B24A764D +:100A40000528E7D3D0B2252898BFBDE8F081FFDFA5 +:100A5000BDE8F081D0F81811628804F1700348896C +:100A6000C989A4F89850B4F89CC0C9000CFB02FCDA +:100A7000B1FBF0F19CFBF0FC491CA4F89CC089B2CE +:100A800001FB00FCA4F89A10BCF5C84FC4BF491E76 +:100A90005985B6FBF0F1491C1986598C00EBC10150 +:100AA000491EB1FBF0F11984D98B5143B1FBF0F031 +:100AB000D883BDE8F0812DE9F003447E0CB1252CEC +:100AC00003D9BDE8F00312207047002A02BF0020BE +:100AD000BDE8F003704791F80DC01F260123154DA6 +:100AE0004FF00008BCF1000F7AD0BCF1010F1EBF1F +:100AF0001F20BDE8F0037047B0F800C00A7C8F7B70 +:100B000091F80F907A404F7C87EA090742EA072262 +:100B100082EA0C0C5FF000070CF0FF0999FAA9F9C2 +:100B20004FEA1C2C4FEA19699CFAACFC04E0000067 +:100B3000FFDB050053E4B36E4FEA1C6C49EA0C2C52 +:100B40000CEB0C1C7F1C9444FFB21FFA8CFC032F8F +:100B5000E2D38CEA020CFB4F0022ECFB0572120977 +:100B60006FF0240502FB05C2D2B201EBD2078276F8 +:100B700002F007053F7A03FA05F52F4218BFC27647 +:100B80007ED104FB0CF2120C521CD2B25FF00004B6 +:100B900000EB040C9CF814C094453CBFA2EB0C0283 +:100BA000D2B212D30D194FF0000C2D7A03FA0CF7C4 +:100BB0003D421CBF521ED2B2002A69D00CF1010C7A +:100BC0000CF0FF0CBCF1080FF0D304F1010C0CF099 +:100BD000FF04052CDCD33046BDE8F0037047FFE787 +:100BE00090F81AC00C7E474604FB02C2D54C4FF069 +:100BF000000CE2FB054C4FEA1C1C6FF024040CFBBC +:100C00000422D2B201EBD204827602F0070C247ADD +:100C100003FA0CFC14EA0C0F1FBFC2764046BDE875 +:100C2000F003704790F819C0B2FBFCF40CFB1422DF +:100C3000521CD2B25FF0000400EB040C9CF814C00C +:100C400094453CBFA2EB0C02D2B212D30D194FF067 +:100C5000000C2D7A03FA0CF815EA080F1CBF521E7F +:100C6000D2B272B10CF1010C0CF0FF0CBCF1080F08 +:100C7000F0D304F1010C0CF0FF04052CDCD3AAE73F +:100C800009E00CEBC401C1763846BDE8F0037047BB +:100C90000CEBC401C1764046BDE8F0037047AA4A98 +:100CA000016812681140A94A126811430160704737 +:100CB00030B4A749A44B00244FF0010C0A78521C11 +:100CC000D2B20A70202A08BF0C700D781A680CFA8C +:100CD00005F52A42F2D0097802680CFA01F1514078 +:100CE000016030BC704770B46FF01F02010C02EA63 +:100CF00090251F23A1F5AA4054381CBFA1F5AA4096 +:100D0000B0F1550009D0A1F52850AA381EBFA1F5B1 +:100D10002A40B0F1AA00012000D100204FF0000CC1 +:100D2000624601248CEA0106F6431643B6F1FF3F02 +:100D300011D005F001064FEA5C0C4CEAC63C03F00A +:100D4000010652086D085B08641C42EAC632162C84 +:100D5000E8DD70BC704770BC0020704790F804C09C +:100D60003CF01F011CBF0020704730B401785522B1 +:100D700002EA5103C91AC9B201F03304332303EA6A +:100D800091012144447801EB111102EA5405641BDE +:100D9000E4B204F0330503EA94042C4404EB141485 +:100DA00001F00F0104F00F040C448178C07802EACE +:100DB0005105491BC9B201F0330503EA91012944E9 +:100DC00001EB111101F00F01214402EA5004001B54 +:100DD000C0B200F0330403EA9000204400EB10108E +:100DE00000F00F00014402EA5C00ACEB0000C0B26E +:100DF00000F0330203EA9000104400EB101000F002 +:100E00000F00084401288CBF0120002030BC70472F +:100E10000A000ED00123012A0BDB491EC9B210F8CB +:100E200001C0BCF1000F01D0002070475B1C934251 +:100E3000F3DD01207047002A08BF70471144401EAF +:100E400012F0010F03D011F8013D00F8013F5208E4 +:100E500008BF704711F8013C437011F8023D00F8DB +:100E6000023F521EF6D1704770B58CB000F11004ED +:100E70001D4616460DF1FF3C5FF0080014F8012CEA +:100E80008CF8012014F8022D0CF8022F401EF5D129 +:100E900001F1100C6C460DF10F0108201CF8012C1B +:100EA0004A701CF8022D01F8022F401EF6D1204690 +:100EB00013F01CFB7EB16A1E04F130005FF00801E4 +:100EC00010F8013C537010F8023D02F8023F491E31 +:100ED000F6D10CB070BD08982860099868600A982F +:100EE000A8600B98E8600CB070BD38B505460C469C +:100EF000684607F03DFE002808BF38BD9DF9002078 +:100F00002272E07E607294F90A100020511A48BFE4 +:100F1000494295F82D308B42C8BF38BDFF2B08BF22 +:100F200038BDE17A491CC9B2E17295F82E30994278 +:100F300003D8A17A7F2918BF38BDA2720020E072C1 +:100F4000012038BD53E4B36E04620200086202005F +:100F5000740000200C2818BF0B2810D00D2818BFD3 +:100F60001F280CD0202818BF212808D0222818BFFD +:100F7000232804D024281EBF2628002070474FF0C5 +:100F8000010070470C2963D2DFE801F006090E1357 +:100F9000161B323C415C484E002A5BD058E0072AC1 +:100FA00018BF082A56D053E00C2A18BF0B2A51D07C +:100FB0004EE00D2A4ED04BE0A2F10F000C2849D98B +:100FC00046E023B1A2F110000B2843D940E0122AD9 +:100FD00018BF112A3ED090F8380020B1122A37D31A +:100FE0001A2A37D934E0162A32D31A2A32D92FE0F6 +:100FF000A2F10F0103292DD990F8380008B31B2A5C +:1010000028D925E0002B08BF042A21D122E013B102 +:10101000062A1FD01CE0012A1AD11BE01C2A1CBF83 +:101020001D2A1E2A16D013E01F2A18BF202A11D00D +:10103000212A18BF222A0DD0232A1CBF242A262A9F +:1010400008D005E013B10E2A04D001E0052A01D032 +:1010500000207047012070472DE9F0410D460446FD +:10106000866805F02FFA58B905F07EF840F236711F +:1010700004F061FDA060204605F024FA0028F3D0BA +:1010800095B13046A16805F067FD00280CDD2844C5 +:10109000401EB0FBF5F707FB05F1304604F04BFDB1 +:1010A000A0603846BDE8F0810020BDE8F08170B551 +:1010B0000446904228BF70BD101B64280BD325182E +:1010C0008D4206D8042105F07AFD00281CBF284671 +:1010D00070BD204670BD6420F1E711F00C0F13D0F5 +:1010E00001F0040100290DBF4022102296214FF487 +:1010F000167101F5BC71A0EB010388428CBF93FB14 +:10110000F2F0002080B27047022919BF6FF00D0184 +:1011100001EBD0006FF00E0101EB9000F2E7084404 +:1011200018449830002A14BF042100210844704755 +:1011300010B4002A14BF4FF429624FF4A472002B9C +:1011400019BF4FF429634FF0080C4FF4A4734FF00C +:10115000010C00280CBF0124002491F866001CF04B +:101160000C0F08BF0020D11808449830002C14BF81 +:1011700004210021084410BC704700280CBF012343 +:10118000002391F86600002BA0F6482000F50050DF +:1011900018BF04231844496A81422CBF0120002053 +:1011A00012F00C0118BF012131EA000014BF002029 +:1011B0000120704710B413680B66137813F00C030A +:1011C00018BF0123527812F00C0218BF012253EA13 +:1011D000020C04BF10BC7047002B0CBF4FF4A4736B +:1011E0004FF42963002A19BF4FF429624FF0080C0D +:1011F0004FF4A4724FF0010C00280CBF012400240E +:1012000091F866001CF00C0F08BF00201A4410442F +:101210009830002C14BF0422002210444A6A8242F3 +:1012200024BF10BC704791F860004FF0030230F00B +:101230000C0381F8603091F8610020F00C0081F817 +:10124000610008BF81F86020002808BF81F8612094 +:1012500010BC704710F0010F1CBF0120704710F048 +:10126000020F1CBF0220704710F0040018BF0820B6 +:1012700070472DE9F0470446174689464FF00108AC +:1012800008460DF0FAF8054648460DF0FAF810F059 +:10129000010F18BF012624D015F0010F18BF01233C +:1012A0002AD000BF56EA030108BF4FF0000810F033 +:1012B000070F08BF002615F0070F08BF002394F89A +:1012C0006400B0420CBF00203046387094F86510BE +:1012D000994208BF00237B70002808BF002B25D14E +:1012E00015E010F0020F18BF0226D5D110F0040F40 +:1012F00014BF08260026CFE715F0020F18BF0223FF +:10130000D0D115F0040F14BF08230023CAE74846C4 +:101310000DF0BDF8B4F87010401A00B247F6FE7137 +:10132000884201DC002801DC4FF0000816B1082ECD +:101330000CD018E094F86400012818BF022812D0DD +:1013400004281EBF0828FFDF032D0CD194F8C0012C +:1013500048B1B4F8C401012894F8640006D0082804 +:1013600001D0082038704046BDE8F087042818BF37 +:101370000420F7D1F5E7012814BF0228704710F0C8 +:101380000C0018BF0420704738B4CBB2C1F3072C4F +:10139000C1B2C0F30724012B07D0022B09D0042BC4 +:1013A00008BFBCF1040F2DD006E0BCF1010F03D142 +:1013B00028E0BCF1020F25D0012906D0022907D070 +:1013C000042908BF042C1DD004E0012C02D119E02F +:1013D000022C17D001EA0C0161F3070204EA0301B1 +:1013E00061F30F22D1B211F0020F18BF022310D007 +:1013F000C2F307218DF8003011F0020F18BF02214F +:101400001BD111E0214003EA0C03194061F30702EC +:10141000E6E711F0010F18BF0123E9D111F0040F25 +:1014200014BF08230023E3E711F0010F18BF0121C7 +:1014300003D111F0040118BF08218DF80110082B09 +:1014400001BF000C012804208DF80000BDF8000049 +:1014500038BC70474FF0000C082902D0042909D08D +:1014600011E001280FD10420907082F803C013808E +:1014700001207047012806D00820907082F803C030 +:1014800013800120704700207047162A10D12A22AD +:101490000C2818BF0D280FD04FF0230C1F280DD09B +:1014A00031B10878012818BF002805D0162805D0CA +:1014B00000207047012070471A70FBE783F800C0D6 +:1014C000F8E7012908D002290BD0042912BF082906 +:1014D00040F6A660704707E0002804BF40F2E240F3 +:1014E000704740F6C410704700B5FFDF40F2E2409D +:1014F00000BD00000178406829B190F82C1190F8E7 +:101500008C0038B901E001F0BDBD19B1042901D04A +:10151000012070470020704770B50C460546062133 +:1015200002F0C4FC606008B1002006E007212846F4 +:1015300002F0BCFC606018B101202070002070BD7A +:10154000022070BD2DE9FC470C4606466946FFF7B0 +:10155000E3FF00287DD19DF8000050B1FDF7EEF8C3 +:10156000B0427CD0214630460AF008FC002873D1F6 +:101570002DE00DF097F9B04271D02146304612F0BF +:10158000B6FA002868D1019D95F8F00022E001200C +:1015900000E00020804695F839004FF0010A4FF036 +:1015A0000009F0B195F83A0080071AD584F8019047 +:1015B00084F800A084F80490E68095F83B1021722E +:1015C000A98F6181E98FA18185F8399044E0019D5F +:1015D00095F82C0170350028DBD1287F0028D8D061 +:1015E000D5E7304602F0A5FD070000D1FFDF384601 +:1015F00001F0B5FF40B184F801900F212170E68021 +:10160000208184F804A027E0304602F080FD070026 +:1016100000D1FFDFB8F1000F21D0384601F0F7FF0D +:10162000B8B19DF8000038B90198D0F81801418888 +:10163000B14201D180F80090304607F00DFF84F8E8 +:1016400001900C21217084F80490E680697F21725A +:1016500000E004E085F81C900120BDE8FC87002034 +:10166000FBE71CB56946FFF757FF00B1FFDF68468F +:1016700001F014FDFE4900208968A1F8F2001CBDAC +:101680002DE9FC4104460E46062002F0B7FB054654 +:10169000072002F0B3FB2844C7B20025A8463E4409 +:1016A00017E02088401C80B22080B04202D3404620 +:1016B000A4F8008080B2B84204D3B04202D2002025 +:1016C000BDE8FC816946FFF727FF0028F8D06D1CB4 +:1016D000EDB2AE42E5D84FF6FF7020801220EFE762 +:1016E00038B54FF6FF70ADF800000DE00621BDF8EB +:1016F000000002F0EDFB04460721BDF8000002F0F7 +:10170000E7FB0CB100B1FFDF00216846FFF7B8FF2F +:101710000028EBD038BD70B507F00CFF0BF034FF9C +:10172000D44C4FF6FF76002526836683D2A0257021 +:1017300001680079A4F14002657042F8421FA11CC3 +:101740001071601C12F0EFFA1B2020814FF4A4717D +:101750006181A081E18107212177617703212174D3 +:10176000042262746082A082A4F13E00E1820570CE +:101770004680BF480C300570A4F11000057046800B +:1017800084F8205070BD70B5B94C16460D466060A7 +:10179000217007F047FEFFF7A3FFFFF7BCFF20789B +:1017A0000FF0BDFFB6480DF0D0F92178606812F057 +:1017B0005FFA20780BF0DCF8284608F0AFFEB0485E +:1017C000FCF7C7FF217860680AF0B2FB3146207849 +:1017D00012F024FDBDE870400BF0D6BE10B5012418 +:1017E0000AB1002010BD21B1012903D000242046F8 +:1017F00010BD02210CF024FDF9E710B50378044672 +:10180000002B406813460A46014609D05FF00100EC +:10181000FFF78EFC6168496A884203D9012010BD38 +:101820000020F5E7002010BD2DE9F04117468A7829 +:101830001E46804642B11546C87838B1044669074D +:1018400006D52AB1012104E00725F5E70724F6E7CC +:101850000021620702D508B1012000E0002001420A +:1018600006D0012211464046FFF7C7FF98B93DE078 +:1018700051B1002201214046FFF7BFFF58B9600770 +:1018800034D50122114620E060B1012200214046FA +:10189000FFF7B3FF10B10920BDE8F081680725D537 +:1018A000012206E068074FEA44700AD5002814DBDD +:1018B000002201214046FFF7A0FFB8B125F0040542 +:1018C00014E0002812DA012200214046FFF795FFBC +:1018D00060B100BF24F0040408E001221146404634 +:1018E000FFF78BFF10B125F00405F3E73D7034706E +:1018F0000020D1E770B58AB0044600886946FFF73A +:101900000BFE002806D1A08830B1012804D002289F +:1019100002D012200AB070BD04AB03AA214668466B +:10192000FFF782FF0500F5D19DF800100120002689 +:101930000029019906D081F8C101019991F80C1292 +:10194000B1BB2DE081F82F01019991F8561139B9F9 +:10195000019991F82E1119B9019991F8971009B1CF +:101960003A2519E00199059681F82E01019A9DF812 +:101970000C0082F83001019B9DF8102083F8312182 +:10198000A388019CA4F832318DF814008DF815203D +:1019900005AA0020FFF70EFC019880F82F6126E0D1 +:1019A000019991F8C01119B9019991F8971009B1ED +:1019B0003A2519E00199059681F8C00101989DF832 +:1019C0000C2080F8C221019B9DF8100083F8C30110 +:1019D000A388019CA4F8C4318DF814208DF815005B +:1019E00005AA0120FFF7E6FB019880F8C1612846AF +:1019F00090E710B504460020A17801B90120E278F3 +:101A00000AB940F0020001F058FB002803D120463B +:101A1000BDE810406EE710BD70B5044691F8650052 +:101A200091F866300D4610F00C0F00D1002321898B +:101A3000A088FFF774FB696A814229D2401A401CD2 +:101A4000A1884008091A8AB2A2802189081A208137 +:101A5000668895F864101046FFF73FFB864200D277 +:101A600030466080E68895F8651020890AE000001D +:101A70007800002018080020FFFFFFFF1F00000073 +:101A8000D8060020FFF729FB864200D23046E080CE +:101A900070BDF0B585B00D46064603A9FFF73CFDC5 +:101AA00000282DD19DF80C0060B300220499FB2082 +:101AB000B1F84E30FB2B00D30346B1F85040FB2069 +:101AC000FB2C00D30446DFF85CC59CE88110009035 +:101AD0000197CDF808C0ADF80230ADF80640684671 +:101AE000FFF79AFF6E80BDF80400E880BDF808009B +:101AF0006881BDF80200A880BDF80600288100209A +:101B000005B0F0BD0122D1E72DE9F04186B00446D1 +:101B100000886946FFF700FD002876D12189E0881A +:101B200001F0E4FA002870D1A188608801F0DEFAA3 +:101B300000286AD12189E08801F0CFFA002864D119 +:101B4000A188608801F0C9FA07005ED1208802A947 +:101B5000FFF79FFF00B1FFDFBDF81010628809207A +:101B6000914252D3BDF80C10E28891424DD3BDF89A +:101B70001210BDF80E2023891144A2881A44914204 +:101B800043D39DF80010019D4FF00008012640F658 +:101B9000480041B185F8B761019991F8F81105F550 +:101BA000DB7541B91AE085F82561019991F84A1170 +:101BB00005F5927509B13A2724E0E18869806188CA +:101BC000E9802189814200D30146A980A188814210 +:101BD00000D208462881012201990FE0E18869803E +:101BE0006188E9802189814200D30146A980A188CA +:101BF000814200D208462881019900222846FFF739 +:101C00000BFF2E7085F80180384606B044E67BE76E +:101C100070B504460CF0FCFDB0B12078182811D145 +:101C2000207901280ED1E088062102F03FF9040056 +:101C300008D0208807F010FC2088062102F048F91F +:101C400000B1FFDF012070BDF74D28780028FAD0E1 +:101C5000002666701420207020223146201DFCF7DB +:101C600016FC022020712E70ECE710B50446FCF73C +:101C7000DBFC002813D0207817280FD1207968B119 +:101C8000E088072102F012F940B1008807F0E4FB78 +:101C9000E088072102F01CF900B1FFDF012010BD30 +:101CA0002DE9F0475FEA000800D1FFDFDE4802219E +:101CB0001A308146FFF7E4FC00B1FFDFDA4C062062 +:101CC000678B02F09BF80546072002F097F828443E +:101CD000C5B2681CC6B2608BB04203D14046FFF764 +:101CE000C4FF58B9608BA84203D14046FFF790FF6C +:101CF00020B9608B4146FFF725FC38B1404601F022 +:101D000003FA0028E7D10120BDE8F0870221484608 +:101D1000FFF7B6FC10B9608BB842DCD14046BDE895 +:101D2000F04712F0C1BA10B501F053F908B10C2018 +:101D300010BD0BF07DFC002010BD10B504460078EE +:101D400018B1012801D0122010BD01F053F920B1C3 +:101D50000BF0C0FD08B10C2010BD207801F013F984 +:101D6000E21D04F11703611CBDE810400BF0DABC62 +:101D700010B5044601F02DF908B10C2010BD2078F3 +:101D800028B1012803D0FF280BD0122010BD01F08C +:101D9000FAF8611C0BF00CFC08B1002010BD072004 +:101DA00010BD01200BF03EFCF7E710B50BF095FDE0 +:101DB00008B1002010BD302010BD10B5044601F060 +:101DC00019F908B10C2010BD20460BF080FD002051 +:101DD00010BD10B501F00EF920B10BF07BFD08B17C +:101DE0000C2010BD0BF0F6FC002010BDFF2181700F +:101DF0004FF6FF7181808D4949680A7882718A881F +:101E000002814988418101214170002070477CB5E1 +:101E10000025022A19D015DC12F10C0F15D009DCAF +:101E200012F1280F11D012F1140F0ED012F1100F71 +:101E300011D10AE012F1080F07D012F1040F04D0FB +:101E40004AB902E0D31E052B05D8012806D0022886 +:101E500008D003280AD0122528467CBD1046FDF77D +:101E600013F8F9E710460CF06BFEF5E70846144648 +:101E70006946FFF751FB08B10225EDE79DF8000028 +:101E80000198002580F86740E6E710B51346012267 +:101E9000FEF7EAFF002010BD10B5044610F02FFA3F +:101EA000052804D020460FF029FC002010BD0C208E +:101EB00010BD10B5044601F09DF808B10C2010BD0E +:101EC0002146002007F037FB002010BD10B5044666 +:101ED0000FF0A3FC50B108F0A6FD38B1207808F04F +:101EE00029FB20780DF04DF9002010BD0C2010BD0D +:101EF00010B5044601F07EF808B10C2010BD214653 +:101F0000012007F018FB002010BD38B504464FF63D +:101F1000FF70ADF80000A079E179884216D02079F1 +:101F2000FCF7E3FA90B16079FCF7DFFA70B10022B8 +:101F3000A079114612F0A0FD40B90022E0791146C7 +:101F400012F09AFD10B9207A072801D9122038BD65 +:101F500008F076FD60B910F0D2F948B90021684662 +:101F6000FFF78EFB20B1204606F044F9002038BD73 +:101F70000C2038BD2DE9FC41817805461A2925D071 +:101F80000EDC16292ED2DFE801F02D2D2D2D2D216E +:101F90002D2D2D2D2D2D2D2D2D2D2D2D2D21212195 +:101FA0002A291FD00BDCA1F11E010C291AD2DFE86F +:101FB00001F019191919191919191919190D3A399D +:101FC00004290FD2DFE801F00E020E022888B0F5D6 +:101FD000706F07D201276946FFF79EFA20B10220F1 +:101FE000BDE8FC811220FBE79DF8000000F0D2FF65 +:101FF000019C10B104F58A7401E004F5C6749DF8E3 +:10200000000000F0C7FF019E10B106F2151601E0B6 +:1020100006F28D166846FFF76DFA08B1207838B1E0 +:102020000C20DDE70C620200180800207800002078 +:102030002770A8783070684601F030F80020CFE7AC +:102040007CB50D466946FFF767FA002618B12E6089 +:102050002E7102207CBD9DF8000000F09BFF019CCA +:102060009DF80000703400F095FF019884F84260FC +:1020700081682960017B297194F842100029F5D10B +:1020800000207CBD10B5044600F0B4FF20B10BF079 +:1020900021FC08B10C2010BD207800F074FFE2791B +:1020A000611C0BF093FD08B1002010BD022010BD93 +:1020B00010B5886E60B1002241F8682F0120CA7106 +:1020C0008979884012F0CCFC002800D01F2010BD78 +:1020D0000C2010BD1CB50C466946FFF71DFA002800 +:1020E00009D19DF8000000280198B0F8700000D0D8 +:1020F000401C208000201CBD1CB504460088694699 +:10210000FFF70AFA08B102201CBD606828B1DDE9BA +:102110000001224601F04CF81CBDDDE90001FFF78B +:10212000C7FF1CBD70B51C460D4618B1012801D073 +:10213000122070BD1946104601F078F830B12146E2 +:10214000284601F07DF808B1002070BD302070BD38 +:1021500070B5044600780E46012804D018B1022854 +:1021600001D0032840D1607828B1012803D002288B +:1021700001D0032838D1E07B10B9A078012833D1F1 +:10218000A07830F005012FD110F0050F2CD0628916 +:10219000E188E0783346FFF7C5FF002825D1A07815 +:1021A00005281DD16589A289218920793346FFF749 +:1021B000B9FF002819D1012004EB40014A891544D8 +:1021C0002218D378927893420ED1CA8889888A429D +:1021D0000AD1401CC0B20228EED3E088A84203D343 +:1021E000A07B08B1072801D9122070BD002070BD66 +:1021F00010B586B0044600F0E1FE10B10C2006B028 +:1022000010BD022104F10A0001F02FF8A0788DF82A +:102210000800A0788DF8000060788DF80400207820 +:102220008DF80300A07B8DF80500E07B00B1012054 +:102230008DF80600A078C10717D0E07801F00CF8FF +:102240008DF80100E088ADF80A006089ADF80C0057 +:10225000A078400716D5207900F0FEFF8DF8020027 +:102260002089ADF80E00A0890AE040070AD5E07881 +:1022700000F0F2FF8DF80200E088ADF80E006089F2 +:10228000ADF8100002A80FF0D4FA0028B7D16846C4 +:102290000CF07CFFB3E710B504460121FFF758FFAF +:1022A000002803D12046BDE81040A1E710BD027808 +:1022B000012A01D0BAB118E042783AB1012A05D01A +:1022C000022A12D189B1818879B100E059B14188DF +:1022D00049B1808838B101EB8101490000EB8000F1 +:1022E000B1EB002F01D2002070471220704770B56B +:1022F000044600780D46012809D010F000F80528A2 +:1023000003D00FF0A6F9002800D00C2070BD0CF00F +:102310000AFE88B10CF01CFE0CF018FF0028F5D165 +:1023200025B160780CF0ACFE0028EFD1A188608860 +:10233000BDE870400FF0A3BA122070BD10B504467E +:102340000121FFF7B4FF002804D12046BDE810406A +:102350000121CCE710BDF0B5871FDDE9056540F62A +:102360007B44A74213D28F1FA74210D288420ED8B7 +:10237000B2F5FA7F0BD2A3F10A00241FA04206D2C5 +:10238000521C4A43B2EB830F01DAAE4201D900205E +:10239000F0BD0120F0BD2DE9FC47477A894604468F +:1023A00017F0050F7ED0F8087CD194F83A0008B9F0 +:1023B000012F77D10025A8462E46F90789F0010A9A +:1023C00019D0208A514600F031FFE8B360895146A8 +:1023D00000F036FFC0B3208A6189884262D8A18E9E +:1023E000E08DCDE90001238D628CA18BE08AFFF79F +:1023F000B2FF48B30125B8070ED504EB4500828E25 +:10240000C18DCDE90012038D428C818BC08AFFF70C +:10241000A2FFC8B1A8466D1C78071ED504EB45067F +:102420005146308A00F002FF70B17089514600F0C9 +:1024300007FF48B1308A7189884253D8B18EF08D38 +:10244000CDE90001338D00E00BE0728CB18BF08A96 +:10245000FFF781FF28B12E466D1CB9F1000F03D0A4 +:1024600030E03020BDE8FC87F80707D0780705D5B5 +:1024700004EB460160894989884233D1228A0121CF +:102480001BE0414503D004EB4100008A024404EB09 +:102490004100C38A868AB34224D1838B468BB342E0 +:1024A00020D100E01EE0438C068CB3421AD1038D8C +:1024B000C08C834216D1491CC9B2A942E1D36089BC +:1024C00090420FD3207810B101280BD102E0A07800 +:1024D0000028F9D1607838B1012805D0022803D04E +:1024E000032801D01220BDE70020BBE7002152E7FE +:1024F0000178C90702D0406811F0A9BE11F076BE7C +:1025000010B50078012800D00020FCF7B8FC0020AE +:1025100010BD2DE9F0478EB00D46AFF6A422D2E9EA +:102520000092014690462846FFF735FF06000CD181 +:1025300000F044FD40B9FE4F387828B90CF0B2F9EC +:10254000A0F57F41FF3903D00C200EB0BDE8F08725 +:10255000032105F1100000F088FEF54809AA3E3875 +:102560000990F4480A90F248062110380B900CA804 +:1025700001F06AFC040037D00021FEF77CF904F179 +:1025800030017B8ABA8ACB830A84797C0091BA466F +:102590003B7CBA8A798A208801F044FD00B1FFDFD4 +:1025A000208806F058FF218804F10E0000F02CFD71 +:1025B000E1A004F1120700680590032105A804F0CA +:1025C0006DFF002005A90A5C3A54401CC0B20328E4 +:1025D000F9D3A88B6080688CA080288DE080687A11 +:1025E000410703D508270AE00920AEE7C10701D05B +:1025F000012704E0800701D5022700E000273A46C2 +:10260000BAF8160011460FF0CFF90146A062204635 +:102610000FF0D8F93A4621460020FEF7AEFD00B98A +:102620000926C34A21461C320020FEF7C3FD0027BD +:1026300084F8767084F87770A87800F0A4FC60764F +:10264000D5F80300C4F81A00B5F80700E083C4F811 +:10265000089084F80C80012084F8200101468DF850 +:102660000070684604F01AFF9DF8000000F00701B2 +:10267000C0F3C1021144C0F3401008448DF80000BB +:10268000401D2076092801D20830207601212046FD +:10269000FEF7F1F868780CF051FCEEBBA9782878C9 +:1026A000EA1C0CF01EFC48B10CF052FCA97828780A +:1026B000EA1C0CF0BFFC060002D052E0122650E0EB +:1026C000687A00F005010020CA0700D001208A07BF +:1026D00001D540F00200490701D540F008000CF098 +:1026E000E9FB06003DD1214603200CF0CDFC06009D +:1026F00037D10CF0D2FC060033D1697A01F0050124 +:102700008DF80810697AC90708D06889ADF80A0001 +:10271000288AADF80C0000E023E00120697A8A07DE +:1027200000D5401C490707D505EB40004189ADF8AD +:102730000E10008AADF8100002A80FF07AF80646D5 +:1027400095F83A0000B101200CF0C6FB4EB90CF030 +:10275000FDFC060005D1A98F20460FF00BF80600FE +:1027600008D0208806F078FE2088062101F0B0FB12 +:1027700000B1FFDF3046E8E601460020C9E638B583 +:102780006B48007878B90FF0BAFD052805D00CF039 +:1027900089F8A0F57F41FF3905D068460FF0B3F8FE +:1027A000040002D00CE00C2038BD0098008806F030 +:1027B00053FE00980621008801F08AFB00B1FFDF7C +:1027C000204638BD1CB582894189CDE900120389B4 +:1027D000C28881884088FFF7BEFD08B100201CBD7B +:1027E00030201CBD70B50546FFF7ECFF00280ED168 +:1027F0002888062101F05AFB040007D000F042FCB3 +:1028000020B1D4F81801017831B901E0022070BD7F +:10281000D4F86411097809B13A2070BD052181719D +:10282000D4F8181100200881D4F81811A88848811C +:10283000D4F81811E8888881D4F818112889C8813B +:10284000D4F81801028941898A4204D88279082A79 +:1028500001D88A4201D3122070BD29884180D4F862 +:10286000181102200870002070BD3EB50446FEF726 +:1028700075FAB0B12E480125A0F1400245702368D9 +:1028800042F8423F237900211371417069460620C6 +:1028900001F095FA00B1FFDF684601F06EFA10B161 +:1028A0000EE012203EBDBDF80440029880F8205191 +:1028B000684601F062FA18B9BDF80400A042F4D1EC +:1028C00000203EBD70B505460088062101F0EEFAF5 +:1028D000040007D000F0D6FB20B1D4F81811087816 +:1028E00030B901E0022070BDD4F86401007808B16D +:1028F0003A2070BDB020005D10F0010F22D0D5F855 +:1029000002004860D5F806008860D4F8180169898B +:1029100010228181D4F8180105F10C010E3004F564 +:102920008C74FBF78AFD216803200870288805E075 +:1029300018080020840000201122330021684880FC +:10294000002070BD0C2070BD38B504460078EF281B +:102950004DD86088ADF80000009800F097FC88B36F +:102960006188080708D4D4E9012082423FD8202A90 +:102970003DD3B0F5804F3AD8207B18B3072836D81E +:10298000607B28B1012803D0022801D003282ED172 +:102990004A0703D4022801D0032805D1A07B08B13F +:1029A000012824D1480707D4607D28B1012803D02D +:1029B000022801D003281AD1C806E07D03D50128DA +:1029C00015D110E013E0012801D003280FD1C8066B +:1029D00009D4607E012803D0022801D0032806D143 +:1029E000A07E0F2803D8E07E18B1012801D0122064 +:1029F00038BD002038BDF8B514460D46064608F02F +:102A00001FF808B10C20F8BD3046FFF79DFF0028E5 +:102A1000F9D1FCF73EFA2870B07554B9FF208DF853 +:102A2000000069460020FCF71EFA69460020FCF70A +:102A30000EFA3046BDE8F840FCF752B90022DAE75A +:102A40000078C10801D012207047FA4981F82000AF +:102A50000020704710B504460078C00704D1608894 +:102A600010B1FCF7D7F980B12078618800F001023D +:102A7000607800F02FFC002806D1FCF7B3F901467E +:102A80006088884203D9072010BD122010BD6168FC +:102A9000FCF7E9F9002010BD10B504460078C00726 +:102AA00004D1608810B1FBF78AFE70B1207861888C +:102AB00000F00102607800F00DFC002804D160886D +:102AC0006168FCF7C4F9002010BD122010BD7CB570 +:102AD000044640784225012808D8A078FBF767FE15 +:102AE00020B120781225012802D090B128467CBD63 +:102AF000FCF7DBF920B1A0880028F7D08028F5D8B2 +:102B0000FCF7DAF960B160780028EFD0207801286E +:102B100008D006F0C3FD044607F05DFC00287FD016 +:102B20000C207CBDFBF7F5FF10B9FCF7B7F990B3AB +:102B300007F086FF0028F3D1FBF700FEA0F57F41E8 +:102B4000FF39EDD1FCF707F8A68842F21070464332 +:102B5000A079FCF770F9FBF739FEF8B100220721E4 +:102B600001A801F071F9040058D0B3480021846035 +:102B70002046FDF72DFD2046FCF732FDAD4D04F15A +:102B800030006A8AA98AC2830184FBF726FE60B1FD +:102B9000E88A01210DE0FFE712207CBD31460020CC +:102BA00007F0CBFC88B3FFDF44E0FCF787F9014670 +:102BB000E88A07F091FD0146A0620022204606F057 +:102BC00070FDFBF70AFE38B9FCF778F9024621469A +:102BD0000120FEF7D2FAD0B1964A21461C320120DC +:102BE000FEF7E8FA687C00902B7CAA8A698A208824 +:102BF00001F018FA00B1FFDF208806F02CFC314606 +:102C0000204607F09AFC00B1FFDF13E008E007213F +:102C1000BDF8040001F05CF900B1FFDF09207CBDC4 +:102C200044B1208806F018FC2088072101F050F9F3 +:102C300000B1FFDF00207CBD002148E770B50D46E4 +:102C4000072101F033F9040003D094F88F0110B18B +:102C50000AE0022070BD94F87D00142801D01528E8 +:102C600002D194F8DC0108B10C2070BD1022294675 +:102C700004F5C870FBF7E1FB012084F88F01002008 +:102C800070BD10B5072101F011F918B190F88F113E +:102C900011B107E0022010BD90F87D10142903D077 +:102CA000152901D00C2010BD022180F88F110020C1 +:102CB00010BD2DE9FC410C464BF6803212219442A6 +:102CC0001DD8E4B16946FEF727FC002815D19DF810 +:102CD000000000F05FF9019E9DF80000703600F0E2 +:102CE00059F9019DAD1C2F88224639463046FDF723 +:102CF00065FC2888B842F6D10020BDE8FC81084672 +:102D0000FBE77CB5044600886946FEF705FC002811 +:102D100010D19DF8000000F03DF9019D9DF80000E4 +:102D2000703500F037F90198A27890F82C10914294 +:102D300001D10C207CBD7F212972A9720021E9728A +:102D4000E17880F82D10217980F82E10A17880F894 +:102D50002C1000207CBD1CB50C466946FEF7DCFB40 +:102D600000280AD19DF8000000F014F9019890F8AD +:102D70008C0000B10120207000201CBD7CB50D46E8 +:102D800014466946FEF7C8FB002809D19DF80000EB +:102D900000F000F9019890F82C00012801D00C20D7 +:102DA0007CBD9DF8000000F0F5F8019890F87810CF +:102DB000297090F87900207000207CBD70B50D4618 +:102DC0001646072101F072F818B381880124C388E0 +:102DD000428804EB4104AC4217D842F210746343BA +:102DE000A4106243B3FBF2F2521E94B24FF4FA7293 +:102DF000944200D91446A54200D22C46491C641CBA +:102E0000B4FBF1F24A43521E91B290F8C8211AB9AC +:102E100001E0022070BD01843180002070BD10B53A +:102E20000C46072101F042F840B1022C08D91220CB +:102E300010BD000018080020780000200220F7E7ED +:102E400014F0010180F8FD10C4F3400280F8FC206A +:102E500004D090F8FA1009B107F054FC0020E7E71D +:102E6000017889B1417879B141881B290CD38188D7 +:102E70001B2909D3C188022906D3F64902680A65CD +:102E800040684865002070471220704710B504461E +:102E90000EF086FD204607F0D8FB0020C8E710B5ED +:102EA00007F0D6FB0020C3E72DE9F04115460F4699 +:102EB00006460122114638460EF076FD04460121F1 +:102EC000384607F009FC844200D20446012130460E +:102ED00000F065F806460121002000F060F8311886 +:102EE000012096318C4206D901F19600611AB1FB9E +:102EF000F0F0401C80B228800020BDE8F08110B5C1 +:102F0000044600F077F808B10C2091E7601C0AF045 +:102F100038FE207800F00100FBF718FE207800F062 +:102F200001000CF010F8002082E710B504460720DD +:102F300000F056FF08B10C207AE72078C00711D0C6 +:102F400000226078114611F097FD08B112206FE75A +:102F5000A06809F01DFB6078D4F8041009F021FB8B +:102F6000002065E7002009F013FB00210846F5E783 +:102F700010B505F036FE00205AE710B5006805F0E0 +:102F800084F8002054E718B1022801D001207047CE +:102F90000020704708B1002070470120704710B52D +:102FA000012904D0022905D0FFDF204640E7C000F8 +:102FB000503001E080002C3084B2F6E710B50FF0FD +:102FC0009EF9042803D0052801D0002030E7012015 +:102FD0002EE710B5FFF7F2FF10B10CF07BF828B91F +:102FE00007F02EFD20B1FBF78CFD08B101201FE793 +:102FF00000201DE710B5FFF7E1FF18B907F020FD2D +:10300000002800D0012013E72DE9FE4300250F46DC +:1030100080460A260421404604F069FA4046FDF73E +:103020003EFE062000F0EAFE044616E06946062051 +:1030300000F0C5FE0BE000BFBDF80400B84206D0AA +:103040000298042241460E30FBF7CAF950B1684697 +:1030500000F093FE0500EFD0641E002C06DD002D6D +:10306000E4D005E04046FDF723FEF5E705B9FFDFB4 +:10307000D8F80000FDF737FE761E01D00028C9D031 +:10308000BDE8FE8390F8F01090F88C0020B919B1DB +:10309000042901D0012070470020704701780029E1 +:1030A0000AD0416891F8FA20002A05D0002281F860 +:1030B000FA20406807F026BB704770B514460546F5 +:1030C000012200F01BF9002806D121462846BDE860 +:1030D0007040002200F012B970BDFB2802D8B1F593 +:1030E000296F01D911207047002070471B38E12853 +:1030F00006D2B1F5A47F03D344F29020814201D9D6 +:1031000012207047002070471FB55249403191F896 +:103110002010CA0702D102781D2A0AD08A0702D4D9 +:1031200002781C2A28D049073DD40178152937D0C8 +:1031300039E08088ADF8000002A9FEF7EDF900B192 +:10314000FFDF9DF80800FFF725FF039810F8601FC8 +:103150008DF8021040788DF803000020ADF80400CF +:1031600001B9FFDF9DF8030000B9FFDF6846FEF7F5 +:1031700040FCD8B1FFDF19E08088ADF800004FF4C3 +:103180002961FB20ADF80410ADF80200ADF806008F +:10319000ADF808106846FEF73AFD38B1FFDF05E0EC +:1031A000807BC00702D0002004B041E60120FBE78D +:1031B000F8B50746508915460C4640B1B0F5004FAA +:1031C00005D20022A878114611F056FC08B1122051 +:1031D000F8BDA06E04F1700630B1A97894F86E00C5 +:1031E000814201D00C20F8BD012184F86F10A9782C +:1031F00084F86E106968A1666989A4F86C10288942 +:10320000B084002184F86F1028886946FEF762FFB9 +:10321000B08CBDF80010081A00B2002804DD214669 +:103220003846FEF745FFDDE70020F8BD042803D34C +:1032300021B9B0F5804F01D90020704701207047B7 +:10324000042803D321B9B0F5804F01D9002070477D +:1032500001207047D8070020012802D018B10020B3 +:103260007047022070470120704710B500224FF4CC +:10327000C84408E030F81230A34200D9234620F8B1 +:103280001230521CD2B28A42F4D3D1E580B2C106C8 +:103290000BD401071CD481064FEAC07101D5B9B91E +:1032A00000E099B1800713D410E0410610D48106E4 +:1032B0000ED4C1074FEA807104D0002902DB400719 +:1032C00004D405E0010703D4400701D4012070476E +:1032D0000020704770B50C460546FF2904D8FBF75F +:1032E0007CFA18B11F2C01D9122070BD2846FBF7BB +:1032F0005EFA08B1002070BD422070BD0AB1012203 +:1033000000E00222024202D1C80802D109B1002025 +:10331000704711207047000030B5058825F400443F +:1033200021448CB24FF4004194420AD2121B92B253 +:103330001B339A4201D2A94307E005F4004121431F +:1033400003E0A21A92B2A9431143018030BD0844A0 +:10335000083050434A31084480B2704770B51D466A +:1033600016460B46044629463046049AFFF7EFFFFF +:103370000646B34200D2FFDF282200212046FBF799 +:1033800086F84FF6FF70A082283EB0B26577608065 +:10339000B0F5004F00D9FFDF618805F13C008142A4 +:1033A00000D2FFDF60880835401B343880B22080AF +:1033B0001B2800D21B2020800020A07770BD8161D7 +:1033C000886170472DE9F05F0D46C188044600F121 +:1033D0002809008921F4004620F4004800F063FB2E +:1033E00010B10020BDE8F09F4FF0000A4FF0010B34 +:1033F000B0450CD9617FA8EB0600401A0838854219 +:1034000019DC09EB06000021058041801AE0608884 +:10341000617F801B471A083F0DD41B2F00DAFFDFA6 +:10342000BD4201DC294600E0B9B2681A0204120C60 +:1034300004D0424502DD84F817A0D2E709EB06006C +:103440000180428084F817B0CCE770B5044600F1E3 +:103450002802C088E37D20F400402BB1104402888C +:10346000438813448B4201D2002070BD00258A425C +:1034700002D30180458008E0891A0904090C4180C3 +:1034800003D0A01D00F01FFB08E0637F0088083315 +:10349000184481B26288A01DFFF73EFFE575012048 +:1034A00070BD70B5034600F12804C588808820F4FB +:1034B00000462644A84202D10020188270BD988997 +:1034C0003588A84206D3401B75882D1A2044ADB21A +:1034D000C01E05E02C1AA5B25C7F20443044401D7C +:1034E0000C88AC4200D90D809C8924B10024147052 +:1034F0000988198270BD0124F9E770B5044600F10E +:103500002801808820F400404518208A002825D012 +:10351000A189084480B2A08129886A881144814227 +:1035200000D2FFDF2888698800260844A1898842E4 +:1035300012D1A069807F2871698819B1201D00F01F +:10354000C2FA08E0637F28880833184481B2628891 +:10355000201DFFF7E1FEA6812682012070BD2DE926 +:10356000F041418987880026044600F12805B942C8 +:1035700019D004F10A0800BF21F400402844418812 +:1035800019B1404600F09FFA08E0637F00880833D5 +:10359000184481B262884046FFF7BEFE761C6189FE +:1035A000B6B2B942E8D13046BDE8F0812DE9F0412C +:1035B00004460B4627892830A68827F40041B4F832 +:1035C0000A8001440D46B74201D10020ECE70AB160 +:1035D000481D106023B1627F691D1846FAF72DFF60 +:1035E0002E88698804F1080021B18A1996B200F08A +:1035F0006AFA06E0637F62880833991989B2FFF797 +:103600008BFE474501D1208960813046CCE7818817 +:10361000C088814201D10120704700207047018994 +:103620008088814201D1012070470020704770B529 +:103630008588C38800F1280425F4004223F4004162 +:1036400014449D421AD08389058A5E1925886388AF +:10365000EC18A64214D313B18B4211D30EE0437F72 +:1036600008325C192244408892B2801A80B2233317 +:10367000984201D211B103E08A4201D1002070BD0D +:10368000012070BD2DE9F0478846C18804460089B5 +:1036900021F4004604F1280720F4004507EB060951 +:1036A00000F001FA002178BBB54204D9627FA81B63 +:1036B000801A002503E06088627F801B801A08382A +:1036C00023D4E28962B1B9F80020B9F802303BB1E5 +:1036D000E81A2177404518DBE0893844801A09E070 +:1036E000801A217740450ADB607FE1890830304449 +:1036F00039440844C01EA4F81280BDE8F08745454F +:1037000003DB01202077E7E7FFE761820020F4E791 +:103710002DE9F74F044600F12805C088884620F4BB +:10372000004A608A05EB0A0608B1404502D2002033 +:10373000BDE8FE8FE08978B13788B6F8029007EBD4 +:103740000901884200D0FFDF207F4FF0000B50EAD4 +:10375000090106D088B33BE00027A07FB94630714D +:10376000F2E7E18959B1607F2944083050440844A8 +:10377000B4F81F1020F8031D94F821108170E2891D +:1037800007EB080002EB0801E1813080A6F802B0E7 +:1037900002985F4650B1637F30880833184481B285 +:1037A0006288A01DFFF7B8FDE78121E0607FE18915 +:1037B00008305044294408442DE0FFE7E089B4F87C +:1037C0001F102844C01B20F8031D94F8211081709D +:1037D00009EB0800E28981B202EB0800E081378042 +:1037E00071800298A0B1A01D00F06DF9A4F80EB090 +:1037F000A07F401CA077A07D08B1E088A08284F85B +:1038000016B000BFA4F812B084F817B001208FE7FB +:10381000E0892844C01B30F8031DA4F81F108078ED +:1038200084F82100EEE710B5818800F1280321F427 +:1038300000442344848AC288A14212D0914210D00D +:10384000818971B9826972B11046FFF7E8FE50B9FB +:103850001089283220F400401044197900798842F8 +:1038600001D1002010BD184610BD00F12803407F93 +:1038700008300844C01E1060088808B9DB1E1360B9 +:1038800008884988084480B270472DE9F04100F16A +:103890002806407F1C4608309046431808884D880B +:1038A000069ADB1EA0B1C01C80B2904214D9801AC7 +:1038B000A04200DB204687B298183A464146FAF704 +:1038C0008FFD002816D1E01B84B2B844002005E02B +:1038D000ED1CADB2F61EE8E7101A80B20119A9423C +:1038E00006D8304422464146BDE8F041FAF778BD9B +:1038F0004FF0FF3058E62DE9F04100F12804407FF9 +:103900001E46083090464318002508884F88069ABE +:10391000DB1E90B1C01C80B2904212D9801AB04216 +:1039200000DB304685B299182A464046FAF785FDF5 +:10393000701B86B2A844002005E0FF1CBFB2E41E45 +:10394000EAE7101A80B28119B94206D82118324626 +:103950004046FAF772FDA81985B2284624E62DE9FB +:10396000F04100F12804407F1E460830904643187D +:10397000002508884F88069ADB1E90B1C01C80B2D3 +:10398000904212D9801AB04200DB304685B29818B6 +:103990002A464146FAF751FD701B86B2A844002022 +:1039A00005E0FF1CBFB2E41EEAE7101A80B28119DD +:1039B000B94206D8204432464146FAF73EFDA819DE +:1039C00085B22846F0E5401D704710B5044600F169 +:1039D0002801C288808820F400431944904206D010 +:1039E000A28922B9228A12B9A28A904201D100206A +:1039F00010BD0888498831B1201D00F064F800200E +:103A00002082012010BD637F62880833184481B290 +:103A1000201DFFF781FCF2E70021C181017741827F +:103A2000C1758175704703881380C28942B1C2880D +:103A300022F4004300F128021A440A60C08970474A +:103A40000020704710B50446808AA0F57F41FF39F9 +:103A500000D0FFDFE088A082E08900B10120A075DE +:103A600010BD4FF6FF71818200218175704710B53E +:103A70000446808AA0F57F41FF3900D1FFDFA07D99 +:103A800028B9A088A18A884201D1002010BD012058 +:103A900010BD8188828A914201D1807D08B10020C9 +:103AA00070470120704720F4004221F400439A42FD +:103AB00007D100F4004001F40041884201D0012008 +:103AC00070470020704730B5044600880D4620F44A +:103AD0000040A84200D2FFDF21884FF40040884315 +:103AE0002843208030BD70B50C00054609D0082C55 +:103AF00000D2FFDF1DB1A1B2286800F044F8201DFC +:103B000070BD0DB100202860002070BD002102684A +:103B100003E093881268194489B2002AF9D100F0B1 +:103B200032B870B500260D460446082900D2FFDFE2 +:103B3000206808B91EE0044620688188A94202D0A6 +:103B400001680029F7D181880646A94201D10068A1 +:103B50000DE005F1080293B20022994209D32844EE +:103B6000491B026081802168096821600160206032 +:103B700000E00026304670BD00230B608A8002689A +:103B80000A600160704700234360021D01810260EA +:103B90007047F0B50F460188408815460C181E4640 +:103BA000AC4200D3641B3044A84200D9FFDFA01907 +:103BB000A84200D9FFDF3819F0BD2DE9F041884651 +:103BC00006460188408815460C181F46AC4200D3B3 +:103BD000641B3844A84200D9FFDFE019A84200D98D +:103BE000FFDF70883844708008EB0400BDE8F08186 +:103BF0002DE9F041054600881E461746841B88467D +:103C0000BC4200D33C442C8068883044B84200D980 +:103C1000FFDFA019B84200D9FFDF68883044688010 +:103C200008EB0400E2E72DE9F04106881D46044652 +:103C3000701980B2174688462080B84201D3C01B55 +:103C400020806088A84200D2FFDF7019B84200D9F6 +:103C5000FFDF6088401B608008EB0600C6E730B5D8 +:103C60000D460188CC18944200D3A41A408898428B +:103C700000D8FFDF281930BD2DE9F041C84D0446BA +:103C80009046A8780E46A04200D8FFDF05EB8607D5 +:103C9000B86A50F8240000B1FFDFB868002816D0D9 +:103CA000304600F044F90146B868FFF73AFF0500D6 +:103CB0000CD0B86A082E40F8245000D3FFDFB94872 +:103CC0004246294650F82630204698472846BDE807 +:103CD000F0812DE9F8431E468C1991460F460546A2 +:103CE000FF2C00D9FFDFB14500D9FFDFE4B200951A +:103CF0004DB300208046E81C20F00300A84200D00D +:103D0000FFDF4946DFF89892684689F8001089F885 +:103D1000017089F8024089F8034089F8044089F865 +:103D2000054089F8066089F80770414600F008F9F7 +:103D3000002142460F464B460098C01C20F003006D +:103D4000009012B10EE00120D4E703EB8106B062CF +:103D5000002005E0D6F828C04CF82070401CC0B206 +:103D6000A042F7D30098491C00EB8400C9B2009030 +:103D70000829E1D3401BBDE8F88310B50446EDF7F0 +:103D80008EFA08B1102010BD2078854A618802EBB8 +:103D9000800092780EE0836A53F8213043B14A1CC8 +:103DA0006280A180806A50F82100A060002010BDD0 +:103DB000491C89B28A42EED86180052010BD70B5D9 +:103DC00005460C460846EDF76AFA08B1102070BDAA +:103DD000082D01D3072070BD25700020608070BDC4 +:103DE0000EB56946FFF7EBFF00B1FFDF6846FFF74E +:103DF000C4FF08B100200EBD01200EBD10B5044661 +:103E0000082800D3FFDF6648005D10BD3EB50546BB +:103E100000246946FFF7D3FF18B1FFDF01E0641CFF +:103E2000E4B26846FFF7A9FF0028F8D02846FFF75C +:103E3000E5FF001BC0B23EBD59498978814201D9D6 +:103E4000C0B27047FF2070472DE9F041544B06295E +:103E500003D007291CD19D7900E0002500244FF6EE +:103E6000FF7603EB810713F801C00AE06319D7F866 +:103E700028E09BB25EF823E0BEF1000F04D0641C82 +:103E8000A4B2A445F2D8334603801846B34201D108 +:103E900000201CE7BDE8F041EEE6A0F57F43FF3BC4 +:103EA00001D0082901D300207047E5E6A0F57F4244 +:103EB000FF3A0BD0082909D2394A9378834205D9B1 +:103EC00002EB8101896A51F8200070470020704799 +:103ED0002DE9F04104460D46A4F57F4143F202006E +:103EE000FF3902D0082D01D30720F0E62C494FF00E +:103EF00000088A78A242F8D901EB8506B26A52F826 +:103F00002470002FF1D027483946203050F8252062 +:103F100020469047B16A284641F8248000F007F80F +:103F200002463946B068FFF727FE0020CFE61D495C +:103F3000403131F810004FF6FC71C01C084070474A +:103F40002DE9F843164E8846054600242868C01C13 +:103F500020F0030028602046FFF7E9FF315D484369 +:103F6000B8F1000F01D0002200E02A68014600925B +:103F700032B100274FEA0D00FFF7B5FD1FB106E093 +:103F800001270020F8E706EB8401009A8A6029687F +:103F9000641C0844E4B22860082CD7D3EBE6000088 +:103FA0003C0800201862020070B50E461D461146FE +:103FB00000F0D3F804462946304600F0D7F82044F4 +:103FC000001D70BD2DE9F04190460D4604004FF0F4 +:103FD000000610D00027E01C20F00300A04200D013 +:103FE000FFDFE5B141460020FFF77DFD0C3000EB1F +:103FF000850617B113E00127EDE7614F04F10C00CE +:10400000AA003C602572606000EB85002060002102 +:104010006068FAF73CFA41463868FFF764FD3046BD +:10402000BDE8F0812DE9FF4F554C804681B02068F6 +:104030009A46934600B9FFDF2068027A424503D9C9 +:10404000416851F8280020B143F2020005B0BDE8F4 +:10405000F08F5146029800F080F886B258460E99CB +:1040600000F084F885B27019001D87B22068A1465F +:1040700039460068FFF755FD04001FD06780258092 +:104080002946201D0E9D07465A4601230095FFF73D +:1040900065F92088314638440123029ACDF800A002 +:1040A000FFF75CF92088C1193846FFF788F9D9F87D +:1040B00000004168002041F82840C7E70420C5E718 +:1040C00070B52F4C0546206800B9FFDF2068017AE3 +:1040D000A9420DD9426852F8251049B1002342F88F +:1040E00025304A880068FFF747FD2168087A06E016 +:1040F00043F2020070BD4A6852F820202AB9401EDF +:10410000C0B2F8D20868FFF701FD002070BD70B59D +:104110001B4E05460024306800B9FFDF3068017A85 +:10412000A94204D9406850F8250000B1041D20467A +:1041300070BD70B5124E05460024306800B9FFDF2F +:104140003068017AA94206D9406850F8251011B1AB +:1041500031F8040B4418204670BD10B50A46012101 +:10416000FFF7F5F8C01C20F0030010BD10B50A469B +:104170000121FFF7ECF8C01C20F0030010BD000087 +:104180008C00002070B50446C2F110052819FAF71A +:1041900054F915F0FF0109D0491ECAB28020A0547D +:1041A0002046BDE870400021FAF771B970BD30B506 +:1041B00005E05B1EDBB2CC5CD55C6C40C454002BCC +:1041C000F7D130BD10B5002409E00B78521E44EA47 +:1041D000430300F8013B11F8013BD2B2DC09002A8D +:1041E000F3D110BD2DE9F04389B01E46DDE9107909 +:1041F00090460D00044622D002460846F949FDF7D4 +:1042000044FE102221463846FFF7DCFFE07B000623 +:1042100006D5F44A3946102310320846FFF7C7FF87 +:10422000102239464846FFF7CDFFF87B000606D539 +:10423000EC4A4946102310320846FFF7B8FF102217 +:1042400000212046FAF723F90DE0103EB6B208EB44 +:104250000601102322466846FFF7A9FF224628469A +:104260006946FDF712FE102EEFD818D0F2B2414683 +:104270006846FFF787FF10234A46694604A8FFF700 +:1042800096FF1023224604A96846FFF790FF2246B6 +:1042900028466946FDF7F9FD09B0BDE8F083102313 +:1042A0003A464146EAE770B59CB01E4605461346BD +:1042B00020980C468DF80800202219460DF10900BF +:1042C000FAF7BBF8202221460DF12900FAF7B5F8DC +:1042D00017A913A8CDE90001412302AA31462846B7 +:1042E000FFF780FF1CB070BD2DE9FF4F9FB014AEEB +:1042F000DDE92D5410AFBB49CDE9007620232031F4 +:104300001AA8FFF76FFF4FF000088DF808804FF0F4 +:1043100001098DF8099054F8010FCDF80A00A08822 +:10432000ADF80E0014F8010C1022C0F340008DF817 +:10433000100055F8010FCDF81100A888ADF8150050 +:1043400015F8010C2C99C0F340008DF8170006A851 +:104350008246FAF772F80AA8834610222299FAF7E1 +:104360006CF8A0483523083802AA40688DF83C80D4 +:10437000CDE900760E901AA91F98FFF733FF8DF84C +:1043800008808DF809902068CDF80A00A088ADF863 +:104390000E0014F8010C1022C0F340008DF810003C +:1043A0002868CDF81100A888ADF8150015F8010CA3 +:1043B0002C99C0F340008DF817005046FAF73DF8ED +:1043C000584610222299FAF738F8864835230838DB +:1043D00002AA40688DF83C90CDE900760E901AA9AB +:1043E0002098FFF7FFFE23B0BDE8F08FF0B59BB03B +:1043F0000C460546DDE922101E461746DDE920324F +:10440000D0F801C0CDF808C0B0F805C0ADF80CC0B8 +:104410000078C0F340008DF80E00D1F80100CDF80F +:104420000F00B1F80500ADF8130008781946C0F385 +:1044300040008DF815001088ADF8160090788DF8C2 +:1044400018000DF119001022F9F7F7FF0DF12900FE +:1044500010223146F9F7F1FF0DF1390010223946EB +:10446000F9F7EBFF17A913A8CDE90001412302AA30 +:1044700021462846FFF7B6FE1BB0F0BDF0B5A3B04D +:1044800017460D4604461E46102202A82899F9F741 +:10449000D4FF06A820223946F9F7CFFF0EA8202224 +:1044A0002946F9F7CAFF1EA91AA8CDE90001502331 +:1044B00002AA314616A8FFF795FE1698206023B091 +:1044C000F0BDF0B589B00446DDE90E070D46397838 +:1044D000109EC1F340018DF8001031789446C1F36D +:1044E00040018DF801101968CDF802109988ADF8D7 +:1044F000061099798DF808100168CDF809108188A7 +:10450000ADF80D1080798DF80F0010236A466146D2 +:1045100004A8FFF74CFE2246284604A9FDF7B5FC87 +:10452000D6F801000090B6F80500ADF80400D7F801 +:104530000100CDF80600B7F80500ADF80A0000202C +:10454000039010236A46214604A8FFF730FE224656 +:10455000284604A9FDF799FC09B0F0BD1FB51C68F9 +:1045600000945B68019313680293526803920246B9 +:1045700008466946FDF789FC1FBD10B588B00446A2 +:104580001068049050680590002006900790084637 +:104590006A4604A9FDF779FCBDF80000208008B048 +:1045A00010BD1FB51288ADF800201A88ADF80220A2 +:1045B0000022019202920392024608466946FDF7E4 +:1045C00064FC1FBD7FB5074B14460546083B9A1C8B +:1045D0006846FFF7E6FF224669462846FFF7CDFF0B +:1045E0007FBD00007062020070B5044600780E4680 +:1045F000012813D0052802D0092813D10EE0A068A5 +:1046000061690578042003F059FA052D0AD0782352 +:1046100000220420616903F0A7F903E00420616926 +:1046200003F04CFA31462046BDE8704001F08AB8EC +:1046300010B500F12D03C2799C78411D144064F33C +:104640000102C271D2070DD04A795C7922404A71C9 +:104650000A791B791A400A718278C9788A4200D98E +:10466000817010BD00224A71F5E74178012900D020 +:104670000C21017070472DE9F04F93B04FF0000B03 +:104680000C690D468DF820B0097801260C201746DC +:104690004FF00D084FF0110A4FF008091B2975D291 +:1046A000DFE811F01B00C40207031F035E03710360 +:1046B000A303B803F9031A0462049504A204EF04E7 +:1046C0002D05370555056005F305360639066806DC +:1046D0008406FE062207EB06F00614B120781D289A +:1046E0002AD0D5F808805FEA08004FD001208DF865 +:1046F0002000686A02220D908DF824200A208DF88F +:104700002500A8690A90A8880028EED098F8001023 +:1047100091B10F2910D27DD2DFE801F07C1349DE80 +:10472000FCFBFAF9F8F738089CF6F50002282DD1C1 +:1047300024B120780C2801D00026F0E38DF8202049 +:10474000CBE10420696A03F0B9F9A8880728EED103 +:10475000204600F0F2FF022809D0204600F0EDFFCD +:10476000032807D9204600F0E8FF072802D20120DD +:10477000207004E0002CB8D020780128D7D198F818 +:104780000400C11F0A2902D30A2061E0C4E1A0701D +:10479000D8F80010E162B8F80410218698F80600F5 +:1047A00084F83200012028700320207044E007289C +:1047B000BDD1002C99D020780D28B8D198F80310DD +:1047C00094F82F20C1F3C000C2F3C002104201D000 +:1047D000062000E00720890707D198F8051001425C +:1047E000D2D198F806100142CED194F8312098F831 +:1047F000051020EA02021142C6D194F8322098F83E +:10480000061090430142BFD198F80400C11F0A2945 +:10481000BAD200E008E2617D81427CD8D8F800106D +:104820006160B8F80410218198F80600A072012098 +:1048300028700E20207003208DF82000686A0D90EB +:1048400004F12D000990601D0A900F300B9022E1B9 +:104850002875FCE3412891D1204600F06EFF042822 +:1048600002D1E078C00704D1204600F066FF0F288F +:1048700084D1A88CD5F80C8080B24FF0400BE6694B +:10488000FFF745FC324641465B464E46CDF8009068 +:10489000FFF731F80B208DF82000686A0D90E06971 +:1048A0000990002108A8FFF79FFE2078042806D071 +:1048B000A07D58B1012809D003280AD04AE3052079 +:1048C0002070032028708DF82060CEE184F800A0CD +:1048D00032E712202070EAE11128BCD1204600F016 +:1048E0002CFF042802D1E078C00719D0204600F040 +:1048F00024FF062805D1E078C00711D1A07D022849 +:104900000ED0204608E0CCE084E072E151E124E1E1 +:1049100003E1E9E019E0B0E100F00FFF11289AD1BE +:10492000102208F1010104F13C00F9F786FD6078DE +:1049300001286ED012202070E078C00760D0A07DE2 +:104940000028C8D00128C6D05AE0112890D12046AE +:1049500000F0F3FE082804D0204600F0EEFE1328F5 +:1049600086D104F16C00102208F101010646F9F726 +:1049700064FD207808280DD014202070E178C80745 +:104980000DD0A07D02280AD06278022A04D0032824 +:10499000A1D035E00920F0E708B1012837D1C807D8 +:1049A00013D0A07D02281DD000200090D4E906215C +:1049B00033460EA8FFF777FC10220EA904F13C0045 +:1049C000F9F70EFDC8B1042042E7D4E90912201D11 +:1049D0008DE8070004F12C0332460EA8616BFFF747 +:1049E00070FDE9E7606BC1F34401491E0068C840EF +:1049F00000F0010040F08000D7E72078092806D1B8 +:104A000085F800908DF8209036E32870EFE30920B8 +:104A1000FBE79EE1112899D1204600F08EFE0A287E +:104A200002D1E078C00704D1204600F086FE1528A8 +:104A30008CD104F13C00102208F101010646F9F77F +:104A4000FCFC20780A2816D016202070D4E9093200 +:104A5000606B611D8DE80F0004F15C0304F16C02D2 +:104A600047310EA8FFF7C2FC10220EA93046F9F715 +:104A7000B7FC18B1F9E20B20207073E22046FFF773 +:104A8000D7FDA078216AC0F110020B18002118464A +:104A9000F9F7FDFC26E3394608A8FFF7A5FD064611 +:104AA0003CE20228B7D1204600F047FE042804D398 +:104AB000204600F042FE082809D3204600F03DFEC3 +:104AC0000E2829D3204600F038FE122824D2A07DDB +:104AD0000228A0D10E208DF82000686A0D9098F869 +:104AE00001008DF82400F5E3022894D1204600F05F +:104AF00024FE002810D0204600F01FFE0128F9D027 +:104B0000204600F01AFE0C28F4D004208DF8240072 +:104B100098F801008DF8250060E21128FCD1002CE6 +:104B2000FAD020781728F7D16178606A022912D06C +:104B30005FF0000101EB4101182606EBC1011022D4 +:104B4000405808F10101F9F778FC0420696A00F087 +:104B5000E7FD2670F0E50121ECE70B28DCD1002C05 +:104B6000DAD020781828D7D16078616A02281CD062 +:104B70005FF0000000EB4002102000EBC20009587B +:104B8000B8F8010008806078616A02280FD0002020 +:104B900000EB4002142000EBC2000958404650F8D8 +:104BA000032F0A604068486039E00120E2E70120F5 +:104BB000EEE71128B0D1002CAED020781928ABD167 +:104BC0006178606A022912D05FF0000101EB4101B7 +:104BD0001C2202EBC1011022405808F10101F9F733 +:104BE0002CFC0420696A00F09BFD1A20B6E001212C +:104BF000ECE7082890D1002C8ED020781A288BD191 +:104C0000606A98F80120017862F347010170616AD7 +:104C1000D8F8022041F8012FB8F806008880042057 +:104C2000696A00F07DFD90E2072011E638780128DE +:104C300094D1182204F114007968F9F7FEFBE079A9 +:104C4000C10894F82F0001EAD001E07861F3000078 +:104C5000E070217D002974D12178032909D0C00793 +:104C600025D0032028708DF82090686A0D9041208F +:104C700008E3607DA178884201D90620E8E5022694 +:104C80002671E179204621F0E001E171617A21F09D +:104C9000F0016172A17A21F0F001A172FFF7C8FC66 +:104CA0002E708DF82090686A0D900720EAE20420AB +:104CB000ABE6387805289DD18DF82000686A0D9004 +:104CC000B8680A900720ADF824000A988DF830B033 +:104CD0006168016021898180A17A8171042020703E +:104CE000F8E23978052985D18DF82010696A0D918F +:104CF000391D09AE0EC986E80E004121ADF8241019 +:104D00008DF830B01070A88CD7F80C8080B2402697 +:104D1000A769FFF70EFA41463A463346C846CDF832 +:104D20000090FEF71CFE002108A8FFF75DFCE0786C +:104D300020F03E00801CE0702078052802D00F2073 +:104D40000CE04AE1A07D20B1012802D0032802D066 +:104D500002E10720BEE584F80080EDE42070EBE47A +:104D6000102104F15C0002F0C2FB606BB0BBA07DBF +:104D700018B1012801D00520FDE006202870F84870 +:104D80006063A063C2E23878022894D1387908B110 +:104D90002875B7E3A07D022802D0032805D022E0C1 +:104DA000B8680028F5D060631CE06078012806D060 +:104DB000A07994F82E10012805D0E94806E0A179E1 +:104DC00094F82E00F7E7B8680028E2D06063E07836 +:104DD000C00701D0012902D0E14803E003E0F868F0 +:104DE0000028D6D0A06306200FE68DF82090696ACF +:104DF0000D91E1784846C90709D06178022903D1AD +:104E0000A17D29B1012903D0A17D032900D007206C +:104E1000287033E138780528BBD1207807281ED0C8 +:104E200084F800A005208DF82000686A0D90B8680D +:104E30000A90ADF824A08DF830B003210170E1781C +:104E4000CA070FD0A27D022A1AD000210091D4E90E +:104E5000061204F15C03401CFFF725FA6BE384F8AB +:104E60000090DFE7D4E90923211D8DE80E0004F14D +:104E70002C0304F15C02401C616BFFF722FB5AE338 +:104E8000626BC1F34401491E1268CA4002F001017D +:104E900041F08001DAE738780528BDD18DF820008F +:104EA000686A0D90B8680A90ADF824A08DF830B00B +:104EB000042100F8011B102204F15C01F9F7BDFA8E +:104EC000002108A8FFF790FB2078092801D01320C3 +:104ED00044E70A2020709AE5E078C10742D0A17D1E +:104EE000012902D0022927D038E0617808A80129D9 +:104EF00016D004F16C010091D4E9061204F15C03B0 +:104F0000001DFFF7BBFA0A20287003268DF82080C9 +:104F1000686A0D90002108A8FFF766FBE1E2C7E28E +:104F200004F15C010091D4E9062104F16C03001D39 +:104F3000FFF7A4FA0026E9E7C0F3440114290DD2D3 +:104F40004FF0006101EBB0104FEAB060E0706078A4 +:104F5000012801D01020BDE40620FFE6607801287A +:104F60003FF4B6AC0A2050E5E178C90708D0A17D2E +:104F7000012903D10B202870042030E028702EE096 +:104F80000E2028706078616B012818D004F15C0352 +:104F900004F16C020EA8FFF7E1FA2046FFF748FB88 +:104FA000A0780EAEC0F1100230440021F9F76FFA7C +:104FB00006208DF82000686A09960D909BE004F1A8 +:104FC0006C0304F15C020EA8FFF7C8FAE8E7397831 +:104FD000022903D139790029D0D0297592E28DF8C0 +:104FE0002000686A0D9056E538780728F6D1D4E994 +:104FF00009216078012808D004F16C00CDE9000295 +:10500000029105D104F16C0304E004F15C00F5E7C2 +:1050100004F15C0304F14C007A680646216AFFF74C +:1050200063F96078012822D1A078216AC0F11002CA +:105030000B1800211846F9F72AFAD4E90923606B06 +:1050400004F12D018DE80F0004F15C0300E05BE248 +:1050500004F16C0231460EA8FFF7C8F910220EA920 +:1050600004F13C00F9F7BCF908B10B20ACE485F879 +:10507000008000BF8DF82090686A0D908DF824A004 +:1050800009E538780528A9D18DF82000686A0D90C7 +:10509000B8680A90ADF824A08DF830B080F8008090 +:1050A000617801291AD0D4E9092104F12D03A66BF6 +:1050B00003910096CDE9013204F16C0304F15C0226 +:1050C00004F14C01401CFFF791F9002108A8FFF7FB +:1050D0008BFA6078012805D015203FE6D4E9091243 +:1050E000631DE4E70E20287006208DF82000686A12 +:1050F000CDF824B00D90A0788DF82800CBE4387856 +:105100000328C0D1E079C00770D00F202870072095 +:1051100065E7387804286BD11422391D04F1140096 +:10512000F9F78BF9616A208CA1F80900616AA0780F +:10513000C871E179626A01F003011172616A627AF1 +:105140000A73616AA07A81F8240016205DE485F86C +:1051500000A08DF82090696A50460D9192E0000001 +:10516000706202003878052842D1B868A861617879 +:10517000606A022901D0012100E0002101EB410118 +:10518000142606EBC1014058082102F0B0F96178FD +:10519000606A022901D0012100E0002101EB4101F8 +:1051A00006EBC101425802A8E169FFF70BFA6078EB +:1051B000626A022801D0012000E0002000EB4001DB +:1051C000102000EBC1000223105802A90932FEF79B +:1051D000EEFF626AFD4B0EA80932A169FFF7E1F903 +:1051E0006178606A022904D0012103E044E18DE086 +:1051F000BFE0002101EB4101182606EBC101A278B6 +:1052000040580EA9F9F719F96178606A022901D0AE +:10521000012100E0002101EB410106EBC1014158F1 +:10522000A0780B18C0F1100200211846F9F72FF9E9 +:1052300005208DF82000686A0D90A8690A90ADF8E5 +:1052400024A08DF830B0062101706278616A022ACC +:1052500001D0012200E0002202EB420206EBC20272 +:10526000401C89581022F9F7E8F8002108A8FFF738 +:10527000BBF91220C5F818B028708DF82090686A24 +:105280000D900B208DF8240005E43878052870D1A6 +:105290008DF82000686A0D90B8680A900B20ADF870 +:1052A00024000A98072101706178626A022901D0FE +:1052B000012100E0002101EB4103102101EBC301BA +:1052C00051580988A0F801106178626A022902D059 +:1052D000012101E02FE1002101EB4103142101EB49 +:1052E000C30151580A6840F8032F4968416059E0EA +:1052F0001920287001208DF8300074E616202870DF +:105300008DF830B0002108A8FFF76EF9032617E1E9 +:1053100014202870AEE6387805282AD18DF82000B0 +:10532000686A0D90B8680A90ADF824A08DF830B086 +:1053300080F800906278616A4E46022A01D001220C +:1053400000E0002202EB42021C2303EBC202401CDD +:1053500089581022F9F771F8002108A8FFF744F9DD +:10536000152028708DF82060686A0D908DF82460F3 +:1053700039E680E0387805287DD18DF82000686A0C +:105380000D90B8680A90ADF8249009210170616908 +:10539000097849084170616951F8012FC0F802206D +:1053A0008988C18020781C28A8D1A1E7E078C007AF +:1053B00002D04FF0060C01E04FF0070C6078022895 +:1053C0000AD000BF4FF0000000EB040101F1090119 +:1053D00005D04FF0010004E04FF00100F4E74FF07A +:1053E00000000B78204413EA0C030B7010F8092F0F +:1053F00002EA0C02027004D14FF01B0C84F800C0CA +:10540000D2B394F801C0BCF1010F00D09BB990F861 +:1054100000C0E0465FEACC7C04D028F001060670AC +:10542000102606E05FEA887C05D528F002060670A3 +:1054300013262E70032694F801C0BCF1020F00D091 +:1054400092B991F800C05FEACC7804D02CF0010644 +:105450000E70172106E05FEA8C7805D52CF0020665 +:105460000E701921217000260078D0BBCAB3C3BBCF +:105470001C20207035E012E002E03878062841D187 +:105480001A2015E4207801283CD00C283AD0204678 +:10549000FFF7EBF809208DF82000686A0D9031E0E5 +:1054A0003878052805D00620387003261820287083 +:1054B00046E005208DF82000696A0D91B9680A91CF +:1054C0000221ADF8241001218DF830100A990870DE +:1054D000287D4870394608A8FFF786F80646182048 +:1054E0002870012E0ED02BE001208DF82000686A74 +:1054F0000D9003208DF82400287D8DF8250085F877 +:1055000014B012E0287D80B11D2020701720287073 +:105510008DF82090686A0D9002208DF8240039469D +:1055200008A8FFF761F806460AE00CB1FE202070DB +:105530009DF8200020B1002108A8FFF755F80CE4E1 +:1055400013B03046BDE8F08F2DE9F04387B00C462C +:105550004E6900218DF804100120257803460227AA +:105560004FF007094FF0050C85B1012D53D0022DE6 +:1055700039D1FE2030708DF80030606A059003202C +:105580008DF80400207E8DF8050063E02179012963 +:1055900025D002292DD0032928D0042923D1B17D7B +:1055A000022920D131780D1F042D04D30A3D032D8B +:1055B00001D31D2917D12189022914D38DF8047034 +:1055C000237020899DF80410884201E0686202007F +:1055D00018D208208DF80000606A059057E07078B6 +:1055E0000128EBD0052007B0BDE8F0831D20307006 +:1055F000E4E771780229F5D131780C29F3D18DF8DF +:105600000490DDE7083402F804CB94E80B0082E84C +:105610000B000320E7E71578052DE4D18DF800C0D5 +:10562000656A0595956802958DF8101094F80480C8 +:10563000B8F1010F13D0B8F1020F2DD0B8F1030F5C +:105640001CD0B8F1040FCED1ADF804700E20287034 +:10565000207E687000216846FEF7C6FF0CE0ADF8BA +:1056600004700B202870207E002100F01F0068705D +:105670006846FEF7B9FF37700020B4E7ADF8047054 +:105680008DF8103085F800C0207E687027701146B4 +:105690006846FEF7A9FFA6E7ADF804902B70207FBF +:1056A0006870607F00F00100A870A07F00F01F000C +:1056B000E870E27F2A71C0071CD094F8200000F047 +:1056C0000700687194F8210000F00700A87100211C +:1056D0006846FEF789FF2868F062A8883086A879B6 +:1056E00086F83200A069407870752879B0700D2076 +:1056F0003070C1E7A9716971E9E700B587B0042886 +:105700000CD101208DF800008DF8040000200591D7 +:105710008DF8050001466846FEF766FF07B000BD3C +:1057200070B50C46054602F0C9F921462846BDE889 +:1057300070407823002202F017B908B10078704752 +:105740000C20704770B50C0005784FF000010CD0AC +:1057500021702146EFF7D1FD69482178405D8842EC +:1057600001D1032070BD022070BDEFF7C6FD0020FF +:1057700070BD0279012A05D000220A704B78012BF6 +:1057800002D003E0042070470A758A610279930011 +:10579000521C0271C15003207047F0B587B00F460C +:1057A00005460124287905EB800050F8046C7078D8 +:1057B000411E02290AD252493A46083901EB8000BB +:1057C000314650F8043C2846984704460CB1012C59 +:1057D00011D12879401E10F0FF00287101D0032458 +:1057E000E0E70A208DF80000706A0590002101961C +:1057F0006846FFF7A7FF032CD4D007B02046F0BDC2 +:1058000070B515460A46044629461046FFF7C5FFFF +:10581000064674B12078FE280BD1207C30B10020E0 +:105820002870294604F10C00FFF7B7FF2046FEF769 +:105830001CFF304670BD704770B50E4604467C2292 +:105840000021F8F724FE0225012E03D0022E04D0F9 +:10585000052070BD0120607000E065702046FEF7F5 +:1058600004FFA575002070BD28B1027C1AB10A465C +:1058700000F10C01C4E70120704710B5044686B062 +:10588000042002F01BF92078FE2806D000208DF8B5 +:10589000000069462046FFF7E7FF06B010BD7CB563 +:1058A0000E4600218DF804104178012903D0022909 +:1058B00003D0002405E0046900E044690CB1217CB8 +:1058C00089B16D4601462846FFF753FF032809D1E9 +:1058D000324629462046FFF793FF9DF80410002921 +:1058E00000D004207CBD04F10C05EBE730B40C467D +:1058F0000146034A204630BC024B0C3AFEF751BE2B +:10590000AC6202006862020070B50D46040011D05E +:1059100085B1220100212846F8F7B9FD102250492F +:105920002846F8F78AFD4F48012101704470456010 +:10593000002070BD012070BD70B505460024494EA1 +:1059400011E07068AA7B00EB0410817B914208D1C2 +:10595000C17BEA7B914204D10C222946F8F740FD35 +:1059600030B1641CE4B230788442EAD3002070BDC8 +:10597000641CE0B270BD70B50546FFF7DDFF00287E +:1059800005D1384C20786178884201D3002070BD61 +:105990006168102201EB00102946F8F74EFD2078CF +:1059A000401CC0B2207070BD2E48007870472D4951 +:1059B0000878012802D0401E08700020704770B59A +:1059C0000D460021917014461180022802D0102843 +:1059D00015D105E0288890B10121A17010800CE05C +:1059E000284613B1FFF7C7FF01E0FFF7A5FFA0703E +:1059F00010F0FF0F03D0A8892080002070BD012087 +:105A000070BD0023DBE770B5054614460E0009D0D3 +:105A100000203070A878012806D003D911490A78EF +:105A200090420AD9012070BD24B1287820702888BE +:105A3000000A5070022008700FE064B1496810221B +:105A400001EB001120461039F8F7F7FC2878207395 +:105A50002888000A607310203070002070BD00009C +:105A6000BB620200900000202DE9F04190460C46F8 +:105A700007460025FE48072F00EB881607D2DFE80F +:105A800007F00707070704040400012500E0FFDF13 +:105A900006F81470002D13D0F548803000EB880113 +:105AA00091F82700202803D006EB4000447001E065 +:105AB00081F8264006EB44022020507081F82740F0 +:105AC000BDE8F081F0B51F4614460E460546202A73 +:105AD00000D1FFDFE649E648803100EB871C0CEB84 +:105AE000440001EB8702202E07D00CEB46014078E2 +:105AF0004B784870184620210AE092F8253040780B +:105B000082F82500F6E701460CEB4100057040786D +:105B1000A142F8D192F82740202C03D00CEB44048A +:105B2000637001E082F826300CEB4104202363709F +:105B300082F82710F0BD30B50D46CE4B4419002237 +:105B4000181A72EB020100D2FFDFCB48854200DD5C +:105B5000FFDFC9484042854200DAFFDFC548401CEC +:105B6000844207DA002C01DB204630BDC148401CCE +:105B7000201830BDBF48C043FAE710B5044601689D +:105B8000407ABE4A52F82020114450B10220084405 +:105B900020F07F40EDF763F894F90810BDE810405D +:105BA000C9E70420F3E72DE9F047B14E803696F8B7 +:105BB0002D50DFF8BC9206EB850090F8264034E0CB +:105BC00009EB85174FF0070817F81400012806D0D5 +:105BD00004282ED005282ED0062800D0FFDF01F0A3 +:105BE00025F9014607EB4400427806EB850080F872 +:105BF000262090F82720A24202D1202280F82720D8 +:105C0000084601F01EF92A4621460120FFF72CFF25 +:105C10009B48414600EB041002682046904796F8E6 +:105C20002D5006EB850090F82640202CC8D1BDE809 +:105C3000F087022000E003208046D0E710B58C4CAE +:105C40002021803484F8251084F8261084F8271049 +:105C5000002084F8280084F82D0084F82E10411EBE +:105C6000A16044F8100B2074607420736073A073FB +:105C70008449E07720750870487000217C4A103C08 +:105C800002F81100491CC9B22029F9D30120ECF710 +:105C9000D6FE0020ECF7D3FE012084F82200EDF7B9 +:105CA000FFF87948EDF711F9764CA41E207077487B +:105CB000EDF70BF96070BDE81040ECF74DBE10B584 +:105CC000ECF76FFE6F4CA41E2078EDF717F96078A3 +:105CD000EDF714F9BDE8104001F0E0B8202070475E +:105CE0000020ECF785BE70B5054601240E46AC4099 +:105CF0005AB1FFF7F5FF0146654800EBC500C0F853 +:105D00001015C0F81465634801E06248001D046086 +:105D100070BD2DE9F34F564C0025803404EB810A09 +:105D200089B09AF82500202821D0691E0291544993 +:105D3000009501EB0017391D03AB07C983E8070085 +:105D4000A18BADF81C10A07F8DF81E009DF81500EA +:105D5000A046C8B10226494951F820400399A2192A +:105D6000114421F07F41019184B102210FE0012013 +:105D7000ECF765FE0020ECF762FEECF730FE01F078 +:105D80008DF884F82F50A9E00426E4E700218DF86F +:105D90001810022801D0012820D103980119099870 +:105DA000081A801C9DF81C1020F07F4001B10221D0 +:105DB000353181420BD203208DF815000398C4F1D0 +:105DC0003201401A20F07F40322403900CE098F812 +:105DD000240018B901F043FA002863D0322C03D212 +:105DE00014B101F04FF801E001F058F8254A10789D +:105DF00018B393465278039B121B00219DF818405C +:105E0000994601281AD0032818D000208DF81E00CA +:105E1000002A04DD981A039001208DF818009DF8DF +:105E20001C0000B1022103981B4A20F07F40039020 +:105E300003AB099801F03EF810B110E00120E5E74E +:105E40009DF81D0018B99BF80000032829D08DF893 +:105E50001C50CDF80C908DF818408DF81E509DF810 +:105E6000180010B30398012381190022184615E089 +:105E7000840A0020FF7F841E0020A107CC6202005C +:105E8000840800209A00002017780100A75B010019 +:105E900000F0014004F50140FFFF3F00ECF722FE57 +:105EA00006E000200BB0BDE8F08F0120ECF7C7FD45 +:105EB00097F90C20012300200199ECF713FEF87BE1 +:105EC000C00701D0ECF7F7FE012188F82F108AF8FF +:105ED000285020226946FE48F8F7AFFA0120E1E792 +:105EE0002DE9F05FDFF8E883064608EB860090F8BE +:105EF0002550202D1FD0A8F180002C4600EB8617DE +:105F0000A0F50079DFF8CCB305E0A24607EB4A0024 +:105F10004478202C0AD0ECF730FE09EB04135A46E3 +:105F200001211B1D00F0C6FF0028EED0AC4202D0BC +:105F3000334652461EE0E84808B1AFF30080ECF764 +:105F40001CFE98F82F206AB1D8F80C20411C891A41 +:105F50000902CA1701EB12610912002902DD0020B3 +:105F6000BDE8F09F3146FFF7D4FE08B10120F7E706 +:105F700033462A4620210420FFF7A4FDEFE72DE950 +:105F8000F041D34C2569ECF7F8FD401B0002C11726 +:105F900000EB1160001200D4FFDF94F8220000B182 +:105FA000FFDF012784F8227094F82E00202800D10A +:105FB000FFDF94F82E60202084F82E00002584F85E +:105FC0002F5084F8205084F82150C4482560007870 +:105FD000022833D0032831D000202077A068401C4D +:105FE00005D04FF0FF30A0600120ECF728FD002025 +:105FF000ECF725FDECF721FEECF719FEECF7EFFCD2 +:106000000EF0D6FDB648056005604FF0E0214FF474 +:106010000040B846C1F88002ECF7BBFE94F82D7042 +:106020003846FFF75DFF0028FAD0A948803800EB1A +:10603000871010F81600022802D006E00120CCE7F5 +:106040003A4631460620FFF70FFD84F8238004EB23 +:10605000870090F82600202804D0A048801E4078B1 +:10606000ECF752FF207F002803D0ECF7D6FD257710 +:10607000657725E5964910B591F82D2000248039E3 +:1060800001EB821111F814302BB1641CE4B2202C06 +:10609000F8D3202010BD934901EB041108600020C3 +:1060A000C87321460120FFF7DFFC204610BD10B564 +:1060B000012801D0032800D171B3854A92F82D3010 +:1060C000834C0022803C04EB831300BF13F8124082 +:1060D0000CB1082010BD521CD2B2202AF6D37F4A40 +:1060E00048B1022807D0072916D2DFE801F01506CB +:1060F000080A0C0E100000210AE01B2108E03A21DA +:1061000006E0582104E0772102E0962100E0B52165 +:1061100051701070002010BD072010BD6F4810B5E1 +:106120004078ECF79CFD80B210BD10B5202811D24C +:10613000674991F82D30A1F1800202EB831414F825 +:1061400010303BB191F82D3002EB831212F8102081 +:10615000012A01D0002010BD91F82D200146002019 +:10616000FFF782FC012010BD10B5ECF706FDBDE87D +:106170001040ECF774BD2DE9F0410E46544F017804 +:106180002025803F0C4607EB831303E0254603EBF5 +:1061900045046478944202D0202CF7D108E0202CEA +:1061A00006D0A14206D103EB41014978017007E016 +:1061B000002085E403EB440003EB45014078487080 +:1061C000494F7EB127B1002140F22D40AFF300804E +:1061D0003078A04206D127B100214FF48660AFF39A +:1061E0000080357027B1002140F23540AFF30080C8 +:1061F000012065E410B542680B689A1A1202D417A0 +:1062000002EB1462121216D4497A91B1427A82B921 +:10621000364A006852F82110126819441044001DD3 +:10622000891C081A0002C11700EB11600012322805 +:1062300001DB012010BD002010BD2DE9F047294EE3 +:10624000814606F500709846144600EB811712E06F +:1062500006EB0415291D4846FFF7CCFF68B988F8FE +:106260000040A97B99F80A00814201D80020DEE4B1 +:1062700007EB44004478202CEAD10120D7E42DE933 +:10628000F047824612480E4600EB8600DFF8548045 +:1062900090F825402020107008F5007099461546AA +:1062A00000EB86170BE000BF08EB04105146001D01 +:1062B000FFF7A0FF28B107EB44002C704478202C96 +:1062C000F2D1297889F800104B46224631460FE07A +:1062D000040B0020FFFF3F00000000009A00002098 +:1062E00000F500408408002000000000CC6202009D +:1062F0005046BDE8F047A0E72DE9FC410F460446B3 +:106300000025FE4E10E000BF9DF80000256806EB5A +:1063100000108168204600F0E1FD2068A84202D10B +:106320000020BDE8FC8101256B4601AA39462046C4 +:10633000FFF7A5FF0028E7D02846F2E770B504462E +:10634000EF480125A54300EB841100EB85104022A6 +:10635000F8F773F8EB4E26B1002140F29D40AFF301 +:106360000080E748803000EB850100EB8400D0F826 +:106370002500C1F8250026B1002140F2A140AFF36D +:106380000080284670BD8A4203D003460520FFF7EF +:1063900099BB202906D0DA4A02EB801000EB4100BD +:1063A00040787047D649803101EB800090F8250095 +:1063B0007047D24901EB0010001DFFF7DEBB7CB532 +:1063C0001D46134604460E4600F1080221461846B3 +:1063D000ECF752FC94F908000F2804DD1F382072F6 +:1063E0002068401C206096B10220C74951F8261051 +:1063F000461820686946801B20F07F40206094F991 +:1064000008002844C01C1F2803DA012009E00420EA +:10641000EBE701AAECF730FC9DF8040010B10098FE +:10642000401C00900099206831440844C01C20F0B2 +:106430007F4060607CBDFEB50C46064609786079F9 +:10644000907220791F461546507279B12179002249 +:106450002846A368FFF7B3FFA9492846803191F881 +:106460002E20202A0AD00969491D0DE0D4E9022313 +:10647000217903B02846BDE8F040A0E7A349497858 +:10648000052900D20521314421F07F4100F026FD8D +:1064900039462846FFF730FFD4E9023221796846B1 +:1064A000FFF78DFF2B4600213046019A00F002FDD8 +:1064B000002806D103B031462846BDE8F04000F080 +:1064C0000DBDFEBD2DE9F14F84B000F0C3FCF0B16D +:1064D00000270498007800284FF000006DD1884D07 +:1064E000884C82468346803524B1002140F2045016 +:1064F000AFF3008095F82D8085F823B0002624B1F5 +:10650000002140F20950AFF3008017B105E00127E8 +:10651000DFE74046FFF712FF804624B1002140F23A +:106520001150AFF30080ECF728FB814643466A46E2 +:106530000499FFF780FF24B1002140F21750AFF318 +:10654000008095F82E0020280CD029690098401A68 +:106550000002C21700EB1260001203D5684600F07B +:10656000BDFC01264CB1002140F22150AFF3008068 +:10657000002140F22650AFF300806B46644A0021B0 +:10658000484600F097FC98B127B941466846FFF7A6 +:10659000B3FE064326B16846FFF7EFFA0499886018 +:1065A0004FF0010A24B1002140F23A50AFF30080CD +:1065B00095F82300002897D1504605B073E42DE9E3 +:1065C000F04F89B08B46824600F044FC4C4C80343E +:1065D00030B39BF80000002710B1012800D0FFDF86 +:1065E000484D25B1002140F2F950AFF300804349F6 +:1065F000012001EB0A18A946CDF81C005FEA090644 +:1066000004D0002140F20160AFF30080079800F051 +:1066100018FC94F82D50002084F8230067B119E08D +:1066200094F82E000127202800D1FFDF9BF80000FE +:106630000028D5D0FFDFD3E72846FFF77FFE0546C9 +:1066400026B1002140F20B60AFF3008094F82300E4 +:106650000028D3D126B1002140F21560AFF30080AD +:10666000ECF78BFA2B4602AA59460790FFF7E3FE98 +:1066700098F80F005FEA060900F001008DF813009A +:1066800004D0002140F21F60AFF300803B462A4651 +:1066900002A9CDF800A0079800F02BFC064604EBF9 +:1066A000850090F828000090B9F1000F04D0002177 +:1066B00040F22660AFF3008000F0B8FB0790B9F11C +:1066C000000F04D0002140F22C60AFF3008094F85A +:1066D0002300002892D1B9F1000F04D0002140F22C +:1066E0003460AFF300800DF1080C9CE80E00C8E99F +:1066F0000112C8F80C30BEB30CE000008408002082 +:10670000840A002000000000CC6202009A000020F1 +:10671000FFFF3F005FEA090604D0002140F241601C +:10672000AFF300800098B84312D094F82E002028D0 +:106730000ED126B1002140F24660AFF3008028461A +:10674000FFF7CEFB20B99BF80000D8B3012849D051 +:10675000B9F1000F04D0002140F26360AFF3008074 +:10676000284600F05CFB01265FEA090504D0002101 +:1067700040F26C60AFF30080079800F062FB25B137 +:1067800000214FF4CE60AFF300808EB194F82D005D +:1067900004EB800090F82600202809D025B10021C4 +:1067A00040F27760AFF30080F7484078ECF7ACFB3D +:1067B00025B1002140F27C60AFF3008009B0304683 +:1067C000BDE8F08FFFE7B9F1000F04D0002140F2DF +:1067D0004E60AFF3008094F82D2051460420FFF75F +:1067E00043F9C0E7002E3FF409AF002140F25960A1 +:1067F000AFF3008002E72DE9F84FE44D814695F8AC +:106800002D004FF00008E24C4FF0010B474624B139 +:10681000002140F28A60AFF30080584600F011FB7F +:1068200085F8237024B1002140F28F60AFF300801F +:1068300095F82D00FFF782FD064695F8230028B154 +:10684000002CE4D0002140F295604BE024B10021FF +:1068500040F29960AFF30080CC48803800EB86119D +:1068600011F81900032856D1334605EB830A4A462E +:106870009AF82500904201D1012000E0002000900C +:106880000AF125000021FFF776FC0146009801423D +:1068900003D001228AF82820AF77E1B324B1002188 +:1068A00040F29E60AFF30080324649460120FFF778 +:1068B000DBF89AF828A024B1002140F2A960AFF3D8 +:1068C000008000F0B3FA834624B1002140F2AE60AC +:1068D000AFF3008095F8230038B1002C97D0002149 +:1068E00040F2B260AFF3008091E7BAF1000F07D039 +:1068F00095F82E00202803D13046FFF7F1FAE0B1D9 +:1069000024B1002140F2C660AFF30080304600F0B1 +:1069100086FA4FF0010824B1002140F2CF60AFF3B6 +:106920000080584600F08DFA24B1002140F2D36077 +:10693000AFF300804046BDE8F88F002CF1D0002175 +:1069400040F2C160AFF30080E6E70120ECF750B8F9 +:106950008D48007870472DE9F0418C4C94F82E005A +:1069600020281FD194F82D6004EB860797F8255056 +:10697000202D00D1FFDF8549803901EB861000EB27 +:106980004500407807F8250F0120F87084F82300AF +:10699000294684F82E50324602202234FFF764F84C +:1069A0000020207005E42DE9F0417A4E774C012556 +:1069B00038B1012821D0022879D003287DD0FFDF0B +:1069C00017E400F05FFAFFF7C6FF207E00B1FFDF9B +:1069D00084F821500020ECF732F8A168481C04D05C +:1069E000012300221846ECF77DF814F82E0F2178C9 +:1069F00006EB01110A68012154E0FFF7ACFF01200A +:106A0000ECF71DF894F8210050B1A068401C07D0A5 +:106A100014F82E0F217806EB01110A68062141E0D7 +:106A2000207EDFF86481002708F10208012803D0E6 +:106A300002281ED0FFDFB5E7A777ECF7EEF898F84D +:106A40000000032801D165772577607D524951F810 +:106A5000200094F8201051B948B161680123091A47 +:106A600000221846ECF73EF8022020769AE72776B7 +:106A700098E784F8205000F005FAA07F50B198F80C +:106A8000010061680123091A00221846ECF72AF870 +:106A9000257600E0277614F82E0F217806EB0111F9 +:106AA0000A680021BDE8F041104700E005E03648E3 +:106AB0000078BDE8F041ECF727BAFFF74CFF14F877 +:106AC0002E0F217806EB01110A680521EAE710B5BF +:106AD0002E4C94F82E00202800D1FFDF14F82E0F42 +:106AE00021782C4A02EB01110A68BDE8104004210C +:106AF00010477CB5254C054694F82E00202800D17F +:106B0000FFDFA068401C00D0FFDF94F82E00214971 +:106B100001AA01EB0010694690F90C002844ECF73B +:106B2000ABF89DF904000F2801DD012000E00020F2 +:106B3000009908446168084420F07F41A16094F8FE +:106B40002100002807D002B00123BDE870400022D8 +:106B50001846EBF7C7BF7CBD30B5104A0B1A541C62 +:106B6000B3EB940F1ED3451AB5EB940F1AD393428F +:106B700003D9101A43185B1C14E0954210D9511A1E +:106B80000844401C43420DE098000020040B002004 +:106B90000000000084080020CC620200FF7F841EF9 +:106BA000FFDF0023184630BD0123002201460220EA +:106BB000EBF798BF0220EBF742BFEBF7DEBF2DE902 +:106BC000FE4FEE4C05468A4694F82E00202800D150 +:106BD000FFDFEA4E94F82E10A0462046A6F520725C +:106BE00002EB011420218DF8001090F82D10376968 +:106BF00000EB8101D8F8000091F82590284402AA02 +:106C000001A90C36ECF738F89DF90800002802DDE0 +:106C10000198401C0190A0680199642D084452D34A +:106C2000D74B00225B1B72EB02014CD36168411A07 +:106C300021F07F41B1F5800F45D220F07F40706098 +:106C400086F80AA098F82D1044466B464A4630460E +:106C5000FFF7F3FAB0B3A068401C10D0EBF78DFF3C +:106C6000A168081A0002C11700EB11600012022887 +:106C70002BDD0120EBF7E3FE4FF0FF30A06094F82E +:106C80002D009DF8002020210F34FFF77CFBA17F11 +:106C9000BA4A803A02EB8111E27F01EB420148706F +:106CA00054F80F0C284444F80F0C012020759DF86F +:106CB0000000202803D0B3484078ECF725F90120E4 +:106CC000BDE8FE8F01E00020FAE77760FBE72DE9E1 +:106CD000F047AA4C074694F82D00A4F1800606EB75 +:106CE000801010F8170000B9FFDF94F82D50A0466F +:106CF000A54C24B1002140F6EA00AFF3008040F635 +:106D0000F60940F6FF0A06EB851600BF16F81700D5 +:106D1000012819D0042811D005280FD006280DD03D +:106D20001CB100214846AFF300800FF02DF8002C75 +:106D3000ECD000215046AFF30080E7E72A46394601 +:106D40000120FEF791FEF2E74FF0010A4FF0000933 +:106D5000454624B1002140F60610AFF300805046AE +:106D600000F06FF885F8239024B1002140F60B1055 +:106D7000AFF3008095F82D00FFF7E0FA064695F88E +:106D8000230028B1002CE4D0002140F611101FE0B0 +:106D900024B1002140F61510AFF3008005EB86000A +:106DA00000F1270133463A462630FFF7E4F924B1D3 +:106DB000002140F61910AFF3008000F037F882464A +:106DC00095F8230038B1002CC3D0002140F61F10E5 +:106DD000AFF30080BDE785F82D60012085F8230022 +:106DE000504600F02EF8002C04D0002140F62C1064 +:106DF000AFF30080BDE8F08730B504465F480D462C +:106E000090F82D005D49803901EB801010F81400D6 +:106E100000B9FFDF5D4800EB0410C57330BD574972 +:106E200081F82D00012081F82300704710B55848E3 +:106E300008B1AFF30080EFF3108000F0010072B6EC +:106E400010BD10B5002804D1524808B1AFF300803E +:106E500062B610BD50480068C005C00D10D0103893 +:106E600040B2002804DB00F1E02090F8000405E0C7 +:106E700000F00F0000F1E02090F8140D4009704779 +:106E80000820704710B53D4C94F82400002804D128 +:106E9000F4F712FF012084F8240010BD10B5374C20 +:106EA00094F82400002804D0F4F72FFF002084F881 +:106EB000240010BD10B51C685B68241A181A24F051 +:106EC0007F4420F07F40A14206D8B4F5800F03D262 +:106ED000904201D8012010BD002010BDD0E9003241 +:106EE000D21A21F07F43114421F07F41C0E90031E3 +:106EF00070472DE9FC418446204815468038089C9F +:106F000000EB85160F4616F81400012804D002285D +:106F100002D00020BDE8FC810B46204A01216046DA +:106F2000FFF7C8FFF0B101AB6A4629463846FFF7C4 +:106F3000A6F9B8B19DF804209DF800102846FFF787 +:106F400022FA06EB440148709DF8000020280DD07D +:106F500006EB400044702A4621460320FEF784FDDC +:106F60000120D7E72A4621460420F7E703480121FC +:106F700000EB850000F8254FC170ECE7040B002002 +:106F8000FF1FA107980000200000000084080020D7 +:106F9000000000000000000004ED00E0FFFF3F00E3 +:106FA0002DE9F041044680074FF000054FF001063F +:106FB0000CD56B480560066000F0E8F920B169481F +:106FC000016841F48061016024F00204E0044FF0A4 +:106FD000FF3705D564484660C0F8087324F4805430 +:106FE000600003D56148056024F08044E0050FD5BA +:106FF0005F48C0F80052C0F808735E490D60091D73 +:107000000D605C4A04210C321160066124F4807426 +:10701000A00409D558484660C0F80052C0F808736B +:107020005648056024F40054C4F38030C4F3C031E2 +:10703000884200D0FFDF14F4404F14D0504846601F +:10704000C0F808734F488660C0F80052C0F8087353 +:107050004D490D600A1D16608660C0F808730D600A +:10706000166024F4404420050AD5484846608660EE +:10707000C0F80873C0F848734548056024F40064FC +:107080000DF070FD4348044200D0FFDFBDE8F08101 +:10709000F0B50022202501234FEA020420FA02F174 +:1070A000C9072DD051B2002910DB00BF4FEA51179C +:1070B0004FEA870701F01F0607F1E02703FA06F6FB +:1070C000C7F88061BFF34F8FBFF36F8F0CDB00BF3A +:1070D0004FEA51174FEA870701F01F0607F1E02733 +:1070E00003FA06F6C7F8806204DB01F1E02181F8BB +:1070F000004405E001F00F0101F1E02181F8144D99 +:1071000002F10102AA42C9D3F0BD10B5224C2060A1 +:107110000846F4F7EAFE2068FFF742FF2068FFF711 +:10712000B7FF0DF045F900F092F90DF01BFD0DF0E1 +:1071300058FCEBF7B5FEBDE810400DF0EDB910B509 +:10714000154C2068FFF72CFF2068FFF7A1FF0DF01A +:1071500009FDF4F7C9FF0020206010BD0A20704728 +:10716000FC1F00403C17004000C0004004E5014007 +:10717000008000400485004000D0004004D500405D +:1071800000E0004000F0004000F5004000B000408A +:1071900008B50040FEFF0FFD9C00002070B5264999 +:1071A0000A680AB30022154601244B685B1C4B6039 +:1071B0000C2B00D34D600E7904FA06F30E681E42C4 +:1071C0000FD0EFF3108212F0010272B600D001224C +:1071D0000C689C430C6002B962B6496801600020EB +:1071E00070BD521C0C2AE0D3052070BD4FF0E02189 +:1071F0004FF48000C1F800027047EFF3108111F0E6 +:10720000010F72B64FF0010202FA00F20A48036859 +:1072100042EA0302026000D162B6E7E706480021B5 +:1072200001604160704701218140034800680840C7 +:1072300000D0012070470000A0000020012081073D +:10724000086070470121880741600021C0F80011E3 +:1072500018480170704717490120087070474FF0B7 +:107260008040D0F80001012803D01248007800289F +:1072700000D00120704710480068C00700D00120EE +:1072800070470D480C300068C00700D001207047DF +:107290000948143000687047074910310A68D20362 +:1072A00006D5096801F00301814201D10120704730 +:1072B00000207047A8000020080400404FF08050D4 +:1072C000D0F830010A2801D0002070470120704713 +:1072D00000B5FFF7F3FF20B14FF08050D0F8340134 +:1072E00008B1002000BD012000BD4FF08050D0F853 +:1072F00030010E2801D000207047012070474FF068 +:107300008050D0F83001062803D0401C01D0002066 +:107310007047012070474FF08050D0F830010D28A1 +:1073200001D000207047012070474FF08050D0F806 +:107330003001082801D000207047012070474FF02D +:107340008050D0F83001102801D000207047012073 +:10735000704700B5FFF7F3FF30B9FFF7DCFF18B94E +:10736000FFF7E3FF002800D0012000BD00B5FFF7C4 +:10737000C6FF38B14FF08050D0F83401062803D34F +:10738000401C01D0002000BD012000BD00B5FFF76A +:10739000B6FF48B14FF08050D0F83401062803D32F +:1073A000401C01D0012000BD002000BD0021017063 +:1073B000084670470146002008707047EFF31081BF +:1073C00001F0010172B60278012A01D0012200E029 +:1073D00000220123037001B962B60AB10020704790 +:1073E0004FF400507047E9E7EFF3108111F0010FFF +:1073F00072B64FF00002027000D162B600207047F2 +:10740000F2E700002DE9F04115460E46044600273C +:1074100000F0EBF8A84215D3002341200FE000BF95 +:1074200094F84220A25CF25494F84210491CB1FB3B +:10743000F0F200FB12115B1C84F84210DBB2AB428D +:10744000EED3012700F0DDF83846BDE8F08172493F +:1074500010B5802081F800047049002081F84200B6 +:1074600081F84100433181F8420081F84100433105 +:1074700081F8420081F841006948FFF797FF6848AA +:10748000401CFFF793FFEBF793FCBDE8104000F0C2 +:10749000B8B840207047614800F0A7B80A460146D6 +:1074A0005E48AFE7402070475C48433000F09DB82D +:1074B0000A46014659484330A4E7402101700020A4 +:1074C000704710B504465548863000F08EF820709D +:1074D000002010BD0A460146504810B58630FFF71F +:1074E00091FF08B1002010BD42F2070010BD70B539 +:1074F0000C460646412900D9FFDF4A48006810388B +:1075000040B200F054F8C5B20D2000F050F8C0B2FF +:10751000854201D3012504E0002502E00DB1EBF71F +:107520008AFC224631463D48FFF76CFF0028F5D023 +:1075300070BD2DE9F0413A4F0025064617F10407CA +:1075400057F82540204600F041F810B36D1CEDB20D +:10755000032DF5D33148433000F038F8002825D00A +:107560002E4800F033F8002820D02C48863000F058 +:107570002DF800281AD0EBF734FC2948FFF71EFF3E +:10758000B0F5005F00D0FFDFBDE8F0412448FFF711 +:107590002BBF94F841004121265414F8410F401CA0 +:1075A000B0FBF1F201FB12002070D3E74DE7002899 +:1075B00004DB00F1E02090F8000405E000F00F008B +:1075C00000F1E02090F8140D4009704710F8411FB9 +:1075D0004122491CB1FBF2F302FB131140788142B6 +:1075E00001D1012070470020704710F8411F4078FA +:1075F000814201D3081A02E0C0F141000844C0B240 +:10760000704710B50648FFF7D9FE002803D1BDE842 +:107610001040EBF7D1BB10BD0DE000E0340B0020B3 +:10762000AC00002004ED00E070B5154D2878401C3A +:10763000C4B26878844202D000F0DBFA2C7070BDCE +:107640002DE9F0410E4C4FF0E02600BF00F0C6FAE5 +:107650000EF09AFB40BF20BF677820786070D6F8A4 +:107660000052E9F798FE854305D1D6F8040210B917 +:107670002078B842EAD000F0ACFA0020BDE8F081F2 +:10768000BC0000202DE9F04101264FF0E02231033B +:107690004FF000084046C2F88011BFF34F8FBFF390 +:1076A0006F8F204CC4F800010C2000F02EF81E4D06 +:1076B0002868C04340F30017286840F01000286095 +:1076C000C4F8046326607F1C02E000BF0EF05CFB80 +:1076D000D4F800010028F9D01FB9286820F0100064 +:1076E0002860124805686660C4F80863C4F8008121 +:1076F0000C2000F00AF82846BDE8F08110B50446D9 +:10770000FFF7C0FF2060002010BD002809DB00F05B +:107710001F02012191404009800000F1E020C0F8E3 +:107720008012704700C0004010ED00E008C5004026 +:107730002DE9F047FF4C0646FF21A06800EB06123A +:1077400011702178FF2910D04FF0080909EB0111C1 +:1077500009EB06174158C05900F0F4F9002807DD7D +:10776000A168207801EB061108702670BDE8F0874B +:1077700094F8008045460DE0A06809EB05114158DA +:10778000C05900F0DFF9002806DCA068A84600EB2D +:1077900008100578FF2DEFD1A06800EB061100EB73 +:1077A00008100D700670E1E7F0B5E24B04460020CA +:1077B00001259A680C269B780CE000BF05EB0017AA +:1077C000D75DA74204D106EB0017D7598F4204D0EA +:1077D000401CC0B28342F1D8FF20F0BD70B5FFF766 +:1077E000ECF9D44C08252278A16805EB02128958DF +:1077F00000F0A8F9012808DD2178A06805EB011147 +:107800004058BDE87040FFF7CFB9FFF7A1F8BDE8D9 +:107810007040EBF779BB2DE9F041C64C2578FFF7B6 +:10782000CCF9FF2D6ED04FF00808A26808EB0516C2 +:10783000915900F087F90228A06801DD80595DE0C8 +:1078400000EB051109782170022101EB0511425C62 +:107850005AB1521E4254815901F5800121F07F41F5 +:1078600081512846FFF764FF34E00423012203EB33 +:10787000051302EB051250F803C0875CBCF1000F42 +:1078800010D0BCF5007F10D9CCF3080250F806C028 +:107890000CEB423C2CF07F4C40F806C0C3589A1ABF +:1078A000520A09E0FF2181540AE0825902EB4C326E +:1078B00022F07F428251002242542846FFF738FFCF +:1078C0000C21A06801EB05114158E06850F8272011 +:1078D000384690472078FF2814D0FFF76EF92278B9 +:1078E000A16808EB02124546895800F02BF90128DF +:1078F00093DD2178A06805EB01114058BDE8F04107 +:10790000FFF752B9BDE8F081F0B51D4614460E46AA +:107910000746FF2B00D3FFDFA00700D0FFDF85481D +:10792000FF210022C0E90247C57006710170427054 +:1079300082701046012204E002EB0013401CE15467 +:10794000C0B2A842F8D3F0BD70B57A4C064665784F +:107950002079854200D3FFDFE06840F82560607839 +:10796000401C6070284670BD2DE9FF5F1D468B46A8 +:107970000746FF24FFF721F9DFF8B891064699F88A +:107980000100B84200D8FFDF00214FF001084FF09E +:107990000C0A99F80220D9F808000EE008EB011350 +:1079A000C35CFF2B0ED0BB4205D10AEB011350F88C +:1079B00003C0DC450CD0491CC9B28A42EED8FF2C6A +:1079C00002D00DE00C46F6E799F803108A4203D185 +:1079D000FF2004B0BDE8F09F1446521C89F8022035 +:1079E00008EB04110AEB0412475440F802B00421DA +:1079F000029B0022012B01EB04110CD040F8012066 +:107A00004FF4007808234FF0020C454513D9E905DF +:107A1000C90D02D002E04550F2E7414606EB413283 +:107A200003EB041322F07F42C250691A0CEB0412DC +:107A3000490A81540BE005B9012506EB453103EBFA +:107A4000041321F07F41C1500CEB0411425499F80A +:107A500000502046FFF76CFE99F80000A84201D0C4 +:107A6000FFF7BCFE3846B4E770B50C460546FFF795 +:107A7000A4F8064621462846FFF796FE0446FF284E +:107A80001AD02C4D082101EB0411A868415830464A +:107A900000F058F800F58050C11700EBD1404013BA +:107AA0000221AA6801EB0411515C09B100EB4120ED +:107AB000002800DC012070BD002070BD2DE9F047DA +:107AC00088468146FFF770FE0746FF281BD0194DF8 +:107AD0002E78A8683146344605E0BC4206D02646DA +:107AE00000EB06121478FF2CF7D10CE0FF2C0AD023 +:107AF000A6420CD100EB011000782870FF2804D0BA +:107B0000FFF76CFE03E0002030E6FFF753F8414634 +:107B10004846FFF7A9FF0123A968024603EB0413B7 +:107B2000FF20C854A878401EB84200D1A87001EBCD +:107B3000041001E0000C002001EB06110078087031 +:107B4000104613E6081A0002C11700EB116000127C +:107B50007047000010B5202000F07FF8202000F0D2 +:107B60008DF84D49202081F80004E9F712FC4B49BB +:107B700008604B48D0F8041341F00101C0F8041329 +:107B8000D0F8041341F08071C0F804134249012079 +:107B90001C39C1F8000110BD10B5202000F05DF8BF +:107BA0003E480021C8380160001D01603D4A481E62 +:107BB00010603B4AC2F80803384B1960C2F8000154 +:107BC000C2F8600138490860BDE81040202000F08C +:107BD00055B834493548091F086070473149334862 +:107BE000086070472D48C8380160001D521E0260B1 +:107BF00070472C4901200860BFF34F8F70472DE973 +:107C0000F0412849D0F8188028480860244CD4F85E +:107C100000010025244E6F1E28B14046E9F712FBF3 +:107C200040B9002111E0D4F8600198B14046E9F76D +:107C300009FB48B1C4F80051C4F860513760BDE891 +:107C4000F041202000F01AB831684046BDE8F0410C +:107C50000EF0A4B8FFDFBDE8F08100280DDB00F0D6 +:107C60001F02012191404009800000F1E020C0F88E +:107C70008011BFF34F8FBFF36F8F7047002809DB70 +:107C800000F01F02012191404009800000F1E02036 +:107C9000C0F880127047000020E000E0C8060240F3 +:107CA00000000240180502400004024001000001EB +:107CB0005E4800210170417010218170704770B5DD +:107CC000054616460C460220EAF714FE57490120E5 +:107CD00008705749F01E086056480560001F046090 +:107CE00070BD10B50220EAF705FE5049012008706A +:107CF00051480021C0F80011C0F80411C0F8081163 +:107D00004E494FF40000086010BD48480178D9B1D1 +:107D10004B4A4FF4000111604749D1F8003100226D +:107D2000002B1CBFD1F80431002B02D0D1F8081170 +:107D300019B142704FF0100104E04FF001014170A1 +:107D400040490968817002704FF00000EAF7D2BD27 +:107D500010B50220EAF7CEFD34480122002102705E +:107D60003548C0F80011C0F80411C0F808110260CD +:107D700010BD2E480178002904BF407870472E4876 +:107D8000D0F80011002904BF02207047D0F800117C +:107D900000291CBFD0F80411002905D0D0F8080133 +:107DA000002804BF01207047002070471F4800B51D +:107DB0000278214B4078C821491EC9B282B1D3F85C +:107DC00000C1BCF1000F10D0D3F8000100281CBF87 +:107DD000D3F8040100280BD0D3F8080150B107E014 +:107DE000022802D0012805D002E00029E4D1FFDFFB +:107DF000002000BD012000BD0C480178002904BF0F +:107E0000807870470C48D0F8001100291CBFD0F8CA +:107E10000411002902D0D0F8080110B14FF0100071 +:107E2000704708480068C0B270470000BE000020DC +:107E300010F5004008F5004000F0004004F5014056 +:107E400008F5014000F400405748002101704170DE +:107E5000704770B5064614460D460120EAF74AFD04 +:107E600052480660001D0460001D05605049002056 +:107E7000C1F850014F490320086050494E4808603E +:107E8000091D4F48086070BD2DE9F0410546464880 +:107E90000C46012606704B4945EA024040F08070CE +:107EA0000860FFF72CFA002804BF47480460002749 +:107EB000464CC4F80471474945480860002D02BF8C +:107EC000C4F800622660BDE8F081012D18BFFFDF15 +:107ED000C4F80072266041493F480860BDE8F0815F +:107EE0003148017871B13B4A394911603749D1F8BD +:107EF00004210021002A08BF417002D0384A1268CC +:107F0000427001700020EAF7F5BC2748017800298B +:107F100004BF407870472D48D0F80401002808BFFE +:107F200070472F480068C0B27047002808BF7047EC +:107F30002DE9F0471C480078002808BFFFDF234CDC +:107F4000D4F80401002818BFBDE8F0874FF00209FB +:107F5000C4F80493234F3868C0F30018386840F021 +:107F600010003860D4F80401002804BF4FF4004525 +:107F70004FF0E02608D100BFC6F880520DF004FF94 +:107F8000D4F804010028F7D0B8F1000F03D1386805 +:107F900020F010003860C4F80893BDE8F0870B4962 +:107FA0000120886070470000C100002008F50040F3 +:107FB000001000401CF500405011004098F50140B1 +:107FC0000CF0004004F5004018F5004000F00040BF +:107FD0000000020308F501400000020204F5014020 +:107FE00000F4004010ED00E0012804BF41F6A47049 +:107FF0007047022804BF41F288307047042804BF4C +:1080000046F218007047082804BF47F2A0307047B6 +:1080100000B5FFDF41F6A47000BD10B5FE48002496 +:1080200001214470047044728472C17280F825404A +:10803000C462846380F83C4080F83D40FF2180F8B2 +:108040003E105F2180F83F1018300DF09FFFF3497C +:10805000601E0860091D0860091D0C60091D08608C +:10806000091D0C60091D0860091D0860091D0860D4 +:10807000091D0860091D0860091D0860091D0860C8 +:10808000091D0860091D086010BDE549486070477A +:10809000E448016801F00F01032904BF0120704783 +:1080A000016801F00F01042904BF02207047016834 +:1080B00001F00F01052904D0006800F00F00062828 +:1080C00007D1D948006810F0060F0CBF0820042023 +:1080D000704700B5FFDF012000BD012812BF022854 +:1080E00000207047042812BF08284FF4C87070475A +:1080F00000B5FFDF002000BD012804BF2820704725 +:10810000022804BF18207047042812BF08284FF423 +:10811000A870704700B5FFDF282000BD70B5C148CA +:10812000016801F00F01032908BF012414D0016880 +:1081300001F00F01042904BF022418210DD00168A9 +:1081400001F00F0105294BD0006800F00F00062850 +:108150001CBFFFDF012443D02821AF48C26A806AD8 +:10816000101A0E18082C04BF4EF6981547F2A030CE +:108170002DD02046042C08BF4EF628350BD0012800 +:1081800008BF41F6A47506D0022C1ABFFFDF41F6E6 +:10819000A47541F28835012C08BF41F6A47016D0B1 +:1081A000022C08BF002005D0042C1ABFFFDF0020DE +:1081B0004FF4C8702D1A022C08BF41F2883006D047 +:1081C000042C1ABFFFDF41F6A47046F21800281AEB +:1081D0004FF47A7100F2E730B0FBF1F0304470BD3B +:1081E0009148006810F0060F0CBF082404244FF4D7 +:1081F000A871B2E710B58D49026801F118040A634D +:1082000042684A63007A81F83800207E48B1207FB6 +:10821000F6F781F9A07E011C18BF0121207FF6F737 +:1082200069F9607E002808BF10BD607FF6F773F91A +:10823000E07E011C18BF0121607FBDE81040F6F709 +:1082400059B930B50024054601290AD0022908BFD2 +:108250004FF0807405D0042916BF08294FF0C74499 +:10826000FFDF44F4847040F480107149086045F4E5 +:10827000403001F1040140F00070086030BD30B5BD +:108280000024054601290AD0022908BF4FF0807456 +:1082900005D0042916BF08294FF0C744FFDF44F476 +:1082A000847040F480106249086045F4403001F168 +:1082B000040140F0007008605E48D0F8000100281A +:1082C00018BFFFDF30BD2DE9F04102274FF0E02855 +:1082D00001250024C8F88071BFF34F8FBFF36F8F63 +:1082E000554804600560FFF751F8544E18B13068E6 +:1082F00040F480603060FFF702F838B1306820F059 +:10830000690040F0960040F0004030604D494C4814 +:1083100008604FF01020806CB0F1FF3F04D04A4954 +:108320000A6860F317420A60484940F25B600860DF +:10833000091F40F203100860081F05603949032037 +:10834000086043480560444A42491160444A434931 +:108350001160121F43491160016821F440710160EE +:10836000016841F480710160C8F8807231491020C1 +:10837000C1F80403284880F83140C46228484068A6 +:10838000002808BFBDE8F081BDE8F0410047274A5A +:108390000368C2F81A308088D08302F11800017295 +:1083A00070471D4B10B51A7A8A4208D10146062241 +:1083B000981CF6F715F8002804BF012010BD002016 +:1083C00010BD154890F825007047134A5170107081 +:1083D0007047F0B50546800000F1804000F5805000 +:1083E0008B88C0F820360B78D1F8011043EA0121C0 +:1083F000C0F8001605F10800012707FA00F61A4C2C +:10840000002A04BF2068B04304D0012A18BFFFDF50 +:1084100020683043206029E0280C0020000E004036 +:10842000C40000201015004014140040100C00205F +:108430001415004000100040FC1F00403C17004095 +:108440002C000089781700408C150040381500403A +:108450005016004000000E0408F501404080004026 +:10846000A4F501401011004040160040206807FAB2 +:1084700005F108432060F0BD0CF0C4BCFE4890F844 +:1084800032007047FD4AC17811600068FC49000263 +:1084900008607047252808BF02210ED0262808BF93 +:1084A0001A210AD0272808BF502106D00A2894BFD5 +:1084B0000422062202EB4001C9B2F24A1160F249DD +:1084C000086070472DE9F047EB4CA17A012956D09E +:1084D000022918BFBDE8F087627E002A08BFBDE808 +:1084E000F087012950D0E17E667F0D1C18BF012561 +:1084F0005FF02401DFF894934FF00108C9F84C8035 +:10850000DFF88CA34718DAF80000B84228BFFFDF75 +:108510000020C9F84C01CAF80070300285F0010152 +:1085200040EA015040F0031194F82000820002F16B +:10853000804202F5C042C2F81015D64901EB800115 +:10854000A07FC20002F1804202F5F832C2F8141591 +:10855000D14BC2F81035E27FD30003F1804303F51D +:10856000F833C3F81415CD49C3F8101508FA00F014 +:1085700008FA02F10843CA490860BDE8F087227E84 +:10858000002AAED1BDE8F087A17E267F002914BF66 +:10859000012500251121ADE72DE9F041C14E8046AE +:1085A00003200D46C6F80002BD49BF4808602846B2 +:1085B0000CF02CFCB04F0124B8F1000F04BFBC72CA +:1085C000346026D0B8F1010F23D1B848006860B9F3 +:1085D00015F00C0F09D0C6F80443012000F0DAFEB4 +:1085E000F463346487F83C4002E0002000F0D2FEDF +:1085F00028460CF0F3FC0220B872FEF7B7FE38B93B +:10860000FEF7C4FE20B9AA48016841F4C021016008 +:1086100074609E48C4649E4800682946BDE8F041E5 +:1086200050E72DE9F0479F4E814603200D46C6F8DE +:108630000002DFF86C829C48C8F8000008460CF085 +:10864000E5FB28460CF0CAFC01248B4FB9F1000F62 +:1086500003D0B9F1010F0AD031E0BC72B86B40F41D +:108660008010B8634FF48010C8F8000027E00220A3 +:10867000B872B86B40F40010B8634FF40010C8F83B +:1086800000008A48006860B915F00C0F09D0C6F8E0 +:108690000443012000F07EFEF463346487F83C401C +:1086A00002E0002000F076FEFEF760FE38B9FEF72B +:1086B0006DFE20B97E48016841F4C0210160EAF7EF +:1086C000F7FA2946BDE8F047FCE62DE9F84F754C6E +:1086D0008246032088461746C4F80002DFF8C0919E +:1086E0007148C9F8000010460CF090FBDFF8C4B1E7 +:1086F000614E0125BAF1000F04BFCBF80040B572FE +:1087000004D0BAF1010F18BFFFDF2FD06A48C0F8BC +:1087100000806B4969480860B06B40F40020B0638A +:10872000D4F800321021C4F808130020C4F8000265 +:10873000DFF890C18A03CCF80020C4F80001C4F827 +:108740000C01C4F81001C4F80401C4F81401C4F801 +:1087500018015D4800680090C4F80032C9F8002094 +:10876000C4F80413BAF1010F14D026E038460CF017 +:1087700035FCFEF7FBFD38B9FEF708FE20B94C4882 +:10878000016841F4C02101605048CBF8000002208C +:10879000B072BBE74548006860B917F00C0F09D00C +:1087A000C4F80453012000F0F5FDE563256486F864 +:1087B0003C5002E0002000F0EDFD4FF40020C9F82D +:1087C00000003248C56432480068404528BFFFDFDA +:1087D00039464046BDE8F84F74E62DE9F041264C95 +:1087E0000646002594F8310017468846002808BF41 +:1087F000FFDF16B1012E16D021E094F831000128D8 +:1088000008D094F83020394640460CF014FBE16A59 +:10881000451814E094F830103A4640460CF049FBF5 +:10882000E16A45180BE094F8310094F83010012803 +:108830003A46404609D00CF064FBE16A45183A46D6 +:1088400029463046BDE8F0413FE70CF014FBE16AF1 +:108850004518F4E72DE9F84F124CD4F8000220F047 +:108860000309D4F804034FF0100AC0F30018C4F849 +:1088700008A300262CE00000280C0020241500404E +:108880001C150040081500405415004000800040B1 +:108890004C850040006000404C81004010110040B9 +:1088A00004F5014000100040000004048817004057 +:1088B00068150040ACF50140488500404881004003 +:1088C000A8F5014008F501401811004004100040CF +:1088D000C4F80062FC48FB490160FC4D0127A97AFD +:1088E000012902D0022903D015E0297E11B912E036 +:1088F000697E81B1A97FEA7F07FA01F107FA02F2E6 +:108900001143016095F82000800000F1804000F5DF +:10891000C040C0F81065FF208DF80000C4F8106159 +:10892000276104E09DF80000401E8DF800009DF8CE +:10893000000018B1D4F810010028F3D09DF8000011 +:10894000002808BFFFDFC4F81061002000F022FDFE +:108950006E72AE72EF72C4F80092B8F1000F18BFD9 +:10896000C4F804A3BDE8F88FFF2008B58DF8000017 +:10897000D7480021C0F810110121016105E000BFB6 +:108980009DF80010491E8DF800109DF8001019B1D7 +:10899000D0F810110029F3D09DF80000002808BF7E +:1089A000FFDF08BD0068CB4920F07F4008607047BA +:1089B0004FF0E0200221C0F8801100F5C070BFF335 +:1089C0004F8FBFF36F8FC0F80011704710B490E85D +:1089D0001C10C14981E81C10D0E90420C1E9042021 +:1089E00010BC70474FF0E0210220C1F80001704731 +:1089F000BA4908707047BA490860704770B50546B3 +:108A0000EAF756F9B14C2844E16A884298BFFFDF83 +:108A100001202074EAF74CF9B24A28440021606131 +:108A2000C2F84411B0490860A06BB04940F480001E +:108A3000A063D001086070BD70B5A44C0546AC4A77 +:108A40000220207410680E4600F00F00032808BFB3 +:108A5000012213D0106800F00F00042808BF022282 +:108A60000CD0106800F00F0005281BD0106800F033 +:108A70000F0006281CBFFFDF012213D094F831003D +:108A800094F83010012815D028460CF081FA954949 +:108A900060610020C1F844016169E06A08449249BC +:108AA000086070BD9348006810F0060F0CBF0822E4 +:108AB0000422E3E7334628460CF038FAE7E7824918 +:108AC0004FF4800008608148816B21F4800181634C +:108AD000002101747047C20002F1804202F5F832B1 +:108AE000854BC2F81035C2F81415012181407F482A +:108AF00001607648826B1143816370477948012198 +:108B00004160C1600021C0F84411774801606F489E +:108B1000C1627047794908606D48D0F8001241F091 +:108B20004001C0F8001270476948D0F8001221F0E7 +:108B30004001C0F800127149002008607047644885 +:108B4000D0F8001221F01001C0F80012012181615B +:108B500070475E49FF2081F83E005D480021C0F863 +:108B60001C11D0F8001241F01001C0F8001270473B +:108B7000574981B0D1F81C21012A0DD0534991F8F1 +:108B80003E10FF290DBF00204942017001B008BF0F +:108B90007047012001B07047594A126802F07F0205 +:108BA000524202700020C1F81C0156480068009033 +:108BB000EFE7F0B517460C00064608BFFFDF434D50 +:108BC00014F0010F2F731CBF012CFFDF002E0CBF10 +:108BD000012002206872EC7201281CBF0228FFDF0E +:108BE000F0BD3A4981F83F007047384A136C036082 +:108BF000506C086070472DE9F84F38480078042819 +:108C000028BFFFDF314CDFF8C080314D94F83C00C5 +:108C100000260127E0B1D5F8040110F1000918BFC2 +:108C20004FF00109D5F81001002818BF012050EAC3 +:108C300009014FF4002B17D08021C5F80813C8F89C +:108C400000B084F83C6090F0010F18BFBDE8F88FC9 +:108C5000DFF89090D9F84C01002871D0A07A012853 +:108C60006FD002286ED0D1E0D5F80001DFF890A0D7 +:108C700030B3C5F800616F61FF20009002E0401E34 +:108C8000009005D0D5F81C0100280098F7D000B955 +:108C9000FFDFDAF8000000F07F0A94F83F0050454B +:108CA0003CBF002000F076FB84F83EA0C5F81C61B4 +:108CB000C5F808731348006800902F64AF6326E07E +:108CC00022E0000000000E0408F50140280C0020FE +:108CD000001000403C150040100C0020C400002093 +:108CE00004150040008000404485004004F5014028 +:108CF000101500401414004004110040601500409D +:108D0000481500401C110040B9F1000F03D0B9F123 +:108D1000000F2ED05CE0DAF8000000F07F0084F84D +:108D20003E00C5F81C6194F83D1061B194F83F1005 +:108D300081421BD2002000F02DFB2F64AF6315E0B1 +:108D400064E04CE04EE0FE49096894F83F308AB296 +:108D5000090C984203D30F2A06D9022904D2012014 +:108D600000F018FB2F6401E02F64AF63F548006842 +:108D700000908022C5F80423F3498F64F348036808 +:108D8000A0F1040CDCF800C043F698273B4463458F +:108D900015D2026842F210731A440260C1F84861A9 +:108DA000EC49EB480860091FEB480860EB48C0F845 +:108DB00000B0A06B40F40020A063BDE8F88F06600F +:108DC000C1F84861C5F80823C8F800B0C1F8486187 +:108DD0008020C5F80803C8F800B0BDE8F88F207EF1 +:108DE00010B913E0607E88B1A07FE17F07FA00F040 +:108DF00007FA01F10843C8F8000094F82000800049 +:108E000000F1804000F5C040C0F81065C9F84C7012 +:108E1000D34800682064D34800686064D248A16BDE +:108E20000160A663217C002019B1D9F84411012901 +:108E300000D00021A27A012A6ED0022A74D000BF8D +:108E4000D5F8101101290CBF1021002141EA0008BA +:108E5000C648016811F0FF0F03D0D5F8141101299D +:108E600000D0002184F83210006810F0FF0F03D00A +:108E7000D5F81801012800D0002084F83300BC4840 +:108E8000006884F83400FEF774FF012818BF002042 +:108E900084F83500C5F80061C5F80C61C5F81061AB +:108EA000C5F80461C5F81461C5F81861B1480068D7 +:108EB0000090A548C0F84461AF480068DFF8BC9254 +:108EC0000090D9F80000A062A9F104000068E062F7 +:108ED000AB48016801F00F01032908BF012013D03E +:108EE000016801F00F01042908BF02200CD00168BD +:108EF00001F00F01052926D0006800F00F000628B8 +:108F00001CBFFFDF01201ED084F83000A07A84F857 +:108F1000310002282CD11EE0D5F80C01012814BF25 +:108F2000002008208CE7FFE7D5F80C01012814BFCA +:108F300000200220934A1268012A14BF0422002252 +:108F4000104308437CE79048006810F0060F0CBF00 +:108F500008200420D8E7607850B18C490968097866 +:108F60000840217831EA000008BF84F8247001D05D +:108F700084F82460DFF818A218F0020F06D0E9F791 +:108F800097FEA16A081ADAF81010884718F0010F46 +:108F900018BF4FF0000B0DD0E9F78AFEE16ADAF84E +:108FA0001420081A594690477A48007810F0010FAB +:108FB0002FD10CE018F0020F18BF4FF0010BEBD1CE +:108FC00018F0080F18BF4FF0020BE5D1ECE7DFF8FF +:108FD000BCB1DBF80000007800F00F00072828BFC4 +:108FE00084F8256015D2DBF80000062200F10901A3 +:108FF000A01CF5F7F5F940B9207ADBF800100978E4 +:10900000B0EBD11F08BF012001D04FF0000084F861 +:109010002500E17A4FF0000011F0020F1CBF18F09C +:10902000020F18F0040F19D111F0100F1CBF94F8A3 +:109030003320002A02D094F835207AB111F0080FBD +:109040001CBF94F82420002A08D111F0040F02D08C +:1090500094F8251011B118F0010F01D04FF0010064 +:10906000617A19B168B1FFF7F5FB10E03E484A4953 +:109070000160D5F8000220F00300C5F80002E77295 +:1090800005E001290AD0022918BFFFDF0DD018F032 +:10909000010F14D0DAF80000804745E06672E772ED +:1090A000A7729621227B002006E06672E7720220FA +:1090B000A072227B96210120FFF78FFBE7E718F0D3 +:1090C000020F2AD018F0040F21D1FEF74FF9F0B9A2 +:1090D000FEF75CF9D8B931480168001F0068C0F399 +:1090E000006CC0F3425500F00F03C0F30312C0F34D +:1090F0000320BCF1000F0AD0002B1CBF002A00285F +:1091000005D1002918BF032D38BF48F0040827EA0D +:109110009800DAF80410884706E018F0080F18BF26 +:10912000DAF8080056D08047A07A022818BFBDE8B8 +:10913000F88F207C002808BFBDE8F88F02492FE097 +:10914000741500401C11004000800040488500401C +:1091500014100040ACF501404881004004F5014086 +:1091600004B500404C85004008F501404016004021 +:109170001014004018110040448100404485004014 +:109180001015004000140040141400400415004065 +:10919000100C0020C40000200000040454140040FF +:1091A000C1F8446102281DD0012818BFFFDFE16A21 +:1091B0006069884298BFFFDFD4F81400C9F8000046 +:1091C000A06B4FF4800140F48000A06382480160EE +:1091D000BDE8F88F18F0100F14BFDAF80C00FFDFAD +:1091E000A1D1A1E76169E06A0844E7E738B57B49A6 +:1091F00004460220887201212046FFF763F9784A6D +:1092000004F13D001060774B0020C3F8440176491B +:10921000C1F80001C1F80C01C1F81001C1F8040146 +:10922000C1F81401C1F818017048006800900120CD +:109230009864101D00681168884228BFFFDF38BDA0 +:109240002DE9F843654A88460024917A0125684F44 +:10925000012902D0022903D015E0117E11B912E0D4 +:10926000517E81B1917FD37F05FA01F105FA03F3B5 +:109270001943396092F82010890001F1804101F50D +:10928000C041C1F8104506460220907201213046C7 +:10929000FFF718F9524906F13D000860514AC2F83B +:1092A00044415148C0F80041C0F80C41C0F8104199 +:1092B000C0F80441C0F81441C0F818414B48006898 +:1092C00000909564081D00680968884228BFFFDF88 +:1092D000B8F1000F1CBF4FF400303860BDE8F883D0 +:1092E000022810B50DD0012804BF42F6CE3010BDC3 +:1092F000042817BF082843F6A440FFDF41F66A00A0 +:1093000010BDFDF7E5FF30B9FDF7F9FF002808BFF4 +:1093100041F6583001D041F2643041F29A010844DC +:1093200010BD314910B50020C1F800023049314864 +:109330000860324930480860091D31480860091D3D +:1093400030480860091D30480860091D2F48086032 +:10935000091D2F48086001200BF058FD1E494FF4ED +:109360003810086010BD22494FF43810086070476B +:109370002848016803291BBF00680228012000203B +:109380007047244801680B291BBF00680A28012088 +:109390000020704720490968C9B9204A204913684C +:1093A00070B123F0820343F07D0343F00043136068 +:1093B0000A6822F0100242F0600242F0004205E02A +:1093C00023F0004313600A6822F000420A60034958 +:1093D00081F83D007047000004F50140280C002092 +:1093E00044850040008000400010004018110040FB +:1093F00008F50140000004041011004098F50140F8 +:109400000410004044810040141000401C11004032 +:109410001010004050150040881700403C170040D5 +:109420007C17004010B5404822220021F5F72FF8A4 +:109430003D480024017821F010010170012104F061 +:10944000FFFE3A494FF6FF7081F822408884384980 +:109450000880488010BD704734498A8C824218BF0A +:109460007047002081F822004FF6FF708884704713 +:109470002D49016070472E49088070472B498A8C1E +:10948000A2F57F43FF3B03D00021016008467047EF +:1094900091F822202549012A1ABF016001200020ED +:1094A0007047224901F1220091F82220012A04BFCD +:1094B00000207047012202701D48008888841046F1 +:1094C00070471B49488070471849194B8A8C5B8844 +:1094D0009A4206D191F82220002A1EBF0160012085 +:1094E0007047002070471148114A818C5288914280 +:1094F00009D14FF6FF71818410F8221F19B10021A4 +:10950000017001207047002070470848084A818C8C +:109510005288914205D190F8220000281CBF0020FB +:109520007047012070470000960C0020700C00204E +:10953000CC0000207047584A012340B1012818BFD1 +:1095400070471370086890608888908170475370E6 +:109550000868C2F802008888D08070474E4A10B16F +:10956000012807D00EE0507860B1D2F80200086000 +:10957000D08804E0107828B19068086090898880CD +:109580000120704700207047434910B1012803D0E3 +:1095900006E0487810B903E0087808B10120704768 +:1095A0000020704730B58DB00C4605460D220021D5 +:1095B00004A8F4F76CFFE0788DF81F0020798DF88F +:1095C0001E0060798DF81D00286800906868019081 +:1095D000A8680290E868039068460AF087FF207840 +:1095E0009DF82F1088420CD160789DF82E1088428B +:1095F00007D1A0789DF82D10884202BF01200DB040 +:1096000030BD00200DB030BD30B50C4605468DB0E4 +:109610004FF0030104F1030012B1FDF749FF01E02F +:10962000FDF765FF60790D2220F0C00040F040009A +:109630006071002104A8F4F72AFFE0788DF81F007C +:1096400020798DF81E0060798DF81D002868009043 +:1096500068680190A8680290E868039068460AF07C +:1096600045FF9DF82F0020709DF82E0060709DF83A +:109670002D00A0700DB030BD10B5002904464FF08C +:10968000060102D0FDF714FF01E0FDF730FF60791D +:1096900020F0C000607110BDD0000020FE4840687E +:1096A00070472DE9F0410F46064601461446012059 +:1096B00005F06FF8054696F86500FEF795FC4AF24E +:1096C000B12108444FF47A71B0FBF1F0718840F297 +:1096D00071225143C0EB4100001BA0F55A7402F007 +:1096E0005AFF002818BF1E3CAF4234BF28463846F8 +:1096F000A04203D2AF422CBF3C462C467462BDE868 +:10970000F0812DE9FF4F8BB0044690F86500884644 +:109710000390DDE90D1008430A90E0480027057822 +:109720000C2D28BFFFDFDE4E36F8159094F88851D7 +:109730000C2D28BFFFDFDA4830F81500484480B20E +:10974000009094F87D000D280CBF012000200790A8 +:109750000D98002804BF94F82C0103282BD10798FA +:1097600048B3B4F8AA01404525D1D4F83401C4F86F +:109770002001608840F2E2414843C4F82401B4F873 +:109780007A01B4F806110844C4F82801204602F012 +:109790000CFFB4F8AE01E08294F8AC016075B4F847 +:1097A000B0016080B4F8B201A080B4F8B401E080E8 +:1097B000022084F82C01D4F884010990D4F88001A7 +:1097C0000690B4F80661B4F87801D4F874110191E8 +:1097D0000D9921B194F8401151B100F0D6B804F5BB +:1097E000807104917431059104F5B075091D07E08D +:1097F00004F5AA710491091D059104F5A275091DCE +:109800000891B4F87010A8EB0000A8EB01010FFA62 +:1098100080F90FFA81FBB9F1000F05DAD4F8700175 +:1098200001900120D9460A909C484FF0000A007927 +:10983000A8B3F2F77FFB90B3B4F8180102282ED337 +:1098400094F82C0102282AD094F8430138BB94F8EC +:10985000880100900C2828BFFFDF9148009930F85C +:10986000110000F5C86080B2009094F82C01012826 +:109870007ED0608840F2E2414843009901F0E6F86A +:10988000D4F8342180B206EB0B01A1EB0901821A56 +:1098900001FB02AAC4F83401012084F8430194F8C2 +:1098A0002C01002865D0012800F01482022800F065 +:1098B0007181032818BFFFDF00F04782A7EB0A0180 +:1098C0000198FCF738F90599012640F271220860E9 +:1098D0000898A0F80080002028702E710598006874 +:1098E000A8606188D4F834015143C0EB41006B4952 +:1098F000A0F54E70C8618969814287BF04990860EC +:10990000049801600498616A0068084400F5D47006 +:10991000E86002F040FE10B1E8681E30E8606E7149 +:10992000B4F8F000A0EB080000B20028C4BF032088 +:109930006871079800280E9800F06982E0B100BFB6 +:10994000B4F8181100290CBF0020B4F81A01A4F8CB +:109950001A0194F81C21401C504388420CD26879AB +:10996000401E002808DD6E71B4F81A01401C01E0A9 +:109970000FE05AE0A4F81A010D98002800F06A825E +:1099800094F84001002800F061820FB00220BDE889 +:10999000F08F94F8800003283DD03F4894F865107C +:1099A00090F82C00F7F78DFDE18A40F271225143C7 +:1099B00000EB4100CDF80800D4F82401009901F033 +:1099C00045F8D4F82021D4F82811821A01FB02AA04 +:1099D000C4F820010099029801F038F8D4F8301149 +:1099E000C4F83001411A8A44608840F2E241484399 +:1099F000009901F02BF806EB0B01D4F82821A1EB1C +:109A00000901891AD4F83421C4F83401821A491E94 +:109A100001FB02AA40E7E18A40F27122D4F8240156 +:109A2000514300EB41000290C6E70698002808BFAA +:109A3000FFDF94F86510184890F82C00F7F741FD07 +:109A40000990E08A40F271214143099800EB4100FE +:109A5000009900F0FBFFC4F83001608840F2E24159 +:109A60004843009900F0F2FFC4F8340103A902A8AA +:109A7000FFF7BBF8DDE90160039FE9F7F0F8014665 +:109A80003046FDF769F800F10F06E9F711F9381AC9 +:109A9000801B009006E00000B80C0020E0000020D1 +:109AA000E4620200B4F83401214686B20120D4F801 +:109AB000289004F06EFE074694F86500FEF794FACD +:109AC0004AF2B12108444FF47A7BB0FBFBF0618885 +:109AD00040F271225143C0EB4100801BA0F55A7641 +:109AE00002F059FD002818BF1E3EB94534BF384664 +:109AF0004846B04203D2B9452CBF4E463E46666248 +:109B000094F86500FEF7E9FA00F2E140B0FBFBF1E2 +:109B100006980F1894F86500FEF7DFFA064694F8E9 +:109B20006500FEF761FA30444AF2AB310844B0FBFD +:109B3000FBF1E08A40F2712242430998D4F8306187 +:109B400000EB4200401A801B384400993138471A14 +:109B5000607D40F2E24110FB01F994F8650000904D +:109B600010F00C0F0ABF00984EF62830FEF73CFAB2 +:109B70004AF2B1210844B0FBFBF000EB460000EBD9 +:109B800009060098FEF7B8FA304400F18401FE4857 +:109B9000816193E6E18A40F27122D4F824015143B5 +:109BA00000EB4100009900F051FFC4F830016188DA +:109BB00040F2E2404843009900F048FFC4F8340105 +:109BC00087B221460120D4F828B004F0E2FD814696 +:109BD00094F86500FEF708FA4AF2B12101444FF407 +:109BE0007A70B1FBF0F0618840F271225143C0EB12 +:109BF0004100C01BA0F55A7702F0CDFC002818BF29 +:109C00001E3FCB4534BF48465846B84203D2CB45E9 +:109C10002CBF5F464F4667621EBB0E9808B394F890 +:109C200065603046FEF7E0F94AF2B12101444FF495 +:109C30007A70B1FBF0F0D4F83011E28A084440F2B7 +:109C40007123D4F824115A4301EB42010F1A304614 +:109C5000FEF752FA01460998401A3844A0F120074D +:109C60000AE0E18A40F27122D4F82401514300EB6A +:109C70004100D4F83011471AD4F82821D4F8201123 +:109C8000D4F8300101FB0209607D40F2E24110FB93 +:109C900001FB94F8656016F00C0F0ABF30464EF6D3 +:109CA0002830FEF7A1F94AF2B12101444FF47A704D +:109CB000B1FBF0F000EB490000EB0B093046FEF77A +:109CC0001BFA484400F16001AF488161012084F82B +:109CD0002C01F3E5618840F271225143D4F834013C +:109CE000D4F82821C0EB410101FB09F706EB0B0179 +:109CF000891AD4F820C1D4F83031491E0CFB023245 +:109D000001FB0029607D40F2E24110FB01FB94F869 +:109D1000656016F00C0F0ABF30464EF62830FEF78D +:109D200063F94AF2B12101444FF47A70B1FBF0F0CB +:109D300000EB490000EB0B093046FEF7DDF9484423 +:109D400000F1600190488161B8E5618840F27122BC +:109D5000D4F834015143C0EB410000FB09F794F8FB +:109D60007C0024281CBF94F87D0024280BD1B4F873 +:109D7000AA01A8EB000000B2002804DB94F8AD01B2 +:109D8000002818BF03900A9800B3FEB9099800286C +:109D90001ABF06980028FFDF94F8650010F00C0F3A +:109DA00014BF4EF62830FEF71FF94AF2B1210144E4 +:109DB0004FF47A70B1FBF0F03F1A94F86500FEF7AB +:109DC0009BF90999081A3844A0F12007D4F83411F6 +:109DD00006EB0B0000FB01F6039810F00C0F0ABF16 +:109DE00003984EF62830FEF7FFF84AF2B1210144FD +:109DF0004FF47A70B1FBF0F000EB46060398FEF7E3 +:109E00007BF9304400F160015F48816156E500282C +:109E10007FF496AD94F82C0100283FF4ADAD618835 +:109E200040F27122D4F834015143C0EB410128467D +:109E3000F7F712F90004000C3FF49EAD18990029C1 +:109E400018BF088001200FB0BDE8F08F94F87C01A6 +:109E5000FCF7D1FC94F87C012946FCF7B0FB20B15B +:109E60000D9880F0010084F841010FB00020BDE89A +:109E7000F08F2DE9F843454C0246434F00266168B8 +:109E8000606A052A60D2DFE802F003464B4F5600B5 +:109E9000A07A002560B101216846FDF709FB9DF815 +:109EA000000042F210710002B0FBF1F201FB12055A +:109EB000F4F720FE4119A069FBF73DFEA06126746E +:109EC000032060754FF0010884F81480607AD0B9DF +:109ED000A06A80B1F4F70EFE0544F4F785FC411941 +:109EE000A06A884224BF401BA06204D2C4F8288024 +:109EF000F5F72BFE07E0207B04F11001FCF75FFB78 +:109F0000002808BFFFDF2684FCF739F87879BDE820 +:109F1000F843E8F7F9BFBDE8F843002100F0B3BD0E +:109F2000C1F88001BDE8F883D1F88001BDE8F843AD +:109F3000012100F0A8BD84F83060FCF720F87879A2 +:109F4000BDE8F843E8F7E0BFFFDFBDE8F8832DE99F +:109F5000F04F0E4C824683B020788B4601270025B7 +:109F6000094E4FF00209032804BF207B50457DD1E4 +:109F7000606870612078032818BFFFDF4FF0030886 +:109F8000BBF1080F73D203E0E0000020B80C002002 +:109F9000DFE80BF0040F32322D9999926562F5F7E4 +:109FA000ABF9002818BFFFDF86F8028003B0BDE8D8 +:109FB000F08FF4F77AFF68B9F4F716FC0546E0690C +:109FC000A84228BFE56105D2281A0421FCF7F7FD55 +:109FD000E56138B1F5F723FD002818BFFFDF03B0B6 +:109FE000BDE8F08F03B00020BDE8F04F41E703B0BB +:109FF000BDE8F04FFEF7FFBD2775257494F83000DB +:10A000004FF0010A58B14FF47A71A069FBF793FD44 +:10A01000A061002104F11000F7F71EF80EE0F4F73C +:10A0200069FD82465146A069FBF785FDA061514656 +:10A0300004F11000F7F710F800F1010A208C411C20 +:10A040000A293CBF50442084606830B1208C401CF9 +:10A050000A2828BF84F8159001D284F81580607A08 +:10A06000A8B9A06AE8B1F4F745FD01E02FE02AE0C5 +:10A070008046F4F7B9FB00EB0801A06A884224BFD0 +:10A08000A0EB0800A0620CD2A762F5F75EFD207B72 +:10A09000FCF74BF82570707903B0BDE8F04FE8F796 +:10A0A00033BF207B04F11001FCF789FA002808BFB8 +:10A0B000FFDF03B0BDE8F08F207BFCF736F825709A +:10A0C00003B0BDE8F08FFFDF03B0BDE8F08FBAF159 +:10A0D000200F28BFFFDFDFF8E886072138F81A00D5 +:10A0E000F9F7E4FE040008BFFFDFBAF1200F28BF34 +:10A0F000FFDF38F81A002188884218BFFFDF4FF0D1 +:10A10000200A7461BBF1080F80F06181DFE80BF079 +:10A110000496A0A099FEFDFCC4F88051F580C4F817 +:10A12000845194F8410138B9FCF71EF8D4F84C1169 +:10A13000FCF712FD00281BDCB4F83E11B4F87000E7 +:10A14000814206D1B4F8F410081AA4F8F6002046AB +:10A1500005E0081AA4F8F600B4F83E112046A4F869 +:10A160007010D4F86811C4F84C11C0F870111DE0DB +:10A17000B4F83C11B4F87000081AA4F8F600B4F86A +:10A180003C112046A4F87010D4F84C11C4F86811A2 +:10A19000C4F87011D4F85411C4F80011D4F858114F +:10A1A000C4F87411B4F85C11A4F8781102F008F93D +:10A1B000FBF7B4FF804694F86500FDF715FF4AF2FF +:10A1C000B12108444FF47A71B0FBF1F0D4F83411A6 +:10A1D00040F27122084461885143C0EB4100A0F174 +:10A1E000300AB8F1B70F98BF4FF0B70821460120E9 +:10A1F00004F0CFFA4044AAEB0000A0F21D38A246BA +:10A200002146012004F0C5FADAF824109C3081427E +:10A2100088BF0D1AC6F80C80454528BF4546B56075 +:10A22000D4F86C01A0F5D4703061FCF762FC84F8BE +:10A23000407186F8029003B0BDE8F08F02F0A6F9F5 +:10A2400001E0FEF7D8FC84F8407103B0BDE8F08F60 +:10A25000FBF78AFFD4F8702101461046FCF77CFC1E +:10A2600048B1628840F27123D4F834115A43C1EBEB +:10A270004201B0FBF1F094F87D100D290FD0B4F835 +:10A280007010B4F83E210B189A42AEBF501C401C0F +:10A290000844A4F83E0194F8420178B905E0B4F806 +:10A2A0003E01401CA4F83E0108E0B4F83E01B4F8B9 +:10A2B000F410884204BF401CA4F83E01B4F87A01AF +:10A2C0000DF1040B401CA4F87A01B4F89A00B4F81C +:10A2D0009810401AB4F87010401E08441FFA80F914 +:10A2E0000BE000231A462046CDF800B0FFF709FA2C +:10A2F00068B3012818BFFFDF48D0B4F83E11A9EBBE +:10A30000010000B2002802E053E047E05FE0E8DA35 +:10A31000082084F88D0084F88C70204601F012FE2D +:10A3200084F82C5194F87C514FF6FF77202D00D300 +:10A33000FFDF28F8157094F87C01FBF7F6FE84F82F +:10A340007CA1707903B0BDE8F04FE8F7DDBDA06EE9 +:10A35000002804BF03B0BDE8F08FB4F83E01B4F8A4 +:10A360009420801A01B20029DCBF03B0BDE8F08F51 +:10A37000B4F86C000144491E91FBF0F189B201FB75 +:10A380000020A4F8940003B0BDE8F08FB4F83E01BB +:10A39000BDF804100844A4F83E01AEE7FEF7E4FA65 +:10A3A000FEF729FC4FF0E020C0F8809203B0BDE832 +:10A3B000F08F94F82C01042818BFFFDF84F82C518B +:10A3C00094F87C514FF6FF77202DB2D3B0E7FFDF32 +:10A3D00003B0BDE8F08F10B5FA4C207850B10120E1 +:10A3E0006072F5F7D8FB2078032805D0207A002882 +:10A3F00008BF10BD0C2010BD207BFCF7FCF9207BB2 +:10A40000FCF765FC207BFBF790FE002808BFFFDF10 +:10A410000020207010BD2DE9F04FEA4F83B038784E +:10A4200001244FF0000840B17C720120F5F7B3FB26 +:10A430003878032818BF387A0DD0DFF88C9389F864 +:10A44000034069460720F9F7BAFC002818BFFFDF70 +:10A450004FF6FF7440E0387BFCF7CDF9387BFCF712 +:10A4600036FC387BFBF761FE002808BFFFDF87F86A +:10A470000080E2E7029800281CBF90F82C11002908 +:10A480002AD00088A0421CBFDFF834A34FF0200B75 +:10A490003AD00721F9F70AFD040008BFFFDF94F85E +:10A4A0007C01FCF714FC84F82C8194F87C514FF665 +:10A4B000FF76202D28BFFFDF2AF8156094F87C0175 +:10A4C000FBF733FE84F87CB169460720F9F777FC87 +:10A4D000002818BFFFDF12E06846F9F74EFC00289D +:10A4E000C8D011E0029800281CBF90F82C11002958 +:10A4F00005D00088A0F57F41FF39CAD104E0684645 +:10A50000F9F73BFC0028EDD089F8038087F830800C +:10A5100087F80B8003B00020BDE8F08FAA4948718E +:10A520000020887001220A7048700A71C870A5491D +:10A53000087070E7A449087070472DE9F84FA14CE6 +:10A5400006460F462078002862D1A048FBF792FD0E +:10A55000207320285CD04FF00308666084F80080E8 +:10A56000002565722572AEB1012106F58E70FCF7EB +:10A57000BEFF0620F9F742FC81460720F9F73EFCB2 +:10A5800096F81C114844B1FBF0F200FB1210401C7D +:10A5900086F81C01FBF7C2FD40F2F651884238BF35 +:10A5A00040F2F65000F5A0701FFA80F9F4F7A2FA15 +:10A5B000012680B3A672F4F717F9E061FBF7D4FD2A +:10A5C000824601216846FCF769FF9DF8000042F2CF +:10A5D00010710002B0FBF1F201FB120000EB090167 +:10A5E0005046FBF7A8FAA762A061267584F815808B +:10A5F0002574207B04F11001FBF7E1FF002808BF60 +:10A60000FFDF25840020F5F7C6FA0020BDE8F88FAB +:10A610000C20BDE8F88FFFE7E761FBF7A5FD494691 +:10A62000FBF789FAA061A57284F830600120FDF77C +:10A6300054FD4FF47A7100F2E140B0FBF1F0381AAA +:10A64000A0F5AB60A5626063CFE75F4948707047D3 +:10A650005D49087170475B4810B5417A00291CBFFD +:10A66000002010BD816A51B990F8301039B1416AAB +:10A67000406B814203D9F5F768FA002010BD012034 +:10A6800010BD2DE9F041504C0646E088401CE080AA +:10A69000D4E902516078D6F8807120B13A46284654 +:10A6A000F6F705FD0546A068854205D02169281A00 +:10A6B00008442061FCF71DFAA560AF4209D896F85E +:10A6C0002C01012805D0E078002804BF0120BDE856 +:10A6D000F0810020BDE8F08110B504460846FDF782 +:10A6E00083FC4AF2B12108444FF47A71B0FBF1F0D7 +:10A6F00040F2E241614300F54E7081428CBF081A7E +:10A70000002010BD70B5044682B0002084F84001DE +:10A7100094F8FB00002807BF94F82C01032802B02E +:10A7200070BDFBF721FDD4F8702101461046FCF7FF +:10A7300013FA0028DCBF02B070BD628840F27123BA +:10A74000D4F834115A43C1EB4201B0FBF1F0B4F834 +:10A750007010401C0844A4F83C01B4F8F400B4F8AC +:10A760003C21801A00B20028DCBF02B070BD01207D +:10A7700084F84201B4F89A00B4F8982001AE801A27 +:10A78000401E084485B212E00096B4F83C11002344 +:10A7900001222046FEF7B5FF002804BF02B070BDBD +:10A7A000012815D0022812BFFFDF02B070BDB4F837 +:10A7B0003C01281A00B20028BCBF02B070BDE3E71C +:10A7C000F00C0020B80C0020E00000204F9F01009A +:10A7D000B4F83C01BDF804100844A4F83C01E6E7D5 +:10A7E000F8B50422002506295BD2DFE801F0072630 +:10A7F0000319192A044680F82C2107E00446C948A9 +:10A80000C078002818BF84F82C210AD0FBF7B7FBCA +:10A81000A4F87A51B4F87000A4F83E0184F84251CB +:10A82000F8BD0095B4F8F410012300222046FEF78D +:10A8300068FF002818BFFFDFE8E7032180F82C112C +:10A84000F8BD0646876AB0F83401314685B201206A +:10A8500003F09FFF044696F86500FDF7C5FB4AF23A +:10A86000B12108444FF47A71B0FBF1F0718840F2E5 +:10A8700071225143C0EB4100401BA0F55A7501F015 +:10A880008AFE002818BF1E3DA74234BF2046384626 +:10A89000A84228BF2C4602D2A74228BF3C46746279 +:10A8A000F8BDFFDFF8BD2DE9F05F9E4EB1780229BB +:10A8B00006BFF1880029BDE8F09F7469C4F88401DF +:10A8C00094F86500FDF718FCD4F88411081AB168F3 +:10A8D0000144B160F1680844F060746994F8430180 +:10A8E000002808BFBDE8F09F94F82C01032818BF8A +:10A8F000BDE8F09F94F8655037780C2F28BFFFDF34 +:10A90000894E36F8178094F888710C2F28BFFFDF26 +:10A9100036F81700404494F8888187B2B8F10C0FDC +:10A9200028BFFFDF36F8180000F5C8601FFA80F86E +:10A930002846FDF7E1FBD4F884114FF0000A0E1A07 +:10A9400015F00C0F0ABF28464EF62830FDF74CFBD9 +:10A950004FF47A7900F2E730B0FBF9F0361A284666 +:10A96000FDF7CAFBD4F8001115F00C0FA1EB000B9A +:10A970000ABF28464EF62830FDF736FB4AF2B121D1 +:10A980000844B0FBF9F0ABEB0000A0F160017943A3 +:10A99000B1FBF8F1292202EB50006031A0EB51022B +:10A9A00000EB5100B24201D8B04201D8F1F774FB7C +:10A9B000608840F2E2414843394600F047F8C4F865 +:10A9C000340184F843A1BDE8F09F70B505465548B1 +:10A9D00090F802C0BCF1020F07BF406900F5C074D7 +:10A9E000524800F12404002904BF256070BD4FF4D3 +:10A9F0007A7601290DD002291CBFFFDF70BD1046F9 +:10AA0000FEF76EFC00F2E140B0FBF6F0281A206081 +:10AA100070BD1846FDF761FB00F2E140B0FBF6F0B7 +:10AA2000281A206070BD4148007800281CBF002013 +:10AA3000704710B50720F9F7D3F980F0010010BD79 +:10AA40003A480078002818BF0120704730B5024608 +:10AA50000020002908BF30BDA2FB0110490A41EACD +:10AA6000C051400A4C1C40F100000022D4F1FF31DB +:10AA700040F2A17572EB000038BFFFDF04F5F4600F +:10AA8000B0FBF5F030BD2DE9F843284C0025814698 +:10AA900084F83050D4F8188084F82C10E5722570B2 +:10AAA0000127277239466068F5F792FD6168C1F8A1 +:10AAB0007081267B81F87C61C1F88091C1F8748136 +:10AAC000B1F80080202E28BFFFDF194820F816803B +:10AAD000646884F82C510023A4F878511A4619466A +:10AAE00020460095FEF70DFE002818BFFFDFC4F8D2 +:10AAF0002851C4F8205184F82C71A4F83E51A4F8D0 +:10AB00003C5184F84251B4F87000401EA4F8700023 +:10AB1000A4F87A51FBF733FA02484079BDE8F843CC +:10AB2000E8F7F2B9E0000020E4620200B80C00206F +:10AB3000F00C0020012804D0022805D0032808D1F9 +:10AB400005E0012907D004E0022904D001E004292E +:10AB500001D000207047012070472DE9F0410E46DA +:10AB6000044603F08AFC0546204603F08AFC0446AE +:10AB7000F6F770FBFB4F010015D0386990F86420A0 +:10AB80008A4210D090F8C0311BB190F8C2312342F4 +:10AB90001FD02EB990F85D30234201D18A4218D8D7 +:10ABA00090F8C001A8B12846F6F754FB70B1396996 +:10ABB00091F86520824209D091F8C00118B191F84E +:10ABC000C301284205D091F8C00110B10120BDE8B1 +:10ABD000F0810020FBE730B5E24C85B0E069002849 +:10ABE0005FD0142200216846F3F751FC206990F8E9 +:10ABF0006500FDF7F9F94FF47A7100F5FA70B0FBD2 +:10AC0000F1F5206990F86500FDF776FA2844ADF873 +:10AC1000060020690188ADF80010B0F87010ADF89A +:10AC200004104188ADF8021090F8A20130B1A0697B +:10AC3000C11C039103F002FB8DF81000206990F80D +:10AC4000A1018DF80800E169684688472069002164 +:10AC500080F8A21180F8A1110399002921D090F861 +:10AC6000A01100291DD190F87C10272919D09DF83A +:10AC70001010039A002914D013780124FF2B12D04E +:10AC8000072B0ED102290CD15178FF2909D100BF21 +:10AC900080F8A0410399C0F8A4119DF8101080F825 +:10ACA000A31105B030BD1B29F2D9FAE770B5AD4C40 +:10ACB000206990F87D001B2800D0FFDF2069002567 +:10ACC00080F8A75090F8D40100B1FFDF206990F818 +:10ACD000A81041B180F8A8500188A0F8D81180F8D8 +:10ACE000D6510E2108E00188A0F8D81180F8D6517D +:10ACF000012180F8DA110D2180F8D4110088F9F7CC +:10AD000006FAF8F79FFE2079E8F7FEF8206980F848 +:10AD10007D5070BD70B5934CA07980072CD5A0787C +:10AD2000002829D162692046D37801690D2B01F1F1 +:10AD300070005FD00DDCA3F102034FF001050B2B77 +:10AD400019D2DFE803F01A1844506127182C183A7A +:10AD50006400152B6FD008DC112B4BD0122B5AD06E +:10AD6000132B62D0142B06D166E0162B71D0172B53 +:10AD700070D0FF2B6FD0FFDF70BD91F87F200123D3 +:10AD80001946F6F7FFF80028F6D12169082081F866 +:10AD90007F0070BD1079BDE8704001F090BC91F863 +:10ADA0007E00C00700D1FFDF01F048FC206910F8E9 +:10ADB0007E1F21F00101017070BD91F87D00102807 +:10ADC00000D0FFDF2069112180F8A75008E091F83A +:10ADD0007D00142800D0FFDF2069152180F8A750DE +:10ADE00080F87D1070BD91F87D00152800D0FFDF40 +:10ADF000172005E091F87D00152800D0FFDF19200D +:10AE0000216981F87D0070BDBDE870404EE7BDE866 +:10AE1000704001F028BC91F87C2001230021F6F756 +:10AE2000B1F800B9FFDF0E200FE011F87E0F20F01F +:10AE3000040008701DE00FE091F87C200123002140 +:10AE4000F6F7A0F800B9FFDF1C20216981F87C002B +:10AE500070BD12E01BE022E091F87E00C0F301100B +:10AE6000012800D0FFDF206910F87E1F21F01001BB +:10AE70000170BDE8704001F0E1BB91F87C20012336 +:10AE80000021F6F77FF800B9FFDF1F20DDE791F81A +:10AE90007D00212801D000B1FFDF2220B0E7BDE80E +:10AEA000704001F0D7BB2F48016991F87E2013074D +:10AEB00002D501218170704742F0080281F87E209E +:10AEC0008069C07881F8E10001F0AFBB10B5254C76 +:10AED00021690A88A1F8162281F8140291F8640009 +:10AEE00001F091FB216981F8180291F8650001F0E9 +:10AEF0008AFB216981F81902012081F812020020E1 +:10AF000081F8C0012079BDE81040E7F7FDBF10B51A +:10AF1000144C05212069FFF763FC206990F85A1052 +:10AF2000012908D000F5F57103F001FC2079BDE896 +:10AF30001040E7F7E9BF022180F85A1010BD10B5A4 +:10AF4000084C01230921206990F87C207030F6F725 +:10AF500019F848B12169002001F8960F087301F82B +:10AF60001A0C10BD000100200120A070F9E770B597 +:10AF7000F74D012329462869896990F87C200979D1 +:10AF80000E2A01D1122903D000241C2A03D004E088 +:10AF9000BDE87040D3E7142902D0202A07D008E08A +:10AFA00080F87C4080F8A240BDE87040AFE71629E9 +:10AFB00006D0262A01D1162902D0172909D00CE083 +:10AFC00000F87C4F80F82640407821280CD01A20C9 +:10AFD00017E090F87D20222A07D0EA69002A03D0E2 +:10AFE000FF2901D180F8A23132E780F87D4001F0DD +:10AFF00025FB286980F8974090F8C0010028F3D01D +:10B000000020BDE8704061E710B5D14C216991F88E +:10B010007C10202902D0262902D0A2E7FFF756FF94 +:10B020002169002081F87C0081F8A20099E72DE9D0 +:10B03000F843C74C206990F87C10202908D00027DD +:10B0400090F87D10222905D07FB300F17C0503E044 +:10B050000127F5E700F17D0510F8B01F41F004016C +:10B060000170A06903F015FA4FF00108002608B33B +:10B070003946A069FFF771FDE0B16A46A169206910 +:10B08000F6F7F7F890B3A06903F001FA2169A1F887 +:10B09000AA01B1F8701001F0AAFA40B32069282182 +:10B0A00080F88D1080F88C8058E0FFE70220A070B7 +:10B0B000BDE8F883206990F8C00110B11E20FFF7A9 +:10B0C00005FFAFB1A0692169C07881F8E20008FAF4 +:10B0D00000F1C1F3006000B9FFDF20690A2180F8A8 +:10B0E0007C1090F8A20040B9FFDF06E009E02AE0FA +:10B0F0002E7001F0A3FAFFF7D6FE206980F8976062 +:10B10000D6E7226992F8C00170B1B2F8703092F8B7 +:10B110006410B2F8C40102F5D572F6F79BF968B174 +:10B120002169252081F87C00206900F17D0180F8EB +:10B1300097608D4212D180F87D600FE00020FFF70C +:10B14000C5FE2E70F0E720699DF8001080F8AC1164 +:10B150009DF8011080F8AD1124202870206900F1BD +:10B160007D018D4203D1BDE8F84301F067BA80F854 +:10B17000A2609DE770B5764C01230B21206990F801 +:10B180007D207030F5F7FEFE202650BB206901239C +:10B19000002190F87D207030F5F7F4FE0125F0B124 +:10B1A000206990F87C0024281BD0A06903F04FF997 +:10B1B000C8B1206990F8B01041F0040180F8B010D7 +:10B1C000A1694A7902F0070280F85D20097901F04F +:10B1D000070180F85C1090F8C1311BBB06E0A57038 +:10B1E00036E6A67034E6BDE870405CE690F8C03103 +:10B1F000C3B900F164035E788E4205D1197891429B +:10B2000002D180F897500DE000F503710D700288AF +:10B210004A8090F85C200A7190F85D0048712079AE +:10B22000E7F772FE2169212081F87D00BDE87040BA +:10B2300001F0FBB9F8B5464C206990F87E0010F09B +:10B24000300F04D0A07840F00100A070F8BDA069D4 +:10B2500003F0E2F850B3A06903F0D8F80746A069FC +:10B2600003F0D8F80646A06903F0CEF80546A069B9 +:10B2700003F0CEF801460097206933462A46303065 +:10B2800003F0BFF9A079800703D56069C07814285E +:10B290000FD0216991F87C001C280AD091F85A003F +:10B2A00001280ED091F8B70158B907E0BDE8F84081 +:10B2B000F9E52169012081F85A0002E091F8B60110 +:10B2C00030B1206910F87E1F41F0100101700EE0CE +:10B2D00091F87E0001F5FC7240F0200081F87E00BC +:10B2E00031F8300B03F017FA2079E7F70DFEBDE8CF +:10B2F000F84001F09AB970B5154C206990F87E10AD +:10B30000890707D590F87C20012308217030F5F7D4 +:10B3100039FEF8B1206990F8AA00800712D4A0691C +:10B3200003F056F8216981F8AB00A06930F8052FC9 +:10B33000A1F8AC204088A1F8AE0011F8AA0F40F0A7 +:10B3400002000870206990F8AA10C90705D011E022 +:10B35000000100200120A0707AE590F87E008007AF +:10B3600000D5FFDF206910F87E1F41F00201017057 +:10B3700001F05BF92069002590F87C10062906D1C0 +:10B3800080F87C5080F8A2502079E7F7BDFD206955 +:10B3900090F8A8110429DFD180F8A8512079E7F7A7 +:10B3A000B3FD206990F87C100029D5D180F8A25017 +:10B3B0004EE570B5FB4C01230021206990F87D20FB +:10B3C0007030F5F7DFFD012578B9206990F87D2010 +:10B3D000122A0AD0012305217030F5F7D3FD10B1F0 +:10B3E0000820A07034E5A57032E5206990F8A80027 +:10B3F00008B901F01AF92169A06901F5847102F018 +:10B40000C8FF2169A069D83102F0CEFF206990F809 +:10B41000DC0100B1FFDF21690888A1F8DE0101F538 +:10B42000F071A06902F0A3FF2169A06901F5F47130 +:10B4300002F0A5FF206980F8DC51142180F87D100E +:10B440002079BDE87040E7F75FBD70B5D54C0123AA +:10B450000021206990F87D207030F5F793FD0125DB +:10B46000A8B1A06902F04FFF98B1A0692169B0F8B6 +:10B470000D00A1F8AA01B1F8701001F0B8F858B1A8 +:10B480002069282180F88D1080F88C50E0E4A570A8 +:10B49000DEE4BDE8704006E5A0692169027981F823 +:10B4A000AC21B0F80520A1F8AE2102F01FFF216900 +:10B4B000A1F8B001A06902F01CFF2169A1F8B20156 +:10B4C000A06902F01DFF2169A1F8B4010D2081F8E7 +:10B4D0007D00BDE47CB5B34CA079C00738D0A0692D +:10B4E00001230521C578206990F87D207030F5F79B +:10B4F00049FD68B1AD1E0A2D06D2DFE805F0090945 +:10B500000505090905050909A07840F00800A070A3 +:10B51000A07800281CD1A06902F0BEFE00286ED0E1 +:10B52000A0690226C5781DB1012D01D0162D18D1B4 +:10B53000206990F87C00F5F70DFD90B1216991F834 +:10B540007C001F280DD0202803D0162D16D0A67001 +:10B550007CBD262081F87C00162D02D02A20FFF722 +:10B56000B5FC0C2D5BD00CDC0C2D48D2DFE805F0CF +:10B5700036331F48BEBE4BB55ABE393C2020A070A2 +:10B580007CBD0120142D6ED008DC0D2D6CD0112D4A +:10B590006BD0122D6ED0132D31D168E0152D7FD0D8 +:10B5A000162D6FD0182D6ED0FF2D28D198E0206970 +:10B5B0000123194690F87F207030F5F7E3FC00284E +:10B5C00008D1A06902F0CCFE216981F88E01072024 +:10B5D00081F87F008CE001F0EDF889E0FFF735FF9E +:10B5E00086E001F0C7F883E0206990F87D1011290A +:10B5F00001D0A6707CE0122180F87D1078E075E023 +:10B60000FFF7D7FE74E0206990F87D001728F0D18D +:10B6100001F014F821691B2081F87D0068E0FFF734 +:10B620006AFE65E0206990F87E00C00703D0A0782C +:10B6300040F0010023E06946A06902F0D0FE9DF8C9 +:10B64000000000F02501206900F8B01F9DF80110EE +:10B6500001F04901417000F0E8FF206910F87E1FF9 +:10B6600041F0010117E018E023E025E002E0FFF7D8 +:10B6700066FC3DE0216991F87E10490704D5A07071 +:10B6800036E00DE00FE011E000F0CFFF206910F888 +:10B690007E1F41F0040101702AE0FFF7CBFD27E097 +:10B6A00001F030F824E0FFF765FD21E0FFF7BFFC73 +:10B6B0001EE0A06900790DE0206910F8B01F41F08C +:10B6C00004010170A06902F0F7FE162810D1A069EC +:10B6D00002F0F6FEFFF798FC0AE0FFF748FC07E0EF +:10B6E000E16919B1216981F8A20101E0FFF7DBFBF3 +:10B6F0002169F1E93002401C42F10002C1E9000277 +:10B700007CBD70B5274CA07900074AD5A0780028E9 +:10B7100047D1206990F8E400FE2800D1FFDF2069BE +:10B72000FE21002580F8E41090F87D10192906D13B +:10B7300080F8A75000F082FF206980F87D502069D2 +:10B7400090F87C101F2902D0272921D119E090F808 +:10B750007D00F5F7FFFB78B120692621012380F8F1 +:10B760007C1090F87D200B217030F5F70BFC78B938 +:10B770002A20FFF7ABFB0BE02169202081F87C0039 +:10B7800006E0012180F8A11180F87C5080F8A250D9 +:10B79000206990F87F10082903D10221217080F8D8 +:10B7A000E41021E40001002010B5FD4C216991F85E +:10B7B000AC210AB991F8642081F8642091F8AD2198 +:10B7C0000AB991F8652081F8652010B10020FFF7D3 +:10B7D0007DFB206902F041FF002806D02069BDE80A +:10B7E000104000F5F57102F0A2BF16E470B5EC4C04 +:10B7F00006460D46206990F8E400FE2800D0FFDFE1 +:10B800002269002082F8E46015B1A2F8A400E7E400 +:10B8100022F89E0F01201071E2E470B5E04C012384 +:10B820000021206990F87C207030F5F7ABFB0028F0 +:10B830007BD0206990F8B61111B190F8B71139B1E9 +:10B8400090F8C01100296FD090F8C11119B36BE0C6 +:10B8500090F87D1024291CD090F87C10242918D051 +:10B860005FF0000300F5D67200F5DB7102F096FE82 +:10B870002169002081F8B60101461420FFF7B6FFC8 +:10B88000216901F13000C28A21F8E62F408B4880FF +:10B8900050E00123E6E790F87D2001230B21703072 +:10B8A000F5F770FB68BB206990F8640000F0ABFE10 +:10B8B0000646206990F8650000F0A5FE054620695F +:10B8C00090F8C2113046FFF735F9D8B1206990F8E9 +:10B8D000C3112846FFF72EF9A0B12269B2F87030E3 +:10B8E00092F86410B2F8C40102F5D572F5F7B2FD12 +:10B8F00020B12169252081F87C001BE00020FFF7A2 +:10B90000E5FA11E020690123032190F87D207030D1 +:10B91000F5F738FB40B920690123022190F87D201A +:10B920007030F5F72FFB08B1002059E400211620F4 +:10B93000FFF75CFF012053E410B5E8BB984C206989 +:10B9400090F87E10CA0702D00121092052E08A0730 +:10B950000AD501210C20FFF749FF206910F8AA1F22 +:10B9600041F00101017047E04A0702D5012113208F +:10B9700040E00A0705D510F8E11F417101210720B9 +:10B9800038E011F0300F3BD090F8B711A1B990F822 +:10B99000B611E1B190F87D1024292FD090F87C10D9 +:10B9A00024292BD05FF0000300F5D67200F5DB717F +:10B9B00002F0F4FD216900E022E011F87E0F20F092 +:10B9C000200040F010000870002081F83801206944 +:10B9D00090F87E10C90613D502F03FFEFFF797FAE4 +:10B9E000216901F13000C28A21F8E62F408B48809E +:10B9F00001211520FFF7FAFE0120F6E60123D3E727 +:10BA00000020F2E670B5664C206990F8E410FE293B +:10BA100078D1A178002975D190F87F2001231946AB +:10BA20007030F5F7AFFA00286CD1206990F88C11CE +:10BA300049B10021A0F89C1090F88D1180F8E61013 +:10BA4000002102205BE090F87D200123042170306A +:10BA5000F5F798FA0546FFF76FFF002852D1284600 +:10BA600000F00CFF00284DD120690123002190F83F +:10BA70007C207030F5F786FA78B120690123042123 +:10BA800090F87D207030F5F77DFA30B9206990F894 +:10BA9000960010B10021122031E0206990F87C203E +:10BAA0000A2A0DD0002D2DD1012300217030F5F789 +:10BAB00069FA78B1206990F8A81104290AD105E043 +:10BAC00010F8E21F01710021072018E090F8AA0089 +:10BAD000800718D0FFF7A1FE002813D120690123A9 +:10BAE000002190F87C207030F5F74CFA002809D03E +:10BAF000206990F8A001002804D00021FF20BDE8B3 +:10BB0000704073E609E000210C20FFF76FFE20690A +:10BB100010F8AA1F41F0010101701DE43EB5054671 +:10BB20006846FDF7ABFC00B9FFDF22220021009838 +:10BB3000F2F7ADFC0321009802F096FB0098017823 +:10BB400021F010010170294602F0B3FB144C0D2DB9 +:10BB500043D00BDCA5F102050B2D19D2DFE805F06F +:10BB600022184B191922185718192700152D5FD0C4 +:10BB700008DC112D28D0122D0BD0132D09D0142D37 +:10BB800006D155E0162D2CD0172D6AD0FF2D74D07C +:10BB9000FFDFFDF786FC002800D1FFDF3EBD00007F +:10BBA000000100202169009891F8E61017E0E26892 +:10BBB00000981178017191884171090A8171518849 +:10BBC000C171090A0172E4E70321009802F072FCD6 +:10BBD0000621009802F072FCDBE700980621017153 +:10BBE000D7E70098D4F8101091F8C221027191F8AB +:10BBF000C3114171CDE72169009801F5887102F008 +:10BC0000D7FB21690098DC3102F0DCFBC1E7FA497F +:10BC1000D1E90001CDE90101206901A990F8B00046 +:10BC200000F025008DF80400009802F006FCB0E753 +:10BC30002069B0F84810009802F0D6FB2069B0F8EF +:10BC4000E810009802F0D4FB2069B0F84410009886 +:10BC500002F0D2FB2069B0F8E610009802F0D0FBA9 +:10BC600097E7216991F8C00100280098BCD111F82C +:10BC7000642F02714978BCE7FFE7206990F8A3219F +:10BC8000D0F8A411009802F022FB82E7DB4810B53F +:10BC9000006990F8821041B990F87D2001230621B7 +:10BCA0007030F5F76FF9002800D001209DE570B5E0 +:10BCB000D24D286990F8801039B1012905D00229A8 +:10BCC00006D0032904D0FFDF03E4B0F8F41037E016 +:10BCD00090F87F10082936D0B0F89810B0F89A2064 +:10BCE00000248B1C9A4206D3511A891E0C04240C82 +:10BCF00001D0641EA4B290F8961039B190F87C205F +:10BD0000012309217030F5F73DF940B3FFF7BEFF7D +:10BD100078B129690020B1F89020B1F88E108B1C01 +:10BD20009A4203D3501A801E00D0401EA04200D277 +:10BD300084B20CB1641EA4B22869B0F8F410214496 +:10BD4000A0F8F0102DE5B0F898100329BDD330F815 +:10BD5000701F428D1144491CA0F8801021E5002479 +:10BD6000EAE770B50C4605464FF4087200212046FC +:10BD7000F2F78DFB258014E5F8F7A2B92DE9F04123 +:10BD80000D4607460721F8F791F8041E3CD094F8B9 +:10BD9000C8010026A8B16E70092028700BE0268427 +:10BDA00084F8C861D4F8CA016860D4F8CE01A860EC +:10BDB000B4F8D201A88194F8C8010028EFD12E71FF +:10BDC000AEE094F8D40190B394F8D4010D2813D0C8 +:10BDD0000E2801D0FFDFA3E02088F8F798F9074686 +:10BDE000F7F745FE78B96E700E20287094F8D601EA +:10BDF00028712088E88014E02088F8F788F9074641 +:10BE0000F7F735FE10B10020BDE8F0816E700D200F +:10BE1000287094F8D60128712088E88094F8DA0117 +:10BE2000287284F8D4613846F7F71BFE78E0FFE704 +:10BE300094F80A0230B16E701020287084F80A62FB +:10BE4000AF806DE094F8DC0190B16E700A2028702C +:10BE50002088A880D4F8E011C5F80610D4F8E411C1 +:10BE6000C5F80A10B4F8E801E88184F8DC6157E00D +:10BE700094F8040270B16E701A20287005E000BFBB +:10BE800084F80462D4F80602686094F8040200287A +:10BE9000F6D145E094F8EA0188B16E70152028705B +:10BEA00008E000BF84F8EA6104F5F6702B1D07C8AE +:10BEB00083E8070094F8EA010028F3D130E094F811 +:10BEC000F80170B16E701C20287084F8F861D4F805 +:10BED000FA016860D4F8FE01A860B4F80202A881F3 +:10BEE0001EE094F80C0238B11D20287084F80C6212 +:10BEF000D4F80E02686013E094F81202002883D090 +:10BF00006E701620287007E084F81262D4F81402CC +:10BF10006860B4F81802288194F812020028F3D15E +:10BF2000012071E735480021C16101620846704770 +:10BF300030B5324D0C46E860FFF7F4FF00B1FFDF8B +:10BF40002C7130BD002180F87C1080F87D1080F8C5 +:10BF5000801090F8FB1009B1022100E00321FEF7E8 +:10BF60003FBC2DE9F041254C0546206909B100216F +:10BF700004E0B0F80611B0F8F6201144A0F806115C +:10BF800090F88C1139B990F87F2001231946703050 +:10BF9000F4F7F8FF30B1206930F89C1FB0F85A2050 +:10BFA00011440180206990F8A23033B1B0F89E109E +:10BFB000B0F8F6201144A0F89E1090F9A670002F5A +:10BFC00006DDB0F8A410B0F8F6201144A0F8A410D3 +:10BFD00001213D2615B180F88D6017E02278022AF4 +:10BFE0000ED0012A15D0A2784AB380F88C1012F036 +:10BFF000140F11D01E2117E0FC6202000001002086 +:10C0000090F8E620062A3CD016223AE080F88C1000 +:10C0100044E090F88E2134E0110702D580F88D605D +:10C020003CE0910603D5232180F88D1036E090077F +:10C0300000D1FFDF21692A2081F88D002AE02BB191 +:10C04000B0F89E20B0F8A0309A4210D2002F05DD43 +:10C05000B0F8A420B0F8A0309A4208D2B0F89C30D2 +:10C06000B0F89A20934204D390F88C310BB122227D +:10C0700007E090F880303BB1B0F89830934209D394 +:10C08000082280F88D20C1E7B0F89820062A01D355 +:10C090003E22F6E7206990F88C1019B12069BDE8BE +:10C0A000F0414FE7BDE8F0410021FEF799BB2DE9D3 +:10C0B000F047FF4C81460D4620690088F8F739F8B3 +:10C0C000060000D1FFDFA0782843A070A0794FF0D0 +:10C0D00000058006206904D5A0F8985080F8045126 +:10C0E00003E030F8981F491C0180FFF7CFFD4FF0A7 +:10C0F000010830B3E088000506D5206990F8821069 +:10C1000011B1A0F88E501CE02069B0F88E10491CC7 +:10C1100089B2A0F88E10B0F890208A4201D3531A49 +:10C1200000E0002327897F1DBB4201D880F896805C +:10C13000914206D3A0F88E5080F80A822079E6F763 +:10C14000E3FEA0794FF0020710F0600F0ED02069D7 +:10C1500090F8801011B1032908D102E080F88080A6 +:10C1600001E080F880700121FEF73AFB206990F829 +:10C170008010012904D1E188C90501D580F88070BB +:10C18000B9F1000F72D1E188890502D5A0F81851E4 +:10C1900004E0B0F81811491CA0F8181100F035FBA4 +:10C1A000FEF719FDFFF72EFC2769B7F8F800401CD1 +:10C1B000A7F8F80097F8FC0028B100F01BFFA8B121 +:10C1C000A7F8F85012E000F012FF08B1A7F8F850F5 +:10C1D00000F015FF50B197F80401401CC0B287F879 +:10C1E0000401022802D927F8F85F3D732069012372 +:10C1F000002190F87D207030F4F7C4FE20B920694A +:10C2000090F87D000C2859D120690123002190F875 +:10C210007C207030F4F7B6FE48B32069012300217A +:10C2200090F87F207030F4F7ADFE00B3206990F8ED +:10C230008010022942D190F80401C0B93046F7F7C6 +:10C24000E6F9A0B1216991F8E400FE2836D1B1F8F1 +:10C25000F200012832D981F8FA80B1F89A00B1F8D9 +:10C260009820831E9A4203DB012004E032E025E09F +:10C27000801A401E80B2B1F8F82023899A4201D377 +:10C28000012202E09A1A521C92B2904200D9104642 +:10C29000012801D181F8FA5091F86F2092B98A6E85 +:10C2A00082B1B1F89420B1F87010511A09B2002986 +:10C2B00008DD884200DB084680B203E021690120E6 +:10C2C00081F8FA502169B1F870201044A1F8F40007 +:10C2D000FFF7EDFCE088C0F340214846FFF741FE40 +:10C2E000206980F8FB50BDE8F047FDF7FCB87049C5 +:10C2F00002468878CB78184312D10846006942B1CB +:10C300008979090703D590F87F00082808D0012013 +:10C310007047B0F84C10028E914201D8FEF7B1B9C7 +:10C320000020704770B5624C05460E46E0882843F1 +:10C33000E080A80703D5E80700D0FFDF6661EA07C1 +:10C340004FF000014FF001001AD0A661F278062AE2 +:10C3500002D00B2A14D10AE0226992F87D30172B03 +:10C360000ED10023E2E92E3302F8370C08E02269EF +:10C3700092F87D30112B03D182F8811082F8A80049 +:10C38000AA0718D56269D278052A02D00B2A12D1E1 +:10C390000AE0216991F87D20152A0CD10022E1E9FB +:10C3A000302201F83E0C06E0206990F87D20102A2A +:10C3B00001D180F88210280601D50820E07083E4BE +:10C3C0002DE9F84301273A4C002567F30701E58082 +:10C3D000A570E570257020618946804680F8FB7065 +:10C3E0000088F7F7A6FE00B9FFDF20690088FDF797 +:10C3F00042F820690088FDF764F82069B0F8F2106F +:10C4000071B190F8E410FE290FD190F88C1189B128 +:10C4100090F87F20012319467030F4F7B3FD78B10E +:10C42000206990F8E400FE2804D0206990F8E40028 +:10C43000FFF774FB206990F8FD1089B1258118E0A1 +:10C440002069A0F89C5090F88D1180F8E61000212A +:10C450000220FFF7CBF9206980F8FA500220E7E7C5 +:10C4600090F8C81119B9018C8288914200D881884E +:10C47000218130F8F61F491E8EB230F8021F314478 +:10C4800020F86019018831440180FFF7FFFB20B1DB +:10C49000206930F88E1F314401802069B0F8F21015 +:10C4A000012902D8491CA0F8F2102EB102E00000C8 +:10C4B0000001002080F8045180F8FA5090F87D10B7 +:10C4C0000B2901D00C2916D1B0F87020B0F8AA3190 +:10C4D000D21A12B2002A0EDBD0F8AC11816090F8AB +:10C4E000B01101730321F4F773F8206980F87D50CF +:10C4F00080F8B27026E0242910D1B0F87010B0F89E +:10C50000AA21891A09B2002908DB90F8C001FFF7B7 +:10C510004BF9206900F87D5F857613E090F87C1078 +:10C52000242901D025290DD1B0F87010B0F8AA0146 +:10C53000081A00B2002805DB0120FFF735F9206951 +:10C5400080F87C5020690146B0F8F6207030F4F78E +:10C55000B2FAFC480090FC4BFC4A4146484600F0C9 +:10C560007DFC216A11B16078FCF7B5FA20690123DE +:10C57000052190F87D207030F4F704FD002803D0E9 +:10C58000BDE8F84300F0FDB9BDE8F88300F015BD43 +:10C59000EF49C8617047EE48C069002800D001200B +:10C5A0007047EB4A50701162704710B5044600881E +:10C5B000A4F8CC01B4F8B001A4F8CE01B4F8B201EB +:10C5C000A4F8D001B4F8B401A4F8D201012084F891 +:10C5D000C801DF480079E6F797FC02212046F3F70F +:10C5E000F7FF002004F87D0F0320E07010BD401A13 +:10C5F00000B247F6FE71884201DC002801DC012010 +:10C6000070470020704710B5012808D0022808D0D4 +:10C61000042808D0082806D0FFDF204610BD0124DA +:10C62000FBE70224F9E70324F7E7C9480021006982 +:10C6300020F8A41F8178491C81707047C44800B558 +:10C64000016911F8A60F401E40B20870002800DAF8 +:10C65000FFDF00BDBE482721006980F87C10002163 +:10C6600080F8A011704710B5B94C206990F8A81156 +:10C67000042916D190F87C20012300217030F4F7B2 +:10C6800081FC00B9FFDF206990F8AA10890703D464 +:10C69000062180F87C1004E0002180F8A21080F8C8 +:10C6A000A811206990F87E00800707D5FFF7C6FF24 +:10C6B000206910F87E1F21F00201017010BDA4490D +:10C6C00010B5096991F87C200A2A09D191F8E22075 +:10C6D000824205D1002081F87C0081F8A20010BDC3 +:10C6E00091F87E20130706D522F0080081F87E001D +:10C6F000BDE81040A2E7FF2801D0FFDF10BDBDE874 +:10C700001040A7E7F8B5924C01230A21206990F860 +:10C710007C207030F4F736FC38B3A06901F07CFE61 +:10C72000C8B1A06901F072FE0746A06901F072FE6F +:10C730000646A06901F068FE0546A06901F068FEA2 +:10C7400001460097206933462A46303001F059FFF0 +:10C75000206901F082FF2169002081F8A20081F8A0 +:10C760007C00BDE8F840FEF7D2BBA07840F00100A5 +:10C77000A070F8BD10B5764C01230021206990F817 +:10C780007D207030F4F7FEFB30B1FFF74EFF2169DA +:10C79000102081F87D0010BD20690123052190F84B +:10C7A0007D207030F4F7EEFB08B1082000E0012096 +:10C7B000A07010BD70B5664C01230021206990F86F +:10C7C0007D207030F4F7DEFB012588B1A06901F00F +:10C7D000C4FD2169A1F8AA01B1F87010FFF707FFA5 +:10C7E00040B12069282180F88D1080F88C50E6E552 +:10C7F000A570E4E52169A06901F5D67101F0A8FDF5 +:10C8000021690B2081F87D00D9E510B5FEF779FF8D +:10C81000FEF760FE4E4CA079400708D5A07830B9ED +:10C82000206990F87F00072801D101202070FEF7D1 +:10C8300071FAA079C00609D5A07838B9206990F8B6 +:10C840007D100B2902D10C2180F87D10E0780007C3 +:10C850000ED520690123052190F87D207030F4F772 +:10C8600091FB30B10820A0702169002081F8D4012B +:10C8700010BDBDE81040002000F0C4BB10B5344C22 +:10C88000216991F87D2048B3102A06D0142A07D0D8 +:10C89000152A1AD01B2A2CD11AE001210B2019E0ED +:10C8A000FAF702FE0C2817D32069082100F58870DA +:10C8B000FAF7FEFD28B120690421DC30FAF7F8FD13 +:10C8C00000B9FFDF0121042004E000F017F803E0C5 +:10C8D00001210620FEF78AFF012010BD212A08D180 +:10C8E00091F8970038B991F8C00110B191F8C101E1 +:10C8F00008B1002010BD01211720EBE770B5144CE2 +:10C900000025206990F88F1101290AD002292ED123 +:10C9100090F8A810F1B1062180F8E610012102205C +:10C9200020E090F8D411002921D100F1C80300F5CE +:10C930008471002200F5C870F4F796FA01210520F1 +:10C9400010E00000AFC00100EFC2010025C30100EC +:10C950000001002090F8B000400701D5112000E050 +:10C960000D200121FEF742FF206980F88F5126E556 +:10C9700030B5FB4C05462078002818BFFFDFE57175 +:10C9800030BDF7490120887170472DE9F14FF54D11 +:10C990002846446804F1700794F86510608F94F895 +:10C9A0008280268F082978D0F4F797FBB8F1000F22 +:10C9B00004BF001D80B2864238BF304600F0FF0839 +:10C9C000DFF89C93E848C9F8240009F134006E6848 +:10C9D000406800F1700A90F882B096F86510358FC3 +:10C9E000708F08295DD0F4F778FB00BFBBF1000F12 +:10C9F00004BF001D80B2854238BF2846C0B29AF8F5 +:10CA00001210002918BF04210844C0B296F865101E +:10CA1000FBF735FCB87C002847D007F15801D24815 +:10CA200091E80E1000F5027585E80E10B96EC0F899 +:10CA30002112F96EC0F8251200F58170FBF7DBFFBB +:10CA4000C848007800280CBF0120002080F00101B8 +:10CA5000C6480176D7E91412C0E90412A0F5837222 +:10CA6000D9F82410FBF7F5F994F86500012808BF00 +:10CA700000220CD0022808BF012208D0042808BFD9 +:10CA8000032204D008281ABFFFDF002202224146F9 +:10CA90000120FBF7F9F90EE0FFE70421F4F71DFB95 +:10CAA00084E70421F4F719FBA0E7D9F82400FBF789 +:10CAB000A2FFFBF715FA009850B994F8650094F8B6 +:10CAC000661010F00C0F08BF00219620FBF7B4FF92 +:10CAD00094F8642001210020FCF76BF894F82C00F6 +:10CAE000012808BFFCF735F8022089F80000FCF7A0 +:10CAF0003FFC002818BFFFDFBDE8F88F2DE9F04F9D +:10CB0000DFF860A28BB050469AF800204068AAF186 +:10CB10001401059190F8751000F1700504464FF06E +:10CB200008080127AAF13406A1B3012900F0068103 +:10CB3000022900F00781032918BFFFDF00F01881E8 +:10CB4000306A0423017821F008010170AA7908EA0B +:10CB5000C202114321F004010170EA7903EA820262 +:10CB6000114321F01001017095F80590F06AF6F775 +:10CB70005EFD8046FCF7C9FCB9F1020F00F00081B0 +:10CB8000B9F1010F00F00081B9F1030F00F000814D +:10CB900000F003B9FFE795F80CC04FF002094FF021 +:10CBA000000BBCF1240F1CBF6B7B242B08D0BCF105 +:10CBB0001F0F18BFBCF1200F2AD0222B4DD077E0D9 +:10CBC00094F864109AB190F8AC01002874D0082948 +:10CBD00018BF042969D0082818BF042865D0012986 +:10CBE00018BF012853D000BF4FF0020164E090F855 +:10CBF0001201002860D0082918BF042955D0082840 +:10CC000018BF042851D0012918BF01283FD0EBE7F5 +:10CC1000222B22D0002A4BD090F8C20194F8641045 +:10CC200010F0040F18BF40460CD0082918BF042983 +:10CC30003BD0082818BF042837D0012918BF012885 +:10CC400025D0D1E710F0010F18BF3846EDD110F014 +:10CC5000020F18BF4846E8D12EE04AB390F8C2212F +:10CC600090F85D0094F8641002EA000010F0040FE0 +:10CC700018BF40460ED0082918BF042915D008282F +:10CC800018BF042811D0012918BF0128ACD14FF0DA +:10CC9000010111E010F0010F18BF3846EBD110F080 +:10CCA000020F18BF4846E6D106E04FF0080103E046 +:10CCB00094F864100429F8D0A08E11F00C0F18BF5E +:10CCC0004FF42960F4F709FA218E814238BF0846F3 +:10CCD000ADF80400A4F84C000598FCF7F5FB60B132 +:10CCE0007289316A42F48062728172694FF48060A5 +:10CCF000904703206871EF7022E709AA01A9F06A42 +:10CD0000F6F7CFFB306210B195F8371021B10598D6 +:10CD1000FCF7AEFB6F7113E79DF8241031B9A0F852 +:10CD200000B080F802B0012101F09EFABDF80410B5 +:10CD3000306A01F0C7FB85F8059001E70598FCF71C +:10CD400097FBFDE6B4F84C00ADF8040009AA01A970 +:10CD5000F06AF6F7A6FB3062002808BFFFDFEFE6B7 +:10CD60002401002058010020300D0020380F002041 +:10CD70000598FCF7A9FB002808BFFFDFE0E600BF2D +:10CD800030EA080009D106E030EA080005D102E0E7 +:10CD9000B8F1000F01D0012100E00021306A0278D3 +:10CDA00042EA01110170697C00291CBF69790129DF +:10CDB0003BD005F15801FD4891E80E1000F50278CE +:10CDC00088E80E10A96EC0F82112E96EC0F825128D +:10CDD00000F58170FBF70FFE9AF8000000280CBFE9 +:10CDE00001210021F2480176D5E91212C0E90412AE +:10CDF000A0F58371326AFBF72CF894F864000128DF +:10CE000008BF00220CD0022808BF012208D0042845 +:10CE100008BF032204D008281ABFFFDF0022022225 +:10CE2000FB210020FBF730F803E0FBF7E4FDFBF704 +:10CE300057F8012194F865200846FBF7BAFE3771D0 +:10CE4000306A0188F181807830743770FCF799FA84 +:10CE5000002818BFFFDF0BB0BDE8F08F2DE9F043CD +:10CE6000D44D87B081462878DDF838801E461746B5 +:10CE70000C4628B9002F1CBF002EB8F1000F00D1BE +:10CE8000FFDFC5F81C80C5E90D94C5E905764FF0B4 +:10CE90000000A8716871E870A8702871C64E68819A +:10CEA000A881307804F170072088F7F742F9E8622A +:10CEB0002088F7F72CF92863FBF705FA94F9670047 +:10CEC000FBF7DAFA04F11200FBF76CFD04F10E0037 +:10CED000FBF7D8FA307800280CBF03200120FBF7BD +:10CEE00087FDB64890E80E108DE80E10D0E90410CA +:10CEF000CDE90410307800280CBFB148B148049047 +:10CF00006846FBF763FDF87EFBF7C4FAFBF76AFDA2 +:10CF100094F86F0078B9A06E68B1B88C39888842EF +:10CF200009D1B4F86C1001220844B88494F86E005A +:10CF3000A16EF8F7D8FE3078002804BFFF2094F8DF +:10CF400064401AD094F8651097F81280258F608F8E +:10CF5000082926D0F4F7C1F8B8F1000F04BF001D6E +:10CF600080B2854238BF2846C0B2B97C002918BFBC +:10CF70000421084494F86540C0B22146FBF77FF9CC +:10CF80003078214688B10120FBF74BFB7068D0F860 +:10CF90000001FBF733FD0120FFF7F7FC07B0BDE808 +:10CFA000F0830421F4F799F8D6E70020FBF739FB6A +:10CFB000FFF7A4FD07B0BDE8F0837F4800B5017816 +:10CFC0003438007819B1022818BFFFDF00BD0128EE +:10CFD00018BFFFDF00BD774810B50078022818BFE2 +:10CFE000FFDFBDE8104000F070BA00F06EBA714883 +:10CFF000007970476F488089C0F3002070476D4802 +:10D00000C07870472DE9F04706006B48694D4068CD +:10D0100000F17004686A90F8019018BF012E03D1E6 +:10D02000296B07F0F1FF6870687800274FF001085E +:10D03000A0B101283CD0022860D003281CBFFFDF2C +:10D04000BDE8F087012E08BFBDE8F087286BF6F732 +:10D05000E3FCE879BDE8F047E5F756BF012E14D0B0 +:10D06000A86A002808BFFFDF2889C21CD5E909107B +:10D07000F1F7E3F9A86A686201224946286BF6F7DE +:10D0800047FB022E08BFBDE8F087D4E91401401C1D +:10D0900041F10001C4E91401E079012801D1E771EF +:10D0A00001E084F80780E879BDE8F047E5F72CBF98 +:10D0B000012E14D0A86A002808BFFFDF2889C21CEF +:10D0C000D5E90910F1F7B9F9A86A68620022494662 +:10D0D000286BF6F71DFB022E08BFBDE8F087D4E9E8 +:10D0E0001410491C40F10000C4E91410E079012833 +:10D0F0000CBFE77184F80780BDE8F087012E06D0E9 +:10D10000286BF6F789FC022E08BFBDE8F087D4E94A +:10D110001410491C40F10000C4E91410E079012802 +:10D12000BFD1BCE72DE9F041234D2846A5F13404D9 +:10D13000406800F170062078012818BFFFDFB07842 +:10D140000127002158B1B1706289042042F0040225 +:10D150006281626990472878002818BF3771216A78 +:10D160000322087832EA000009D1628912F4806F44 +:10D1700005D042F002026281626902209047A169F3 +:10D180000020884760B3607950BB287818B30E48F8 +:10D19000007810F0100F04D10449097811F0100F35 +:10D1A0001ED06189E1B9A16AA9B90FE0300D002054 +:10D1B000380F0020240100205801002004630200E1 +:10D1C000BB220200A7A8010032010020218911B171 +:10D1D00010F0100F04D0BDE8F0410020FFF7D5BBE0 +:10D1E000BDE8F04100F071B92DE9F05FCC4E044686 +:10D1F0003046A6F134054068002700F1700A28780F +:10D20000B846022818BFFFDFA889FF2240F400704B +:10D21000A881706890F864101046FBF730F89AF80F +:10D2200012004FF00109002C00F0F080FAF77DFEAB +:10D23000FAF76BFE90B99AF8120078B1686A4178F3 +:10D2400061B100789AF80710C0F3C000884205D198 +:10D2500085F80290BDE8F05F00F037B9686A417860 +:10D260002981002908BFAF6203D0286BF6F70AFABC +:10D27000A862A88940F02000A881EF70706800F1D2 +:10D28000700B044690F82C0001281BD1FBF757FCCB +:10D2900059462046F3F729FEA0B13078002870687F +:10D2A0000CBF00F59A7000F50170218841809BF851 +:10D2B000081001719BF80910417180F80090E8791D +:10D2C000E5F722FE686A9AF806100078C0F380003D +:10D2D00088423AD0706800F1700490F87500002818 +:10D2E0002FD002284AD06771307800281CBF2079DF +:10D2F000002809D027716A89394642F010026A81F4 +:10D300006A694FF010009047E078A0B1E770FCF731 +:10D31000EAF8002808BFFFDF08206A89002142F0F0 +:10D3200008026A816A699047D4E91210491C40F1E9 +:10D330000000C4E91210A07901280CBFA77184F87D +:10D340000690A88940F48070A881696A9AF807302D +:10D350000878C0F3C0029A424DD1726800F0030011 +:10D3600002F17004012818BF02282DD003281CBF29 +:10D37000687940F0040012D068713CE0E86AF6F782 +:10D38000BCF8002808BFFFDFD4E91210491C40F1A7 +:10D390000000C4E91210E879E5F7B6FDA3E784F8C8 +:10D3A0000290AA89484642F40062AA816A8942F042 +:10D3B00001026A816A699047E079012801D1E77129 +:10D3C00019E084F8079016E04878D8B1A98941F4AB +:10D3D0000061A981A96A71B1FB2884BF687940F016 +:10D3E0001000C9D8A879002808BFC84603D08020FB +:10D3F0006A69002190470120A9698847E0B36879EC +:10D40000A0B13AE0E0790128DBD1D8E7002818BFC5 +:10D41000FAF7C5FDA88940F04000A881E97801200D +:10D42000491CC9B2E97001292DD8E5E7307890B9D7 +:10D430003C48007810F0100F04D13B49097811F0F6 +:10D44000100F1AD06989B9B9A96A21B9298911B10E +:10D4500010F0100F11D0B8F1000F1CBF0120FFF722 +:10D46000D1FDFFF74BFBB8F1000F08BFBDE8F09FFF +:10D470000220BDE8F05FC5E5FFE7B8F1000F1CBF73 +:10D480000020FFF7BFFDBDE8F05F00F01EB870B5EB +:10D490000D4606462248224900784C6850B1FAF7FA +:10D4A000F7FD034694F8642029463046BDE87040F5 +:10D4B000FDF78BBAFAF7ECFD034694F86420294691 +:10D4C0003046BDE8704004F0FCBE154910B54C680C +:10D4D000FBF714FBFBF7F3FAFBF7BCF9FBF768FA71 +:10D4E000FAF7FEFC94F82C00012808BFFBF727FB95 +:10D4F00094F86F0038B9A06E28B1002294F86E003D +:10D500001146F8F7F0FB094C00216269A0899047A9 +:10D51000E2696179A07890470020207010BD00007A +:10D520005801002032010020300D0020240100208D +:10D530002DE9F047FA4F894680463D782C0014D0FB +:10D540000126012D11DB601EC4B207EBC40090F868 +:10D550005311414506D10622494600F5AA70F0F75D +:10D560003FFF28B1761CAE42EDDD1020BDE8F0870C +:10D570002046BDE8F087EA498A78824286BF08449F +:10D5800090F843010020704710B540F2D3120021FB +:10D59000E348F0F77CFF0822FF21E248F0F777FF2D +:10D5A000E1480021417081704FF46171818010BDAC +:10D5B0002DE9F0410E460546FFF7BAFFD84C10287A +:10D5C00016D004EBC00191F85A0110F0010F1CBFF6 +:10D5D0000120BDE8F081607808283CBF012081F877 +:10D5E0005A011CD26078401C60700120BDE8F081B7 +:10D5F0006078082813D222780127501C207004EB91 +:10D60000C2083068C8F85401B088A8F85801102A38 +:10D6100028BFFFDF88F8535188F85A71E2E70020ED +:10D62000BDE8F081C04988707047BF488078704776 +:10D630002DE9F041BA4D00272878401E44B2002C55 +:10D6400030DB00BF05EBC40090F85A0110F0010F69 +:10D6500024D06878E6B2401E687005EBC6083046F4 +:10D6600088F85A7100F0E8FA102817D12878401E7F +:10D67000C0B22870B04211D005EBC001D1F85301FF +:10D68000C8F85301D1F85701C8F85701287800F0BD +:10D69000D3FA10281CBF284480F80361601E44B2EE +:10D6A000002CCFDAA0488770BDE8F0819C498A78C9 +:10D6B000824286BF01EB0010C01C002070472DE99C +:10D6C000F0470127994690463D460026FFF730FF78 +:10D6D000102820D0924C04EBC00191F85A1101F0AF +:10D6E000010600F0A9FA102815D0B9F1000F18BFF3 +:10D6F00089F80000A17881420DD904EB001111F1E5 +:10D70000030F08D0204490F84B5190F83B010128BA +:10D710000CBF0127002748EA060047EA0501084038 +:10D72000BDE8F0872DE9F05F1F4690468946064622 +:10D73000FFF7FEFE7A4C054610282ED000F07CFA4A +:10D7400010281CBF1220BDE8F09FA07808283ED208 +:10D75000A6781022701CA07004EB061909F10300D2 +:10D760004146F3F768FB09F1830010223946F3F7CD +:10D7700062FB10213846F3F74BFB3444102184F848 +:10D7800043014046F3F744FB84F84B0184F803510E +:10D79000002084F83B01BDE8F09FA078082816D24D +:10D7A00025784FF0000A681C207004EBC50BD9F8EF +:10D7B0000000CBF85401B9F80400ABF85801102D63 +:10D7C00028BFFFDF8BF853618BF85AA1C0E7072011 +:10D7D000BDE8F09F2DE9F041514CA078401E45B2C4 +:10D7E000002DB8BFBDE8F081EAB2A078401EC1B2FA +:10D7F000A17054FA85F090F803618A423DD004EBA1 +:10D80000011004EB0213D0F803C0C3F803C0D0F832 +:10D8100007C0C3F807C0D0F80BC0C3F80BC0D0F8DE +:10D820000FC0C3F80FC0D0F883C0C3F883C0D0F8CE +:10D8300087C0C3F887C0D0F88BC0C3F88BC0D0F8BE +:10D840008F00C3F88F006318A01801EB410193F813 +:10D8500003C102EB420204EB410180F803C104EB77 +:10D860004202D1F80BC1C2F80BC1B1F80F11A2F8F6 +:10D870000F1193F83B1180F83B1104EBC60797F8A2 +:10D880005A0110F0010F1CD1304600F0D5F91028D4 +:10D8900017D12078401EC0B22070B04211D004EBE6 +:10D8A000C000D0F85311C7F85311D0F85701C7F88A +:10D8B0005701207800F0C0F910281CBF204480F8E0 +:10D8C0000361681E45B2002D8EDABDE8F08116496D +:10D8D0004870704714484078704738B14AF2B81120 +:10D8E000884203D810498880012070470020704783 +:10D8F0000D488088704710B5FFF71AFE102804D035 +:10D9000000F09AF9102818BF10BD082010BD044976 +:10D910008A78824286BF01EB001083300020704776 +:10D92000600F00206C01002060010020FE4B93F886 +:10D9300002C084459CBF00207047184490F8030142 +:10D9400003EBC00090F853310B70D0F85411116004 +:10D95000B0F85801908001207047F34A114491F8C3 +:10D960000321F2490A700268C1F8062080884881C4 +:10D97000704770B516460C460546FBF7D5F8FAF722 +:10D98000C4F9EA48407868B1E748817851B12A196A +:10D99000002E0CBF8330C01CFAF791F9FAF7D8F9C2 +:10D9A000012070BD002070BD10B5FAF7FFF9002806 +:10D9B00004BFFF2010BDBDE81040FAF71DBAFAF70A +:10D9C000F5B9D9498A7882429CBF00207047084443 +:10D9D00090F8030101EBC00090F85A0100F001003B +:10D9E00070472DE9F047D04D00273E4628780028A3 +:10D9F00086BF4FF01009DFF83883BDE8F087AC78B8 +:10DA000021000CD00122012909DB601EC4B22819B3 +:10DA100090F80331B34203D0521C8A42F5DD4C46E4 +:10DA2000A14286BF05EB0410C01C002005EBC60A0E +:10DA30009AF85A1111F0010F16D050B1102C04D0E1 +:10DA4000291991F83B11012903D01021F3F7E0F9CE +:10DA500050B108F8074038467B1C9AF853210AF564 +:10DA6000AA71DFB2FAF7B5FC701CC6B22878B042D2 +:10DA7000C5D8BDE8F0872DE9F041AB4C002635460E +:10DA8000A07800288CBFAA4FBDE8F0816119C0B210 +:10DA900091F80381A84286BF04EB0510C01C00204A +:10DAA00091F83B11012903D01021F3F7B1F958B1D6 +:10DAB00004EBC800BD5590F8532100F5AA7130461B +:10DAC000731CDEB2FAF785FC681CC5B2A078A842C8 +:10DAD000DCD8BDE8F0810144934810B500EB02109A +:10DAE0000A4601218330FAF7EAF8BDE81040FAF758 +:10DAF0002FB90A468D4910B5497841B18A4B9978BA +:10DB000029B10244D81CFAF7DAF8012010BD002030 +:10DB100010BD854A01EB410102EB41010268C1F8E9 +:10DB20000B218088A1F80F0170472DE9F0417E4D4F +:10DB300007460024A878002898BFBDE8F081C0B24D +:10DB4000A04217D905EB041010F1830612D0102162 +:10DB50003046F3F75DF968B904EB440005EB400883 +:10DB600008F20B113A463046FBF74EFDB8F80F01AC +:10DB7000A8F80F01601CC4B2A878A042DFD8BDE8A5 +:10DB8000F081014610226B48F3F755B96948704798 +:10DB900065498A78824203D90A1892F843210AB16A +:10DBA0000020704700EB400001EB400000F20B103A +:10DBB00070475D498A78824206D9084490F83B0153 +:10DBC000002804BF01207047002070472DE9F04174 +:10DBD0000E460746144606213046F3F719F9524D12 +:10DBE00098B1A97871B105F59D7011F0010F18BFBA +:10DBF00000F8014FA978490804D0447000F8024F9A +:10DC0000491EFAD10120BDE8F08138463146FFF7C0 +:10DC10008FFC10280CD000F00FF8102818BF08282F +:10DC200006D0284480F83B414FF00100BDE8F08168 +:10DC30004FF00000BDE8F0813B4B10B4844698786B +:10DC400001000ED0012201290BDB401EC0B21C18BE +:10DC500094F80341644504BF10BC7047521C8A42CB +:10DC6000F3DD10BC1020704770B52F4C01466218D0 +:10DC7000A078401EC0B2A07092F8035181423CD0FF +:10DC800004EB011304EB001C01EB4101DCF8036021 +:10DC9000C3F80360DCF80760C3F80760DCF80B60CA +:10DCA000C3F80B60DCF80F60C3F80F60DCF883602A +:10DCB000C3F88360DCF88760C3F88760DCF88B60AA +:10DCC000C3F88B60DCF88FC0C3F88FC0231800EB5B +:10DCD000400093F803C104EB400082F803C104EB59 +:10DCE0004101D0F80BC1C1F80BC1B0F80F01A1F888 +:10DCF0000F0193F83B0182F83B0104EBC50696F84F +:10DD00005A0110F0010F18BF70BD2846FFF794FFAD +:10DD1000102818BF70BD2078401EC0B22070A842E5 +:10DD200008BF70BD08E00000600F00206001002007 +:10DD30006C0100203311002004EBC000D0F8531117 +:10DD4000C6F85311D0F85701C6F857012078FFF7ED +:10DD500073FF10281CBF204480F8035170BD0000E1 +:10DD60004078704730B50546007801F00F0220F08A +:10DD70000F0010432870092912D2DFE801F00507CF +:10DD800005070509050B0F0006240BE00C2409E02C +:10DD9000222407E001240020E87003E00E2401E0C3 +:10DDA0000024FFDF6C7030BD007800F00F0070477A +:10DDB0000A68C0F803208988A0F807107047D0F8D7 +:10DDC00003200A60B0F80700888070470A68C0F82E +:10DDD00009208988A0F80D107047D0F809200A6042 +:10DDE000B0F80D00888070470278402322F040028E +:10DDF00003EA81111143017070470078C0F380106D +:10DE000070470278802322F0800203EAC111114397 +:10DE1000017070470078C009704770B514460E460F +:10DE200005461F2A88BFFFDF2246314605F109005B +:10DE3000F0F703FBA01D687070BD70B544780E4606 +:10DE40000546062C38BFFFDFA01F84B21F2C88BFF9 +:10DE50001F24224605F109013046F0F7EEFA20466C +:10DE600070BD70B514460E4605461F2A88BFFFDFF9 +:10DE70002246314605F10900F0F7DFFAA01D68706F +:10DE800070BD0968C0F80F1070470A88A0F8132009 +:10DE900089784175704790F8242001F01F0122F025 +:10DEA0001F02114380F824107047072988BF0721FB +:10DEB00090F82420E02322F0E00203EA411111430C +:10DEC00080F8241070471F3008F065B810B504467C +:10DED00000F000FB002818BF204410BDC17811F0ED +:10DEE0003F0F1BBF027912F0010F0022012211F037 +:10DEF0003F0F1BBF037913F0020F002301231A44C5 +:10DF000002EB4202530011F03F0F1BBF027912F0E7 +:10DF1000080F0022012203EB420311F03F0F1BBF49 +:10DF2000027912F0040F00220122134411F03F0F76 +:10DF30001BBF027912F0200F0022012202EBC20265 +:10DF400003EB420311F03F0F1BBF027912F0100FD9 +:10DF50000022012202EB42021A4411F03F0F1BBFC4 +:10DF6000007910F0400F00200120104410F0FF0055 +:10DF700014BF012100210844C0B2704770B5027877 +:10DF8000417802F00F02082A4DD2DFE802F00408BF +:10DF90000B4C4C4C0F14881F1F280AD943E00C2946 +:10DFA00007D040E0881F1F2803D93CE0881F1F28A6 +:10DFB00039D8012070BD4A1EFE2A34D88446C07864 +:10DFC00000258209032A09D000F03F04601C884222 +:10DFD00004D86046FFF782FFA04201D9284670BDF1 +:10DFE0009CF803004FF0010610F03F0F1EBF1CF11C +:10DFF0000400007810F0100F13D06446042160462E +:10E0000000F068FA002818BF14EB0000E6D0017891 +:10E0100001F03F012529E1D280780221B1EB501FA8 +:10E02000DCD3304670BD002070BD70B5017801258D +:10E0300001F00F01002404290AD007290DD0082976 +:10E040001CBF002070BD40780E2836D0204670BD21 +:10E050004078801F1F2830D9F8E7844640789CF824 +:10E0600003108A09032AF1D001F03F06711C814296 +:10E07000ECD86046FFF732FFB042E7D89CF80300C7 +:10E0800010F03F0F1EBF1CF10400007810F0100FBD +:10E0900013D066460421604600F01CFA002818BF21 +:10E0A00016EB0000D2D0017801F03F012529CDD236 +:10E0B00080780221B1EB501FC8D3284670BD10B440 +:10E0C000017801F00F01032920D0052921D14478DE +:10E0D000B0F81910B0F81BC0B0F81730827D222CB0 +:10E0E00017D1062915D3B1F5486F98BFBCF5FA7F53 +:10E0F0000FD272B1082A98BF8A420AD28B429CBFC3 +:10E10000B0F81D00B0F5486F03D805E040780C2842 +:10E1100002D010BC0020704710BC012070472DE9D0 +:10E12000F0411F4614460D00064608BFFFDF21469A +:10E13000304600F0CFF9040008BFFFDF30193A463F +:10E140002946BDE8F041F0F778B9C07800F03F000B +:10E150007047C02202EA8111C27802F03F021143E7 +:10E16000C1707047C07880097047C9B201F00102E0 +:10E17000C1F340031A4402EB4202C1F3800303EBF4 +:10E180004202C1F3C00302EB4302C1F3001303EBED +:10E1900043031A44C1F3401303EBC30302EB4302EE +:10E1A000C1F380131A4412F0FF0202D0521CD2B203 +:10E1B0000171C37802F03F0103F0C0031943C1703D +:10E1C000511C417070472DE9F0410546C078164654 +:10E1D00000F03F041019401C0F46FF2888BFFFDFE6 +:10E1E000281932463946001DF0F727F9A019401CBE +:10E1F0006870BDE8F081C178407801F03F01401AB5 +:10E20000401E80B2704710B590F803C00B460CF06A +:10E210003F0144780CF03F0CA4EB0C0CACF1010C6A +:10E220001FFA8CF4944288BF14462BB10844011D98 +:10E2300022461846F0F701F9204610BD4078704795 +:10E2400000B5027801F0030322F003021A430270C2 +:10E25000012914BF0229002104D0032916BFFFDFC2 +:10E26000012100BD417000BD00B5027801F003033B +:10E2700022F003021A430270012914BF022900216F +:10E2800004D0032916BFFFDF012100BD417000BD8E +:10E29000007800F003007047417841B1C078192838 +:10E2A00003D2BC4A105C884201D101207047002093 +:10E2B000704730B501240546C17019293CBFB548E7 +:10E2C000445C02D3FF2918BFFFDF6C7030BD70B50E +:10E2D00015460E4604461B2A88BFFFDF65702A4696 +:10E2E0003146E01CBDE87040F0F7A7B8B0F8070071 +:10E2F0007047B0F809007047C172090A017370478E +:10E30000B0F80B00704730B4B0F80720B0F809C07F +:10E31000B0F805300179941F40F67A45AC4298BFB9 +:10E32000BCF5FA7F0ED269B1082998BF914209D293 +:10E3300093429FBFB0F80B00B0F5486F012030BC8E +:10E3400098BF7047002030BC7047001D07F023BE07 +:10E35000021D0846114607F01EBEB0F809007047BE +:10E36000007970470A684260496881607047426876 +:10E370000A60806848607047098881817047808999 +:10E38000088070470A68C0F80E204968C0F812106B +:10E390007047D0F80E200A60D0F81200486070472D +:10E3A0000968C0F816107047D0F81600086070476A +:10E3B0000A68426049688160704742680A60806804 +:10E3C000486070470968C1607047C068086070475E +:10E3D000007970470A684260496881607047426806 +:10E3E0000A608068486070470171090A417170478E +:10E3F0008171090AC17170470172090A417270473F +:10E400008172090AC172704780887047C08870475E +:10E41000008970474089704701891B2924BF4189C1 +:10E42000B1F5A47F07D381881B2921BFC088B0F52F +:10E43000A47F01207047002070470A684260496845 +:10E440008160704742680A6080684860704701795F +:10E4500011F0070F1BBF407910F0070F00200120BB +:10E460007047017911F0070F1BBF407910F0070FBB +:10E470000020012070470171704700797047417199 +:10E480007047407970478171090AC1717047C0882F +:10E4900070470179407901F007023F498A5C012AFF +:10E4A00006D800F00700085C01289CBF01207047D7 +:10E4B00000207047017170470079704741717047C3 +:10E4C0004079704730B50C460546FB2988BFFFDF11 +:10E4D0006C7030BDC378024613F03F0008BF704730 +:10E4E0000520127903F03F0312F0010F37D0002905 +:10E4F00014BF0B20704700BF12F0020F32D0012969 +:10E5000014BF801D704700BF12F0040F2DD00229E8 +:10E5100014BF401C704700BF12F0080F28D0032919 +:10E5200014BF801C704700BF12F0100F23D00429C5 +:10E5300014BFC01C704700BF12F0200F1ED0052969 +:10E540001ABF1230C0B2704712F0400F19D006291E +:10E550001ABF401CC0B27047072918D114E0002927 +:10E56000CAD114E00129CFD111E00229D4D10EE0A3 +:10E570000329D9D10BE00429DED108E00529E3D134 +:10E5800005E00629E8D102E0834288BF70470020F9 +:10E5900070470000246302001C63020030B490F84E +:10E5A00064508C88B1F808C015F00C0F1BD000BF68 +:10E5B000B4F5296F98BF4FF4296490F8655015F0B1 +:10E5C0000C0F17D0BCF5296F98BF4FF4296C4A88FF +:10E5D000C988A0F84420A0F84810A0F84640A0F848 +:10E5E0004AC030BC7047002B1CBF157815F00C0FCB +:10E5F000DED1E2E7002B1CBF527812F00C0FE1D104 +:10E60000E5E7DDF800C08181C2810382A0F812C075 +:10E6100070471B2202838282C281828142800281F2 +:10E62000028042848284828359B14FF429614183FC +:10E63000C18241820182C18041818180C184018582 +:10E6400070474FF4A4714183C18241820182C1802D +:10E6500041818180C18401857047F0B4B0F84820C1 +:10E66000818F468EC58E8A4228BF0A4690F8651073 +:10E670004FF0000311F00C0F18BF4FF4296106D1C1 +:10E68000B0F84AC0B0F840108C4538BF61464286A9 +:10E69000C186048FB0F83AC0944238BF14468C4506 +:10E6A00038BF8C460487A0F83AC0B2420ABFA942DC +:10E6B0004FF0010C4FF0000C058EB0F84410C28FE3 +:10E6C000848E914228BF114690F8642012F00C0FFE +:10E6D00018BF4FF4296206D1B0F84660B0F8422066 +:10E6E000964238BF324690F85A60022E0AD0018610 +:10E6F0008286A9420ABFA2420120002040EA0C0003 +:10E70000F0BC70478D4238BF2946944238BF22463C +:10E7100080F85A30EBE7508088899080C889D08093 +:10E72000088A1081488A508101201070704730B4E7 +:10E7300002884A80B0F830C0A1F804C0838ECB8034 +:10E74000428E0A81C48E4C81B0F85650A54204BF57 +:10E75000B0F85240944208D1B0F858409C4202BFF1 +:10E76000B0F854306345002301D04FF001030B7320 +:10E7700000F13003A0F852201A464B89D3848B88CD +:10E780009384CA88A0F858204FF00100087030BC6C +:10E79000704730B404460A46088E91F864104FF46E +:10E7A000747311F00C0F1CBF03EB801080B21ED0ED +:10E7B000918E814238BF0846118F92F865C01CF0D7 +:10E7C0000C0F1CBF03EB811189B218D0538F8B4201 +:10E7D00038BF194692F866301CF00C0F08BF0023B2 +:10E7E000002C0CBF0122002230BCF2F798BC022999 +:10E7F00007BF80003C30C000703080B2D8E7BCF169 +:10E80000020F07BF89003C31C900703189B2DDE7D2 +:10E810002DE9F041044606F099FCC8B9FE4F78682E +:10E8200090F8221001260025012914D00178012931 +:10E830001BD090F8281001291CBF0020BDE8F081F2 +:10E84000657018212170D0F82A10616080F8285076 +:10E850000120BDE8F081657007212170416A616087 +:10E8600080F822500120BDE8F081657014212170EC +:10E87000811C2022201DEFF7E0FD257279680D70C4 +:10E8800081F82850E54882888284C26B527B80F8E8 +:10E89000262080F82260C86B0088F5F738FCF5F771 +:10E8A000E0F8D5E7DC4840680178002914BF80888B +:10E8B0004FF6FF70704730B5D74C83B00D462078C7 +:10E8C0007F2808BFFFDF94F900307F202070D4F844 +:10E8D00004C09CF85000062808BF002205D09CF810 +:10E8E000500008280CBF022201229CF85400CDE9F8 +:10E8F000000302929CF873309CF880200CF13201E6 +:10E90000284606F08FFC03B0BDE8304006F01FBE7D +:10E910002DE9F04106F05FFC002818BF06F0E4FB8B +:10E92000BD4C606800F1840290F87610895C80F834 +:10E930008010002003F07EF828B3FAF753F86068DF +:10E94000B74990F855000D5C2846F9F7A3FD6068BB +:10E950004FF0000680F8735090F8801011F00C0F03 +:10E960000CBF25200F20F9F76CFC606890F8801030 +:10E970000120F9F711FE606890F84010032918BFD4 +:10E9800002290FD103E0BDE8F04101F02FB990F862 +:10E9900076108430085C012804D101221146002041 +:10E9A000FAF707F9FAF7D5F8606890F88050012D6A +:10E9B00007BF0127032100270521A068FFF799F869 +:10E9C000616881F8520040B1002F18BF402521D066 +:10E9D000F9F787F92846FAF79DF86068806DFAF72D +:10E9E0000DF8606890F85410FF291CBF6D30FEF7D9 +:10E9F000B4FFFF21606880F8531080F8541080F84D +:10EA0000626080F8616080F87D60062180F85010B7 +:10EA1000BDE8F08115F00C0F14BF55255025D7E740 +:10EA200070B57D4C0646606800F150052046806850 +:10EA300041B1D0F80510C5F81D10B0F80900A5F8CF +:10EA4000210003E005F11D01FFF7B9F9A068FFF708 +:10EA5000D4F985F82400A0680021032E018002D09B +:10EA6000052E04D03DE00321FFF77CF939E00521B4 +:10EA7000FFF778F96068C06B00F10E01A068FFF73E +:10EA800000FA6068C06B00F11201A068FFF7FDF9A1 +:10EA9000D4E90110CA6B527D8275CA6BD28AC275E5 +:10EAA000120A0276CA6B52884276120A8276CA6BC2 +:10EAB0009288C276120A0277CA6BD2884277120A0B +:10EAC0008277C96B0831FFF7FEF96068C06B017E81 +:10EAD000A068FFF7E0F9606890F88610A068FFF77B +:10EAE000E4F905F11D01A068FFF770F995F824100D +:10EAF000A068FFF786F9606800F1320590F8316090 +:10EB000090F8511091B190F84010032906D190F877 +:10EB10003910002918BF90F8560001D190F8530021 +:10EB2000FFF736F800281CBF012605462946A068D5 +:10EB3000FFF73EF93146A068BDE87040FFF754B9D1 +:10EB40003549496881F84B00704770B5324D002453 +:10EB50000126A8606968A1F8814081F8834081F8A6 +:10EB6000506091F85020022A1FBF91F850100129DF +:10EB7000FFDF70BD06F0CDFA6868047080F82240AF +:10EB800080F8284090F8520030B1F9F7CDFFF9F73E +:10EB9000BCF8686880F852406868072180F84A40ED +:10EBA00080F8396080F8404080F8554080F84B404C +:10EBB00080F87D4080F8381070BD2DE9F041164C8A +:10EBC000054686B0606890F85000012818BF0228FA +:10EBD00005D003281EBF0C2006B0BDE8F081687A7E +:10EBE000022839D0F9F76FFB0220F9F701FF0D4930 +:10EBF00001F10C0090E80D108DE80D10D1E907012E +:10EC0000CDE904016846F9F7E1FE606890F94B0030 +:10EC1000F9F732FCA06807E07401002044110020DD +:10EC20004363020040630200F9F7E5FEFC48F9F790 +:10EC3000B9FEFC48F9F726FC606890F831103230D4 +:10EC4000F9F7A5FB0F210720F9F7BFFB606890F8E3 +:10EC50003900E0B1FEF70FFF6168287A01F1840204 +:10EC600081F87600287A805C81F880006868886581 +:10EC70002A68CA65687A68B1012824D00525022867 +:10EC800008BF81F850506FD0032878D080E0FEF79D +:10EC9000A8FEE1E7E44B91F83850002291F85500C6 +:10ECA000401CA3FB006C4FEA5C0CACEB8C0C60448A +:10ECB00081F8550025FA00F010F0010F03D1501C27 +:10ECC000C2B2032AEAD3002681F87D6091F8490098 +:10ECD000002804BF91F85100002841D0F7F744FA0A +:10ECE000074660683946406CF7F736FFDFF83C832B +:10ECF000054690FBF8F008FB105041423846F6F705 +:10ED00001AFF6168486495FBF8F08A6F10448867C1 +:10ED1000FEF7EEFD01466068826F914220D847649D +:10ED2000866790F8510000281CBF0120FEF7FDFE09 +:10ED30000121606890F84A20002A1CBF90F8492001 +:10ED4000002A0DD090F8313000F13202012B04D1AD +:10ED5000527902F0C002402A08D03230FAF78CFC17 +:10ED60006168042081F8500012E008E00125FEF7F8 +:10ED70000DFF61682A463231FAF746FCF0E7002AB7 +:10ED800018BFFFDF012000F089FF606880F8505055 +:10ED900006B00020BDE8F08170B5A54D686890F818 +:10EDA000501004292ED005291CBF0C2070BD90F8EE +:10EDB0007D100026002990F883104FEA511124D0CD +:10EDC000002908BF012407D0012908BF022403D06D +:10EDD000022914BF00240824C06D00281CBF002095 +:10EDE00000F05CFF6868806DF9F708FE686890F8CD +:10EDF0004010022943D0032904BF90F86C10012968 +:10EE000041D04DE0FFF784FD52E0002908BF012406 +:10EE100007D0012908BF022403D0022914BF00240F +:10EE20000824C06D00281CBF002000F037FF686870 +:10EE3000806DF9F7E3FD686890F84010022906D06C +:10EE4000032904BF90F86C10012904D010E090F859 +:10EE50006C1002290CD1224614F00C0F04D090F84B +:10EE60004C00012808BF042201210020F9F7A1FE6F +:10EE70006868072180F8804080F8616016E090F8AB +:10EE80006C1002290CD1224614F00C0F04D090F81B +:10EE90004C00012808BF042201210020F9F789FE57 +:10EEA0006868082180F8804080F8616080F8501020 +:10EEB000002070BD5E49002210F0010F496802D0A9 +:10EEC000012281F8842010F0080F03D0114408209B +:10EED00081F88400002070475549496881F848004E +:10EEE000704710B5524C636893F83030022B14BF52 +:10EEF000032B00280BD100291ABF02290120002072 +:10EF00001146FEF7F8FC08281CBF012010BD606800 +:10EF100090F83000002816BF022800200120BDE82C +:10EF20001040FAF731BB4248406890F830000028A2 +:10EF300016BF022800200120FAF726BB3C49496889 +:10EF400081F8300070473A49496881F84A007047B3 +:10EF500070B5374C616891F83000002816BF022860 +:10EF60000020012081F8310001F13201FAF7F6FAB0 +:10EF7000606890F83010022916BF03290121002192 +:10EF800080F8511090F8312000F132034FF0000565 +:10EF9000012A04BF5B7913F0C00F0AD000F13203DD +:10EFA000012A04D15A7902F0C002402A01D000227D +:10EFB00000E0012280F84920002A04BF002970BD2A +:10EFC0008567F7F7D1F86168486491F85100002827 +:10EFD0001CBF0020FEF7A9FD0026606890F84A10CB +:10EFE00000291ABF90F84910002970BD90F831200F +:10EFF00000F13201012A04D1497901F0C001402910 +:10F0000005D02946BDE870403230FAF735BBFEF72F +:10F01000BDFD61683246BDE870403231FAF7F4BA9E +:10F020004063020046630200ABAAAAAA40420F0056 +:10F030007401002070B5FF4D0C4600280CBF012361 +:10F040000023696881F8393081F842004FF00800E8 +:10F0500081F856000CD1002C1ABF022C0120002090 +:10F060001146FEF748FC6968082881F8560001D06F +:10F07000002070BD022C14BF032C1220F8D170BDEB +:10F08000002818BF112070470328EA4A526808BFB9 +:10F09000D16382F840000020704710B5E54C6068ED +:10F0A00090F8401003291CBF002180F8601001D0A7 +:10F0B000002010BD0123C16B1A460020F2F738F87A +:10F0C0006168CA6B526A904294BF0120002081F8A7 +:10F0D0006000EDE7D748416891F84000032804D06C +:10F0E000012818BF022807D004E091F84200012847 +:10F0F00008BF70470020704791F84100012814BFF5 +:10F1000003280120F6D1704770B5F9F7F7FCF9F73D +:10F11000D6FCF9F79FFBF9F74BFCC64C002560685D +:10F1200090F8520030B1F9F7FFFCF8F7EEFD606897 +:10F1300080F8525060680121A0F8815080F8835017 +:10F1400080F8501080F82850002070BDB94810B5E4 +:10F150004068643006F0B1FB002010BDB5480121C5 +:10F16000406890F84020032A03BF80F82A10C26B41 +:10F170001288002218BF80F82A20828580F8281083 +:10F180007047AC49496881F88600704701780023D0 +:10F1900011F0010FA749496809D04278032A08BF36 +:10F1A000CB6381F84020012281F884201346027845 +:10F1B00012F0040F0CD082784FF0000C032A08BF25 +:10F1C000C1F83CC081F840200B44082283F8842019 +:10F1D000C27881F830200279002A16BF022A012362 +:10F1E000002381F8393081F84120427981F83820B4 +:10F1F000807981F848004FF0000070478D484068E2 +:10F200008030704770B58B4C06460D46606890F8AC +:10F210005000032818BFFFDF022E1EBF032EFFDFA2 +:10F2200070BD002D18BF06F0A1F900216068A0F89C +:10F23000811080F88310012180F8501070BD00F01B +:10F24000D5BC2DE9F0477B4C0646894660684FF0F7 +:10F250000108072E90F8397038BF032540D3082ED7 +:10F2600084BF0020BDE8F08790F85010062908BF41 +:10F27000002105D090F8501008290CBF022101216F +:10F2800090F8800005F0AEFF002873D1A068C17827 +:10F2900011F03F0F12D0027912F0010F0ED0616809 +:10F2A0004FF0050591F85220002A18BFB9F1000F60 +:10F2B00016D091F88010012909D011E011F03F0F0C +:10F2C0001ABF007910F0100F002F53D14CE04FF00F +:10F2D00001024FF00501FEF74CFB616881F8520016 +:10F2E000A16808782944C0F3801030B1487900F053 +:10F2F000C000402808BF012000D00020616891F8BC +:10F300005210002918BF002807D0FEF74DFB014618 +:10F31000606880F8531080F86180606890F853103E +:10F32000FF292AD080F854100846FEF74AFB40EA2D +:10F330000705606890F85320FF2A18BF002D10D0F1 +:10F34000072E0ED3A068C17811F03F0F09D00179C4 +:10F3500011F0020F05D00B21FEF7BDFB606880F8AD +:10F3600062802846BDE8F087FEF75FF9002808BFF5 +:10F37000BDE8F0870120BDE8F087A36890F8392048 +:10F3800059191B78C3F3801C00F153036046FEF744 +:10F3900096F90546CDE72DE9F043264C87B0A068E5 +:10F3A000FEF7E0FE7F264FF00108002558B1022746 +:10F3B00001287DD0022800F0EF80F9F74BFA07B062 +:10F3C0000620BDE8F083F9F745FA616891F840003E +:10F3D000032800F01581A068C27812F03F0F05D015 +:10F3E000037913F0100F18BF012700D10027002F59 +:10F3F00014BF0823012312F03F0F00F001810079B0 +:10F4000033EA000240F0FC8010F0020F08D091F8BF +:10F410008000002105F064FE002808BF012000D014 +:10F4200000208DF80C508DF810508DF814504FF0CE +:10F43000FF0801E074010020D0B105AA03A904A8C7 +:10F4400000F07AFC606890F831809DF80C0000288C +:10F4500018BF48F002080BD1A068FEF7DBFC81461C +:10F460000121A068FEF732FD4946F8F79AFF28B35C +:10F47000FFB1012000F0DDFB002852D020787F286A +:10F4800008BFFFDF94F900102670606890F85420E0 +:10F49000CDE90021029590F8733090F8802000F1BA +:10F4A0003201404605F0BEFE606880F86C50A3E073 +:10F4B00038E041460020FFF7FEF9A1E0606890F8CF +:10F4C0004100032818BF02282BD19DF81000002806 +:10F4D00027D09DF80C00002823D1F7B1012000F0BF +:10F4E000A8FB00281DD020787F2808BFFFDF94F9F3 +:10F4F00000102670606890F85420CDE90021029534 +:10F5000090F8733090F8802000F13201FE2005F071 +:10F5100089FE606880F86C506EE0FE210020FFF7E5 +:10F52000CAF96DE0F9F796F9A0681821C27812F0CF +:10F530003F0F65D00279914362D10421FEF7C6FCEA +:10F54000616891F84020032A01BF8078B7EB501F13 +:10F5500091F86000002853D04FF0010000F069FBE3 +:10F56000E8B320787F2808BFFFDF94F900102670E9 +:10F57000606890F85420CDE90021029590F873302E +:10F5800090F8802000F13201FF2005F04BFE60680A +:10F5900080F86C8030E000BFF9F75CF9606890F8A3 +:10F5A000400003282CD0A0681821C27812F03F0F29 +:10F5B00026D0007931EA000022D1012000F039FB89 +:10F5C00068B120787F2808BFFFDF94F9001026700B +:10F5D000606890F85420CDE90021029500E00FE02A +:10F5E00090F8733090F8802000F13201FF2005F090 +:10F5F00019FE606880F86C7007B00320BDE8F083E6 +:10F6000007B00620BDE8F083F0B5FE4C074683B096 +:10F6100060686D460078002818BFFFDF002661682B +:10F620008E70C86B02888A8042884A8382888A8367 +:10F63000C088C88381F8206047B10121A068FEF727 +:10F6400045FC0546A0680078C10907E06946A06846 +:10F65000FEF7B5FBA0680078C0F380116068012751 +:10F6600090F85120002A18BF002904D06A7902F0CE +:10F67000C002402A26D090F84A20002A18BF00294C +:10F6800003D0697911F0C00F1CD000F10E00E3F730 +:10F69000B3FC616891F85400FF2819D001F1080209 +:10F6A000C91DFEF743F9002808BFFFDF6068C17974 +:10F6B00041F00201C171D0F86D104161B0F87110D4 +:10F6C00001830FE02968C0F80E10A9884182E0E7A5 +:10F6D000C86B427ECA71D0F81A208A60C08B8881BC +:10F6E0004E610E8360680770C26B90F84B1082F811 +:10F6F0006710C06B0088F4F70AFDF4F7A3F903B0B4 +:10F70000F0BD2DE9F041BF4C0546002760684FF081 +:10F7100001083E4690F84000012818BF022802D098 +:10F72000032818BFFFDF5DB1A068FEF727FC18B9FA +:10F73000A068FEF77AFC18B100F08FFB074645E0A1 +:10F74000606890F850007F25801F06283ED2DFE8D1 +:10F7500000F003191924352FAA48F9F709FA0028EF +:10F7600008BF2570F9F7EBF9606890F8520030B1E6 +:10F77000F9F7DAF9F8F7C9FA606880F85260F9F732 +:10F7800069F830E09F48F9F7F3F9002808BF2570C1 +:10F79000F9F7D5F905F0EAFEC3E09A48F9F7E8F978 +:10F7A000002808BF2570F9F7CAF9F9F753F81AE0ED +:10F7B0009448F9F7DDF930B9257004E09148F9F77C +:10F7C000D7F90028F8D0F9F7BAF9AAE0102F80F09D +:10F7D0003881DFE807F01E9DA6AAF1F108B3F2F127 +:10F7E000F1F10C832051BDE8F041FFF791B80320FF +:10F7F00002F020F9002870D000210320FFF710F953 +:10F80000012211461046F9F7D4F961680C2081F8FD +:10F810005000BDE8F081606800F15005042002F05E +:10F8200009F900287DD00E202870012002F0FDFC8F +:10F83000A06861680078C0F3401081F8750000216D +:10F840000520FFF7EDF87048A1684FF0200CC26B5F +:10F850000B78527B23F020030CEA42121A430A7001 +:10F86000C16B95F825304A7B1A404A73C06B28213A +:10F8700080F86610BDE8F081062002F0DBF8002871 +:10F880004FD0614D0F2085F85000022002F0CDFCD2 +:10F890006068012190F880200846F9F78AF9A0688D +:10F8A00061680078C0F3401081F8750001210520DF +:10F8B000FFF7B6F8E86B80F80D80A068017821F0BA +:10F8C00020010170F9F75DFD002818BFFFDF282037 +:10F8D000E96B81F86600BDE8F08122E0052002F0C6 +:10F8E000A9F8F0B101210320FFF79AF8F9F749FDD3 +:10F8F000002818BFFFDF6068012190F880200846CB +:10F90000F9F757F961680D2081F85000BDE8F081E2 +:10F910006068A0F8816080F8836080F85080BDE85E +:10F92000F081BDE8F04100F061B96168032081F821 +:10F930005000BDE8F041082002F077BC606890F804 +:10F940008310490908BF012507D0012908BF0225F6 +:10F9500003D0022914BF00250825C06D00281CBF54 +:10F96000002000F09BF96068806DF9F747F8606847 +:10F9700090F84010022906D0032904BF90F86C10BB +:10F98000012904D010E090F86C1002290CD12A460D +:10F9900015F00C0F04D090F84C00012808BF042289 +:10F9A00001210020F9F705F96068072180F88050EF +:10F9B00080F8616041E000E043E0606890F8831007 +:10F9C000490908BF012507D0012908BF022503D036 +:10F9D000022914BF00250825C06D00281CBF002087 +:10F9E00000F05CF96068806DF9F708F8606890F8DD +:10F9F000401002290AD0032904BF90F86C10012995 +:10FA000008D014E0740100204411002090F86C101C +:10FA100002290CD12A4615F00C0F04D090F84C00A6 +:10FA2000012808BF042201210020F9F7C2F860680C +:10FA3000082180F8805080F8616080F85010BDE89F +:10FA4000F081FFDFBDE8F08170B5FE4C606890F892 +:10FA5000503000210C2B38D001220D2B40D00E2B22 +:10FA600055D00F2B1CBFFFDF70BD042002F0DDFB63 +:10FA7000606890F880100E20F8F7E3FB606890F85B +:10FA8000800010F00C0F14BF282100219620F8F7F9 +:10FA9000D3FFF9F75EF86068052190F88050A06800 +:10FAA000FEF727F8616881F8520048B115F00C0F95 +:10FAB0000CBF50255525F8F714F92846F9F72AF810 +:10FAC00061680B2081F8500070BDF9F742F8002101 +:10FAD0009620F8F7B1FF6168092081F8500070BDE9 +:10FAE00090F88010FF20F8F7ACFB606890F8800079 +:10FAF00010F00C0F14BF282100219620F8F79CFF6E +:10FB0000F9F727F861680A2081F8500070BDA0F865 +:10FB1000811080F8831080F850200020FFF774FDDA +:10FB2000BDE87040032002F080BB70B5C54C606832 +:10FB300090F850007F25801F062828BF70BDDFE8A1 +:10FB400000F0171F1D032A11BE48F9F711F800280D +:10FB500008BF2570F8F7F3FFF8F77CFEBDE87040AA +:10FB6000FEF7D6BEB748F9F703F8C8B9257017E015 +:10FB7000B448F8F7FDFF40B9257006E005F0F6FC43 +:10FB8000B048F8F7F5FF0028F6D0F8F7D8FFBDE841 +:10FB9000704000F02BB8AB48F8F7EAFF0028E5D03A +:10FBA000F8F7CDFF60680021643005F037FEBDE84E +:10FBB000704000F01BB870B5A24C06460D460129F6 +:10FBC00008D0606890F880203046BDE87040134649 +:10FBD00002F077BBF8F75CFA61680346304691F8AB +:10FBE00080202946BDE8704002F06BBB70B5F8F785 +:10FBF00085FFF8F764FFF8F72DFEF8F7D9FE914C72 +:10FC00000025606890F8520030B1F8F78DFFF8F7E2 +:10FC10007CF8606880F852506068022180F85010CB +:10FC2000A0F8815080F88350BDE87040002002F0B9 +:10FC3000FCBA70B5834D06460421A868FEF746F964 +:10FC4000044605F0C8FA002808BF70BD207800F00F +:10FC50003F00252814D2F8F761FA217811F0800FBF +:10FC60000CBF1E214FF49671B4F80120C2F30C02B0 +:10FC700012FB01F10A1AB2F5877F28BF814201D237 +:10FC8000002070BD68682188A0F88110A17880F8F4 +:10FC900083103046BDE8704001F0CCBE2DE9F04144 +:10FCA000684C0746606800F1810690F883004009BF +:10FCB00008BF012507D0012808BF022503D002286C +:10FCC00014BF00250825F8F78DFE307800F03F06B8 +:10FCD0003046F8F7DFFB606880F8736090F86C00DE +:10FCE00002280CBF4020FF202946F8F7AAFA27B1C6 +:10FCF00029460120F8F795FC05E060682A46C16DA9 +:10FD00000120F8F7E2FCF8F724FF0521A068FDF7D1 +:10FD1000F0FE6168002881F8520008BFBDE8F0815C +:10FD200015F00C0F0CBF50245524F7F7DAFF2046CE +:10FD3000BDE8F041F8F7EEBE2DE9F74F414C002544 +:10FD4000914660688A4690F8510000280CBF4FF039 +:10FD500001084FF00008A0680178CE090121FEF7E4 +:10FD6000B5F836B1407900F0C000402808BF012640 +:10FD700000D00026606890F85210002961D090F8F9 +:10FD800040104FF0000B032906D190F839100029DC +:10FD900018BF90F856700ED1A068C17811F03F0FCF +:10FDA0001CBF007910F0010F02D105F061F940B3DA +:10FDB000606890F85370FF2F18BF082F21D0384685 +:10FDC000FDF7D9FB002818BF4FF00108002E38D0EE +:10FDD000606890F8620030B1FDF7F1FD054660689B +:10FDE00080F862B02DE03846FDF791FD054601210F +:10FDF000A068FEF76BF801462846F9F7D3FB0546E5 +:10FE00001FE0F6B1606890F86100D0B9A068C178D1 +:10FE100011F03F0F05D0017911F0010F18BF0B2130 +:10FE200000D105210022FDF7A4FD616881F8520090 +:10FE300038B1FDF7B9FDFF2803D06168012581F8CD +:10FE4000530001E0740100208AF800500098067009 +:10FE500089F8008003B0BDE8F08F2DE9F04FFF4C2A +:10FE600087B00025606890F850002E46801F4FF044 +:10FE70007F08062880F0D581DFE800F00308088BB2 +:10FE8000FDDB00F0F8FB054600F0CCB9F348F8F7CD +:10FE90006FFE002808BF84F80080F8F750FEA068C5 +:10FEA000FDF782FF0546072861D1A068FEF75AF9E1 +:10FEB0000146606890F86C208A4258D190F8501042 +:10FEC000062908BF002005D090F8500008280CBF74 +:10FED0000220012005F08AF970B90321A068FDF71E +:10FEE000F5FF002843D001884078C1F30B010009D9 +:10FEF00005F07BFC00283AD000212846FFF7A1F945 +:10FF0000A0B38DF80C608DF808608DF8046062680D +:10FF1000FF2592F8500008280CBF02210121A0689B +:10FF2000C37813F03F0F1CBF007910F0020F12D0FE +:10FF300092F8800005F0D4F868B901AA03A902A8D4 +:10FF4000FFF7FAFE606890F831509DF80C00002829 +:10FF500018BF45F002052B469DF804209DF80810B7 +:10FF60009DF80C0000F0D5F9054603E0FFE705F029 +:10FF7000FDFA0225606890F85200002800F05281D6 +:10FF8000F8F7D2FDF7F7C1FE606880F8526000F024 +:10FF900049B9A068FDF708FF0646A1686068CA78FD +:10FFA00090F86D309A4221D10A7990F86E309A42D9 +:10FFB0001CD14A7990F86F309A4217D18A7990F81B +:10FFC00070309A4212D1CA7990F871309A420DD1AC +:10FFD0000A7A90F872309A4208D1097890F8740041 +:10FFE000C1F38011814208BF012500D00025F8F738 +:10FFF00031FC9A48F8F7BCFD002808BF84F800805F +:020000040002F8 +:10000000F8F79DFD042E11D185B120787F2808BF17 +:10001000FFDF94F9003084F80080606890F8732066 +:1000200090F87D1090F8540005F06EFB062500F066 +:10003000F9B802278948F8F79BFD002808BF84F823 +:100040000080F8F77CFDA068FDF7AEFE0546A068CD +:10005000FEF788F8082D08BF00287CD1A0684FF073 +:100060000301C27812F03F0F75D0007931EA000029 +:1000700071D1606800E095E000F1500890F8390017 +:10008000002814BF98F8066098F803604FF0000944 +:1000900098F8020078B1FDF787FC0546FF280AD0E2 +:1000A0000146A068401DFDF758FCB5420CBF4FF05B +:1000B00001094FF000090021A068FDF707FF0622A3 +:1000C00008F11D01EEF78CF940B9A068FDF795FE27 +:1000D00098F82410884208BF012000D0002059EA77 +:1000E00000095DD0606800F1320590F831A098F801 +:1000F000010038B13046FDF74BFD00281CBF054616 +:100100004FF0010A4FF00008A06801784FEAD11BB8 +:100110000121FDF7DBFEBBF1000F07D0407900F0B5 +:10012000C000402808BF4FF0010B01D04FF0000B7A +:100130000121A068FDF7CAFE06222946EEF750F914 +:1001400030B9A068FDF766FE504508BF012501D013 +:100150004FF0000500E023E03BEA050018BFFF2E4A +:100160000DD03046FDF7D3FB060008D00121A06872 +:10017000FDF7ACFE01463046F9F714FA804645EA31 +:10018000080019EA000F0BD060680121643005F007 +:1001900045FB01273846FFF737FA052002F045F8FE +:1001A0003D463FE002252D48F8F7E2FC002808BF55 +:1001B00084F80080F8F7C3FCA068FDF7F5FD06465B +:1001C000A068FDF7CFFF072E08BF00282AD1A0683E +:1001D0004FF00101C27812F03F0F23D00279914312 +:1001E00020D1616801F150060021FDF76FFE062263 +:1001F00006F11D01EEF7F4F8A0B9A068FDF7FDFDCA +:1002000096F8241088420DD160680121643005F011 +:1002100005FBFF21022000F009F8002818BF032584 +:1002200000E0FFDF07B02846BDE8F08F2DE9F0437E +:100230000A4C0F4601466068002683B090F87D2086 +:10024000002A35D090F8500008280CBF022501255F +:10025000A168C87810F03F0F02E000007401002090 +:10026000FD484FF000084FF07F0990F900001CBFD7 +:10027000097911F0100F22D07F2808BFFFDF94F911 +:10028000001084F80090606890F85420CDE90021B7 +:10029000029590F8733090F8802000F132013846D2 +:1002A00004F0C0FF05F0AAFA10B305F050F92CE0F5 +:1002B000002914BF0221012180F87D10C2E77F28A8 +:1002C00008BFFFDF94F9001084F80090606890F890 +:1002D0005420CDE90021029590F8733090F88020E9 +:1002E00000F13201384604F09DFF05F030F90CE0D2 +:1002F0000220FFF79EFC30B16068012680F86C8018 +:10030000F8F7A8FA01E005F031F903B03046BDE88E +:10031000F0832DE9F047D04C054684B09A46174645 +:100320000E46A068FDF71EFF4FF00109002800F0FF +:10033000CF804FF00208012808D0022800F00E817B +:1003400005F014F904B04046BDE8F087A068092123 +:10035000C27812F03F0F00F059810279914340F0CA +:100360005581616891F84010032906D012F0020F00 +:1003700008BFFF2118D05DB115E00021FDF7A6FDF3 +:1003800061680622C96B1A31EEF72AF848BB1EE0F5 +:10039000FDF740FD05460121A068FDF797FD2946C0 +:1003A000F7F7FFFF18B15146012000F051B960681E +:1003B00090F84100032818BF022840F02781002E42 +:1003C0001CBFFE21012040F0438100F01FB9A0684E +:1003D000FDF713FD6168C96B497E884208BF01269D +:1003E00000D00026A068C17811F03F0F05D0017938 +:1003F00011F0020F01D06DB338E0616891F842202E +:10040000012A01D096B11BE0D6B90021FDF75EFDAF +:1004100061680268C96BC1F81A208088C883A06827 +:10042000FDF7EBFC6168C96B487609E091F8530071 +:1004300091F85610884203D004B04046BDE8F087DA +:100440006068643005F02EFA002840D004B00F2018 +:10045000BDE8F08767B1FDF7DDFC05460121A06826 +:10046000FDF734FD2946F7F79CFF08B1012200E0B3 +:100470000022616891F84200012807D040B92EB9E6 +:1004800091F8533091F856108B4201D1012100E0D0 +:1004900000210A421BD0012808BF002E11D14FF0C5 +:1004A0000001A068FDF712FD61680268C96BC1F820 +:1004B0001A208088C883A068FDF79FFC6168C96B1B +:1004C00048766068643005F0EDF90028BED19DE003 +:1004D00060682F46554690F840104FF002080329F7 +:1004E000AAD0A168CA7812F03F0F1BBF097911F09A +:1004F000020F002201224FF0FF0A90F85010082945 +:100500000CBF0221012192B190F8800004F0E8FDB7 +:1005100068B95FB9A068FDF77DFC07460121A068B6 +:10052000FDF7D4FC3946F7F73CFF48B1AA465146DF +:100530000020FFF77BFE002818BF4FF003087BE781 +:10054000606890F84100032818BF02287FF474AF58 +:10055000002E18BF4FF0FE0AE9D16DE7616891F8EF +:100560004030032B52D0A0684FF0090CC27812F033 +:100570003F0F4BD002793CEA020C47D1022B06D048 +:1005800012F0020F08BFFF2161D0E5B35EE012F068 +:10059000020F4FF07F0801D04DB114E001F164006B +:1005A00005F080F980B320787F2842D013E067B34C +:1005B000FDF730FC05460121A068FDF787FC2946C0 +:1005C000F7F7EFFE08B36068643005F06BF9D8B157 +:1005D00020787F282DD094F9001084F8008060687E +:1005E00090F85420CDE90021CDF8089090F87330B0 +:1005F00090F8802000F13201504604F013FE0D20E7 +:1006000004B0BDE8F08716E000E001E00220F7E763 +:10061000606890F84100032818BF0228F6D1002E28 +:10062000F4D04FF0FE014FF00200FEF744F9022033 +:10063000E6E7FFDFCFE7FDF7EDFB05460121A06808 +:10064000FDF744FC2946F7F7ACFE38B151460220CD +:10065000FEF731F9DAE7000074010020606890F8D5 +:100660004100032818BF0228D0D1002E1CBFFE2154 +:100670000220EDD1CAE72DE9F84F4FF00008F74806 +:10068000F8F776FA7F27F54C002808BF2770F8F7AF +:1006900056FAA068FDF788FB81460121FEF7D1FDDF +:1006A000616891F88020012A14D0042A1CBF082A0E +:1006B000FFDF00F0D781606890F8520038B1F8F79A +:1006C00033FAF7F722FB6168002081F852004046B8 +:1006D000BDE8F88F0125E24EB9F1080F3AD2DFE804 +:1006E00009F03EC00439393914FC0546F8F7B2F870 +:1006F000002D72D0606890F84000012818BF0228D1 +:100700006BD120787F2869D122E018B391F840009E +:10071000022802D0012818D01CE020787F2808BFCA +:10072000FFDF94F90000277000906068FF2190F8C7 +:10073000733090F85420323004F02FFF61680020AD +:100740004FF00C0881F87D00B5E720787F2860D154 +:10075000FFDF5EE0F8F77EF84FF00608ABE74FF0FA +:100760000008002800F0508191F84000022836D09F +:1007700001284BD003289ED1A068CA6BC37892F899 +:100780001AC0634521D1037992F81BC063451CD17F +:10079000437992F81CC0634517D1837992F81DC044 +:1007A000634512D1C37992F81EC063450DD1037A17 +:1007B00092F81FC0634508D1037892F819C0C3F3BB +:1007C0008013634508BF012300D0002391F8421035 +:1007D00001292CD0C3B300F013B93FE019E0207811 +:1007E0007F2808BFFFDF94F9000027700090606841 +:1007F000FF2190F8733090F85420323004F0CDFE91 +:1008000060684FF00C0880F87D5054E720787F280E +:100810009ED094F90000277000906068FF2190F846 +:10082000733090F85420323004F0B7FE16E0002BFD +:100830007ED102F11A01FDF7C2FAA068FDF7DDFAD8 +:100840006168C96B4876DBE0FFE796F85600082838 +:1008500070D096F8531081426AD0D5E04FF0060868 +:1008600029E7054691F8510000280CBF4FF0010B15 +:100870004FF0000B4FF00008A06810F8092BD209C8 +:1008800007D0407900F0C000402808BF4FF0010AAF +:1008900001D04FF0000A91F84000032806D191F8EA +:1008A0003900002818BF91F8569001D191F8539063 +:1008B0004846FDF72CF80090D8B34846FCF75BFE9D +:1008C000002818BF4FF0010BBAF1000F37D0A06815 +:1008D000A14600F10901009800E0B6E0F8F762FED9 +:1008E0005FEA0008D9F8040090F8319018BF49F089 +:1008F0000209606890F84010032924D0F7F7AAFF96 +:10090000002DABD0F7F75DFD002808BFB8F1000F50 +:100910007DD020787F2808BFFFDF94F90000277082 +:1009200000906068494690F8733090F8542002E0D7 +:1009300066E004E068E0323004F02FFE8EE7606885 +:1009400090F83190D5E7A168C06BCA78837E9A424F +:100950001BD10A79C37E9A4217D14A79037F9A4202 +:1009600013D18A79437F9A420FD1CA79837F9A4201 +:100970000BD10A7AC37F9A4207D10978407EC1F32E +:100980008011814208BF012700D0002796F853004C +:10099000082806D096F85610884208BF4FF0010983 +:1009A00001D04FF00009B8F1000F05D1BBF1000FE5 +:1009B00004D0F7F706FD08B1012000E000204DB19A +:1009C00096F84210012903D021B957EA090101D054 +:1009D000012100E00021084216D0606890F8421022 +:1009E000012908BF002F0BD1C06B00F11A01A068CC +:1009F000FDF7E5F9A068FDF700FA6168C96B487674 +:100A00004FF00E0857E602E0F7F724FF26E760688C +:100A100090F84100032818BF02287FF41FAFBAF1F5 +:100A2000000F3FF41BAF20787F2808BFFFDF94F949 +:100A30000000277000906068FE2190F8733090F8F5 +:100A40005420323004F0A9FD08E791F8481000293D +:100A500018BF00283FF47EAE0BE0000074010020B8 +:100A600044110020B9F1070F7FF474AE00283FF461 +:100A700071AEFEF790FC80461DE60000D0F8001134 +:100A800049B1D0E941231A448B691A448A61D0E9FB +:100A90003F12D16003E0FE4AD0F8FC101162D0E9A9 +:100AA0003F1009B1086170470028FCD00021816126 +:100AB00070472DE9FF4F06460C46488883B040F248 +:100AC000E24148430190E08A002500FB01FA94F8D6 +:100AD0007C0090460D2822D00C2820D024281ED03F +:100AE00094F87D0024281AD000208346069818B177 +:100AF0000121204603F0C0F894F8641094F86500D2 +:100B0000009094F8F0200F464FF47A794AB1012A08 +:100B100061D0022A44D0032A5DD0FFDFB5E0012076 +:100B2000E3E7B8F1000F00D1FFDFD94814F8641FE4 +:100B3000243090F83400F0F7C4FC01902078F8F7E6 +:100B4000CFFB4D4600F2E730B0FBF5F1DFF8409304 +:100B5000D9F80C0001EB00082078F8F7C1FB01463A +:100B600014F86409022816D0012816D040F6340083 +:100B700008444AF2EF010844B0FBF5F10198D9F8B6 +:100B80001C20411A514402EB08000D18012084F882 +:100B9000F0002D1D78E02846EAE74FF4C860E7E74B +:100BA000DFF8EC92A8F10100D9F80810014300D158 +:100BB000FFDFB848B8F1000F016801EB0A0506D065 +:100BC000D9F8080000F22630A84200D9FFDF032040 +:100BD00084F8F00058E094F87C20019D242A05D088 +:100BE00094F87D30242B01D0252A3AD1B4F8702016 +:100BF000B4F81031D21A521C12B2002A31DB94F828 +:100C0000122172B3174694F8132102B110460090D6 +:100C1000022916D0012916D040F6340049F60852B0 +:100C20008118022F12D0012F12D040F63400104448 +:100C3000814210D9081A00F5FA70B0FBF9F00544AA +:100C40000FE04846EAE74FF4C860E7E74846EEE7BA +:100C50004FF4C860EBE7401A00F5FA70B0FBF9F00A +:100C60002D1AB8F1000F0FD0DFF82482D8F8080051 +:100C700018B9B8F8020000B1FFDFD8F8080000F298 +:100C80002630A84200D9FFDF05B9FFDF2946D4F896 +:100C9000F400F4F750FFC4F8F400B06000203070A6 +:100CA0004FF0010886F80480204603F040F8ABF1CD +:100CB0000101084202D186F8058005E094F8F000B1 +:100CC000012844D003207071606A3946009A01F00F +:100CD00042FBF060069830EA0B0035D029463046DA +:100CE000F0F7BAF987B2204603F021F8B8420FD8DE +:100CF000074686F8058005FB07F1D4F8F400F4F701 +:100D00001AFFB06029463046F0F7A6F9384487B29A +:100D10003946204602F0B0FFB068C4F8F400A06E77 +:100D2000002811D0B4F87000B4F89420801A01B2F1 +:100D3000002909DD34F86C0F0144491E91FBF0F1E4 +:100D400089B201FB0020208507B0BDE8F08F0220AA +:100D5000B9E72DE9F04106460C46012001F0DBFA27 +:100D6000C5B20B2001F0D7FAC0B2854200D0FFDF38 +:100D70000025082C7ED2DFE804F00461696965C6AD +:100D80008293304601F0DDFA0621F3F78FF8040074 +:100D900000D1FFDF304601F0D4FA2188884200D02C +:100DA000FFDF94F8F00000B9FFDF204602F00FFEED +:100DB000374E21460020B5607580F561FDF7E9FCEE +:100DC00000F19807606AB84217D994F86500F7F700 +:100DD0000BF9014694F864004FF47A72022828D087 +:100DE000012828D040F6340008444AF2473108442C +:100DF000B0FBF2F1606A0844C51B21460020356152 +:100E0000FDF7C7FC618840F2E24251439830081A6E +:100E1000A0F22630706194F8652094F86410606A3E +:100E200001F099FAA0F5CB70B061BDE8F041F5F79B +:100E300060BE1046D8E74FF4C860D5E7BDE8F04182 +:100E400002F02FBEBDE8F041F7F7D5BE304601F005 +:100E500078FA0621F3F72AF8040000D1FFDF3046C4 +:100E600001F06FFA2188884200D0FFDF01220021C3 +:100E7000204600E047E0BDE8F04101F089BAF7F70D +:100E800073FDF7F7B8FE02204FF0E02104E0000008 +:100E9000CC11002084010020C1F88002BDE8F0815F +:100EA000304601F04EFA0621F3F700F8040000D1B5 +:100EB000FFDF304601F045FA2188884200D0FFDF8D +:100EC00094F8F000042800D0FFDF84F8F05094F884 +:100ED000FA504FF6FF76202D00D3FFDFFA4820F8B6 +:100EE000156094F8FA00F5F720F900B9FFDF20202B +:100EF00084F8FA002046FFF7C1FDF4480078BDE809 +:100F0000F041E2F701B8FFDFC8E770B5EE4C00250D +:100F1000443C84F82850E07868B1E570FEF71EF98B +:100F20002078042803D0606AFFF7A8FD6562E748CF +:100F30000078E1F7E9FFBDE8704001F03ABA70B51A +:100F4000E14C0146443CE069F5F706FE6568A2788D +:100F500090FBF5F172B140F27122B5FBF2F292B260 +:100F6000A36B01FB02F6B34202D901FB123200E08F +:100F70000022A2634D43002800DAFFDF2946E06922 +:100F8000F4F7D9FDE06170BD2DE9F05FFEF736F9A9 +:100F90008246CD48683800F1240881684646D8F872 +:100FA0001800F4F7C8FD0146F069F5F7D5FD4FF0DC +:100FB0000009074686F835903C4640F28F254E469C +:100FC0001EE000BF0AEB06000079F7F70DF80146B6 +:100FD0004AF2B12001444FF47A70B1FBF0F008EB13 +:100FE0008602414692681044844207D3241A91F83D +:100FF0003500A4F28F24401C88F83500761CF6B228 +:1010000098F83600B042DDD8002C10DD98F8351085 +:10101000404608EB81018968A14208D24168C91B9A +:10102000B1F5247F00D30D466C4288F8359098F8CE +:101030003560C3460AEB060898F80400F6F7D4FFBB +:101040004AF2B12101444FF47A7AB1FBFAF298F8EE +:101050000410082909D0042909D0002013180429F4 +:101060000AD0082908D0252207E0082000E0022045 +:1010700000EB40002830F1E70F22521D4FF4A8701A +:10108000082914D0042915D0022916D04FF0080CD5 +:101090005FF0280012FB0C00184462190BEB86036A +:1010A00010449A68D84690420BD8791925E04FF041 +:1010B000400CEFE74FF0100CECE74FF0040C182059 +:1010C000E8E798F8352098F836604046B24210D2EA +:1010D000521C88F835203C1B986862198418084611 +:1010E000F6F782FF4AF2B1210144B1FBFAF001198F +:1010F00003E080F83590D8F80410D8F81C00BDE85B +:10110000F05FF4F718BD2DE9FE4F14460546FEF7D3 +:1011100075F8DFF8B4A10290AAF1440A50469AF893 +:1011200035604FF0000B0AEB86018968CAF83C1065 +:10113000F4B3044600780027042825D005283ED0C3 +:10114000FFDFA04639466069F4F7F5FC0746F5F77E +:101150000BF881463946D8F80440F5F7FDFC401EEF +:1011600090FBF4F0C14361433846F4F7E4FC0146D8 +:10117000C8F81C004846F5F7EFFC002800DDFFDF4B +:10118000012188F813108DE0D4F81490D4F804806D +:1011900001F07AF9070010D0387800B9FFDF7969DB +:1011A00078684A460844414601F05AF9074600E08B +:1011B0000BE04045C5D9FFDFC3E75F46C1E7606A82 +:1011C00001F004F940F6B837BBE7C1690AEB460005 +:1011D0000191408D10B35446DAF81400FFF7AFFECA +:1011E0006168E069F4F7A7FC074684F835B0019C14 +:1011F000D0462046DAF81410F5F7AEFC81463946A1 +:101200002046F5F7A9FCD8F804200146B9FBF2F016 +:10121000B1FBF2F1884242D0012041E0F4F7A4FF93 +:10122000FFF78DFEFFF7B0FE9AF83510DAF804905C +:101230000AEB81010746896800913946DAF81C00FB +:10124000F5F78AFC00248046484504DB98FBF9F456 +:1012500004FB09F41AE0002052469AF8351007E022 +:1012600002EB800304F28F249B68401C1C44C0B234 +:101270008142F5D851B10120F6F7B6FE4AF2B1210C +:1012800001444FF47A70B1FBF0F004440099A8EBEC +:1012900004000C1A00D5FFDFCAF83C40A7E7002085 +:1012A00088F813009AF802005446B8B13946E0694C +:1012B000F5F752FC0146A26B40F2712042438A428C +:1012C00006D2C4F83CB009E03412002080010020AE +:1012D000E06B511A884200D30846E063AF6085F89E +:1012E00000B001202871029F94F835003F1DC05DB9 +:1012F000F6F77AFE4AF23B5101444FF47A70B1FBA3 +:10130000F0F0E16BFE300844E8602078042808D152 +:1013100094F8350004EB4000408D0A2801D20320E8 +:1013200000E00220687104EB4600408DC0B1284601 +:101330006168EFF791FE82B20020761C0CE000BFDE +:1013400004EB4001B0424B8D13449BB24B8501D35B +:101350005B1C4B85401CC0B294F836108142EFD222 +:10136000A8686061A06194F8350004EB4001488DE5 +:10137000401C488594F83500C05D082803D0042837 +:1013800003D000210BE0082100E0022101EB410124 +:1013900028314FF4A872082804D0042802D002286B +:1013A00007D028220A44042805D0082803D0252184 +:1013B00002E01822F6E70F21491D08280CD0042866 +:1013C0000CD002280CD0082011FB0020E16B8842D1 +:1013D00008D20120BDE8FE8F4020F5E71020F3E79A +:1013E0000420F1E70020F5E770B5FE4C061D14F867 +:1013F000352F905DF6F7F8FD4FF47A7100F2E73083 +:10140000B0FBF1F0D4F8071045182078805DF6F7AE +:1014100073FE2178895D082903D0042903D00022B6 +:101420000BE0082200E0022202EB420228324FF4D5 +:10143000A873082904D0042902D0022907D0282340 +:101440001344042905D0082903D0252202E01823DB +:10145000F6E70F22521D08290AD004290AD00229D2 +:101460000AD0082112FB0131081A281A293070BD50 +:101470004021F7E71021F5E70421F3E72DE9FF41CB +:1014800007460C46012000F046FFC5B20B2000F0D5 +:1014900042FFC0B2854200D0FFDF20460126002572 +:1014A000D04C082869D2DFE800F004304646426894 +:1014B0006865667426746078002819D1FDF79EFE71 +:1014C000009594F835108DF808104188C90411D0A2 +:1014D000206C019003208DF80900C24824388560F3 +:1014E000C56125746846FDF768FB002800D0FFDF62 +:1014F000BDE8FF81FFF778FF0190E07C10B18DF827 +:101500000950EAE78DF80960E7E7607840B1207C90 +:1015100008B9FDF7F9FD6574BDE8FF41F4F72FBD8B +:10152000A674FDF739FC0028E2D0FFDFE0E7BDE854 +:10153000FF41F7F760BBFDF761FE4088C00407D0AC +:1015400001210320FDF75EFEA7480078E1F7DCFCEF +:10155000002239466846FFF7D6FD38B1694638465D +:1015600000F0EDFE0028C3D1FFDFC1E7E670FFF712 +:10157000CCFCBDE7BDE8FF41C7E4FFDFB8E7994910 +:1015800050B101228A704A6840F27123B2FBF3F233 +:1015900002EB0010886370470020887070472DE9C7 +:1015A000F05F894640F271218E4E48430025044683 +:1015B000706090462F46D0074AF2B12A4FF47A7BEA +:1015C0000FD0B9F800004843B0600120F6F70CFDD9 +:1015D00000EB0A01B1FBFBF0241AB7680125A4F265 +:1015E0008F245FEA087016D539F8151040F2712083 +:1015F000414306EB85080820C8F80810F6F7F4FC0C +:1016000000EB0A01B1FBFBF0241AD8F80800A4F2A1 +:101610008F2407446D1CA74219D9002D17D0391B00 +:10162000B1FBF5F0B268101AB1FBF5F205FB12122E +:10163000801AB060012008E0B1FBF5F306EB8002F0 +:101640009468E31A401CC0B29360A842F4D3BDE88A +:10165000F09F2DE9F041634C00262078042804D047 +:101660002078052801D00C2018E401206070607CEF +:10167000002538B1EFF3108010F0010F72B610D0D2 +:1016800001270FE0FDF7BAFD074694F82000F5F7B3 +:10169000B2F87888C00411D000210320FDF7B2FD14 +:1016A0000CE00027607C38B1A07C28B1FDF72CFD50 +:1016B0006574A574F4F763FC07B962B694F820006A +:1016C000F5F705FB94F8280030B184F8285020780D +:1016D000052800D0FFDF0C26657000F06AFE30465A +:1016E00012E4404810B5007808B1FFF7B2FF00F0EF +:1016F000D4FE3C4900202439086210BD10B53A4C94 +:1017000058B1012807D0FFDFA06841F66A0188427E +:1017100000D3FFDF10BD40F6C410A060F4E73249EB +:1017200008B508702F4900200870487081F828001B +:10173000C8700874487488742022486281F8202098 +:10174000243948704FF6FF7211F1680121F810201A +:10175000401CC0B22028F9D30020FFF7CFFFFFF7CD +:10176000C0FF1020ADF80000012269460420FFF7F9 +:1017700016FF08BD7FB51B4C05460E46207810B1FC +:101780000C2004B070BD95F8652095F86410686A67 +:1017900000F0C5FEC5F80401656295F8F00000B1DF +:1017A000FFDF104900202439C861052121706070D5 +:1017B00084F82800014604E004EB4102491C5085EE +:1017C000C9B294F836208A42F6D284F83500304601 +:1017D000FFF7D5FE0548F4F74DFC84F820002028DB +:1017E00007D105E0F0110020800100207D140200E7 +:1017F000FFDFF4F7B9FC606194F82010012268461D +:10180000FFF781FC00B9FFDF94F82000694600F083 +:1018100096FD00B9FFDF0020B3E7F94810B5007866 +:1018200008B1002010BD0620F2F7DAFA80F00100BE +:1018300010BDF8B5F24D0446287800B1FFDF002056 +:10184000009023780246DE0701466B4605D060888B +:10185000A188ADF80010012211462678760706D53A +:10186000E088248923F8114042F00802491C491EEF +:1018700085F836101946FFF792FE0020F8BD1FB517 +:1018800011B1112004B010BDDD4C217809B10C203C +:10189000F8E70022627004212170114605E000BFC4 +:1018A00004EB4103491C5A85C9B294F836308B4287 +:1018B000F6D284F83520FFF762FED248F4F7DAFB5F +:1018C00084F82000202800D1FFDF00F0DDFD10B1FA +:1018D000F4F74AFC05E0F4F747FC40F6B831F4F7BA +:1018E0002AF9606194F8201001226846FFF70BFC8A +:1018F00000B9FFDF94F82000694600F020FD00B930 +:10190000FFDF0020BEE770B5BD4C616A0160FFF7E4 +:10191000A0FE050002D1606AFFF7B0F80020606207 +:10192000284670BD7FB5B64C2178052901D00C2022 +:1019300027E7B3492439C860606A00B9FFDF606AED +:1019400090F8F00000B1FFDF606A90F8FA002028FC +:1019500000D0FFDFAC48F4F78DFB616A0546202814 +:1019600081F8FA000E8800D3FFDFA548443020F844 +:101970001560606A90F8FA00202800D1FFDF00238C +:1019800001226846616AFFF794F8606A694690F838 +:10199000FA0000F0D4FC00B9FFDF00206062F0E63E +:1019A000974924394870704710B540F2E24300FB74 +:1019B00003F4002000F0B3FD844201D9201A10BDC9 +:1019C000002010BD70B50D46064601460020FCF70C +:1019D000E0FE044696F86500F6F706FB014696F829 +:1019E00064004FF47A72022815D0012815D040F611 +:1019F000340008444AF247310844B0FBF2F17088E1 +:101A000040F271225043C1EB4000A0F22630A542C3 +:101A100006D2214605E01046EBE74FF4C860E8E740 +:101A20002946814204D2A54201D2204600E0284640 +:101A3000706270BD70B50546FDF7E0FB7049007837 +:101A400024398C689834072D30D2DFE805F004344F +:101A500034252C34340014214FF4A873042810D0FA +:101A60000822082809D02A2102280FD011FB0240A1 +:101A700000222823D118441819E0402211FB02400B +:101A8000F8E7102211FB02402E22F3E7042211FB9B +:101A9000024000221823EDE7282100F04BFC04440B +:101AA00004F5317403E004F5B07400E0FFDF54483E +:101AB000C06BA04201D9012070BD002070BD70B57F +:101AC0004F4C243C607870B1D4E904512846A26898 +:101AD000EFF7EDFA2061A84205D0A169401B084448 +:101AE000A061F5F706F82169A068884201D820783E +:101AF00008B1002070BD012070BD2DE9F04F0546F2 +:101B000085B016460F461C461846F6F7F5FA05EB63 +:101B100047014718204600F0F5FB4AF2C5714FF423 +:101B20007A7908444D46B0FBF5F0384400F160087E +:101B30003348761C24388068304404902046F6F7F9 +:101B4000DBFAA8EB0007204600F0DCFB0646204647 +:101B5000F6F74AFA301AB0FBF5F03A1A18252820A1 +:101B60004FF4C8764FF4BF774FF0020B082C30D0FB +:101B7000042C2BD00021022C2ED0082311F1280197 +:101B800003EB830C0CEB831319440A444FF0000A57 +:101B9000082C29D0042C22D00021022C29D0054663 +:101BA000082001F5B07100BF00EB0010284481420D +:101BB00032D2082C2AD0042C1ED00020022C28D08F +:101BC0000821283001EB0111084434E03946102384 +:101BD000D6E731464023D3E704231831D0E73D460A +:101BE00040F2EE311020DFE735464FF435614020FA +:101BF000DAE70420B431D7E738461021E2E70000E5 +:101C0000F01100207D140200530D020030464021E7 +:101C1000D8E704211830D5E7082C4FD0042C4AD03F +:101C20000021022C4DD0082311F12801C3EBC30081 +:101C300000EB4310084415182821204600F07AFBD9 +:101C400005EB4001082C42D0042C3DD00026022C8C +:101C50003FD0082016F1280600EB801006EB80002C +:101C60000E180120FA4D8DF804008DF800A08DF8B3 +:101C700005B0A86906F22A260499F3F75CFFCDE9BE +:101C800002062046F6F7B0F94AF23B510144B1FB97 +:101C9000F9F0301AFE38E8630298C5F84080A86170 +:101CA00095F82000694600F04AFB002800D1FFDFCC +:101CB00005B0BDE8F08F39461023B7E73146402321 +:101CC000B4E704231831B1E73E461020C4E74020B2 +:101CD000C2E704201836BFE72DE9FE4F06461C4632 +:101CE000174688464FF0010A1846F6F705FAD84D10 +:101CF000243DA9688A1907EB48011144471820467A +:101D000000F000FB4FF47A7BD84600F6FB00B0FBF6 +:101D1000F8F0384400F120092046F6F7EDF9A968FB +:101D20000246A9EB0100801B871A204600F0EAFA60 +:101D300005462046F6F758F9281AB0FBF8F03A1A8B +:101D4000182528204FF4C8774FF4BF78082C2DD0E1 +:101D5000042C28D00021022C2BD0082311F12801BB +:101D600003EB830C0CEB831319440A44082C28D092 +:101D7000042C21D00021022C28D00546082001F592 +:101D8000B07100BF00EB0010284481422AD2082C19 +:101D900022D0042C1DD00020022C20D00821283075 +:101DA00001EB01112CE041461023D9E739464023CD +:101DB000D6E704231831D3E7454640F2EE31102030 +:101DC000E0E73D464FF435614020DBE70420B431C5 +:101DD000D8E740461021E3E738464021E0E70421F8 +:101DE0001830DDE7082C48D0042C43D00020022C0A +:101DF00046D0082110F12800C1EBC10303EB4111CB +:101E0000084415182821204600F094FA05EB4001FB +:101E1000082C3BD0042C36D00027022C38D00820C8 +:101E200017F1280700EB801007EB80000C1804F571 +:101E300096740C98F6F7D8F84AF23B510144B1FB7E +:101E4000FBF0834DFE30A5F12407E96B06F1FE029D +:101E50000844B9680B191A44824224D93219114432 +:101E60000C1AFE342044B0F1807F37D2642C12D299 +:101E7000642011E040461021BEE738464021BBE710 +:101E800004211830B8E747461020CBE74020C9E7C7 +:101E900004201837C6E720460421F4F790FEE8B185 +:101EA000E86B2044E863E0F703FFB9682938314460 +:101EB0000844CDE9000995F835008DF808000220A6 +:101EC0008DF809006846FCF778FE00B1FFDFFCF7EB +:101ED00063FF00B1FFDF5046BDE8FE8F4FF0000A00 +:101EE000F9E71FB500F021FB594C607880B994F8F0 +:101EF000201000226846FFF706F938B194F8200058 +:101F0000694600F01CFA18B9FFDF01E00120E0701B +:101F1000F4F735F800206074A0741FBD2DE9F84F68 +:101F2000FDF76CF90646451CC07840090CD0012825 +:101F30000CD002280CD000202978824608064FF4E5 +:101F4000967407D41E2006E00120F5E70220F3E78F +:101F50000820F1E72046B5F80120C2F30C0212FB7D +:101F600000F7C80901D010B103E01E2401E0FFDF33 +:101F70000024F6F7D3F8A7EB00092878B77909EB26 +:101F80000408C0F3801010B120B1322504E04FF4F2 +:101F9000FA7501E0FFDF00250C2F00D3FFDF2D488D +:101FA0002D4A30F81700291801FB0821501CB1FBFD +:101FB000F0F5F6F76DF8F6F717F84FF47A7100F2CE +:101FC0007160B0FBF1F1A9EB0100471BA7F15900CB +:101FD000103FB0F5247F11D31D4E717829B9024608 +:101FE000534629462046FFF788FD00F09EFAF3F796 +:101FF000C6FF00207074B074BDE8F88F3078009090 +:102000005346224629463846FFF766FE0028F3D19C +:1020100001210220FDF7F6F8BDE8F84F61E710B5A1 +:102020000446012903D10A482438007830B104203D +:1020300084F8F000BDE81040F3F7A1BF00220121B1 +:10204000204600F0A5F934F8700F401C2080F1E71D +:10205000F0110020646302003F420F002DE9F041BF +:102060000746FDF7CBF8050000D1FFDF287810F018 +:102070000C0F01D0012100E00021F74C606A3030E4 +:10208000FCF7C7FA29783846EFF71BFAA4F12406C3 +:102090000146A069B26802446FB32878082803D0CB +:1020A000042803D000230BE0082300E0022303EB05 +:1020B000430328334FF4A877082804D0042802D01B +:1020C000022810D028273B4408280ED004280ED020 +:1020D00002280ED05FF00800C0EBC00707EB4010ED +:1020E0001844983009E01827EDE74020F4E7102065 +:1020F000F2E70420F0E74FF4FC701044471828780A +:102100003F1DF5F771FF014628784FF47A720228D7 +:102110001DD001281DD040F6340008444AF2EF01DA +:102120000844B0FBF2F03A1A606A40F2E241B0466D +:102130004788F0304F43316A81420DD03946206BD9 +:1021400000F08EF90646B84207D9FFDF05E01046D9 +:10215000E3E74FF4C860E0E70026C04880688642A5 +:1021600007D2616A40F271224888424306EB420678 +:1021700004E040F2E240B6FBF0F0616AC882606AB7 +:10218000297880F86410297880F865100521417558 +:10219000C08A6FF41C71484306EB400040F635419D +:1021A000C8F81C00B0EB410F00D3FFDFBDE8F081A1 +:1021B00010B5052937D2DFE801F00509030D31001C +:1021C000002100E00121BDE8104028E7032180F84C +:1021D000F01010BD0446408840F2E24148439F4958 +:1021E000091D0860D4F818010089E082D4F81801AC +:1021F00080796075D4F8180140896080D4F818019E +:102200008089A080D4F81801C089E0802046A16AA6 +:10221000FFF7D8FB022084F8F00010BD816ABDE80A +:102220001040FFF7CFBBFFDF10BD70B58A4C243CD8 +:102230000928A1683FD2DFE800F0050B0B15131544 +:1022400038380800BDE870404BE6BDE8704065E6F0 +:10225000022803D00020BDE87040FFE60120FAE725 +:10226000E16070BD032802D005281CD000E0E160C9 +:102270005FF0000600F059F9774D012085F828003D +:1022800085F83460686AA9690026C0F8F41080F8FF +:10229000F060E068FFF746FB00B1FFDFF3F76FFE89 +:1022A0006E74AE7470BD0126E4E76C480078BDE83A +:1022B0007040E0F729BEFFDF70BD674924394860F0 +:1022C000704770B5644D0446243DB1B14FF47A7641 +:1022D000012903D0022905D0FFDF70BD1846F5F7AC +:1022E000FCFE05E06888401C68801046F6F7F8FFA1 +:1022F00000F2E730B0FBF6F0201AA86070BD564837 +:1023000000787047082803D0042801D0F5F76CBE88 +:102310004EF628307047002804DB00F1E02090F8EA +:10232000000405E000F00F0000F1E02090F8140D2B +:102330004009704710F00C0000D008467047F4F7D1 +:102340003EB910B50446202800D3FFDF4248443090 +:1023500030F8140010BD70B505460C461046F5F770 +:1023600043FE4FF47A71022C0DD0012C0DD040F6B3 +:10237000340210444AF247321044B0FBF1F02844D2 +:1023800000F5CB7070BD0A46F3E74FF4C862F0E782 +:102390001FB513460A46044601466846FEF789FB08 +:1023A00094F8FA006946FFF7CAFF002800D1FFDF62 +:1023B0001FBD70B5284C0025257094F82000F3F758 +:1023C000B4FE00B9FFDF84F8205070BD2DE9F04164 +:1023D000050000D1FFDF204A0024243AD5F804612B +:1023E0002046631E116A08E08869B04203D3984210 +:1023F00001D203460C460846C9680029F4D104B945 +:1024000004460021C5F80041F035C4B1E068E5603C +:10241000E86000B105612E698846A96156B1B069CE +:1024200030B16F69B84200D2FFDFB069C01BA8614C +:10243000C6F81880084D5CB1207820B902E0E96048 +:102440001562E8E7FFDF6169606808442863ADE66C +:10245000C5F83080AAE60000F011002080010020BD +:1024600010B50C4601461046F4F776FB002806DA54 +:10247000211A491EB1FBF4F101FB040010BD90FBD1 +:10248000F4F101FB140010BD2E48016A002001E0A8 +:102490000846C9680029FBD170472DE9FE43294D44 +:1024A0000120287000264FF6FF7420E00621F1F786 +:1024B000FDFC070000D1FFDF97F8FA00F037F4F7D2 +:1024C00006FC07F80A6BA14617F8FA89B8F1200F45 +:1024D00000D3FFDF1B4A683222F8189097F8FA0001 +:1024E000F3F723FE00B9FFDF202087F8FA006946E2 +:1024F0000620F1F764FC50B1FFDF08E0029830B12C +:1025000090F8F01019B10088A042CFD104E06846DD +:10251000F1F733FC0028F1D02E70BDE8FE8310B532 +:10252000FFF719FF00F5C87010BD064800212430E0 +:1025300090F8352000EB4200418503480078E0F731 +:10254000E3BC0000CC11002080010020012804D051 +:10255000022805D0032808D105E0012907D004E0AE +:10256000022904D001E0042901D000207047012095 +:102570007047F748806890F8A21029B1B0F89E1013 +:10258000B0F8A020914215D290F8A61029B1B0F869 +:10259000A410B0F8A02091420CD2B0F89C20B0F862 +:1025A0009A108A4206D290F88020B0F898001AB1AA +:1025B000884203D3012070470628FBD200207047D1 +:1025C0002DE9F041E24D0746A86800F1700490F84B +:1025D000140130B9E27B002301212046EEF7D2FC42 +:1025E00010B1A08D401CA08501263D21AFB92878EF +:1025F000022808D001280AD06878C8B110F0140F5A +:1026000009D01E2039E0162037E026773EE0A86882 +:1026100090F8160131E0020701D56177F5E78107EF +:1026200001D02A2029E0800600D4FFDF232024E007 +:1026300094F8320028B1E08D411CE185218E88425A +:1026400013D294F8360028B1A08E411CA186218EA9 +:1026500088420AD2A18D608D814203D3AA6892F884 +:10266000142112B9228E914201D3222005E0217C4F +:1026700029B1218D814207D308206077C5E7208DDD +:10268000062801D33E20F8E7207FB0B10020207358 +:10269000607320740221A868FFF78AFDA86890F88B +:1026A000E410012904D1D0F81C110878401E0870EC +:1026B000E878BDE8F041E0F727BCA868BDE8F04144 +:1026C0000021FFF775BDA2490C28896881F8E40054 +:1026D00014D0132812D0182810D0002211280ED0A0 +:1026E00007280BD015280AD0012807D0002805D0CC +:1026F000022803D021F89E2F012008717047A1F80D +:10270000A420704710B5924CA1680A88A1F86021F6 +:1027100081F85E0191F8640001F046FBA16881F840 +:10272000620191F8650001F03FFBA16881F8630147 +:10273000012081F85C01002081F82E01E078BDE8DD +:102740001040E0F7E1BB70B5814C00231946A0684A +:1027500090F87C207030EEF715FC00283DD0A06882 +:1027600090F820110025C9B3A1690978B1BB90F890 +:102770007D00EEF7EFFB88BBA168B1F870000A2876 +:102780002DD905220831E069EBF72AFE10B3A068C5 +:10279000D0F81C11087858B10522491CE069EBF704 +:1027A0001FFE002819D1A068D0F81C01007840B99C +:1027B000A068E169D0F81C010A68C0F80120097915 +:1027C0004171A068D0F81C110878401C08700120E5 +:1027D000FFF779FFA06880F8205170BDFFE7A0687F +:1027E00090F8241111B190F82511C1B390F82E1171 +:1027F0000029F2D090F82F110029EED190F87D0039 +:10280000EEF7A8FB0028E8D1A06890F8640001F07A +:10281000CBFA0646A06890F8650001F0C5FA0546B7 +:10282000A06890F830113046FFF790FEA0B3A06882 +:1028300090F831112846FFF789FE68B3A268B2F814 +:10284000703092F86410B2F8320102F58872EEF737 +:1028500001FE20B3A168252081F87C00BDE7FFE7D9 +:1028600090F87D10242918D090F87C10242914D0D9 +:102870005FF0000300F5897200F59271FBF78EFEA0 +:10288000A16881F8245101F13000C28A21F8E62FB5 +:10289000408B4880142007E005E00123EAE7BDE80B +:1028A000704000202EE71620BDE870400BE710B501 +:1028B000F4F7FAFD0C2813D3254C0821A068D0F8B2 +:1028C00018011E30F4F7F4FD28B1A0680421D830B7 +:1028D000F4F7EEFD00B9FFDFBDE810400320F2E69B +:1028E00010BD10B51A4CA068D0F818110A78002A4B +:1028F0001FD04988028891421BD190F87C20002388 +:1029000019467030EEF73EFB002812D0A068D0F8D0 +:1029100018110978022907D003290BD0042919D0EE +:10292000052906D108200DE090F87D00EEF712FB96 +:1029300040B110BD90F8811039B190F8820000B913 +:10294000FFDF0A20BDE81040BDE6BDE81040AEE75D +:102950008C01002090F8AA008007EAD10C20FFF734 +:10296000B2FEA068002120F89E1F01210171017BA9 +:1029700041F00101017310BD70B5F74CA268556EAE +:10298000EEF702FDEBB2C1B200228B4203D0A36886 +:1029900083F8121102E0A16881F81221C5F3072122 +:1029A000C0F30720814203D0A16881F8130114E726 +:1029B000A06880F8132110E710B5E74C0421A06847 +:1029C000FFF7F6FBA06890F85A10012908D000F52F +:1029D0009E71FBF7ACFEE078BDE81040E0F794BADA +:1029E000022180F85A1010BD70B5DB4CA06890F839 +:1029F000E410FE2955D16178002952D190F87F204A +:102A0000002301217030EEF7BDFA002849D1A068FB +:102A100090F8141109B1022037E090F87C200023CF +:102A200019467030EEF7AEFA28B1A06890F896001B +:102A300008B1122029E0A068002590F87C20122A15 +:102A40001DD004DC032A23D0112A04D119E0182A4E +:102A50001AD0232A26D0002304217030EEF792FAF0 +:102A600000281ED1A06890F87D10192971D020DCB3 +:102A700001292AD0022935D0032932D120E00B20A8 +:102A800003E0BDE8704012E70620BDE870401AE69A +:102A900010F8E21F01710720FFF715FEA06880F80B +:102AA0007C509AE61820FFF70EFEA068A0F89E5012 +:102AB00093E61D2918D01E2916D0212966D149E098 +:102AC00010F8E11F4171072070E00C20FFF7FBFDBB +:102AD000A06820F8A45F817941F00101817100F8BC +:102AE000275C53E013202CE090F8252182BB90F85E +:102AF0002421B2B1242912D090F87C1024290ED0C0 +:102B00005FF0000300F5897200F59271FBF746FD56 +:102B1000A0681E2180F87D1080F8245103E0012375 +:102B2000F0E71E2932D1A068FBF797FDFFF744FFBD +:102B3000A16801F13000C28A21F8E62F408B48805D +:102B40001520FFF7C0FDA068A0F8A45080F87D50C4 +:102B50001CE02AE090F8971051B180F8125180F8EB +:102B600013511820FFF7AFFDA068A0F8A4500DE0A6 +:102B700090F82F1151B990F82E1139B1C16DD0F8DC +:102B80003001FFF7F9FE1820FFF79DFDA06890F8CF +:102B9000E400FE2885D1FFF7A4FEA06890F8E400C9 +:102BA000FE2885D1BDE87040CDE51120FFF78BFDF3 +:102BB000A068CBE7684A0129926819D0002302294E +:102BC0000FD003291ED010B301282BD0032807D122 +:102BD00092F87C00132803D0162801D0182804D1BD +:102BE000704792F8E4000028FAD0D2F8180117E0F4 +:102BF00092F8E4000128F3D0D2F81C110878401EA6 +:102C00000870704792F8E4000328EED17047D2F8BC +:102C10001801B2F870108288891A09B20029F5DB10 +:102C200003707047B2F87000B2F82211401A00B277 +:102C30000028F6DBD2F81C010178491E01707047AC +:102C400070B5044690F87C0000250C2810D00D28A3 +:102C50002ED1D4F81811B4F870008988401C88422D +:102C600026D1D4F864013C4E017811B3FFDF42E075 +:102C7000B4F87000B4F82211401C884218D1D4F87E +:102C80001C01D0F80110A160407920730321204677 +:102C9000EDF7F1FDD4F81C01007800B9FFDF012148 +:102CA000FE20FFF787FF84F87C50012084F8B200F3 +:102CB00093E52188C180D4F81801D4F864114089C3 +:102CC0000881D4F81801D4F8641180894881D4F8B7 +:102CD0001801D4F86411C0898881D4F864010571A1 +:102CE000D4F8641109200870D4F864112088488051 +:102CF000F078E0F709F902212046EDF7BCFD032149 +:102D00002046FFF755FAB068D0F81801007802287D +:102D100000D0FFDF0221FE20FFF74CFF84F87C503B +:102D20005BE52DE9F0410C4C00260327D4F808C0E0 +:102D3000012598B12069C0788CF8E20005FA00F00E +:102D4000C0F3C05000B9FFDFA06800F87C7F468464 +:102D500080F82650BDE8F0818C01002000239CF80B +:102D60007D2019460CF17000EEF70CF970B1607817 +:102D70000028EFD12069C178A06880F8E11080F8C0 +:102D80007D70A0F8A46080F8A650E3E76570E1E7E5 +:102D9000F0B5F74C002385B0A068194690F87D2067 +:102DA0007030EEF7EFF8012580B1A06890F87C0054 +:102DB00023280ED024280CD06846F6F785FB68B18E +:102DC000009801A9C0788DF8040008E0657005B08E +:102DD000F0BD607840F020006070F8E70021A06846 +:102DE00003AB162290F87C00EEF74FFB002648B1AB +:102DF000A0689DF80C20162180F80C2180F80D1198 +:102E0000192136E02069FBF722FB78B121690879A6 +:102E100000F00702A06880F85C20497901F0070102 +:102E200080F85D1090F82F310BBB03E00020FFF716 +:102E300078FFCCE790F82E31CBB900F164035F78CE +:102E4000974205D11A788A4202D180F897500EE055 +:102E500000F5AC71028821F8022990F85C200A7113 +:102E600090F85D0048710D70E078E0F74DF8A068CB +:102E7000212180F87D1080F8A650A0F8A460A6E774 +:102E8000F8B5BB4C00231946A06890F87D2070303F +:102E9000EEF778F840B32069FBF7BEFA48B3206933 +:102EA000FBF7B4FA07462069FBF7B4FA0646206937 +:102EB000FBF7AAFA05462069FBF7AAFA0146009734 +:102EC000A06833462A463030FBF79BFBA1680125FA +:102ED00091F87C001C2810D091F85A00012812D0DB +:102EE00091F8250178B90BE0607840F0010060703E +:102EF000F8BDBDE8F840002013E781F85A5002E021 +:102F000091F8240118B11E2081F87D000BE01D20EE +:102F100081F87D0001F5A57231F8300BFBF7FBFB62 +:102F2000E078DFF7F1FFA068002120F8A41F85708A +:102F3000F8BD10B58E4C00230921A06890F87C20C4 +:102F40007030EEF71FF848B16078002805D1A1680D +:102F500001F8960F087301F81A0C10BD012060707B +:102F600010BD7CB5824C00230721A06890F87C201E +:102F70007030EEF707F838B36078002826D169463C +:102F80002069FBF75FFA9DF80000002500F025019D +:102F9000A06880F8B0109DF8011001F0490180F898 +:102FA000B11080F8A250D0F81811008849888142E9 +:102FB00000D0FFDFA068D0F818110D70D0F86411B0 +:102FC0000A7822B1FFDF16E0012060707CBD30F886 +:102FD000E82BCA80C16F0D71C16F009A8A60019A97 +:102FE000CA60C26F0821117030F8E81CC06F4180C0 +:102FF000E078DFF789FFA06880F87C507CBD70B571 +:103000005B4C00231946A06890F87D207030EDF7E6 +:10301000B9FF012540B9A0680023082190F87C2061 +:103020007030EDF7AFFF10B36078002820D1A068B2 +:1030300090F8AA00800712D42069FBF7C9F9A168AB +:1030400081F8AB00206930F8052FA1F8AC2040884A +:10305000A1F8AE0011F8AA0F40F002000870A068B5 +:103060004FF0000690F8AA10C90702D011E0657071 +:103070009DE490F87D20002319467030EDF782FF23 +:1030800000B9FFDFA06880F87D5080F8A650A0F856 +:10309000A460A06890F87C10012906D180F87C60BB +:1030A00080F8A260E078DFF72FFFA168D1F818015F +:1030B000098842888A42DBD101780429D8D1067078 +:1030C000E078DFF721FFA06890F87C100029CFD1CD +:1030D00080F8A2606BE470B5254DA86890F87C106C +:1030E0001A2902D00220687061E469780029FBD1B6 +:1030F000002480F8A74080F8A240D0F8181100887A +:103100004988814200D0FFDFA868D0F818110C7000 +:10311000D0F864110A780AB1FFDF25E090F8A82002 +:1031200072B180F8A8400288CA80D0F864110C718E +:10313000D0F864210E2111700188D0F864010DE0EF +:1031400030F8E82BCA80C16F0C71C26F0121117277 +:10315000C26F0D21117030F8E81CC06F418000F083 +:10316000A1FEE878DFF7D0FEA86880F87C401EE476 +:103170008C01002070B5FA4CA16891F87C20162AC9 +:1031800001D0132A02D191F8A82012B10220607058 +:103190000DE46278002AFBD181F8E000002581F877 +:1031A000A75081F8A250D1F81801098840888842B8 +:1031B00000D0FFDFA068D0F818010078032800D005 +:1031C000FFDF0321FE20FFF7F5FCA068D0F86411B3 +:1031D0000A780AB1FFDF14E030F8E02BCA8010F85B +:1031E000081BC26F1171C16F0D72C26F0D2111707A +:1031F00030F8E81CC06F418000F054FEE078DFF743 +:1032000083FEA06880F87C504BE470B5D44C092153 +:103210000023A06890F87C207030EDF7B3FE002505 +:1032200018B12069007912281ED0A0680A21002355 +:1032300090F87C207030EDF7A5FE18B12069007978 +:10324000142814D02069007916281AD1A06890F8A3 +:103250007C101F2915D180F87C5080F8A250BDE861 +:1032600070401A20FFF74EBABDE8704061E6A068D2 +:1032700000F87C5F458480F82650BDE87040FFF779 +:103280009BBB0EE470B5B64C2079C00773D02069A3 +:1032900000230521C578A06890F87C207030EDF7F8 +:1032A00071FE98B1062D11D006DC022D0ED0042D32 +:1032B0000CD0052D06D109E00B2D07D00D2D05D022 +:1032C000112D03D0607840F008006070607800280D +:1032D00051D12069FAF7E0FF00287ED0206900254F +:1032E0000226C178891E162977D2DFE801F00B7615 +:1032F00034374722764D76254A457676763A5350CE +:103300006A6D7073A0680023012190F87F207030EF +:10331000EDF738FE08BB2069FBF722F8A16881F8B9 +:103320001601072081F87F0081F8A65081F8A2508D +:1033300056E0FFF76AFF53E0A06890F87C100F2971 +:1033400001D066704CE0617839B980F88150122163 +:1033500080F87C1044E000F0D0FD41E000F0ACFDCE +:103360003EE0FBF7A9F803283AD12069FBF7A8F85B +:10337000FFF700FF34E03BE00079F9E7FFF7ABFE31 +:103380002EE0FFF73CFE2BE0FFF7EBFD28E0FFF718 +:10339000D0FD25E0A0680023194690F87D2070300C +:1033A000EDF7F0FD012110B16078C8B901E061705E +:1033B00016E0A06820F8A45F817000F8276C0FE089 +:1033C0000BE0FFF75DFD0BE000F034FD08E0FFF7D8 +:1033D000DFFC05E000F0FAFC02E00020FFF7A1FCB2 +:1033E000A268F2E93001401C41F10001C2E900018C +:1033F0005EE42DE9F0415A4C2079800741D5607890 +:1034000000283ED1E06801270026C178204619290E +:10341000856805F170006FD2DFE801F04B3E0D6F5B +:10342000C1C1801C34C1556287C1C1C1C1BE8B9569 +:1034300098A4B0C1BA0095F87F2000230121EDF7D0 +:10344000A1FD00281DD1A068082180F87F1080F818 +:10345000A26090E0002395F87D201946EDF792FDDB +:1034600010B1A06880F8A660A0680023194690F803 +:103470007C207030EDF786FD002802D0A06880F82F +:10348000A26067E4002395F87C201946EDF77AFDE9 +:1034900000B9FFDF042008E0002395F87C201946DE +:1034A000EDF770FD00B9FFDF0C20A16881F87C000A +:1034B00050E4002395F87C201946EDF763FD00B930 +:1034C000FFDF0D20F1E7002395F87C201946EDF78A +:1034D00059FD00B9FFDFA0680F2180F8A77008E050 +:1034E00095F87C00122800D0FFDFA068112180F839 +:1034F000A87080F87C102DE451E0002395F87C2022 +:103500001946EDF73FFD20B9A06890F8A80000B972 +:10351000FFDFA068132180F8A770EAE795F87C0028 +:10352000182800D0FFDF1A20BFE7BDE8F04100F007 +:1035300063BD002395F87C201946EDF723FD00B903 +:10354000FFDF0520B1E785F8A66003E4002395F8C6 +:103550007C201946EDF716FD00B9FFDF1C20A4E71B +:103560008C010020002395F87D201946EDF70AFD17 +:1035700000B9FFDFA06880F8A66006E4002395F894 +:103580007C201946EDF7FEFC00B9FFDF1F208CE719 +:10359000BDE8F04100F0F8BC85F87D60D3E7FFDFBF +:1035A0006FE710B5F74C6078002837D120794007D5 +:1035B0000FD5A06890F87C00032800D1FFDFA06839 +:1035C00090F87F10072904D101212170002180F893 +:1035D0007F10FFF70EFF00F0B5FCFFF753FEA07859 +:1035E000000716D5A0680023052190F87C207030D4 +:1035F000EDF7C8FC50B108206070A068D0F86411E5 +:1036000008780D2800D10020087002E00020F9F7AA +:10361000F9FCA068BDE81040FFF712BB10BD2DE912 +:10362000F041D84C07464FF00005607808436070C1 +:10363000207981062046806802D5A0F8985004E0E1 +:10364000B0F89810491CA0F8981000F018FD012659 +:10365000F8B1A088000506D5A06890F8821011B1D5 +:10366000A0F88E5015E0A068B0F88E10491CA0F8A4 +:103670008E1000F0F3FCA068B0F88E10B0F8902027 +:10368000914206D3A0F88E5080F83A61E078DFF7D7 +:103690003BFC207910F0600F08D0A06890F88010F3 +:1036A00021B980F880600121FEF782FD1FB9FFF784 +:1036B00078FFFFF799F93846FEF782FFBDE8F04141 +:1036C000F5F711BFAF4A51789378194313D11146DA +:1036D0000128896808D01079400703D591F87F0048 +:1036E000072808D001207047B1F84C00098E8842A5 +:1036F00001D8FEF7E4B900207047A249C278896872 +:10370000012A06D05AB1182A08D1B1F81011FAF7D7 +:10371000BABEB1F822114172090A81727047D1F81C +:10372000181189884173090A8173704770B5954CE7 +:1037300005460E46A0882843A080A80703D5E807C1 +:1037400000D0FFDFE660E80700D02661A80719D5A2 +:10375000F078062802D00B2814D10BE0A06890F86E +:103760007C1018290ED10021E0E93011012100F868 +:103770003E1C07E0A06890F87C10122902D10021BD +:1037800080F88210280601D50820A07068050AD5A7 +:10379000A0688288B0F87010304600F07FFC304698 +:1037A000BDE87040A9E763E43EB505466846F5F715 +:1037B00065FE00B9FFDF222200210098EAF767FECC +:1037C00003210098FAF750FD0098017821F01001CC +:1037D00001702946FAF76DFD6A4C192D71D2DFE8A8 +:1037E00005F020180D3EC8C8C91266C8C9C959C815 +:1037F000C8C8C8BBC9C971718AC89300A1680098BC +:1038000091F8151103E0A168009891F8E610017194 +:10381000B0E0A068D0F81C110098491CFAF795FD9B +:10382000A8E0A1680098D1F8182192790271D1F826 +:10383000182112894271120A8271D1F81821528915 +:10384000C271120A0272D1F8182192894272120AC8 +:103850008272D1F81811C989FAF74EFD8AE0A06882 +:10386000D0F818110098091DFAF77CFDA068D0F86F +:10387000181100980C31FAF77FFDA068D0F81811E4 +:1038800000981E31FAF77EFDA1680098D831FAF74A +:1038900087FD6FE06269009811780171918841712C +:1038A000090A81715188C171090A017262E03649C1 +:1038B000D1E90001CDE9010101A90098FAF78AFDDB +:1038C00058E056E0A068B0F844100098FAF794FD6C +:1038D000A068B0F8E6100098FAF792FDA068B0F87A +:1038E00048100098FAF780FDA068B0F8E81000983A +:1038F000FAF77EFD3EE0A168009891F83021027150 +:1039000091F83111417135E0A06890F81301EDF79D +:1039100032FD01460098FAF7B2FDA06890F8120156 +:1039200000F03DFA70B1A06890F8640000F037FA3A +:1039300040B1A06890F8121190F86400814201D063 +:10394000002002E0A06890F81201EDF714FD014696 +:103950000098FAF790FD0DE0A06890F80D1100981E +:10396000FAF7A8FDA06890F80C110098FAF7A6FDE8 +:1039700000E0FFDFF5F795FD00B9FFDF0098FFF7E6 +:10398000BCFE3EBD8C0100207C63020010B5F94CEA +:10399000A06890F8121109B990F8641080F86410CA +:1039A00090F8131109B990F8651080F8651000209F +:1039B000FEF7A8FEA068FAF750FE002806D0A0681F +:1039C000BDE8104000F59E71FAF7B1BE10BDF8B524 +:1039D000E84E00250446B060B5807570B57035704E +:1039E0000088F5F748FDB0680088F5F76AFDB4F87F +:1039F000F800B168401C82B201F17000EDF75BF88D +:103A000000B1FFDF94F87D00242809D1B4F87010CC +:103A1000B4F81001081A00B2002801DB707830B148 +:103A200094F87C0024280AD0252808D015E0FFF758 +:103A3000ADFF84F87D50B16881F897500DE0B4F87F +:103A40007010B4F81001081A00B2002805DB707875 +:103A500018B9FFF79BFF84F87C50A4F8F850FEF7E4 +:103A600088FD00281CD1B06890F8E400FE2801D041 +:103A7000FFF79AFEC0480090C04BC14A2146284635 +:103A8000F9F7ECF9B0680023052190F87C2070303C +:103A9000EDF778FA002803D0BDE8F840F8F771BFD9 +:103AA000F8BD10B5FEF765FD20B10020BDE810405F +:103AB0000146B4E5BDE81040F9F77FBA70B50C4691 +:103AC000154606464FF4B47200212046EAF7DFFCA3 +:103AD000268005B9FFDF2868C4F818016868C4F8B3 +:103AE0001C01A868C4F8640182E4F0F7E9BA2DE982 +:103AF000F0410D4607460621F0F7D8F9041E3DD0E7 +:103B0000D4F864110026087858B14A8821888A427E +:103B100007D109280FD00E2819D00D2826D0082843 +:103B20003ED094F83A01D0B36E701020287084F81B +:103B30003A61AF809AE06E7009202870D4F8640171 +:103B4000416869608168A9608089A88133E008467E +:103B5000F0F7DDFA0746EFF78AFF70B96E700E20B6 +:103B60002870D4F864014068686011E00846F0F7F6 +:103B7000CEFA0746EFF77BFF08B1002081E46E70B4 +:103B80000D202870D4F8640141686960008928819B +:103B9000D4F8640106703846EFF763FF66E00EE084 +:103BA0006E7008202870D4F86401416869608168EB +:103BB000A960C068E860D4F86401067056E094F823 +:103BC0003C0198B16E70152028700AE084F83C61C1 +:103BD000D4F83E016860D4F84201A860D4F84601E8 +:103BE000E86094F83C010028F0D13FE094F84A01E5 +:103BF00058B16E701C20287084F84A610A2204F5BE +:103C0000A671281DEAF719FC30E094F8560140B17E +:103C10006E701D20287084F85661D4F858016860D1 +:103C200024E094F8340168B16E701A20287004E022 +:103C300084F83461D4F83601686094F834010028BF +:103C4000F6D113E094F85C01002897D06E7016202E +:103C5000287007E084F85C61D4F85E016860B4F80D +:103C60006201288194F85C010028F3D1012008E466 +:103C7000404A5061D170704770B50D4604464EE021 +:103C8000B4F8F800401CA4F8F800B4F89800401C00 +:103C9000A4F89800204600F0F2F9B8B1B4F88E000C +:103CA000401CA4F88E00204600F0D8F9B4F88E002D +:103CB000B4F89010884209D30020A4F88E000120A7 +:103CC00084F83A012B48C078DFF71EF994F8A20077 +:103CD00020B1B4F89E00401CA4F89E0094F8A60001 +:103CE00020B1B4F8A400401CA4F8A40094F8140176 +:103CF00040B994F87F200023012104F17000EDF712 +:103D000041F920B1B4F89C00401CA4F89C00204666 +:103D1000FEF796FFB4F87000401CA4F870006D1E0A +:103D2000ADB2ADD23FE5134AC2E90601704770B5A6 +:103D30000446B0F8980094F88010D1B1B4F89A1005 +:103D40000D1A2D1F94F8960040B194F87C200023A2 +:103D5000092104F17000EDF715F9B8B1B4F88E60DF +:103D6000204600F08CF980B1B4F89000801B001F51 +:103D70000CE007E08C0100201F360200C53602006F +:103D80002D370200C0F10205DCE72846A84200DA20 +:103D90000546002D01DC002005E5A8B203E510F082 +:103DA0000C0000D00120704710B5012808D002286F +:103DB00008D0042808D0082806D0FFDF204610BD10 +:103DC0000124FBE70224F9E70324F7E770B5CC4CA4 +:103DD000A06890F87C001F2804D0607840F00100B3 +:103DE0006070E0E42069FAF73CFBD8B12069012259 +:103DF0000179407901F0070161F30705294600F0D8 +:103E0000070060F30F21A06880F8A2200022A0F82C +:103E10009E20232200F87C2FD0F8B400BDE870402B +:103E2000FEF7AABD0120FEF77CFFBDE870401E2012 +:103E3000FEF768BCF8B5B24C00230A21A06890F8E0 +:103E40007C207030EDF79EF838B32069FAF7E4FA79 +:103E5000C8B12069FAF7DAFA07462069FAF7DAFA00 +:103E600006462069FAF7D0FA05462069FAF7D0FA33 +:103E700001460097A06833462A463030FAF7C1FB66 +:103E8000A068FAF7EAFBA168002081F8A20081F897 +:103E90007C00BDE8F840FEF78FBD607840F001007F +:103EA0006070F8BD964810B580680088F0F72FF96B +:103EB000BDE81040EFF7C6BD10B5914CA36893F86C +:103EC0007C00162802D00220607010BD60780028A7 +:103ED000FBD1D3F81801002200F11E010E30C833C7 +:103EE000ECF7C2FFA0680021C0E92E11012180F883 +:103EF0008110182180F87C1010BD10B5804CA0688E +:103F000090F87C10132902D00220607010BD6178F7 +:103F10000029FBD1D0F8181100884988814200D0CF +:103F2000FFDFA068D0F8181120692631FAF745FAAA +:103F3000A1682069DC31FAF748FAA168162081F8F7 +:103F40007C0010BD10B56E4C207900071BD5607841 +:103F5000002818D1A068002190F8E400FEF72AFE9E +:103F6000A06890F8E400FE2800D1FFDFA068FE21E1 +:103F700080F8E41090F87F10082904D10221217004 +:103F8000002180F87F1010BD70B55D4D2421002404 +:103F9000A86890F87D20212A05D090F87C20232A5B +:103FA00018D0FFDFA0E590F8122112B990F8132184 +:103FB0002AB180F87D10A86880F8A64094E500F842 +:103FC0007D4F847690F8B1000028F4D00020FEF7F1 +:103FD00099FBF0E790F8122112B990F813212AB159 +:103FE00080F87C10A86880F8A2407DE580F87C40CD +:103FF0000020FEF787FBF5E770B5414C0025A0686F +:10400000D0F8181103884A889A4219D109780429EE +:1040100016D190F87C20002319467030ECF7B2FFDF +:1040200000B9FFDFA06890F8AA10890703D4012126 +:1040300080F87C1004E080F8A250D0F818010570D8 +:10404000A0680023194690F87D207030ECF79AFFA5 +:10405000002802D0A06880F8A65045E5B0F890206E +:10406000B0F88E108A4201D3511A00E000218288F4 +:10407000521D8A4202D3012180F89610704710B574 +:1040800090F8821041B990F87C200023062170300E +:10409000ECF778FF002800D0012010BD70B5114466 +:1040A000174D891D8CB2C078A968012806D040B18F +:1040B000182805D191F8120138B109E0A1F8224180 +:1040C00012E5D1F8180184800EE591F8131191B131 +:1040D000FFF765FE80B1A86890F86400FFF75FFE07 +:1040E00050B1A86890F8121190F86420914203D062 +:1040F00090F8130100B90024A868A0F81041F3E477 +:104100008C01002070B58F4C0829207A6CD2DFE832 +:1041100001F004176464276B6B6458B1F4F7D3F8AB +:10412000F5F7FFF80020A072F4F7B4F9BDE870408D +:10413000F4F758BCF5F717F9BDE87040F1F71FBF69 +:10414000DEF7B6FDF5F752F8D4E90001F1F7F3FC1C +:104150002060A07A401CC0B2A072282824D370BD71 +:10416000A07A0025401EC6B2E0683044F4F700FD96 +:1041700010B9E1687F208855A07A272828BF01253B +:10418000DEF796FDA17A01EB4102C2EB81110844F2 +:104190002946F5F755F8A07A282809D2401CC0B264 +:1041A000A072282828BF70BDBDE87040F4F772B92E +:1041B000207A002818BF00F086F8F4F74BFBF4F7DC +:1041C000F7FBF5F7D0F80120E0725F480078DEF7E2 +:1041D0009BFEBDE87040F1F7D2BE002808BF70BD5D +:1041E000BDE8704000F06FB8FFDF70BD10B5554CF2 +:1041F000207A002804BF0C2010BD00202072E0723D +:10420000607AF2F7F8FA607AF2F761FD607AF1F716 +:104210008CFF00280CBF1F20002010BD002270B5AD +:10422000484C06460D46207A68B12272E272607AE6 +:10423000F2F7E1FA607AF2F74AFD607AF1F775FF7A +:10424000002808BFFFDF4048E560067070BD70B50C +:10425000050007D0A5F5E8503C494C3881429CBF89 +:10426000122070BD374CE068002804BF092070BDE3 +:10427000207A00281CBF0C2070BD3548F1F7FAFEEB +:104280006072202804BF1F2070BDF1F76DFF206011 +:104290001DB12946F1F74FFC2060012065602072B6 +:1042A00000F011F8002070BD2649CA7A002A04BF28 +:1042B000002070471E22027000224270CB684360CB +:1042C000CA7201207047F0B585B0F1F74DFF1D4D62 +:1042D0000746394668682C6800EB80004600204697 +:1042E000F2F73AFCB04206DB6868811B3846F1F70A +:1042F00022FC0446286040F2367621463846F2F722 +:104300002BFCB04204DA31463846F1F714FC04467F +:1043100000208DF8000040F6E210039004208DF894 +:10432000050001208DF8040068460294F2F7CAF8EF +:10433000687A6946F2F743F9002808BFFFDF05B045 +:10434000F0BD000074120020AC010020B5EB3C0071 +:10435000054102002DE9F0410C4612490D68114A51 +:10436000114908321160A0F12001312901D3012047 +:104370000CE0412810D040CC0C4F94E80E0007EB25 +:104380008000241F50F8807C3046B84720600548E4 +:10439000001D0560BDE8F081204601F0EBFCF5E76B +:1043A00006207047100502400100000184630200EE +:1043B00010B55548F2F7FAFF00B1FFDF5248401C34 +:1043C000F2F7F4FF002800D0FFDF10BD2DE9F14F18 +:1043D0004E4E82B0D6F800B001274B48F2F7EEFF00 +:1043E000DFF8248120B9002708F10100F2F7FCFF73 +:1043F000474C00254FF0030901206060C4F80051CC +:10440000C4F80451029931602060DFF808A11BE074 +:10441000DAF80000C00617D50E2000F068F8EFF3B8 +:10442000108010F0010072B600D001200090C4F896 +:104430000493D4F8000120B9D4F8040108B901F0BC +:10444000A3FC009800B962B6D4F8000118B9D4F8FA +:1044500004010028DCD0D4F804010028CCD137B105 +:10446000C6F800B008F10100F2F7A8FF11E008F16A +:104470000100F2F7A3FF0028B6D1C4F80893C4F8EE +:104480000451C4F800510E2000F031F81E48F2F734 +:10449000ABFF0020BDE8FE8F2DE9F0438DB00D4647 +:1044A000064600240DF110090DF1200818E000BFA8 +:1044B00004EB4407102255F827106846E9F7BDFFC2 +:1044C00005EB8707102248467968E9F7B6FF68468A +:1044D000FFF77CFF10224146B868E9F7AEFF641C85 +:1044E000B442E5DB0DB00020BDE8F0836EE70028A4 +:1044F00009DB00F01F02012191404009800000F11A +:10450000E020C0F880127047AD01002004E50040B3 +:1045100000E0004010ED00E0B54900200870704751 +:1045200070B5B44D01232B60B34B1C68002CFCD03C +:10453000002407E00E6806601E68002EFCD0001DF7 +:10454000091D641C9442F5D30020286018680028D7 +:10455000FCD070BD70B5A64E0446A84D3078022838 +:1045600000D0FFDFAC4200D3FFDF7169A44801290E +:1045700003D847F23052944201DD03224271491CB4 +:104580007161291BC1609E49707800F02EF90028E6 +:1045900000D1FFDF70BD70B5954C0D466178884243 +:1045A00000D0FFDF954E082D4BD2DFE805F04A041E +:1045B0001E2D4A4A4A382078022800D0FFDF032007 +:1045C0002070A078012801D020B108E0A06801F097 +:1045D00085F904E004F1080007C8FFF7A1FF0520F2 +:1045E0002070BDE87040F1F7CABCF1F7BDFD01468F +:1045F0006068F2F7B1FAB04202D2616902290BD3C6 +:104600000320F2F7FAFD12E0F1F7AEFD0146606813 +:10461000F2F7A2FAB042F3D2BDE870409AE72078F0 +:1046200002280AD0052806D0FFDF04202070BDE84C +:10463000704000F0D0B8022000E00320F2F7DDFD6A +:10464000F3E7FFDF70BD70B50546F1F78DFD684CEF +:1046500060602078012800D0FFDF694901200870E0 +:104660000020087104208D6048716448C8600220F1 +:104670002070607800F0B9F8002800D1FFDF70BD2D +:1046800010B55B4C207838B90220F2F7CCFD18B990 +:104690000320F2F7C8FD08B1112010BD5948F1F709 +:1046A000E9FC6070202804D00120207000206061A7 +:1046B00010BD032010BD2DE9F0471446054600EB60 +:1046C00084000E46A0F1040801F01BF907464FF0E4 +:1046D000805001694F4306EB8401091FB14201D2AA +:1046E000012100E0002189461CB10069B4EB900F64 +:1046F00002D90920BDE8F0872846DCF7A3FD90B970 +:10470000A84510D3BD4205D2B84503D245EA0600FC +:10471000800701D01020EDE73046DCF793FD10B99B +:10472000B9F1000F01D00F20E4E73748374900689E +:10473000884205D0224631462846FFF7F1FE1AE0AE +:10474000FFF79EFF0028D5D1294800218560C0E9E8 +:1047500003648170F2F7D3FD08B12D4801E04AF2FD +:10476000F87060434FF47A7100F2E730B0FBF1F07B +:104770001830FFF768FF0020BCE770B505464FF022 +:10478000805004696C432046DCF75CFD08B10F20C3 +:1047900070BD01F0B6F8A84201D8102070BD1A48CB +:1047A0001A490068884203D0204601F097F810E0CB +:1047B000FFF766FF0028F1D10D4801218460817068 +:1047C000F2F79DFD08B1134800E013481830FFF7D9 +:1047D0003AFF002070BD10B5054C6078F1F7A5FCDC +:1047E00000B9FFDF0020207010BDF1F7E8BE000027 +:1047F000B001002004E5014000E40140105C0C0021 +:1048000084120020974502005C000020BEBAFECA58 +:1048100050280500645E0100A85B01007E4909681C +:104820000160002070477C4908600020704701212A +:104830008A0720B1012804D042F204007047916732 +:1048400000E0D1670020704774490120086042F2FF +:104850000600704708B50423704A1907103230B1BA +:10486000C1F80433106840F0010010600BE01068DC +:1048700020F001001060C1F808330020C1F80801E1 +:10488000674800680090002008BD011F0B2909D867 +:10489000624910310A6822F01E0242EA40000860B4 +:1048A0000020704742F2050070470F2809D85B4985 +:1048B00010310A6822F4706242EA00200860002089 +:1048C000704742F205007047000100F18040C0F8D7 +:1048D000041900207047000100F18040C0F8081959 +:1048E00000207047000100F18040D0F80009086006 +:1048F00000207047012801D907207047494A52F823 +:10490000200002680A43026000207047012801D994 +:1049100007207047434A52F8200002688A43026029 +:1049200000207047012801D9072070473D4A52F8FE +:104930002000006808600020704702003A494FF0EC +:10494000000003D0012A01D0072070470A60704799 +:10495000020036494FF0000003D0012A01D00720A1 +:1049600070470A60704708B54FF40072510510B1E6 +:10497000C1F8042308E0C1F808230020C1F824018D +:1049800027481C3000680090002008BD08B5802230 +:10499000D10510B1C1F8042308E0C1F808230020B4 +:1049A000C1F81C011E48143000680090002008BDAA +:1049B00008B54FF48072910510B1C1F8042308E0E6 +:1049C000C1F808230020C1F82001154818300068FC +:1049D0000090002008BD10493831096801600020AE +:1049E000704770B54FF080450024C5F80841F2F7D4 +:1049F00092FC10B9F2F799FC28B1C5F82441C5F82A +:104A00001C41C5F820414FF0E020802180F80014BF +:104A10000121C0F8001170BD0004004000050040F5 +:104A2000080100404864020078050040800500400D +:104A30006249634B0A6863499A42096801D1C1F32C +:104A400010010160002070475C495D4B0A685D49B8 +:104A5000091D9A4201D1C0F3100008600020704780 +:104A60005649574B0A68574908319A4201D1C0F359 +:104A7000100008600020704730B5504B504D1C6846 +:104A800042F20803AC4202D0142802D203E01128FB +:104A900001D3184630BDC3004B481844C0F8101568 +:104AA000C0F81425002030BD4449454B0A6842F245 +:104AB00009019A4202D0062802D203E0042801D359 +:104AC00008467047404A012142F8301000207047E4 +:104AD0003A493B4B0A6842F209019A4202D0062841 +:104AE00002D203E0042801D308467047364A012168 +:104AF00002EBC00041600020704770B52F4A304E75 +:104B0000314C156842F2090304EB8002B54204D02F +:104B1000062804D2C2F8001807E0042801D318467A +:104B200070BDC1F31000C2F80008002070BD70B560 +:104B3000224A234E244C156842F2090304EB8002FA +:104B4000B54204D0062804D2D2F8000807E00428B1 +:104B500001D3184670BDD2F80008C0F310000860F9 +:104B6000002070BD174910B50831184808601120A1 +:104B7000154A002102EBC003C3F81015C3F8141541 +:104B8000401C1428F6D3002006E0042804D302EBCE +:104B90008003C3F8001807E002EB8003D3F8004855 +:104BA000C4F31004C3F80048401C0628EDD310BD20 +:104BB0000449064808310860704700005C00002086 +:104BC000BEBAFECA00F5014000F001400000FEFF41 +:104BD000814B1B6803B19847BFF34F8F7F48016833 +:104BE0007F4A01F4E06111430160BFF34F8F00BFC2 +:104BF000FDE710B5EFF3108010F0010F72B601D091 +:104C0000012400E0002400F0DDF850B1DCF7BFFB28 +:104C1000F1F755F8F2F793FAF2F7BEFF7149002069 +:104C2000086004B962B6002010BD2DE9F0410C46C1 +:104C30000546EFF3108010F0010F72B601D0012687 +:104C400000E0002600F0BEF820B106B962B60820E8 +:104C5000BDE8F08101F01EF9DCF79DFB0246002063 +:104C600001234709BF0007F1E02700F01F01D7F833 +:104C70000071CF40F9071BD0202803D222FA00F19F +:104C8000C90727D141B2002904DB01F1E02191F8E5 +:104C9000001405E001F00F0101F1E02191F8141D6D +:104CA0004909082916D203FA01F717F0EC0F11D0C1 +:104CB000401C6428D5D3F2F74DFF4B4A4B490020E6 +:104CC000F2F790FF47494A4808602046DCF7C1FAEE +:104CD00060B904E006B962B641F20100B8E73E48A7 +:104CE00004602DB12846DCF701FB18B1102428E040 +:104CF000404D19E02878022802D94FF4805420E072 +:104D000007240028687801D0D8B908E0C8B1202865 +:104D100017D8A878212814D8012812D001E0A87843 +:104D200078B9E8780B280CD8DCF735FB2946F2F780 +:104D3000ECF9F0F783FF00F017FE2846DCF7F4FAF1 +:104D4000044606B962B61CB1FFF753FF20467FE761 +:104D500000207DE710B5044600F034F800B10120D2 +:104D60002070002010BD244908600020704770B5F5 +:104D70000C4622490D682149214E08310E60102849 +:104D800007D011280CD012280FD0132811D00120E1 +:104D900013E0D4E90001FFF748FF354620600DE03D +:104DA000FFF727FF0025206008E02068FFF7D2FF0B +:104DB00003E0114920680860002020600F48001DB2 +:104DC000056070BD07480A490068884201D101208A +:104DD0007047002070470000C80100200CED00E083 +:104DE0000400FA055C0000204814002000000020A8 +:104DF000BEBAFECA50640200040000201005024042 +:104E0000010000017D49C0B20860704700B57C49CF +:104E1000012808BF03200CD0022808BF042008D0B6 +:104E2000042808BF062004D0082816BFFFDF05208D +:104E300000BD086000BD70B505460C46164610461C +:104E4000F3F7D2F8022C08BF4FF47A7105D0012C89 +:104E50000CBF4FF4C86140F6340144183046F3F7F4 +:104E60003CF9204449F6797108444FF47A71B0FB5B +:104E7000F1F0281A70BD70B505460C460846F4F7E7 +:104E80002FFA022C08BF40F24C4105D0012C0CBF78 +:104E900040F634014FF4AF5149F6CA62511A084442 +:104EA0004FF47A7100F2E140B0FBF1F0281A801E55 +:104EB00070BD70B5064615460C460846F4F710FA64 +:104EC000022D08BF4FF47A7105D0012D0CBF4FF4AD +:104ED000C86140F63401022C08BF40F24C4205D0B4 +:104EE000012C0CBF40F634024FF4AF52891A08442B +:104EF00049F6FC6108444FF47A71B0FBF1F0301AC6 +:104F000070BD70B504460E460846F3F76DF80546C9 +:104F10003046F3F7E2F828444AF2AB3108444FF444 +:104F20007A71B0FBF1F0201A801E70BD2DE9F041BE +:104F300007461E460D4614461046082A16BF04288A +:104F40004EF62830F3F750F807EB4701C1EBC711D5 +:104F500000EBC100022D08BF40F24C4105D0012DED +:104F60000CBF40F634014FF4AF5147182846F4F710 +:104F7000B7F9381A4FF47A7100F6B730B0FBF1F593 +:104F80002046F3F7B9F828443044401DBDE8F081CD +:104F900070B5054614460E460846F3F725F805EBAE +:104FA0004502C2EBC512C0EBC2053046F3F795F8D7 +:104FB0002D1A2046082C16BF04284EF62830F3F789 +:104FC00013F828444FF47A7100F6B730B0FBF1F5CE +:104FD0002046F3F791F82844401D70BD0949082880 +:104FE00018BF0428086803BF20F46C5040F4444004 +:104FF00040F0004020F00040086070470C15004071 +:105000001015004040170040F0B585B00C4605462D +:10501000F9F73EF907466E78204603A96A46EEF78F +:1050200002FD81198EB258B1012F02D0032005B0C4 +:10503000F0BD204604AA0399EEF717FC049D01E099 +:10504000022F0FD1ED1C042E0FD32888BDF80010BD +:10505000001D80B2884201D8864202D14FF0000084 +:10506000E5E702D34FF00200E1E74FF00100DEE791 +:10507000FA48C078FF2814BF0120002070472DE9AE +:10508000F041F74C0746160060680D4603D0F9F76B +:1050900069F8A0B121E0F9F765F8D8B96068F9F7C7 +:1050A00061F8D0B915F00C0F17D06068C17811F015 +:1050B0003F0F1CBF007910F0100F0ED00AE0022E37 +:1050C00008D0E6481FB1807DFF2806D002E0C078F6 +:1050D000FF2802D00120BDE8F0810020BDE8F0816A +:1050E0000A4601460120CAE710B5DC4C1D2200210A +:1050F000A01CE9F7CCF97F206077FF202074E070D6 +:10510000A075A08920F060002030A08100202070D0 +:1051100010BD70B5D249486001200870D248D1490D +:10512000002541600570CD4C1D222946A01CE9F7E1 +:10513000AEF97F206077FF202074E070A075A08911 +:1051400020F060002030A081257070BD2DE9F0476F +:10515000C24C06462078C24F4FF0010907F10808FB +:10516000002520B13878D0B998F80000B8B198F887 +:10517000000068B387F80090D8F804103C2239B3D7 +:105180007570301DE9F759F90520307086F80490E4 +:105190003878002818BF88F8005005D015E03D7019 +:1051A000A11C4FF48E72EAE71D220021A01CE9F732 +:1051B0006EF97F206077FF202074E070A075A089D1 +:1051C00020F060002030A08125700120BDE8F0872C +:1051D0000020BDE8F087A148007800280CBF01201E +:1051E000002070470A460146002048E710B510B17C +:1051F000022810D014E09A4C6068F8F7B3FF78B931 +:105200006068C17811F03F0F1CBF007910F0100FDB +:1052100006D1012010BD9148007B10F0080FF8D195 +:10522000002010BD2DE9FF4F81B08C4D8346DDE994 +:105230000F042978DDF838A09846164600291CBFCF +:1052400005B0BDE8F08F8849097800291CBF05B07A +:10525000BDE8F08FE872B4B1012E08BF012708D075 +:10526000022E08BF022704D0042E16BF082E0327E3 +:10527000FFDFEF7385F81E804FF00008784F8CB188 +:10528000022C1DD020E0012E08BF012708D0022EDD +:1052900008BF022704D0042E16BF082E0327FFDF05 +:1052A000AF73E7E77868F8F75DFF68B97868C178A9 +:1052B00011F03F0F1CBF007910F0100F04D110E067 +:1052C000287B10F0080F0CD14FF003017868F8F735 +:1052D000FDFD30B14178090929740088C0F30B0045 +:1052E0006882CDF800807868F8F73CFF0146012815 +:1052F000BDF8000005F102090CBF40F0010020F0EC +:105300000100ADF8000099F80A2012F0020F4ED10A +:10531000022918BF20F0020049D000BFADF80000FC +:1053200010F0020F04D0002908BF40F0080801D097 +:1053300020F00808ADF800807868C17811F03F0FC0 +:105340001CBF007910F0020F0CD0314622464FF0FE +:105350000100FFF794FE002804BF48F00400ADF8F8 +:10536000000006D099F80A00800860F38208ADF8C2 +:10537000008099F80A004109BDF8000061F3461069 +:10538000ADF8000080B20090BDF80000A8810421B3 +:105390007868F8F79BFD002804BFA88920F060001A +:1053A0000CD0B0F80100C004C00C03D007E040F0FE +:1053B0000200B3E7A88920F060004030A8815CB902 +:1053C00016F00C0F08D07868C17811F03F0F1CBFA1 +:1053D000007910F0100F0DD17868C17811F03F0FEF +:1053E00008D0017911F0400F04D00621F8F76EFDC6 +:1053F00000786877314622460020FFF740FE60BB08 +:105400007968C87810F03F0F3FD0087910F0010F8D +:105410003BD0504605F1040905F10308BAF1FF0F2E +:105420000DD04A464146F8F781FA002808BFFFDF51 +:1054300098F8000040F0020088F8000025E00846D7 +:10544000F8F7DBFC88F800007868F8F7ADFC07286F +:105450000CD249467868F8F7B2FC16E094120020A6 +:10546000CC010020D2120020D40100207868F8F787 +:105470009BFC072809D100217868F8F727FD01680F +:10548000C9F800108088A9F804003146224601209E +:10549000FFF7F5FD80BB7868C17811F03F0F2BD086 +:1054A000017911F0020F27D005F1170605F1160852 +:1054B000BBF1020F18BFBBF1030F08D0F8F774FC63 +:1054C00007280AD231467868F8F787FC12E002987C +:1054D000016831608088B0800CE07868F8F764FC7F +:1054E000072807D101217868F8F7F0FC01683160DE +:1054F0008088B08088F800B0002C04BF05B0BDE8FB +:10550000F08F7868F8F72EFE022804BF05B0BDE8DA +:10551000F08F05F11F047868F8F76DFEAB7AC3F1E0 +:10552000FF01884228BF084605D9A98921F06001FA +:1055300001F14001A981C2B203EB04017868F8F7D8 +:1055400062FEA97A0844A87205B0BDE8F08FB048A1 +:105550000178002918BF704701220270007B10F00B +:10556000080F14BF07200620FCF75FBEA848C17BC8 +:10557000002908BF70470122818921F06001403174 +:1055800081810378002B18BF7047027011F0080F5B +:1055900014BF07200620FCF748BE2DE9FF5F9C4F93 +:1055A000DDF838B0914638780E4600281CBF04B0AC +:1055B000BDE8F09FBC1C1D2200212046E8F767FFD4 +:1055C000944D4FF0010A84F800A06868F8F7ECFBEE +:1055D00018B3012826D0022829D0062818BFFFDFDB +:1055E0002AD000BF04F11D016868F8F726FC20727C +:1055F000484604F1020904F10108FF2821D04A4677 +:105600004146F8F793F9002808BFFFDF98F800003B +:1056100040F0020088F8000031E0608940F013009B +:105620006081DFE7608940F015006081E0E7608914 +:1056300040F010006081D5E7608940F01200608181 +:10564000D0E76868F8F7D9FB88F800006868F8F7D1 +:10565000ABFB072804D249466868F8F7B0FB0EE0B8 +:105660006868F8F7A1FB072809D100216868F8F7F6 +:105670002DFC0168C9F800108088A9F8040084F89E +:1056800009B084F80CA000206073FF20A073A17AF9 +:1056900011F0040F08BF20752AD004F1150804F199 +:1056A0001409022E18BF032E09D06868F8F77CFB96 +:1056B00007280CD241466868F8F78FFB16E000987F +:1056C0000168C8F800108088A8F804000EE0686837 +:1056D000F8F76AFB072809D101216868F8F7F6FB9B +:1056E0000168C8F800108088A8F8040089F80060F4 +:1056F0007F20E0760398207787F800A004B006208A +:10570000BDE8F05FFCF791BD2DE9FF5F424F814698 +:105710009A4638788B4600281CBF04B0BDE8F09F3D +:105720003B48017831B1007B10F0100F04BF04B08A +:10573000BDE8F09F1D227C6800212046E8F7A7FE07 +:1057400048464FF00108661C324D84F8008004F191 +:105750000209FF280BD04A463146F8F7E7F800283F +:1057600008BFFFDF307840F0020030701CE068684E +:10577000F8F743FB30706868F8F716FB072804D287 +:1057800049466868F8F71BFB0EE06868F8F70CFB01 +:10579000072809D100216868F8F798FB0168C9F863 +:1057A00000108088A9F8040004F11D016868F8F76A +:1057B00044FB207284F809A060896BF3000040F07C +:1057C0001A00608184F80C8000206073FF20A073B1 +:1057D00020757F20E0760298207787F8008004B05B +:1057E0000720BDE8F05FFCF720BD094A137C834227 +:1057F00005BF508A88420020012070470448007B82 +:10580000C0F3411002280CBF0120002070470000A7 +:1058100094120020CC010020D4010020C2790D2375 +:1058200041B342BB8188012904D94908818004BF62 +:10583000012282800168012918BF002930D0016847 +:105840006FEA0101C1EBC10202EB011281796FEA3B +:10585000010101EB8103C3EB811111444FEA914235 +:1058600001608188B2FBF1F301FB132181714FF0DC +:10587000010102E01AB14FF00001C1717047818847 +:10588000FF2908D24FF6FF7202EA41018180FF2909 +:1058900084BFFF2282800168012918BF0029CED170 +:1058A0000360CCE7817931B1491E11F0FF018171AC +:1058B0001CBF002070470120704710B50121C17145 +:1058C0008171818004460421F1F7E8FD002818BFAA +:1058D00010BD2068401C206010BD00000B4A022152 +:1058E00011600B490B68002BFCD0084B1B1D186086 +:1058F00008680028FCD00020106008680028FCD050 +:1059000070474FF0805040697047000004E5014047 +:1059100000E4014002000B464FF00000014620D099 +:10592000012A04D0022A04D0032A0DD103E0012069 +:1059300002E0022015E00320072B05D2DFE803F088 +:105940000406080A0C0E100007207047012108E029 +:10595000022106E0032104E0042102E0052100E029 +:105960000621F0F7A4BB0000E24805218170002168 +:10597000017041707047E0490A78012A05D0CA6871 +:105980001044C8604038F1F7B4B88A6810448860A1 +:10599000F8E7002819D00378D849D94A13B1012B68 +:1059A0000ED011E00379012B00D06BB943790BB114 +:1059B000012B09D18368643B8B4205D2C0680EE09D +:1059C0000379012B02D00BB10020704743790BB152 +:1059D000012BF9D1C368643B8B42F5D280689042B9 +:1059E000F2D801207047C44901220A70027972B1CD +:1059F00000220A71427962B104224A7182685232ED +:105A00008A60C068C860BB49022088707047032262 +:105A1000EFE70322F1E770B5B74D04460020287088 +:105A2000207988B100202871607978B10420B14EC6 +:105A30006871A168F068F0F77EF8A860E0685230FD +:105A4000E8600320B07070BD0120ECE70320EEE7B2 +:105A50002DE9F04105460226F0F777FF006800B116 +:105A6000FFDFA44C01273DB12878B8B1012805D04B +:105A7000022811D0032814D027710DE06868C828C7 +:105A800008D30421F1F79BF820B16868FFF773FF92 +:105A9000012603E0002601E000F014F93046BDE8DD +:105AA000F08120780028F7D16868FFF772FF00289E +:105AB000E2D06868017879B1A078042800D0FFDFCF +:105AC00001216868FFF7A7FF8B49E07800F003F930 +:105AD0000028E1D1FFDFDFE7FFF785FF6770DBE735 +:105AE0002DE9F041834C0F46E178884200D0FFDF7A +:105AF00000250126082F7DD2DFE807F0040B2828B7 +:105B00003D434F57A0780328C9D00228C7D0FFDFF4 +:105B1000C5E7A078032802D0022800D0FFDF0420C8 +:105B2000A07025712078B8BB0020FFF724FF7248D1 +:105B30000178012906D08068E06000F0EDF820616E +:105B4000002023E0E078F0F734FCF5E7A0780328A4 +:105B500002D0022800D0FFDF207880BB022F08D0BF +:105B60005FF00500F1F749FBA078032840D0A5704D +:105B700095E70420F6E7A078042800D0FFDF022094 +:105B800004E0A078042800D0FFDF0120A168884746 +:105B9000FFF75EFF054633E003E0A078042800D05D +:105BA000FFDFBDE8F04100F08DB8A078042804D0F4 +:105BB000617809B1022800D0FFDF207818B1BDE874 +:105BC000F04100F08AB8207920B10620F1F715FBEA +:105BD00025710DE0607840B14749E07800F07BF82E +:105BE00000B9FFDF65705AE704E00720F1F705FB15 +:105BF000A67054E7FFDF52E73DB1012D03D0FFDF70 +:105C0000022DF9D14BE70420C0E70320BEE770B5B1 +:105C1000050004D0374CA078052806D101E01020FB +:105C200070BD0820F1F7FFFA08B1112070BD3548AA +:105C3000F0F720FAE070202806D00121F1F7DCF817 +:105C40000020A560A07070BD032070BD294810B56C +:105C5000017809B1112010BD8178052906D00129EC +:105C600006D029B101210170002010BD0F2010BD08 +:105C700000F033F8F8E770B51E4C0546A07808B17F +:105C8000012809D155B12846FFF783FE40B1287895 +:105C900040B1A078012809D00F2070BD102070BD40 +:105CA000072070BD2846FFF79EFE03E0002128462E +:105CB000FFF7B1FE1049E07800F00DF800B9FFDF02 +:105CC000002070BD0B4810B5006900F01DF8BDE85C +:105CD0001040F0F754B9F0F772BC064810B5C07820 +:105CE000F0F723FA00B9FFDF0820F1F786FABDE8E4 +:105CF000104039E6DC010020B41300203D8601008D +:105D0000FF1FA107E15A02000C490A6848F202137A +:105D10009A4302430A607047084A116848F2021326 +:105D200001EA03009943116070470246044B1020BA +:105D30001344FC2B01D8116000207047C8060240B4 +:105D40000018FEBF1EF0040F0CBFEFF30880EFF346 +:105D50000980014A10470000FF7B010001B41EB416 +:105D600000B5F1F76DFC01B40198864601BC01B0A5 +:105D70001EBD00008269034981614FF0010010449B +:105D8000704700005D5D02000FF20C0000F10000A2 +:105D9000694641F8080C20BF70470000FEDF184933 +:105DA0000978F9B90420714608421BD10699154AB1 +:105DB000914217DC0699022914DB02394878DF2862 +:105DC00010D10878FE2807D0FF280BD14FF0010032 +:105DD0004FF000020C4B184741F201000099019A64 +:105DE000094B1847094B002B02D01B68DB6818478A +:105DF0004FF0FF3071464FF00002034B1847000090 +:105E000028ED00E000700200D14B020004000020E9 +:105E1000174818497047FFF7FBFFDBF7CFF900BDC4 +:105E2000154816490968884203D1154A13605B6812 +:105E3000184700BD20BFFDE70F4810490968884298 +:105E400010D1104B18684FF0FF318842F2D080F328 +:105E500008884FF02021884204DD0B4802680321A6 +:105E60000A4302600948804709488047FFDF000075 +:105E7000C8130020C81300200010000000000020FC +:105E8000040000200070020014090040B92F000037 +:105E9000215E0200F0B44046494652465B460FB4CC +:105EA00002A0013001B50648004700BF01BC86468C +:105EB0000FBC8046894692469B46F0BC7047000066 +:105EC0000911000004207146084202D0EFF3098155 +:105ED00001E0EFF30881886902380078102813DBAD +:105EE00020280FDB2C280BDB0A4A12680A4B9A4247 +:105EF00003D1602804DB094A10470220086070477C +:105F0000074A1047074A1047074A12682C3212689E +:105F1000104700005C000020BEBAFECA9B130000C0 +:105F2000554302006F4D0200040000200D4B0E4946 +:105F300008470E4B0C4908470D4B0B4908470D4BC2 +:105F4000094908470C4B084908470C4B06490847C4 +:105F50000B4B054908470B4B034908470A4B0249BD +:105F60000847000041BF000079C10000792D000002 +:105F7000F32B0000812B0000012E0000B71300005E +:105F80003F2900007D2F0000455D020000210160D7 +:105F90004160017270470A6802600B7903717047B3 +:105FA00089970000FF9800005B9A0000C59A0000E6 +:105FB000FF9A0000339B0000659B00009D9B000042 +:105FC0003D9C00007D980000859A0000331200007F +:105FD0000744000053440000B94400004745000056 +:105FE0006146000037470000694700004148000053 +:105FF000DB4800002F490000154A0000354A000028 +:10600000AD160000D1160000F11500004D1600007D +:10601000031700009717000003610000C36200002F +:10602000A1660000BB67000043680000C168000073 +:10603000256900004D6A00001D6B0000896B00009F +:10604000574A00005D4A0000674A0000CF4A00003E +:10605000FB4A0000B74C0000E14C0000194D000065 +:10606000834D00006D4E0000834E00007744000019 +:10607000974E0000B94E0000FF4E000033120000A2 +:10608000331200003312000033120000C12500005B +:1060900047260000632600007F2600000D28000030 +:1060A000A9260000B3260000F526000017270000EF +:1060B000F3270000352800003312000033120000DF +:1060C00097840000B7840000B9840000FD840000BC +:1060D0002B8500001B860000A7860000BB86000001 +:1060E000098700001F880000C1890000E98A0000BC +:1060F0003D740000018B00003312000033120000D9 +:10610000EBB700004DB90000A7B9000021BA0000AC +:10611000CDBA0000010000000000000010011001D5 +:106120003A0200001A020000020004050600000006 +:1061300007111102FFFFFFFF0000FFFFF3B3000094 +:10614000273D0000532100008774000001900000EB +:1061500000000000BF9200009B920000AD92000082 +:10616000000002000000000000020000000000002B +:1061700000010000000000004382000023820000B4 +:10618000918200002D250000EF2400000F25000063 +:10619000DBAA000007AB00000FAD0000FD590000B6 +:1061A000B182000000000000E18200007B250000B9 +:1061B000000000000000000000000000F1AB000043 +:1061C00000000000915A00000300000001555555E1 +:1061D000D6BE898E00006606660C661200000A03B1 +:1061E000AE055208000056044608360CC7FD0000F4 +:1061F0005BFF0000A1FB0000C3FD0000A7A8010099 +:106200009B040100AAAED7AB15412010000000008E +:10621000900A0000900A00007B5700007B570000A6 +:10622000E143000053B200000B7700006320000040 +:10623000BD3A020063BD0100BD570000BD5700001C +:1062400005440000E5B2000093770000D72000006D +:10625000EB3A020079BD0100700170014000380086 +:106260005C0024006801200200000300656C746279 +:10627000000000000000000000000000000000001E +:106280008700000000000000000000000000000087 +:10629000BE83605ADB0B376038A5F5AA9183886C02 +:1062A000010000007746010049550100000000018F +:1062B0000206030405000000070000FB349B5F801A +:1062C000000080001000000000000000000000003E +:1062D000060000000A000000320000007300000009 +:1062E000B4000000F401FA00960064004B00320094 +:1062F0001E0014000A000500020001000049000011 +:1063000000000000D7CF0100E9D1010025D1010034 +:10631000EBCF0100000000008FD40100000101025A +:10632000010202030C0802170D0101020909010113 +:1063300006020918180301010909030305000000FA +:10634000555555252627D6BE898E00002BFB01000A +:1063500003F7010049FA01003FF20100BB220200ED +:10636000B7FB0100F401FA00960064004B00320014 +:106370001E0014000A00050002000100254900006B +:1063800000000000314A0200494A0200614A02004E +:10639000794A0200A94A0200D14A0200FB4A0200DF +:1063A0002F4B02007B470200B7460200A1430200C8 +:1063B0002B5D0200AD730100BD730100E9730100A4 +:1063C000BB740100C3740100D57401002F480200A2 +:1063D000494802001D4802002748020055480200B3 +:1063E0008B480200AB480200C9480200D7480200AF +:1063F000E5480200F54802000D4902002549020067 +:106400003B4902005149020000000000DFBC0000CF +:1064100035BD00004BBD000015590200CD43020000 +:10642000994402000F5C02004D5C0200775C0200A0 +:106430009D710100FD760100674902008D4902004F +:10644000B1490200D74902001C0500402005004068 +:10645000001002007464020008000020E80100003F +:106460004411000098640200F0010020D8110000DF +:10647000A011000001181348140244200B440C061C +:106480004813770B1B2034041ABA0401A40213101A +:08649000327F0B744411C000BF +:00000001FF From 2ba88d305f123e5fa5f6ca1ad72937c6497882e4 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 4 Jul 2024 08:29:49 -0500 Subject: [PATCH 118/211] Only sdk --- bin/build-nrf52.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index 853adb4886..a09b73cb8c 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -31,7 +31,7 @@ echo "Generating NRF52 uf2 file" SRCHEX=.pio/build/$1/firmware.hex # if WM1110 target, merge hex with softdevice 7.3.0 -if (echo $1 | grep -q "wm1110"); then +if (echo $1 | grep -q "wio-sdk-wm1110"); then echo "Merging with softdevice" bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/merged_fimware.hex SRCHEX=.pio/build/$1/merged_fimware.hex From c1df621711a800748d3bc3916910154aaff442d0 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 4 Jul 2024 08:32:59 -0500 Subject: [PATCH 119/211] Sudo --- bin/build-nrf52.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index a09b73cb8c..29b4835202 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -33,6 +33,7 @@ SRCHEX=.pio/build/$1/firmware.hex # if WM1110 target, merge hex with softdevice 7.3.0 if (echo $1 | grep -q "wio-sdk-wm1110"); then echo "Merging with softdevice" + sudo chmod+x ./bin/mergehex bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/merged_fimware.hex SRCHEX=.pio/build/$1/merged_fimware.hex fi From ae420dcd21dd0e34bf743169d3d6a69daa60ff70 Mon Sep 17 00:00:00 2001 From: Manuel <71137295+mverch67@users.noreply.github.com> Date: Fri, 5 Jul 2024 15:58:16 +0200 Subject: [PATCH 120/211] Fix exclude macros (#4233) * fix MESHTASTIC_EXCLUDE_BLUETOOTH * fix HAS_SCREEN=0 * fix MESHTASTIC_EXCLUDE_GPS --- src/RedirectablePrint.cpp | 6 ++++++ src/graphics/Screen.h | 4 ++++ src/mesh/MeshService.cpp | 2 +- src/modules/AdminModule.cpp | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 1851ffbaad..01e5a34a70 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -173,6 +173,7 @@ void RedirectablePrint::log_to_syslog(const char *logLevel, const char *format, void RedirectablePrint::log_to_ble(const char *logLevel, const char *format, va_list arg) { +#if !MESHTASTIC_EXCLUDE_BLUETOOTH if (config.bluetooth.device_logging_enabled && !pauseBluetoothLogging) { bool isBleConnected = false; #ifdef ARCH_ESP32 @@ -211,6 +212,11 @@ void RedirectablePrint::log_to_ble(const char *logLevel, const char *format, va_ delete[] buffer; } } +#else + (void)logLevel; + (void)format; + (void)arg; +#endif } meshtastic_LogRecord_Level RedirectablePrint::getLogLevel(const char *logLevel) diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index e80581d6d9..83c9a7a946 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -22,6 +22,10 @@ class Screen void doDeepSleep() {} void forceDisplay(bool forceUiUpdate = false) {} void startFirmwareUpdateScreen() {} + void increaseBrightness() {} + void decreaseBrightness() {} + void setFunctionSymbal(std::string) {} + void removeFunctionSymbal(std::string) {} void startAlert(const char *) {} void endAlert() {} }; diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index c92b89eb47..e5f33e8e7f 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -269,7 +269,7 @@ bool MeshService::trySendPosition(NodeNum dest, bool wantReplies) assert(node); if (hasValidPosition(node)) { -#if HAS_GPS +#if HAS_GPS && !MESHTASTIC_EXCLUDE_GPS if (positionModule) { LOG_INFO("Sending position ping to 0x%x, wantReplies=%d, channel=%d\n", dest, wantReplies, node->channel); positionModule->sendOurPosition(dest, wantReplies, node->channel); diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 11821a0a3e..e24c62712d 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -232,9 +232,9 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta #if !MESHTASTIC_EXCLUDE_GPS if (gps != nullptr) gps->enable(); -#endif // Send our new fixed position to the mesh for good measure positionModule->sendOurPosition(); +#endif } break; } From 2df8093fef22034d99df783e5ede1a1ca660a52d Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Fri, 5 Jul 2024 22:02:55 +0800 Subject: [PATCH 121/211] update SD_FLASH_SIZE to 0x27000 (#4232) The 7.3.0 softdevice needs the extra 1000 :) --- src/platform/nrf52/softdevice/nrf_sdm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/nrf52/softdevice/nrf_sdm.h b/src/platform/nrf52/softdevice/nrf_sdm.h index 2786a86a45..33b6cc3421 100644 --- a/src/platform/nrf52/softdevice/nrf_sdm.h +++ b/src/platform/nrf52/softdevice/nrf_sdm.h @@ -141,7 +141,7 @@ the start of the SoftDevice (without MBR)*/ * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed * just above the MBR (the usual case). */ -#define SD_FLASH_SIZE 0x26000 +#define SD_FLASH_SIZE 0x27000 /** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual From 8be378c227841cd138f6f3dc3add2ef5f8e51e61 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Fri, 5 Jul 2024 22:03:45 +0800 Subject: [PATCH 122/211] fix typo in build-nrf52.sh (#4231) chmod is the command, '+x' is the argument. --- bin/build-nrf52.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index 29b4835202..fa6eacd237 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -33,7 +33,7 @@ SRCHEX=.pio/build/$1/firmware.hex # if WM1110 target, merge hex with softdevice 7.3.0 if (echo $1 | grep -q "wio-sdk-wm1110"); then echo "Merging with softdevice" - sudo chmod+x ./bin/mergehex + sudo chmod +x ./bin/mergehex bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/merged_fimware.hex SRCHEX=.pio/build/$1/merged_fimware.hex fi From c3d3dfa8c8ea103c4a82eb8d44be5e2a4bc22729 Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Sun, 7 Jul 2024 05:41:29 +1200 Subject: [PATCH 123/211] Tidy Wireless Paper variant files (#4238) * Quick tidy of pins_arduino.h Matches requests made at https://github.com/meshtastic/firmware/pull/4226#discussion_r1664183480) * Tidy variant.h * Change deprecated ADC attenuation parameter From 11dB to 12dB. Resolves compiler warning. Allegly, no impact on function: `This is deprecated, it behaves the same as `ADC_ATTEN_DB_12` --- variants/heltec_wireless_paper/pins_arduino.h | 8 ++---- variants/heltec_wireless_paper/variant.h | 28 ++++++++----------- .../heltec_wireless_paper_v1/pins_arduino.h | 8 ++---- variants/heltec_wireless_paper_v1/variant.h | 28 ++++++++----------- 4 files changed, 26 insertions(+), 46 deletions(-) diff --git a/variants/heltec_wireless_paper/pins_arduino.h b/variants/heltec_wireless_paper/pins_arduino.h index 9e1d8a9a01..2bb44161ab 100644 --- a/variants/heltec_wireless_paper/pins_arduino.h +++ b/variants/heltec_wireless_paper/pins_arduino.h @@ -3,11 +3,7 @@ #include -#define WIFI_Kit_32 true -#define DISPLAY_HEIGHT 64 -#define DISPLAY_WIDTH 128 - -static const uint8_t LED_BUILTIN = 35; +static const uint8_t LED_BUILTIN = 18; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN @@ -65,6 +61,6 @@ static const uint8_t LED = 18; static const uint8_t RST_LoRa = 12; static const uint8_t BUSY_LoRa = 13; -static const uint8_t DIO0 = 14; +static const uint8_t DIO1 = 14; #endif /* Pins_Arduino_h */ diff --git a/variants/heltec_wireless_paper/variant.h b/variants/heltec_wireless_paper/variant.h index 29b8bbbd14..c41d6d9dfe 100644 --- a/variants/heltec_wireless_paper/variant.h +++ b/variants/heltec_wireless_paper/variant.h @@ -1,14 +1,12 @@ #define LED_PIN 18 +#define BUTTON_PIN 0 -// Enable bus for external periherals +// I2C #define I2C_SDA SDA #define I2C_SCL SCL +// Display (E-Ink) #define USE_EINK - -/* - * eink display pins - */ #define PIN_EINK_CS 4 #define PIN_EINK_BUSY 7 #define PIN_EINK_DC 5 @@ -16,32 +14,28 @@ #define PIN_EINK_SCLK 3 #define PIN_EINK_MOSI 2 -/* - * SPI interfaces - */ +// SPI #define SPI_INTERFACES_COUNT 2 +#define PIN_SPI_MISO 10 // MISO +#define PIN_SPI_MOSI 11 // MOSI +#define PIN_SPI_SCK 9 // SCK -#define PIN_SPI_MISO 10 // MISO P0.17 -#define PIN_SPI_MOSI 11 // MOSI P0.15 -#define PIN_SPI_SCK 9 // SCK P0.13 - -#define VEXT_ENABLE 45 // active low, powers the oled display and the lora antenna boost -#define BUTTON_PIN 0 - +// Power +#define VEXT_ENABLE 45 // Active low, powers the E-Ink display #define ADC_CTRL 19 #define BATTERY_PIN 20 #define ADC_CHANNEL ADC2_GPIO20_CHANNEL #define ADC_MULTIPLIER 2 // Voltage divider is roughly 1:1 #define BAT_MEASURE_ADC_UNIT 2 // Use ADC2 -#define ADC_ATTENUATION ADC_ATTEN_DB_11 // Voltage divider output is quite high +#define ADC_ATTENUATION ADC_ATTEN_DB_12 // Voltage divider output is quite high +// LoRa #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module #define LORA_RESET 12 #define LORA_DIO1 14 // SX1262 IRQ #define LORA_DIO2 13 // SX1262 BUSY -#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled #define LORA_SCK 9 #define LORA_MISO 11 diff --git a/variants/heltec_wireless_paper_v1/pins_arduino.h b/variants/heltec_wireless_paper_v1/pins_arduino.h index 9e1d8a9a01..2bb44161ab 100644 --- a/variants/heltec_wireless_paper_v1/pins_arduino.h +++ b/variants/heltec_wireless_paper_v1/pins_arduino.h @@ -3,11 +3,7 @@ #include -#define WIFI_Kit_32 true -#define DISPLAY_HEIGHT 64 -#define DISPLAY_WIDTH 128 - -static const uint8_t LED_BUILTIN = 35; +static const uint8_t LED_BUILTIN = 18; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN @@ -65,6 +61,6 @@ static const uint8_t LED = 18; static const uint8_t RST_LoRa = 12; static const uint8_t BUSY_LoRa = 13; -static const uint8_t DIO0 = 14; +static const uint8_t DIO1 = 14; #endif /* Pins_Arduino_h */ diff --git a/variants/heltec_wireless_paper_v1/variant.h b/variants/heltec_wireless_paper_v1/variant.h index 29b8bbbd14..c41d6d9dfe 100644 --- a/variants/heltec_wireless_paper_v1/variant.h +++ b/variants/heltec_wireless_paper_v1/variant.h @@ -1,14 +1,12 @@ #define LED_PIN 18 +#define BUTTON_PIN 0 -// Enable bus for external periherals +// I2C #define I2C_SDA SDA #define I2C_SCL SCL +// Display (E-Ink) #define USE_EINK - -/* - * eink display pins - */ #define PIN_EINK_CS 4 #define PIN_EINK_BUSY 7 #define PIN_EINK_DC 5 @@ -16,32 +14,28 @@ #define PIN_EINK_SCLK 3 #define PIN_EINK_MOSI 2 -/* - * SPI interfaces - */ +// SPI #define SPI_INTERFACES_COUNT 2 +#define PIN_SPI_MISO 10 // MISO +#define PIN_SPI_MOSI 11 // MOSI +#define PIN_SPI_SCK 9 // SCK -#define PIN_SPI_MISO 10 // MISO P0.17 -#define PIN_SPI_MOSI 11 // MOSI P0.15 -#define PIN_SPI_SCK 9 // SCK P0.13 - -#define VEXT_ENABLE 45 // active low, powers the oled display and the lora antenna boost -#define BUTTON_PIN 0 - +// Power +#define VEXT_ENABLE 45 // Active low, powers the E-Ink display #define ADC_CTRL 19 #define BATTERY_PIN 20 #define ADC_CHANNEL ADC2_GPIO20_CHANNEL #define ADC_MULTIPLIER 2 // Voltage divider is roughly 1:1 #define BAT_MEASURE_ADC_UNIT 2 // Use ADC2 -#define ADC_ATTENUATION ADC_ATTEN_DB_11 // Voltage divider output is quite high +#define ADC_ATTENUATION ADC_ATTEN_DB_12 // Voltage divider output is quite high +// LoRa #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module #define LORA_RESET 12 #define LORA_DIO1 14 // SX1262 IRQ #define LORA_DIO2 13 // SX1262 BUSY -#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled #define LORA_SCK 9 #define LORA_MISO 11 From 7b838d388d7df7c10553639d7a4507182367b0c1 Mon Sep 17 00:00:00 2001 From: "Agent Blu, 006" Date: Sat, 6 Jul 2024 17:45:58 -0700 Subject: [PATCH 124/211] Updated raspbian CI to update apt repository ahead of libbluetooth. (#4243) --- .github/workflows/build_raspbian.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_raspbian.yml b/.github/workflows/build_raspbian.yml index 697d08727f..d262d87395 100644 --- a/.github/workflows/build_raspbian.yml +++ b/.github/workflows/build_raspbian.yml @@ -13,6 +13,7 @@ jobs: - name: Install libbluetooth shell: bash run: | + apt-get update -y apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code From 27dfe10689aad1b70c533d0cefb999d10b38d9ed Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 7 Jul 2024 04:50:47 -0700 Subject: [PATCH 125/211] Fix BLE logging on nrf52 (#4244) * allow ble logrecords to be fetched either by NOTIFY or INDICATE ble types This allows 'lossless' log reading. If client has requested INDICATE (rather than NOTIFY) each log record emitted via log() will have to fetched by the client device before the meshtastic node can continue. * Fix serious problem with nrf52 BLE logging. When doing notifies of LogRecords it is important to use the binary write routines - writing using the 'string' write won't work. Because protobufs can contain \0 nuls inside of them which if being parsed as a string will cause only a portion of the protobuf to be sent. I noticed this because some log messages were not getting through. --------- Co-authored-by: Ben Meadors --- src/RedirectablePrint.cpp | 2 +- src/platform/nrf52/NRF52Bluetooth.cpp | 22 +++++++++++++++------- src/platform/nrf52/NRF52Bluetooth.h | 2 +- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 01e5a34a70..9c3dcdc987 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -206,7 +206,7 @@ void RedirectablePrint::log_to_ble(const char *logLevel, const char *format, va_ #ifdef ARCH_ESP32 nimbleBluetooth->sendLog(buffer, size); #elif defined(ARCH_NRF52) - nrf52Bluetooth->sendLog(reinterpret_cast(buffer)); + nrf52Bluetooth->sendLog(buffer, size); #endif delete[] message; delete[] buffer; diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 56d7ed167d..57035a7c37 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -74,11 +74,16 @@ void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value) LOG_INFO("CCCD Updated: %u\n", cccd_value); // Check the characteristic this CCCD update is associated with in case // this handler is used for multiple CCCD records. + + // According to the GATT spec: cccd value = 0x0001 means notifications are enabled + // and cccd value = 0x0002 means indications are enabled + if (chr->uuid == fromNum.uuid || chr->uuid == logRadio.uuid) { - if (chr->notifyEnabled(conn_hdl)) { - LOG_INFO("fromNum 'Notify' enabled\n"); + auto result = cccd_value == 2 ? chr->indicateEnabled(conn_hdl) : chr->notifyEnabled(conn_hdl); + if (result) { + LOG_INFO("Notify/Indicate enabled\n"); } else { - LOG_INFO("fromNum 'Notify' disabled\n"); + LOG_INFO("Notify/Indicate disabled\n"); } } } @@ -176,7 +181,7 @@ void setupMeshService(void) toRadio.setWriteCallback(onToRadioWrite, false); toRadio.begin(); - logRadio.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ); + logRadio.setProperties(CHR_PROPS_INDICATE | CHR_PROPS_NOTIFY | CHR_PROPS_READ); logRadio.setPermission(secMode, SECMODE_NO_ACCESS); logRadio.setMaxLen(512); logRadio.setCccdWriteCallback(onCccd); @@ -334,9 +339,12 @@ void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_statu screen->endAlert(); } -void NRF52Bluetooth::sendLog(const char *logMessage) +void NRF52Bluetooth::sendLog(const uint8_t *logMessage, size_t length) { - if (!isConnected() || strlen(logMessage) > 512) + if (!isConnected() || length > 512) return; - logRadio.notify(logMessage); + if (logRadio.indicateEnabled()) + logRadio.indicate(logMessage, (uint16_t)length); + else + logRadio.notify(logMessage, (uint16_t)length); } \ No newline at end of file diff --git a/src/platform/nrf52/NRF52Bluetooth.h b/src/platform/nrf52/NRF52Bluetooth.h index 0d621dda25..2229163f81 100644 --- a/src/platform/nrf52/NRF52Bluetooth.h +++ b/src/platform/nrf52/NRF52Bluetooth.h @@ -13,7 +13,7 @@ class NRF52Bluetooth : BluetoothApi void clearBonds(); bool isConnected(); int getRssi(); - void sendLog(const char *logMessage); + void sendLog(const uint8_t *logMessage, size_t length); private: static void onConnectionSecured(uint16_t conn_handle); From f59d98482faa7f8a37bb29bbeb34f0b362923db9 Mon Sep 17 00:00:00 2001 From: geeksville Date: Sun, 7 Jul 2024 05:08:49 -0700 Subject: [PATCH 126/211] Fix build when HAS_NETWORKING is false on nrf52 (#4237) (tested on a rak4631 by setting HAS_ETHERNET false when shrinking image) --- src/mesh/eth/ethClient.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mesh/eth/ethClient.cpp b/src/mesh/eth/ethClient.cpp index 5373f243e6..9f3bb8ab7f 100644 --- a/src/mesh/eth/ethClient.cpp +++ b/src/mesh/eth/ethClient.cpp @@ -12,6 +12,8 @@ #include #include +#if HAS_NETWORKING + #ifndef DISABLE_NTP #include @@ -183,3 +185,5 @@ bool isEthernetAvailable() return true; } } + +#endif \ No newline at end of file From 86ca81b555b6b881cf14997a1cd1d862bc07198f Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sun, 7 Jul 2024 16:06:42 +0200 Subject: [PATCH 127/211] If `toPhoneQueue` is full, still increment `fromNum` to avoid client never getting packets (#4246) --- src/mesh/MeshService.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index e5f33e8e7f..9e2a5b1102 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -299,6 +299,7 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p) } else { LOG_WARN("ToPhone queue is full, dropping packet.\n"); releaseToPool(p); + fromNum++; // Make sure to notify observers in case they are reconnected so they can get the packets return; } } From e1bf4c32f3bade256667e24f706010505a115a9c Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Sun, 7 Jul 2024 19:14:18 +0200 Subject: [PATCH 128/211] Update to SoftDevice 7.3.0 for wio-sdk-wm1110 and wio-tracker-wm1110 (#4248) * Update variant.h * Update wio-tracker-wm1110.json * Update wio-sdk-wm1110.json * Update platformio.ini * Update platformio.ini * Add files via upload * Add files via upload * Update variant.h --- boards/wio-sdk-wm1110.json | 6 +- boards/wio-tracker-wm1110.json | 6 +- variants/wio-sdk-wm1110/nrf52840_s140_v7.ld | 38 + variants/wio-sdk-wm1110/platformio.ini | 3 +- variants/wio-sdk-wm1110/softdevice/ble.h | 652 ++++ variants/wio-sdk-wm1110/softdevice/ble_err.h | 92 + variants/wio-sdk-wm1110/softdevice/ble_gap.h | 2895 +++++++++++++++++ variants/wio-sdk-wm1110/softdevice/ble_gatt.h | 232 ++ .../wio-sdk-wm1110/softdevice/ble_gattc.h | 764 +++++ .../wio-sdk-wm1110/softdevice/ble_gatts.h | 904 +++++ variants/wio-sdk-wm1110/softdevice/ble_hci.h | 135 + .../wio-sdk-wm1110/softdevice/ble_l2cap.h | 495 +++ .../wio-sdk-wm1110/softdevice/ble_ranges.h | 149 + .../wio-sdk-wm1110/softdevice/ble_types.h | 217 ++ .../wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h | 259 ++ .../wio-sdk-wm1110/softdevice/nrf_error.h | 90 + .../wio-sdk-wm1110/softdevice/nrf_error_sdm.h | 73 + .../wio-sdk-wm1110/softdevice/nrf_error_soc.h | 85 + variants/wio-sdk-wm1110/softdevice/nrf_nvic.h | 449 +++ variants/wio-sdk-wm1110/softdevice/nrf_sdm.h | 380 +++ variants/wio-sdk-wm1110/softdevice/nrf_soc.h | 1046 ++++++ variants/wio-sdk-wm1110/softdevice/nrf_svc.h | 98 + .../wio-tracker-wm1110/nrf52840_s140_v7.ld | 38 + variants/wio-tracker-wm1110/platformio.ini | 3 +- variants/wio-tracker-wm1110/softdevice/ble.h | 652 ++++ .../wio-tracker-wm1110/softdevice/ble_err.h | 92 + .../wio-tracker-wm1110/softdevice/ble_gap.h | 2895 +++++++++++++++++ .../wio-tracker-wm1110/softdevice/ble_gatt.h | 232 ++ .../wio-tracker-wm1110/softdevice/ble_gattc.h | 764 +++++ .../wio-tracker-wm1110/softdevice/ble_gatts.h | 904 +++++ .../wio-tracker-wm1110/softdevice/ble_hci.h | 135 + .../wio-tracker-wm1110/softdevice/ble_l2cap.h | 495 +++ .../softdevice/ble_ranges.h | 149 + .../wio-tracker-wm1110/softdevice/ble_types.h | 217 ++ .../softdevice/nrf52/nrf_mbr.h | 259 ++ .../wio-tracker-wm1110/softdevice/nrf_error.h | 90 + .../softdevice/nrf_error_sdm.h | 73 + .../softdevice/nrf_error_soc.h | 85 + .../wio-tracker-wm1110/softdevice/nrf_nvic.h | 449 +++ .../wio-tracker-wm1110/softdevice/nrf_sdm.h | 380 +++ .../wio-tracker-wm1110/softdevice/nrf_soc.h | 1046 ++++++ .../wio-tracker-wm1110/softdevice/nrf_svc.h | 98 + 42 files changed, 18116 insertions(+), 8 deletions(-) create mode 100644 variants/wio-sdk-wm1110/nrf52840_s140_v7.ld create mode 100644 variants/wio-sdk-wm1110/softdevice/ble.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_err.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gap.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gatt.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gattc.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gatts.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_hci.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_l2cap.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_ranges.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_types.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_nvic.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_sdm.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_soc.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_svc.h create mode 100644 variants/wio-tracker-wm1110/nrf52840_s140_v7.ld create mode 100644 variants/wio-tracker-wm1110/softdevice/ble.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_err.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gap.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gatt.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gattc.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gatts.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_hci.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_l2cap.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_ranges.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_types.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_nvic.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_sdm.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_soc.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_svc.h diff --git a/boards/wio-sdk-wm1110.json b/boards/wio-sdk-wm1110.json index 18c87adde9..f45b030d1f 100644 --- a/boards/wio-sdk-wm1110.json +++ b/boards/wio-sdk-wm1110.json @@ -1,7 +1,7 @@ { "build": { "arduino": { - "ldscript": "nrf52840_s140_v6.ld" + "ldscript": "nrf52840_s140_v7.ld" }, "core": "nRF5", "cpu": "cortex-m4", @@ -15,8 +15,8 @@ "softdevice": { "sd_flags": "-DS140", "sd_name": "s140", - "sd_version": "6.1.1", - "sd_fwid": "0x00B6" + "sd_version": "7.3.0", + "sd_fwid": "0x0123" }, "bootloader": { "settings_addr": "0xFF000" diff --git a/boards/wio-tracker-wm1110.json b/boards/wio-tracker-wm1110.json index 029c9c085e..04db525188 100644 --- a/boards/wio-tracker-wm1110.json +++ b/boards/wio-tracker-wm1110.json @@ -1,7 +1,7 @@ { "build": { "arduino": { - "ldscript": "nrf52840_s140_v6.ld" + "ldscript": "nrf52840_s140_v7.ld" }, "core": "nRF5", "cpu": "cortex-m4", @@ -22,8 +22,8 @@ "softdevice": { "sd_flags": "-DS140", "sd_name": "s140", - "sd_version": "6.1.1", - "sd_fwid": "0x00B6" + "sd_version": "7.3.0", + "sd_fwid": "0x0123" }, "bootloader": { "settings_addr": "0xFF000" diff --git a/variants/wio-sdk-wm1110/nrf52840_s140_v7.ld b/variants/wio-sdk-wm1110/nrf52840_s140_v7.ld new file mode 100644 index 0000000000..6aaeb4034f --- /dev/null +++ b/variants/wio-sdk-wm1110/nrf52840_s140_v7.ld @@ -0,0 +1,38 @@ +/* Linker script to configure memory regions. */ + +SEARCH_DIR(.) +GROUP(-lgcc -lc -lnosys) + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xED000 - 0x27000 + + /* SRAM required by Softdevice depend on + * - Attribute Table Size (Number of Services and Characteristics) + * - Vendor UUID count + * - Max ATT MTU + * - Concurrent connection peripheral + central + secure links + * - Event Len, HVN queue, Write CMD queue + */ + RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x20040000 - 0x20006000 +} + +SECTIONS +{ + . = ALIGN(4); + .svc_data : + { + PROVIDE(__start_svc_data = .); + KEEP(*(.svc_data)) + PROVIDE(__stop_svc_data = .); + } > RAM + + .fs_data : + { + PROVIDE(__start_fs_data = .); + KEEP(*(.fs_data)) + PROVIDE(__stop_fs_data = .); + } > RAM +} INSERT AFTER .data; + +INCLUDE "nrf52_common.ld" diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini index 4a23e7a119..619f86e1e2 100644 --- a/variants/wio-sdk-wm1110/platformio.ini +++ b/variants/wio-sdk-wm1110/platformio.ini @@ -11,6 +11,7 @@ board_level = extra build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. +board_build.ldscript = variants/wio-sdk-wm1110/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-sdk-wm1110> lib_deps = ${nrf52840_base.lib_deps} @@ -30,4 +31,4 @@ debug_extra_cmds = echo Running .gdbinit script commands 1 set useSoftDevice = false - end \ No newline at end of file + end diff --git a/variants/wio-sdk-wm1110/softdevice/ble.h b/variants/wio-sdk-wm1110/softdevice/ble.h new file mode 100644 index 0000000000..177b436ad8 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble.h @@ -0,0 +1,652 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON BLE SoftDevice Common + @{ + @defgroup ble_api Events, type definitions and API calls + @{ + + @brief Module independent events, type definitions and API calls for the BLE SoftDevice. + + */ + +#ifndef BLE_H__ +#define BLE_H__ + +#include "ble_err.h" +#include "ble_gap.h" +#include "ble_gatt.h" +#include "ble_gattc.h" +#include "ble_gatts.h" +#include "ble_l2cap.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_COMMON_ENUMERATIONS Enumerations + * @{ */ + +/** + * @brief Common API SVC numbers. + */ +enum BLE_COMMON_SVCS { + SD_BLE_ENABLE = BLE_SVC_BASE, /**< Enable and initialize the BLE stack */ + SD_BLE_EVT_GET, /**< Get an event from the pending events queue. */ + SD_BLE_UUID_VS_ADD, /**< Add a Vendor Specific base UUID. */ + SD_BLE_UUID_DECODE, /**< Decode UUID bytes. */ + SD_BLE_UUID_ENCODE, /**< Encode UUID bytes. */ + SD_BLE_VERSION_GET, /**< Get the local version information (company ID, Link Layer Version, Link Layer Subversion). */ + SD_BLE_USER_MEM_REPLY, /**< User Memory Reply. */ + SD_BLE_OPT_SET, /**< Set a BLE option. */ + SD_BLE_OPT_GET, /**< Get a BLE option. */ + SD_BLE_CFG_SET, /**< Add a configuration to the BLE stack. */ + SD_BLE_UUID_VS_REMOVE, /**< Remove a Vendor Specific base UUID. */ +}; + +/** + * @brief BLE Module Independent Event IDs. + */ +enum BLE_COMMON_EVTS { + BLE_EVT_USER_MEM_REQUEST = BLE_EVT_BASE + 0, /**< User Memory request. See @ref ble_evt_user_mem_request_t + \n Reply with @ref sd_ble_user_mem_reply. */ + BLE_EVT_USER_MEM_RELEASE = BLE_EVT_BASE + 1, /**< User Memory release. See @ref ble_evt_user_mem_release_t */ +}; + +/**@brief BLE Connection Configuration IDs. + * + * IDs that uniquely identify a connection configuration. + */ +enum BLE_CONN_CFGS { + BLE_CONN_CFG_GAP = BLE_CONN_CFG_BASE + 0, /**< BLE GAP specific connection configuration. */ + BLE_CONN_CFG_GATTC = BLE_CONN_CFG_BASE + 1, /**< BLE GATTC specific connection configuration. */ + BLE_CONN_CFG_GATTS = BLE_CONN_CFG_BASE + 2, /**< BLE GATTS specific connection configuration. */ + BLE_CONN_CFG_GATT = BLE_CONN_CFG_BASE + 3, /**< BLE GATT specific connection configuration. */ + BLE_CONN_CFG_L2CAP = BLE_CONN_CFG_BASE + 4, /**< BLE L2CAP specific connection configuration. */ +}; + +/**@brief BLE Common Configuration IDs. + * + * IDs that uniquely identify a common configuration. + */ +enum BLE_COMMON_CFGS { + BLE_COMMON_CFG_VS_UUID = BLE_CFG_BASE, /**< Vendor specific base UUID configuration */ +}; + +/**@brief Common Option IDs. + * IDs that uniquely identify a common option. + */ +enum BLE_COMMON_OPTS { + BLE_COMMON_OPT_PA_LNA = BLE_OPT_BASE + 0, /**< PA and LNA options */ + BLE_COMMON_OPT_CONN_EVT_EXT = BLE_OPT_BASE + 1, /**< Extended connection events option */ + BLE_COMMON_OPT_EXTENDED_RC_CAL = BLE_OPT_BASE + 2, /**< Extended RC calibration option */ +}; + +/** @} */ + +/** @addtogroup BLE_COMMON_DEFINES Defines + * @{ */ + +/** @brief Required pointer alignment for BLE Events. + */ +#define BLE_EVT_PTR_ALIGNMENT 4 + +/** @brief Leaves the maximum of the two arguments. + */ +#define BLE_MAX(a, b) ((a) < (b) ? (b) : (a)) + +/** @brief Maximum possible length for BLE Events. + * @note The highest value used for @ref ble_gatt_conn_cfg_t::att_mtu in any connection configuration shall be used as a + * parameter. If that value has not been configured for any connections then @ref BLE_GATT_ATT_MTU_DEFAULT must be used instead. + */ +#define BLE_EVT_LEN_MAX(ATT_MTU) \ + (offsetof(ble_evt_t, evt.gattc_evt.params.prim_srvc_disc_rsp.services) + ((ATT_MTU)-1) / 4 * sizeof(ble_gattc_service_t)) + +/** @defgroup BLE_USER_MEM_TYPES User Memory Types + * @{ */ +#define BLE_USER_MEM_TYPE_INVALID 0x00 /**< Invalid User Memory Types. */ +#define BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES 0x01 /**< User Memory for GATTS queued writes. */ +/** @} */ + +/** @defgroup BLE_UUID_VS_COUNTS Vendor Specific base UUID counts + * @{ + */ +#define BLE_UUID_VS_COUNT_DEFAULT 10 /**< Default VS UUID count. */ +#define BLE_UUID_VS_COUNT_MAX 254 /**< Maximum VS UUID count. */ +/** @} */ + +/** @defgroup BLE_COMMON_CFG_DEFAULTS Configuration defaults. + * @{ + */ +#define BLE_CONN_CFG_TAG_DEFAULT 0 /**< Default configuration tag, SoftDevice default connection configuration. */ + +/** @} */ + +/** @} */ + +/** @addtogroup BLE_COMMON_STRUCTURES Structures + * @{ */ + +/**@brief User Memory Block. */ +typedef struct { + uint8_t *p_mem; /**< Pointer to the start of the user memory block. */ + uint16_t len; /**< Length in bytes of the user memory block. */ +} ble_user_mem_block_t; + +/**@brief Event structure for @ref BLE_EVT_USER_MEM_REQUEST. */ +typedef struct { + uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ +} ble_evt_user_mem_request_t; + +/**@brief Event structure for @ref BLE_EVT_USER_MEM_RELEASE. */ +typedef struct { + uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ + ble_user_mem_block_t mem_block; /**< User memory block */ +} ble_evt_user_mem_release_t; + +/**@brief Event structure for events not associated with a specific function module. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which this event occurred. */ + union { + ble_evt_user_mem_request_t user_mem_request; /**< User Memory Request Event Parameters. */ + ble_evt_user_mem_release_t user_mem_release; /**< User Memory Release Event Parameters. */ + } params; /**< Event parameter union. */ +} ble_common_evt_t; + +/**@brief BLE Event header. */ +typedef struct { + uint16_t evt_id; /**< Value from a BLE__EVT series. */ + uint16_t evt_len; /**< Length in octets including this header. */ +} ble_evt_hdr_t; + +/**@brief Common BLE Event type, wrapping the module specific event reports. */ +typedef struct { + ble_evt_hdr_t header; /**< Event header. */ + union { + ble_common_evt_t common_evt; /**< Common Event, evt_id in BLE_EVT_* series. */ + ble_gap_evt_t gap_evt; /**< GAP originated event, evt_id in BLE_GAP_EVT_* series. */ + ble_gattc_evt_t gattc_evt; /**< GATT client originated event, evt_id in BLE_GATTC_EVT* series. */ + ble_gatts_evt_t gatts_evt; /**< GATT server originated event, evt_id in BLE_GATTS_EVT* series. */ + ble_l2cap_evt_t l2cap_evt; /**< L2CAP originated event, evt_id in BLE_L2CAP_EVT* series. */ + } evt; /**< Event union. */ +} ble_evt_t; + +/** + * @brief Version Information. + */ +typedef struct { + uint8_t version_number; /**< Link Layer Version number. See + https://www.bluetooth.org/en-us/specification/assigned-numbers/link-layer for assigned values. */ + uint16_t company_id; /**< Company ID, Nordic Semiconductor's company ID is 89 (0x0059) + (https://www.bluetooth.org/apps/content/Default.aspx?doc_id=49708). */ + uint16_t + subversion_number; /**< Link Layer Sub Version number, corresponds to the SoftDevice Config ID or Firmware ID (FWID). */ +} ble_version_t; + +/** + * @brief Configuration parameters for the PA and LNA. + */ +typedef struct { + uint8_t enable : 1; /**< Enable toggling for this amplifier */ + uint8_t active_high : 1; /**< Set the pin to be active high */ + uint8_t gpio_pin : 6; /**< The GPIO pin to toggle for this amplifier */ +} ble_pa_lna_cfg_t; + +/** + * @brief PA & LNA GPIO toggle configuration + * + * This option configures the SoftDevice to toggle pins when the radio is active for use with a power amplifier and/or + * a low noise amplifier. + * + * Toggling the pins is achieved by using two PPI channels and a GPIOTE channel. The hardware channel IDs are provided + * by the application and should be regarded as reserved as long as any PA/LNA toggling is enabled. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * @note Setting this option while the radio is in use (i.e. any of the roles are active) may have undefined consequences + * and must be avoided by the application. + */ +typedef struct { + ble_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */ + ble_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */ + + uint8_t ppi_ch_id_set; /**< PPI channel used for radio pin setting */ + uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */ + uint8_t gpiote_ch_id; /**< GPIOTE channel used for radio pin toggling */ +} ble_common_opt_pa_lna_t; + +/** + * @brief Configuration of extended BLE connection events. + * + * When enabled the SoftDevice will dynamically extend the connection event when possible. + * + * The connection event length is controlled by the connection configuration as set by @ref ble_gap_conn_cfg_t::event_length. + * The connection event can be extended if there is time to send another packet pair before the start of the next connection + * interval, and if there are no conflicts with other BLE roles requesting radio time. + * + * @note @ref sd_ble_opt_get is not supported for this option. + */ +typedef struct { + uint8_t enable : 1; /**< Enable extended BLE connection events, disabled by default. */ +} ble_common_opt_conn_evt_ext_t; + +/** + * @brief Enable/disable extended RC calibration. + * + * If extended RC calibration is enabled and the internal RC oscillator (@ref NRF_CLOCK_LF_SRC_RC) is used as the SoftDevice + * LFCLK source, the SoftDevice as a peripheral will by default try to increase the receive window if two consecutive packets + * are not received. If it turns out that the packets were not received due to clock drift, the RC calibration is started. + * This calibration comes in addition to the periodic calibration that is configured by @ref sd_softdevice_enable(). When + * using only peripheral connections, the periodic calibration can therefore be configured with a much longer interval as the + * peripheral will be able to detect and adjust automatically to clock drift, and calibrate on demand. + * + * If extended RC calibration is disabled and the internal RC oscillator is used as the SoftDevice LFCLK source, the + * RC oscillator is calibrated periodically as configured by @ref sd_softdevice_enable(). + * + * @note @ref sd_ble_opt_get is not supported for this option. + */ +typedef struct { + uint8_t enable : 1; /**< Enable extended RC calibration, enabled by default. */ +} ble_common_opt_extended_rc_cal_t; + +/**@brief Option structure for common options. */ +typedef union { + ble_common_opt_pa_lna_t pa_lna; /**< Parameters for controlling PA and LNA pin toggling. */ + ble_common_opt_conn_evt_ext_t conn_evt_ext; /**< Parameters for enabling extended connection events. */ + ble_common_opt_extended_rc_cal_t extended_rc_cal; /**< Parameters for enabling extended RC calibration. */ +} ble_common_opt_t; + +/**@brief Common BLE Option type, wrapping the module specific options. */ +typedef union { + ble_common_opt_t common_opt; /**< COMMON options, opt_id in @ref BLE_COMMON_OPTS series. */ + ble_gap_opt_t gap_opt; /**< GAP option, opt_id in @ref BLE_GAP_OPTS series. */ + ble_gattc_opt_t gattc_opt; /**< GATTC option, opt_id in @ref BLE_GATTC_OPTS series. */ +} ble_opt_t; + +/**@brief BLE connection configuration type, wrapping the module specific configurations, set with + * @ref sd_ble_cfg_set. + * + * @note Connection configurations don't have to be set. + * In the case that no configurations has been set, or fewer connection configurations has been set than enabled connections, + * the default connection configuration will be automatically added for the remaining connections. + * When creating connections with the default configuration, @ref BLE_CONN_CFG_TAG_DEFAULT should be used in + * place of @ref ble_conn_cfg_t::conn_cfg_tag. + * + * @sa sd_ble_gap_adv_start() + * @sa sd_ble_gap_connect() + * + * @mscs + * @mmsc{@ref BLE_CONN_CFG} + * @endmscs + + */ +typedef struct { + uint8_t conn_cfg_tag; /**< The application chosen tag it can use with the + @ref sd_ble_gap_adv_start() and @ref sd_ble_gap_connect() calls + to select this configuration when creating a connection. + Must be different for all connection configurations added and not @ref BLE_CONN_CFG_TAG_DEFAULT. */ + union { + ble_gap_conn_cfg_t gap_conn_cfg; /**< GAP connection configuration, cfg_id is @ref BLE_CONN_CFG_GAP. */ + ble_gattc_conn_cfg_t gattc_conn_cfg; /**< GATTC connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTC. */ + ble_gatts_conn_cfg_t gatts_conn_cfg; /**< GATTS connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTS. */ + ble_gatt_conn_cfg_t gatt_conn_cfg; /**< GATT connection configuration, cfg_id is @ref BLE_CONN_CFG_GATT. */ + ble_l2cap_conn_cfg_t l2cap_conn_cfg; /**< L2CAP connection configuration, cfg_id is @ref BLE_CONN_CFG_L2CAP. */ + } params; /**< Connection configuration union. */ +} ble_conn_cfg_t; + +/** + * @brief Configuration of Vendor Specific base UUIDs, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_PARAM Too many UUIDs configured. + */ +typedef struct { + uint8_t vs_uuid_count; /**< Number of 128-bit Vendor Specific base UUID bases to allocate memory for. + Default value is @ref BLE_UUID_VS_COUNT_DEFAULT. Maximum value is + @ref BLE_UUID_VS_COUNT_MAX. */ +} ble_common_cfg_vs_uuid_t; + +/**@brief Common BLE Configuration type, wrapping the common configurations. */ +typedef union { + ble_common_cfg_vs_uuid_t vs_uuid_cfg; /**< Vendor Specific base UUID configuration, cfg_id is @ref BLE_COMMON_CFG_VS_UUID. */ +} ble_common_cfg_t; + +/**@brief BLE Configuration type, wrapping the module specific configurations. */ +typedef union { + ble_conn_cfg_t conn_cfg; /**< Connection specific configurations, cfg_id in @ref BLE_CONN_CFGS series. */ + ble_common_cfg_t common_cfg; /**< Global common configurations, cfg_id in @ref BLE_COMMON_CFGS series. */ + ble_gap_cfg_t gap_cfg; /**< Global GAP configurations, cfg_id in @ref BLE_GAP_CFGS series. */ + ble_gatts_cfg_t gatts_cfg; /**< Global GATTS configuration, cfg_id in @ref BLE_GATTS_CFGS series. */ +} ble_cfg_t; + +/** @} */ + +/** @addtogroup BLE_COMMON_FUNCTIONS Functions + * @{ */ + +/**@brief Enable the BLE stack + * + * @param[in, out] p_app_ram_base Pointer to a variable containing the start address of the + * application RAM region (APP_RAM_BASE). On return, this will + * contain the minimum start address of the application RAM region + * required by the SoftDevice for this configuration. + * @warning After this call, the SoftDevice may generate several events. The list of events provided + * below require the application to initiate a SoftDevice API call. The corresponding API call + * is referenced in the event documentation. + * If the application fails to do so, the BLE connection may timeout, or the SoftDevice may stop + * communicating with the peer device. + * - @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST + * - @ref BLE_GAP_EVT_SEC_INFO_REQUEST + * - @ref BLE_GAP_EVT_SEC_REQUEST + * - @ref BLE_GAP_EVT_AUTH_KEY_REQUEST + * - @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST + * - @ref BLE_EVT_USER_MEM_REQUEST + * - @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST + * + * @note The memory requirement for a specific configuration will not increase between SoftDevices + * with the same major version number. + * + * @note At runtime the IC's RAM is split into 2 regions: The SoftDevice RAM region is located + * between 0x20000000 and APP_RAM_BASE-1 and the application's RAM region is located between + * APP_RAM_BASE and the start of the call stack. + * + * @details This call initializes the BLE stack, no BLE related function other than @ref + * sd_ble_cfg_set can be called before this one. + * + * @mscs + * @mmsc{@ref BLE_COMMON_ENABLE} + * @endmscs + * + * @retval ::NRF_SUCCESS The BLE stack has been initialized successfully. + * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized and cannot be reinitialized. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_NO_MEM One or more of the following is true: + * - The amount of memory assigned to the SoftDevice by *p_app_ram_base is not + * large enough to fit this configuration's memory requirement. Check *p_app_ram_base + * and set the start address of the application RAM region accordingly. + * - Dynamic part of the SoftDevice RAM region is larger then 64 kB which + * is currently not supported. + * @retval ::NRF_ERROR_RESOURCES The total number of L2CAP Channels configured using @ref sd_ble_cfg_set is too large. + */ +SVCALL(SD_BLE_ENABLE, uint32_t, sd_ble_enable(uint32_t *p_app_ram_base)); + +/**@brief Add configurations for the BLE stack + * + * @param[in] cfg_id Config ID, see @ref BLE_CONN_CFGS, @ref BLE_COMMON_CFGS, @ref + * BLE_GAP_CFGS or @ref BLE_GATTS_CFGS. + * @param[in] p_cfg Pointer to a ble_cfg_t structure containing the configuration value. + * @param[in] app_ram_base The start address of the application RAM region (APP_RAM_BASE). + * See @ref sd_ble_enable for details about APP_RAM_BASE. + * + * @note The memory requirement for a specific configuration will not increase between SoftDevices + * with the same major version number. + * + * @note If a configuration is set more than once, the last one set is the one that takes effect on + * @ref sd_ble_enable. + * + * @note Any part of the BLE stack that is NOT configured with @ref sd_ble_cfg_set will have default + * configuration. + * + * @note @ref sd_ble_cfg_set may be called at any time when the SoftDevice is enabled (see @ref + * sd_softdevice_enable) while the BLE part of the SoftDevice is not enabled (see @ref + * sd_ble_enable). + * + * @note Error codes for the configurations are described in the configuration structs. + * + * @mscs + * @mmsc{@ref BLE_COMMON_ENABLE} + * @endmscs + * + * @retval ::NRF_SUCCESS The configuration has been added successfully. + * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid cfg_id supplied. + * @retval ::NRF_ERROR_NO_MEM The amount of memory assigned to the SoftDevice by app_ram_base is not + * large enough to fit this configuration's memory requirement. + */ +SVCALL(SD_BLE_CFG_SET, uint32_t, sd_ble_cfg_set(uint32_t cfg_id, ble_cfg_t const *p_cfg, uint32_t app_ram_base)); + +/**@brief Get an event from the pending events queue. + * + * @param[out] p_dest Pointer to buffer to be filled in with an event, or NULL to retrieve the event length. + * This buffer must be aligned to the extend defined by @ref BLE_EVT_PTR_ALIGNMENT. + * The buffer should be interpreted as a @ref ble_evt_t struct. + * @param[in, out] p_len Pointer the length of the buffer, on return it is filled with the event length. + * + * @details This call allows the application to pull a BLE event from the BLE stack. The application is signaled that + * an event is available from the BLE stack by the triggering of the SD_EVT_IRQn interrupt. + * The application is free to choose whether to call this function from thread mode (main context) or directly from the + * Interrupt Service Routine that maps to SD_EVT_IRQn. In any case however, and because the BLE stack runs at a higher + * priority than the application, this function should be called in a loop (until @ref NRF_ERROR_NOT_FOUND is returned) + * every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the BLE stack. Failure to do so + * could potentially leave events in the internal queue without the application being aware of this fact. + * + * Sizing the p_dest buffer is equally important, since the application needs to provide all the memory necessary for the event to + * be copied into application memory. If the buffer provided is not large enough to fit the entire contents of the event, + * @ref NRF_ERROR_DATA_SIZE will be returned and the application can then call again with a larger buffer size. + * The maximum possible event length is defined by @ref BLE_EVT_LEN_MAX. The application may also "peek" the event length + * by providing p_dest as a NULL pointer and inspecting the value of *p_len upon return: + * + * \code + * uint16_t len; + * errcode = sd_ble_evt_get(NULL, &len); + * \endcode + * + * @mscs + * @mmsc{@ref BLE_COMMON_IRQ_EVT_MSC} + * @mmsc{@ref BLE_COMMON_THREAD_EVT_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Event pulled and stored into the supplied buffer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_NOT_FOUND No events ready to be pulled. + * @retval ::NRF_ERROR_DATA_SIZE Event ready but could not fit into the supplied buffer. + */ +SVCALL(SD_BLE_EVT_GET, uint32_t, sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len)); + +/**@brief Add a Vendor Specific base UUID. + * + * @details This call enables the application to add a Vendor Specific base UUID to the BLE stack's table, for later + * use with all other modules and APIs. This then allows the application to use the shorter, 24-bit @ref ble_uuid_t + * format when dealing with both 16-bit and 128-bit UUIDs without having to check for lengths and having split code + * paths. This is accomplished by extending the grouping mechanism that the Bluetooth SIG standard base UUID uses + * for all other 128-bit UUIDs. The type field in the @ref ble_uuid_t structure is an index (relative to + * @ref BLE_UUID_TYPE_VENDOR_BEGIN) to the table populated by multiple calls to this function, and the UUID field + * in the same structure contains the 2 bytes at indexes 12 and 13. The number of possible 128-bit UUIDs available to + * the application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536, + * although restricted to modifying bytes 12 and 13 for each of the entries in the supplied array. + * + * @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by + * the 16-bit uuid field in @ref ble_uuid_t. + * + * @note If a UUID is already present in the BLE stack's internal table, the corresponding index will be returned in + * p_uuid_type along with an @ref NRF_SUCCESS error code. + * + * @param[in] p_vs_uuid Pointer to a 16-octet (128-bit) little endian Vendor Specific base UUID disregarding + * bytes 12 and 13. + * @param[out] p_uuid_type Pointer to a uint8_t where the type field in @ref ble_uuid_t corresponding to this UUID will be + * stored. + * + * @retval ::NRF_SUCCESS Successfully added the Vendor Specific base UUID. + * @retval ::NRF_ERROR_INVALID_ADDR If p_vs_uuid or p_uuid_type is NULL or invalid. + * @retval ::NRF_ERROR_NO_MEM If there are no more free slots for VS UUIDs. + */ +SVCALL(SD_BLE_UUID_VS_ADD, uint32_t, sd_ble_uuid_vs_add(ble_uuid128_t const *p_vs_uuid, uint8_t *p_uuid_type)); + +/**@brief Remove a Vendor Specific base UUID. + * + * @details This call removes a Vendor Specific base UUID. This function allows + * the application to reuse memory allocated for Vendor Specific base UUIDs. + * + * @note Currently this function can only be called with a p_uuid_type set to @ref BLE_UUID_TYPE_UNKNOWN or the last added UUID + * type. + * + * @param[inout] p_uuid_type Pointer to a uint8_t where its value matches the UUID type in @ref ble_uuid_t::type to be removed. + * If the type is set to @ref BLE_UUID_TYPE_UNKNOWN, or the pointer is NULL, the last Vendor Specific + * base UUID will be removed. If the function returns successfully, the UUID type that was removed will + * be written back to @p p_uuid_type. If function returns with a failure, it contains the last type that + * is in use by the ATT Server. + * + * @retval ::NRF_SUCCESS Successfully removed the Vendor Specific base UUID. + * @retval ::NRF_ERROR_INVALID_ADDR If p_uuid_type is invalid. + * @retval ::NRF_ERROR_INVALID_PARAM If p_uuid_type points to a non-valid UUID type. + * @retval ::NRF_ERROR_FORBIDDEN If the Vendor Specific base UUID is in use by the ATT Server. + */ +SVCALL(SD_BLE_UUID_VS_REMOVE, uint32_t, sd_ble_uuid_vs_remove(uint8_t *p_uuid_type)); + +/** @brief Decode little endian raw UUID bytes (16-bit or 128-bit) into a 24 bit @ref ble_uuid_t structure. + * + * @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared + * to the corresponding ones in each entry of the table of Vendor Specific base UUIDs + * to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index + * relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type. + * + * @note If the UUID length supplied is 2, then the type set by this call will always be @ref BLE_UUID_TYPE_BLE. + * + * @param[in] uuid_le_len Length in bytes of the buffer pointed to by p_uuid_le (must be 2 or 16 bytes). + * @param[in] p_uuid_le Pointer pointing to little endian raw UUID bytes. + * @param[out] p_uuid Pointer to a @ref ble_uuid_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Successfully decoded into the @ref ble_uuid_t structure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid UUID length. + * @retval ::NRF_ERROR_NOT_FOUND For a 128-bit UUID, no match in the populated table of UUIDs. + */ +SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uint8_t const *p_uuid_le, ble_uuid_t *p_uuid)); + +/** @brief Encode a @ref ble_uuid_t structure into little endian raw UUID bytes (16-bit or 128-bit). + * + * @note The pointer to the destination buffer p_uuid_le may be NULL, in which case only the validity and size of p_uuid is + * computed. + * + * @param[in] p_uuid Pointer to a @ref ble_uuid_t structure that will be encoded into bytes. + * @param[out] p_uuid_le_len Pointer to a uint8_t that will be filled with the encoded length (2 or 16 bytes). + * @param[out] p_uuid_le Pointer to a buffer where the little endian raw UUID bytes (2 or 16) will be stored. + * + * @retval ::NRF_SUCCESS Successfully encoded into the buffer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid UUID type. + */ +SVCALL(SD_BLE_UUID_ENCODE, uint32_t, sd_ble_uuid_encode(ble_uuid_t const *p_uuid, uint8_t *p_uuid_le_len, uint8_t *p_uuid_le)); + +/**@brief Get Version Information. + * + * @details This call allows the application to get the BLE stack version information. + * + * @param[out] p_version Pointer to a ble_version_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Version information stored successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy (typically doing a locally-initiated disconnection procedure). + */ +SVCALL(SD_BLE_VERSION_GET, uint32_t, sd_ble_version_get(ble_version_t *p_version)); + +/**@brief Provide a user memory block. + * + * @note This call can only be used as a response to a @ref BLE_EVT_USER_MEM_REQUEST event issued to the application. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_block Pointer to a user memory block structure or NULL if memory is managed by the application. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully queued a response to the peer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid user memory block length supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection state or no user memory request pending. + */ +SVCALL(SD_BLE_USER_MEM_REPLY, uint32_t, sd_ble_user_mem_reply(uint16_t conn_handle, ble_user_mem_block_t const *p_block)); + +/**@brief Set a BLE option. + * + * @details This call allows the application to set the value of an option. + * + * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS, @ref BLE_GAP_OPTS, and @ref BLE_GATTC_OPTS. + * @param[in] p_opt Pointer to a @ref ble_opt_t structure containing the option value. + * + * @retval ::NRF_SUCCESS Option set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Unable to set the parameter at this time. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. + */ +SVCALL(SD_BLE_OPT_SET, uint32_t, sd_ble_opt_set(uint32_t opt_id, ble_opt_t const *p_opt)); + +/**@brief Get a BLE option. + * + * @details This call allows the application to retrieve the value of an option. + * + * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS and @ref BLE_GAP_OPTS. + * @param[out] p_opt Pointer to a ble_opt_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Option retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Unable to retrieve the parameter at this time. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. + * @retval ::NRF_ERROR_NOT_SUPPORTED This option is not supported. + * + */ +SVCALL(SD_BLE_OPT_GET, uint32_t, sd_ble_opt_get(uint32_t opt_id, ble_opt_t *p_opt)); + +/** @} */ +#ifdef __cplusplus +} +#endif +#endif /* BLE_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_err.h b/variants/wio-sdk-wm1110/softdevice/ble_err.h new file mode 100644 index 0000000000..d20f6d1416 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_err.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @addtogroup nrf_error + @{ + @ingroup BLE_COMMON + @} + + @defgroup ble_err General error codes + @{ + + @brief General error code definitions for the BLE API. + + @ingroup BLE_COMMON +*/ +#ifndef NRF_BLE_ERR_H__ +#define NRF_BLE_ERR_H__ + +#include "nrf_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* @defgroup BLE_ERRORS Error Codes + * @{ */ +#define BLE_ERROR_NOT_ENABLED (NRF_ERROR_STK_BASE_NUM + 0x001) /**< @ref sd_ble_enable has not been called. */ +#define BLE_ERROR_INVALID_CONN_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x002) /**< Invalid connection handle. */ +#define BLE_ERROR_INVALID_ATTR_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x003) /**< Invalid attribute handle. */ +#define BLE_ERROR_INVALID_ADV_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x004) /**< Invalid advertising handle. */ +#define BLE_ERROR_INVALID_ROLE (NRF_ERROR_STK_BASE_NUM + 0x005) /**< Invalid role. */ +#define BLE_ERROR_BLOCKED_BY_OTHER_LINKS \ + (NRF_ERROR_STK_BASE_NUM + 0x006) /**< The attempt to change link settings failed due to the scheduling of other links. */ +/** @} */ + +/** @defgroup BLE_ERROR_SUBRANGES Module specific error code subranges + * @brief Assignment of subranges for module specific error codes. + * @note For specific error codes, see ble_.h or ble_error_.h. + * @{ */ +#define NRF_L2CAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x100) /**< L2CAP specific errors. */ +#define NRF_GAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x200) /**< GAP specific errors. */ +#define NRF_GATTC_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x300) /**< GATT client specific errors. */ +#define NRF_GATTS_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x400) /**< GATT server specific errors. */ +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif + +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gap.h b/variants/wio-sdk-wm1110/softdevice/ble_gap.h new file mode 100644 index 0000000000..8ebdfa82b0 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_gap.h @@ -0,0 +1,2895 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GAP Generic Access Profile (GAP) + @{ + @brief Definitions and prototypes for the GAP interface. + */ + +#ifndef BLE_GAP_H__ +#define BLE_GAP_H__ + +#include "ble_err.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup BLE_GAP_ENUMERATIONS Enumerations + * @{ */ + +/**@brief GAP API SVC numbers. + */ +enum BLE_GAP_SVCS { + SD_BLE_GAP_ADDR_SET = BLE_GAP_SVC_BASE, /**< Set own Bluetooth Address. */ + SD_BLE_GAP_ADDR_GET = BLE_GAP_SVC_BASE + 1, /**< Get own Bluetooth Address. */ + SD_BLE_GAP_WHITELIST_SET = BLE_GAP_SVC_BASE + 2, /**< Set active whitelist. */ + SD_BLE_GAP_DEVICE_IDENTITIES_SET = BLE_GAP_SVC_BASE + 3, /**< Set device identity list. */ + SD_BLE_GAP_PRIVACY_SET = BLE_GAP_SVC_BASE + 4, /**< Set Privacy settings*/ + SD_BLE_GAP_PRIVACY_GET = BLE_GAP_SVC_BASE + 5, /**< Get Privacy settings*/ + SD_BLE_GAP_ADV_SET_CONFIGURE = BLE_GAP_SVC_BASE + 6, /**< Configure an advertising set. */ + SD_BLE_GAP_ADV_START = BLE_GAP_SVC_BASE + 7, /**< Start Advertising. */ + SD_BLE_GAP_ADV_STOP = BLE_GAP_SVC_BASE + 8, /**< Stop Advertising. */ + SD_BLE_GAP_CONN_PARAM_UPDATE = BLE_GAP_SVC_BASE + 9, /**< Connection Parameter Update. */ + SD_BLE_GAP_DISCONNECT = BLE_GAP_SVC_BASE + 10, /**< Disconnect. */ + SD_BLE_GAP_TX_POWER_SET = BLE_GAP_SVC_BASE + 11, /**< Set TX Power. */ + SD_BLE_GAP_APPEARANCE_SET = BLE_GAP_SVC_BASE + 12, /**< Set Appearance. */ + SD_BLE_GAP_APPEARANCE_GET = BLE_GAP_SVC_BASE + 13, /**< Get Appearance. */ + SD_BLE_GAP_PPCP_SET = BLE_GAP_SVC_BASE + 14, /**< Set PPCP. */ + SD_BLE_GAP_PPCP_GET = BLE_GAP_SVC_BASE + 15, /**< Get PPCP. */ + SD_BLE_GAP_DEVICE_NAME_SET = BLE_GAP_SVC_BASE + 16, /**< Set Device Name. */ + SD_BLE_GAP_DEVICE_NAME_GET = BLE_GAP_SVC_BASE + 17, /**< Get Device Name. */ + SD_BLE_GAP_AUTHENTICATE = BLE_GAP_SVC_BASE + 18, /**< Initiate Pairing/Bonding. */ + SD_BLE_GAP_SEC_PARAMS_REPLY = BLE_GAP_SVC_BASE + 19, /**< Reply with Security Parameters. */ + SD_BLE_GAP_AUTH_KEY_REPLY = BLE_GAP_SVC_BASE + 20, /**< Reply with an authentication key. */ + SD_BLE_GAP_LESC_DHKEY_REPLY = BLE_GAP_SVC_BASE + 21, /**< Reply with an LE Secure Connections DHKey. */ + SD_BLE_GAP_KEYPRESS_NOTIFY = BLE_GAP_SVC_BASE + 22, /**< Notify of a keypress during an authentication procedure. */ + SD_BLE_GAP_LESC_OOB_DATA_GET = BLE_GAP_SVC_BASE + 23, /**< Get the local LE Secure Connections OOB data. */ + SD_BLE_GAP_LESC_OOB_DATA_SET = BLE_GAP_SVC_BASE + 24, /**< Set the remote LE Secure Connections OOB data. */ + SD_BLE_GAP_ENCRYPT = BLE_GAP_SVC_BASE + 25, /**< Initiate encryption procedure. */ + SD_BLE_GAP_SEC_INFO_REPLY = BLE_GAP_SVC_BASE + 26, /**< Reply with Security Information. */ + SD_BLE_GAP_CONN_SEC_GET = BLE_GAP_SVC_BASE + 27, /**< Obtain connection security level. */ + SD_BLE_GAP_RSSI_START = BLE_GAP_SVC_BASE + 28, /**< Start reporting of changes in RSSI. */ + SD_BLE_GAP_RSSI_STOP = BLE_GAP_SVC_BASE + 29, /**< Stop reporting of changes in RSSI. */ + SD_BLE_GAP_SCAN_START = BLE_GAP_SVC_BASE + 30, /**< Start Scanning. */ + SD_BLE_GAP_SCAN_STOP = BLE_GAP_SVC_BASE + 31, /**< Stop Scanning. */ + SD_BLE_GAP_CONNECT = BLE_GAP_SVC_BASE + 32, /**< Connect. */ + SD_BLE_GAP_CONNECT_CANCEL = BLE_GAP_SVC_BASE + 33, /**< Cancel ongoing connection procedure. */ + SD_BLE_GAP_RSSI_GET = BLE_GAP_SVC_BASE + 34, /**< Get the last RSSI sample. */ + SD_BLE_GAP_PHY_UPDATE = BLE_GAP_SVC_BASE + 35, /**< Initiate or respond to a PHY Update Procedure. */ + SD_BLE_GAP_DATA_LENGTH_UPDATE = BLE_GAP_SVC_BASE + 36, /**< Initiate or respond to a Data Length Update Procedure. */ + SD_BLE_GAP_QOS_CHANNEL_SURVEY_START = BLE_GAP_SVC_BASE + 37, /**< Start Quality of Service (QoS) channel survey module. */ + SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP = BLE_GAP_SVC_BASE + 38, /**< Stop Quality of Service (QoS) channel survey module. */ + SD_BLE_GAP_ADV_ADDR_GET = BLE_GAP_SVC_BASE + 39, /**< Get the Address used on air while Advertising. */ + SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET = BLE_GAP_SVC_BASE + 40, /**< Get the next connection event counter. */ + SD_BLE_GAP_CONN_EVT_TRIGGER_START = BLE_GAP_SVC_BASE + 41, /** Start triggering a given task on connection event start. */ + SD_BLE_GAP_CONN_EVT_TRIGGER_STOP = + BLE_GAP_SVC_BASE + 42, /** Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. */ +}; + +/**@brief GAP Event IDs. + * IDs that uniquely identify an event coming from the stack to the application. + */ +enum BLE_GAP_EVTS { + BLE_GAP_EVT_CONNECTED = + BLE_GAP_EVT_BASE, /**< Connected to peer. \n See @ref ble_gap_evt_connected_t */ + BLE_GAP_EVT_DISCONNECTED = + BLE_GAP_EVT_BASE + 1, /**< Disconnected from peer. \n See @ref ble_gap_evt_disconnected_t. */ + BLE_GAP_EVT_CONN_PARAM_UPDATE = + BLE_GAP_EVT_BASE + 2, /**< Connection Parameters updated. \n See @ref ble_gap_evt_conn_param_update_t. */ + BLE_GAP_EVT_SEC_PARAMS_REQUEST = + BLE_GAP_EVT_BASE + 3, /**< Request to provide security parameters. \n Reply with @ref sd_ble_gap_sec_params_reply. + \n See @ref ble_gap_evt_sec_params_request_t. */ + BLE_GAP_EVT_SEC_INFO_REQUEST = + BLE_GAP_EVT_BASE + 4, /**< Request to provide security information. \n Reply with @ref sd_ble_gap_sec_info_reply. + \n See @ref ble_gap_evt_sec_info_request_t. */ + BLE_GAP_EVT_PASSKEY_DISPLAY = + BLE_GAP_EVT_BASE + 5, /**< Request to display a passkey to the user. \n In LESC Numeric Comparison, reply with @ref + sd_ble_gap_auth_key_reply. \n See @ref ble_gap_evt_passkey_display_t. */ + BLE_GAP_EVT_KEY_PRESSED = + BLE_GAP_EVT_BASE + 6, /**< Notification of a keypress on the remote device.\n See @ref ble_gap_evt_key_pressed_t */ + BLE_GAP_EVT_AUTH_KEY_REQUEST = + BLE_GAP_EVT_BASE + 7, /**< Request to provide an authentication key. \n Reply with @ref sd_ble_gap_auth_key_reply. + \n See @ref ble_gap_evt_auth_key_request_t. */ + BLE_GAP_EVT_LESC_DHKEY_REQUEST = + BLE_GAP_EVT_BASE + 8, /**< Request to calculate an LE Secure Connections DHKey. \n Reply with @ref + sd_ble_gap_lesc_dhkey_reply. \n See @ref ble_gap_evt_lesc_dhkey_request_t */ + BLE_GAP_EVT_AUTH_STATUS = + BLE_GAP_EVT_BASE + 9, /**< Authentication procedure completed with status. \n See @ref ble_gap_evt_auth_status_t. */ + BLE_GAP_EVT_CONN_SEC_UPDATE = + BLE_GAP_EVT_BASE + 10, /**< Connection security updated. \n See @ref ble_gap_evt_conn_sec_update_t. */ + BLE_GAP_EVT_TIMEOUT = + BLE_GAP_EVT_BASE + 11, /**< Timeout expired. \n See @ref ble_gap_evt_timeout_t. */ + BLE_GAP_EVT_RSSI_CHANGED = + BLE_GAP_EVT_BASE + 12, /**< RSSI report. \n See @ref ble_gap_evt_rssi_changed_t. */ + BLE_GAP_EVT_ADV_REPORT = + BLE_GAP_EVT_BASE + 13, /**< Advertising report. \n See @ref ble_gap_evt_adv_report_t. */ + BLE_GAP_EVT_SEC_REQUEST = + BLE_GAP_EVT_BASE + 14, /**< Security Request. \n Reply with @ref sd_ble_gap_authenticate +\n or with @ref sd_ble_gap_encrypt if required security information is available +. \n See @ref ble_gap_evt_sec_request_t. */ + BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 15, /**< Connection Parameter Update Request. \n Reply with @ref + sd_ble_gap_conn_param_update. \n See @ref ble_gap_evt_conn_param_update_request_t. */ + BLE_GAP_EVT_SCAN_REQ_REPORT = + BLE_GAP_EVT_BASE + 16, /**< Scan request report. \n See @ref ble_gap_evt_scan_req_report_t. */ + BLE_GAP_EVT_PHY_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 17, /**< PHY Update Request. \n Reply with @ref sd_ble_gap_phy_update. \n + See @ref ble_gap_evt_phy_update_request_t. */ + BLE_GAP_EVT_PHY_UPDATE = + BLE_GAP_EVT_BASE + 18, /**< PHY Update Procedure is complete. \n See @ref ble_gap_evt_phy_update_t. */ + BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 19, /**< Data Length Update Request. \n Reply with @ref + sd_ble_gap_data_length_update. \n See @ref ble_gap_evt_data_length_update_request_t. */ + BLE_GAP_EVT_DATA_LENGTH_UPDATE = + BLE_GAP_EVT_BASE + + 20, /**< LL Data Channel PDU payload length updated. \n See @ref ble_gap_evt_data_length_update_t. */ + BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT = + BLE_GAP_EVT_BASE + + 21, /**< Channel survey report. \n See @ref ble_gap_evt_qos_channel_survey_report_t. */ + BLE_GAP_EVT_ADV_SET_TERMINATED = + BLE_GAP_EVT_BASE + + 22, /**< Advertising set terminated. \n See @ref ble_gap_evt_adv_set_terminated_t. */ +}; + +/**@brief GAP Option IDs. + * IDs that uniquely identify a GAP option. + */ +enum BLE_GAP_OPTS { + BLE_GAP_OPT_CH_MAP = BLE_GAP_OPT_BASE, /**< Channel Map. @ref ble_gap_opt_ch_map_t */ + BLE_GAP_OPT_LOCAL_CONN_LATENCY = BLE_GAP_OPT_BASE + 1, /**< Local connection latency. @ref ble_gap_opt_local_conn_latency_t */ + BLE_GAP_OPT_PASSKEY = BLE_GAP_OPT_BASE + 2, /**< Set passkey. @ref ble_gap_opt_passkey_t */ + BLE_GAP_OPT_COMPAT_MODE_1 = BLE_GAP_OPT_BASE + 3, /**< Compatibility mode. @ref ble_gap_opt_compat_mode_1_t */ + BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT = + BLE_GAP_OPT_BASE + 4, /**< Set Authenticated payload timeout. @ref ble_gap_opt_auth_payload_timeout_t */ + BLE_GAP_OPT_SLAVE_LATENCY_DISABLE = + BLE_GAP_OPT_BASE + 5, /**< Disable slave latency. @ref ble_gap_opt_slave_latency_disable_t */ +}; + +/**@brief GAP Configuration IDs. + * + * IDs that uniquely identify a GAP configuration. + */ +enum BLE_GAP_CFGS { + BLE_GAP_CFG_ROLE_COUNT = BLE_GAP_CFG_BASE, /**< Role count configuration. */ + BLE_GAP_CFG_DEVICE_NAME = BLE_GAP_CFG_BASE + 1, /**< Device name configuration. */ + BLE_GAP_CFG_PPCP_INCL_CONFIG = BLE_GAP_CFG_BASE + 2, /**< Peripheral Preferred Connection Parameters characteristic + inclusion configuration. */ + BLE_GAP_CFG_CAR_INCL_CONFIG = BLE_GAP_CFG_BASE + 3, /**< Central Address Resolution characteristic + inclusion configuration. */ +}; + +/**@brief GAP TX Power roles. + */ +enum BLE_GAP_TX_POWER_ROLES { + BLE_GAP_TX_POWER_ROLE_ADV = 1, /**< Advertiser role. */ + BLE_GAP_TX_POWER_ROLE_SCAN_INIT = 2, /**< Scanner and initiator role. */ + BLE_GAP_TX_POWER_ROLE_CONN = 3, /**< Connection role. */ +}; + +/** @} */ + +/**@addtogroup BLE_GAP_DEFINES Defines + * @{ */ + +/**@defgroup BLE_ERRORS_GAP SVC return values specific to GAP + * @{ */ +#define BLE_ERROR_GAP_UUID_LIST_MISMATCH \ + (NRF_GAP_ERR_BASE + 0x000) /**< UUID list does not contain an integral number of UUIDs. */ +#define BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST \ + (NRF_GAP_ERR_BASE + 0x001) /**< Use of Whitelist not permitted with discoverable advertising. */ +#define BLE_ERROR_GAP_INVALID_BLE_ADDR \ + (NRF_GAP_ERR_BASE + 0x002) /**< The upper two bits of the address do not correspond to the specified address type. */ +#define BLE_ERROR_GAP_WHITELIST_IN_USE \ + (NRF_GAP_ERR_BASE + 0x003) /**< Attempt to modify the whitelist while already in use by another operation. */ +#define BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE \ + (NRF_GAP_ERR_BASE + 0x004) /**< Attempt to modify the device identity list while already in use by another operation. */ +#define BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE \ + (NRF_GAP_ERR_BASE + 0x005) /**< The device identity list contains entries with duplicate identity addresses. */ +/**@} */ + +/**@defgroup BLE_GAP_ROLES GAP Roles + * @{ */ +#define BLE_GAP_ROLE_INVALID 0x0 /**< Invalid Role. */ +#define BLE_GAP_ROLE_PERIPH 0x1 /**< Peripheral Role. */ +#define BLE_GAP_ROLE_CENTRAL 0x2 /**< Central Role. */ +/**@} */ + +/**@defgroup BLE_GAP_TIMEOUT_SOURCES GAP Timeout sources + * @{ */ +#define BLE_GAP_TIMEOUT_SRC_SCAN 0x01 /**< Scanning timeout. */ +#define BLE_GAP_TIMEOUT_SRC_CONN 0x02 /**< Connection timeout. */ +#define BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD 0x03 /**< Authenticated payload timeout. */ +/**@} */ + +/**@defgroup BLE_GAP_ADDR_TYPES GAP Address types + * @{ */ +#define BLE_GAP_ADDR_TYPE_PUBLIC 0x00 /**< Public (identity) address.*/ +#define BLE_GAP_ADDR_TYPE_RANDOM_STATIC 0x01 /**< Random static (identity) address. */ +#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE 0x02 /**< Random private resolvable address. */ +#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE 0x03 /**< Random private non-resolvable address. */ +#define BLE_GAP_ADDR_TYPE_ANONYMOUS \ + 0x7F /**< An advertiser may advertise without its address. \ + This type of advertising is called anonymous. */ +/**@} */ + +/**@brief The default interval in seconds at which a private address is refreshed. */ +#define BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S (900) /* 15 minutes. */ +/**@brief The maximum interval in seconds at which a private address can be refreshed. */ +#define BLE_GAP_MAX_PRIVATE_ADDR_CYCLE_INTERVAL_S (41400) /* 11 hours 30 minutes. */ + +/** @brief BLE address length. */ +#define BLE_GAP_ADDR_LEN (6) + +/**@defgroup BLE_GAP_PRIVACY_MODES Privacy modes + * @{ */ +#define BLE_GAP_PRIVACY_MODE_OFF 0x00 /**< Device will send and accept its identity address for its own address. */ +#define BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY 0x01 /**< Device will send and accept only private addresses for its own address. */ +#define BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY \ + 0x02 /**< Device will send and accept only private addresses for its own address, \ + and will not accept a peer using identity address as sender address when \ + the peer IRK is exchanged, non-zero and added to the identity list. */ +/**@} */ + +/** @brief Invalid power level. */ +#define BLE_GAP_POWER_LEVEL_INVALID 127 + +/** @brief Advertising set handle not set. */ +#define BLE_GAP_ADV_SET_HANDLE_NOT_SET (0xFF) + +/** @brief The default number of advertising sets. */ +#define BLE_GAP_ADV_SET_COUNT_DEFAULT (1) + +/** @brief The maximum number of advertising sets supported by this SoftDevice. */ +#define BLE_GAP_ADV_SET_COUNT_MAX (1) + +/**@defgroup BLE_GAP_ADV_SET_DATA_SIZES Advertising data sizes. + * @{ */ +#define BLE_GAP_ADV_SET_DATA_SIZE_MAX \ + (31) /**< Maximum data length for an advertising set. \ + If more advertising data is required, use extended advertising instead. */ +#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED \ + (255) /**< Maximum supported data length for an extended advertising set. */ + +#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED \ + (238) /**< Maximum supported data length for an extended connectable advertising set. */ +/**@}. */ + +/** @brief Set ID not available in advertising report. */ +#define BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE 0xFF + +/**@defgroup BLE_GAP_EVT_ADV_SET_TERMINATED_REASON GAP Advertising Set Terminated reasons + * @{ */ +#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT 0x01 /**< Timeout value reached. */ +#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED 0x02 /**< @ref ble_gap_adv_params_t::max_adv_evts was reached. */ +/**@} */ + +/**@defgroup BLE_GAP_AD_TYPE_DEFINITIONS GAP Advertising and Scan Response Data format + * @note Found at https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm + * @{ */ +#define BLE_GAP_AD_TYPE_FLAGS 0x01 /**< Flags for discoverability. */ +#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 /**< Partial list of 16 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 /**< Complete list of 16 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 /**< Partial list of 32 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 /**< Complete list of 32 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 /**< Partial list of 128 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 /**< Complete list of 128 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 /**< Short local device name. */ +#define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 /**< Complete local device name. */ +#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A /**< Transmit power level. */ +#define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D /**< Class of device. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E /**< Simple Pairing Hash C. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F /**< Simple Pairing Randomizer R. */ +#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 /**< Security Manager TK Value. */ +#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 /**< Security Manager Out Of Band Flags. */ +#define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 /**< Slave Connection Interval Range. */ +#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 /**< List of 16-bit Service Solicitation UUIDs. */ +#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 /**< List of 128-bit Service Solicitation UUIDs. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 /**< Service Data - 16-bit UUID. */ +#define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 /**< Public Target Address. */ +#define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 /**< Random Target Address. */ +#define BLE_GAP_AD_TYPE_APPEARANCE 0x19 /**< Appearance. */ +#define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A /**< Advertising Interval. */ +#define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B /**< LE Bluetooth Device Address. */ +#define BLE_GAP_AD_TYPE_LE_ROLE 0x1C /**< LE Role. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D /**< Simple Pairing Hash C-256. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E /**< Simple Pairing Randomizer R-256. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 /**< Service Data - 32-bit UUID. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 /**< Service Data - 128-bit UUID. */ +#define BLE_GAP_AD_TYPE_LESC_CONFIRMATION_VALUE 0x22 /**< LE Secure Connections Confirmation Value */ +#define BLE_GAP_AD_TYPE_LESC_RANDOM_VALUE 0x23 /**< LE Secure Connections Random Value */ +#define BLE_GAP_AD_TYPE_URI 0x24 /**< URI */ +#define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D /**< 3D Information Data. */ +#define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF /**< Manufacturer Specific Data. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_FLAGS GAP Advertisement Flags + * @{ */ +#define BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE (0x01) /**< LE Limited Discoverable Mode. */ +#define BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) /**< LE General Discoverable Mode. */ +#define BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) /**< BR/EDR not supported. */ +#define BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER (0x08) /**< Simultaneous LE and BR/EDR, Controller. */ +#define BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST (0x10) /**< Simultaneous LE and BR/EDR, Host. */ +#define BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE \ + (BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE | \ + BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE Limited Discoverable Mode, BR/EDR not supported. */ +#define BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE \ + (BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | \ + BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE General Discoverable Mode, BR/EDR not supported. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_INTERVALS GAP Advertising interval max and min + * @{ */ +#define BLE_GAP_ADV_INTERVAL_MIN 0x000020 /**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */ +#define BLE_GAP_ADV_INTERVAL_MAX 0x004000 /**< Maximum Advertising interval in 625 us units, i.e. 10.24 s. */ + /**@} */ + +/**@defgroup BLE_GAP_SCAN_INTERVALS GAP Scan interval max and min + * @{ */ +#define BLE_GAP_SCAN_INTERVAL_MIN 0x0004 /**< Minimum Scan interval in 625 us units, i.e. 2.5 ms. */ +#define BLE_GAP_SCAN_INTERVAL_MAX 0xFFFF /**< Maximum Scan interval in 625 us units, i.e. 40,959.375 s. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_WINDOW GAP Scan window max and min + * @{ */ +#define BLE_GAP_SCAN_WINDOW_MIN 0x0004 /**< Minimum Scan window in 625 us units, i.e. 2.5 ms. */ +#define BLE_GAP_SCAN_WINDOW_MAX 0xFFFF /**< Maximum Scan window in 625 us units, i.e. 40,959.375 s. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_TIMEOUT GAP Scan timeout max and min + * @{ */ +#define BLE_GAP_SCAN_TIMEOUT_MIN 0x0001 /**< Minimum Scan timeout in 10 ms units, i.e 10 ms. */ +#define BLE_GAP_SCAN_TIMEOUT_UNLIMITED 0x0000 /**< Continue to scan forever. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_BUFFER_SIZE GAP Minimum scanner buffer size + * + * Scan buffers are used for storing advertising data received from an advertiser. + * If ble_gap_scan_params_t::extended is set to 0, @ref BLE_GAP_SCAN_BUFFER_MIN is the minimum scan buffer length. + * else the minimum scan buffer size is @ref BLE_GAP_SCAN_BUFFER_EXTENDED_MIN. + * @{ */ +#define BLE_GAP_SCAN_BUFFER_MIN \ + (31) /**< Minimum data length for an \ + advertising set. */ +#define BLE_GAP_SCAN_BUFFER_MAX \ + (31) /**< Maximum data length for an \ + advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MIN \ + (255) /**< Minimum data length for an \ + extended advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX \ + (1650) /**< Maximum data length for an \ + extended advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED \ + (255) /**< Maximum supported data length for \ + an extended advertising set. */ +/** @} */ + +/**@defgroup BLE_GAP_ADV_TYPES GAP Advertising types + * + * Advertising types defined in Bluetooth Core Specification v5.0, Vol 6, Part B, Section 4.4.2. + * + * The maximum advertising data length is defined by @ref BLE_GAP_ADV_SET_DATA_SIZE_MAX. + * The maximum supported data length for an extended advertiser is defined by + * @ref BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED + * Note that some of the advertising types do not support advertising data. Non-scannable types do not support + * scan response data. + * + * @{ */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x01 /**< Connectable and scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE \ + 0x02 /**< Connectable non-scannable directed advertising \ + events. Advertising interval is less that 3.75 ms. \ + Use this type for fast reconnections. \ + @note Advertising data is not supported. */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x03 /**< Connectable non-scannable directed advertising \ + events. \ + @note Advertising data is not supported. */ +#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x04 /**< Non-connectable scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x05 /**< Non-connectable non-scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x06 /**< Connectable non-scannable undirected advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x07 /**< Connectable non-scannable directed advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x08 /**< Non-connectable scannable undirected advertising \ + events using extended advertising PDUs. \ + @note Only scan response data is supported. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED \ + 0x09 /**< Non-connectable scannable directed advertising \ + events using extended advertising PDUs. \ + @note Only scan response data is supported. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x0A /**< Non-connectable non-scannable undirected advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x0B /**< Non-connectable non-scannable directed advertising \ + events using extended advertising PDUs. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_FILTER_POLICIES GAP Advertising filter policies + * @{ */ +#define BLE_GAP_ADV_FP_ANY 0x00 /**< Allow scan requests and connect requests from any device. */ +#define BLE_GAP_ADV_FP_FILTER_SCANREQ 0x01 /**< Filter scan requests with whitelist. */ +#define BLE_GAP_ADV_FP_FILTER_CONNREQ 0x02 /**< Filter connect requests with whitelist. */ +#define BLE_GAP_ADV_FP_FILTER_BOTH 0x03 /**< Filter both scan and connect requests with whitelist. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_DATA_STATUS GAP Advertising data status + * @{ */ +#define BLE_GAP_ADV_DATA_STATUS_COMPLETE 0x00 /**< All data in the advertising event have been received. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA \ + 0x01 /**< More data to be received. \ + @note This value will only be used if \ + @ref ble_gap_scan_params_t::report_incomplete_evts and \ + @ref ble_gap_adv_report_type_t::extended_pdu are set to true. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED \ + 0x02 /**< Incomplete data. Buffer size insufficient to receive more. \ + @note This value will only be used if \ + @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MISSED \ + 0x03 /**< Failed to receive the remaining data. \ + @note This value will only be used if \ + @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ +/**@} */ + +/**@defgroup BLE_GAP_SCAN_FILTER_POLICIES GAP Scanner filter policies + * @{ */ +#define BLE_GAP_SCAN_FP_ACCEPT_ALL \ + 0x00 /**< Accept all advertising packets except directed advertising packets \ + not addressed to this device. */ +#define BLE_GAP_SCAN_FP_WHITELIST \ + 0x01 /**< Accept advertising packets from devices in the whitelist except directed \ + packets not addressed to this device. */ +#define BLE_GAP_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED \ + 0x02 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL. \ + In addition, accept directed advertising packets, where the advertiser's \ + address is a resolvable private address that cannot be resolved. */ +#define BLE_GAP_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED \ + 0x03 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST. \ + In addition, accept directed advertising packets, where the advertiser's \ + address is a resolvable private address that cannot be resolved. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_TIMEOUT_VALUES GAP Advertising timeout values in 10 ms units + * @{ */ +#define BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX \ + (128) /**< Maximum high duty advertising time in 10 ms units. Corresponds to 1.28 s. \ + */ +#define BLE_GAP_ADV_TIMEOUT_LIMITED_MAX \ + (18000) /**< Maximum advertising time in 10 ms units corresponding to TGAP(lim_adv_timeout) = 180 s in limited discoverable \ + mode. */ +#define BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED \ + (0) /**< Unlimited advertising in general discoverable mode. \ + For high duty cycle advertising, this corresponds to @ref BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX. */ +/**@} */ + +/**@defgroup BLE_GAP_DISC_MODES GAP Discovery modes + * @{ */ +#define BLE_GAP_DISC_MODE_NOT_DISCOVERABLE 0x00 /**< Not discoverable discovery Mode. */ +#define BLE_GAP_DISC_MODE_LIMITED 0x01 /**< Limited Discovery Mode. */ +#define BLE_GAP_DISC_MODE_GENERAL 0x02 /**< General Discovery Mode. */ +/**@} */ + +/**@defgroup BLE_GAP_IO_CAPS GAP IO Capabilities + * @{ */ +#define BLE_GAP_IO_CAPS_DISPLAY_ONLY 0x00 /**< Display Only. */ +#define BLE_GAP_IO_CAPS_DISPLAY_YESNO 0x01 /**< Display and Yes/No entry. */ +#define BLE_GAP_IO_CAPS_KEYBOARD_ONLY 0x02 /**< Keyboard Only. */ +#define BLE_GAP_IO_CAPS_NONE 0x03 /**< No I/O capabilities. */ +#define BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY 0x04 /**< Keyboard and Display. */ +/**@} */ + +/**@defgroup BLE_GAP_AUTH_KEY_TYPES GAP Authentication Key Types + * @{ */ +#define BLE_GAP_AUTH_KEY_TYPE_NONE 0x00 /**< No key (may be used to reject). */ +#define BLE_GAP_AUTH_KEY_TYPE_PASSKEY 0x01 /**< 6-digit Passkey. */ +#define BLE_GAP_AUTH_KEY_TYPE_OOB 0x02 /**< Out Of Band data. */ +/**@} */ + +/**@defgroup BLE_GAP_KP_NOT_TYPES GAP Keypress Notification Types + * @{ */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_START 0x00 /**< Passkey entry started. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_IN 0x01 /**< Passkey digit entered. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_OUT 0x02 /**< Passkey digit erased. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_CLEAR 0x03 /**< Passkey cleared. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_END 0x04 /**< Passkey entry completed. */ +/**@} */ + +/**@defgroup BLE_GAP_SEC_STATUS GAP Security status + * @{ */ +#define BLE_GAP_SEC_STATUS_SUCCESS 0x00 /**< Procedure completed with success. */ +#define BLE_GAP_SEC_STATUS_TIMEOUT 0x01 /**< Procedure timed out. */ +#define BLE_GAP_SEC_STATUS_PDU_INVALID 0x02 /**< Invalid PDU received. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE1_BEGIN 0x03 /**< Reserved for Future Use range #1 begin. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE1_END 0x80 /**< Reserved for Future Use range #1 end. */ +#define BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED 0x81 /**< Passkey entry failed (user canceled or other). */ +#define BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE 0x82 /**< Out of Band Key not available. */ +#define BLE_GAP_SEC_STATUS_AUTH_REQ 0x83 /**< Authentication requirements not met. */ +#define BLE_GAP_SEC_STATUS_CONFIRM_VALUE 0x84 /**< Confirm value failed. */ +#define BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP 0x85 /**< Pairing not supported. */ +#define BLE_GAP_SEC_STATUS_ENC_KEY_SIZE 0x86 /**< Encryption key size. */ +#define BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED 0x87 /**< Unsupported SMP command. */ +#define BLE_GAP_SEC_STATUS_UNSPECIFIED 0x88 /**< Unspecified reason. */ +#define BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS 0x89 /**< Too little time elapsed since last attempt. */ +#define BLE_GAP_SEC_STATUS_INVALID_PARAMS 0x8A /**< Invalid parameters. */ +#define BLE_GAP_SEC_STATUS_DHKEY_FAILURE 0x8B /**< DHKey check failure. */ +#define BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE 0x8C /**< Numeric Comparison failure. */ +#define BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG 0x8D /**< BR/EDR pairing in progress. */ +#define BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED 0x8E /**< BR/EDR Link Key cannot be used for LE keys. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE2_BEGIN 0x8F /**< Reserved for Future Use range #2 begin. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE2_END 0xFF /**< Reserved for Future Use range #2 end. */ +/**@} */ + +/**@defgroup BLE_GAP_SEC_STATUS_SOURCES GAP Security status sources + * @{ */ +#define BLE_GAP_SEC_STATUS_SOURCE_LOCAL 0x00 /**< Local failure. */ +#define BLE_GAP_SEC_STATUS_SOURCE_REMOTE 0x01 /**< Remote failure. */ +/**@} */ + +/**@defgroup BLE_GAP_CP_LIMITS GAP Connection Parameters Limits + * @{ */ +#define BLE_GAP_CP_MIN_CONN_INTVL_NONE 0xFFFF /**< No new minimum connection interval specified in connect parameters. */ +#define BLE_GAP_CP_MIN_CONN_INTVL_MIN \ + 0x0006 /**< Lowest minimum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ +#define BLE_GAP_CP_MIN_CONN_INTVL_MAX \ + 0x0C80 /**< Highest minimum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ + */ +#define BLE_GAP_CP_MAX_CONN_INTVL_NONE 0xFFFF /**< No new maximum connection interval specified in connect parameters. */ +#define BLE_GAP_CP_MAX_CONN_INTVL_MIN \ + 0x0006 /**< Lowest maximum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ +#define BLE_GAP_CP_MAX_CONN_INTVL_MAX \ + 0x0C80 /**< Highest maximum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ + */ +#define BLE_GAP_CP_SLAVE_LATENCY_MAX 0x01F3 /**< Highest slave latency permitted, in connection events. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_NONE 0xFFFF /**< No new supervision timeout specified in connect parameters. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN 0x000A /**< Lowest supervision timeout permitted, in units of 10 ms, i.e. 100 ms. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX 0x0C80 /**< Highest supervision timeout permitted, in units of 10 ms, i.e. 32 s. */ +/**@} */ + +/**@defgroup BLE_GAP_DEVNAME GAP device name defines. + * @{ */ +#define BLE_GAP_DEVNAME_DEFAULT "nRF5x" /**< Default device name value. */ +#define BLE_GAP_DEVNAME_DEFAULT_LEN 31 /**< Default number of octets in device name. */ +#define BLE_GAP_DEVNAME_MAX_LEN 248 /**< Maximum number of octets in device name. */ +/**@} */ + +/**@brief Disable RSSI events for connections */ +#define BLE_GAP_RSSI_THRESHOLD_INVALID 0xFF + +/**@defgroup BLE_GAP_PHYS GAP PHYs + * @{ */ +#define BLE_GAP_PHY_AUTO 0x00 /**< Automatic PHY selection. Refer @ref sd_ble_gap_phy_update for more information.*/ +#define BLE_GAP_PHY_1MBPS 0x01 /**< 1 Mbps PHY. */ +#define BLE_GAP_PHY_2MBPS 0x02 /**< 2 Mbps PHY. */ +#define BLE_GAP_PHY_CODED 0x04 /**< Coded PHY. */ +#define BLE_GAP_PHY_NOT_SET 0xFF /**< PHY is not configured. */ + +/**@brief Supported PHYs in connections, for scanning, and for advertising. */ +#define BLE_GAP_PHYS_SUPPORTED (BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_CODED) /**< All PHYs are supported. */ + +/**@} */ + +/**@defgroup BLE_GAP_CONN_SEC_MODE_SET_MACROS GAP attribute security requirement setters + * + * See @ref ble_gap_conn_sec_mode_t. + * @{ */ +/**@brief Set sec_mode pointed to by ptr to have no access rights.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(ptr) \ + do { \ + (ptr)->sm = 0; \ + (ptr)->lv = 0; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require no protection, open link.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_OPEN(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 1; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require encryption, but no MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 2; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require encryption and MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 3; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require LESC encryption and MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 4; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require signing or encryption, no MITM protection needed.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(ptr) \ + do { \ + (ptr)->sm = 2; \ + (ptr)->lv = 1; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require signing or encryption with MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 2; \ + (ptr)->lv = 2; \ + } while (0) +/**@} */ + +/**@brief GAP Security Random Number Length. */ +#define BLE_GAP_SEC_RAND_LEN 8 + +/**@brief GAP Security Key Length. */ +#define BLE_GAP_SEC_KEY_LEN 16 + +/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key Length. */ +#define BLE_GAP_LESC_P256_PK_LEN 64 + +/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman DHKey Length. */ +#define BLE_GAP_LESC_DHKEY_LEN 32 + +/**@brief GAP Passkey Length. */ +#define BLE_GAP_PASSKEY_LEN 6 + +/**@brief Maximum amount of addresses in the whitelist. */ +#define BLE_GAP_WHITELIST_ADDR_MAX_COUNT (8) + +/**@brief Maximum amount of identities in the device identities list. */ +#define BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT (8) + +/**@brief Default connection count for a configuration. */ +#define BLE_GAP_CONN_COUNT_DEFAULT (1) + +/**@defgroup BLE_GAP_EVENT_LENGTH GAP event length defines. + * @{ */ +#define BLE_GAP_EVENT_LENGTH_MIN (2) /**< Minimum event length, in 1.25 ms units. */ +#define BLE_GAP_EVENT_LENGTH_CODED_PHY_MIN (6) /**< The shortest event length in 1.25 ms units supporting LE Coded PHY. */ +#define BLE_GAP_EVENT_LENGTH_DEFAULT (3) /**< Default event length, in 1.25 ms units. */ +/**@} */ + +/**@defgroup BLE_GAP_ROLE_COUNT GAP concurrent connection count defines. + * @{ */ +#define BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT (1) /**< Default maximum number of connections concurrently acting as peripherals. */ +#define BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT (3) /**< Default maximum number of connections concurrently acting as centrals. */ +#define BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT \ + (1) /**< Default number of SMP instances shared between all connections acting as centrals. */ +#define BLE_GAP_ROLE_COUNT_COMBINED_MAX \ + (20) /**< Maximum supported number of concurrent connections in the peripheral and central roles combined. */ + +/**@} */ + +/**@brief Automatic data length parameter. */ +#define BLE_GAP_DATA_LENGTH_AUTO 0 + +/**@defgroup BLE_GAP_AUTH_PAYLOAD_TIMEOUT Authenticated payload timeout defines. + * @{ */ +#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX (48000) /**< Maximum authenticated payload timeout in 10 ms units, i.e. 8 minutes. */ +#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MIN (1) /**< Minimum authenticated payload timeout in 10 ms units, i.e. 10 ms. */ +/**@} */ + +/**@defgroup GAP_SEC_MODES GAP Security Modes + * @{ */ +#define BLE_GAP_SEC_MODE 0x00 /**< No key (may be used to reject). */ +/**@} */ + +/**@brief The total number of channels in Bluetooth Low Energy. */ +#define BLE_GAP_CHANNEL_COUNT (40) + +/**@defgroup BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS Quality of Service (QoS) Channel survey interval defines + * @{ */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS (0) /**< Continuous channel survey. */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MIN_US (7500) /**< Minimum channel survey interval in microseconds (7.5 ms). */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MAX_US (4000000) /**< Maximum channel survey interval in microseconds (4 s). */ + /**@} */ + +/** @} */ + +/** @defgroup BLE_GAP_CHAR_INCL_CONFIG GAP Characteristic inclusion configurations + * @{ + */ +#define BLE_GAP_CHAR_INCL_CONFIG_INCLUDE (0) /**< Include the characteristic in the Attribute Table */ +#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITH_SPACE \ + (1) /**< Do not include the characteristic in the Attribute table. \ + The SoftDevice will reserve the attribute handles \ + which are otherwise used for this characteristic. \ + By reserving the attribute handles it will be possible \ + to upgrade the SoftDevice without changing handle of the \ + Service Changed characteristic. */ +#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITHOUT_SPACE \ + (2) /**< Do not include the characteristic in the Attribute table. \ + The SoftDevice will not reserve the attribute handles \ + which are otherwise used for this characteristic. */ +/**@} */ + +/** @defgroup BLE_GAP_CHAR_INCL_CONFIG_DEFAULTS Characteristic inclusion default values + * @{ */ +#define BLE_GAP_PPCP_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ +#define BLE_GAP_CAR_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ +/**@} */ + +/** @defgroup BLE_GAP_SLAVE_LATENCY Slave latency configuration options + * @{ */ +#define BLE_GAP_SLAVE_LATENCY_ENABLE \ + (0) /**< Slave latency is enabled. When slave latency is enabled, \ + the slave will wake up every time it has data to send, \ + and/or every slave latency number of connection events. */ +#define BLE_GAP_SLAVE_LATENCY_DISABLE \ + (1) /**< Disable slave latency. The slave will wake up every connection event \ + regardless of the requested slave latency. \ + This option consumes the most power. */ +#define BLE_GAP_SLAVE_LATENCY_WAIT_FOR_ACK \ + (2) /**< The slave will wake up every connection event if it has not received \ + an ACK from the master for at least slave latency events. This \ + configuration may increase the power consumption in environments \ + with a lot of radio activity. */ +/**@} */ + +/**@addtogroup BLE_GAP_STRUCTURES Structures + * @{ */ + +/**@brief Advertising event properties. */ +typedef struct { + uint8_t type; /**< Advertising type. See @ref BLE_GAP_ADV_TYPES. */ + uint8_t anonymous : 1; /**< Omit advertiser's address from all PDUs. + @note Anonymous advertising is only available for + @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED and + @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED. */ + uint8_t include_tx_power : 1; /**< This feature is not supported on this SoftDevice. */ +} ble_gap_adv_properties_t; + +/**@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 Advertising Auxiliary Pointer. */ +typedef struct { + uint16_t aux_offset; /**< Time offset from the beginning of advertising packet to the auxiliary packet in 100 us units. */ + uint8_t aux_phy; /**< Indicates the PHY on which the auxiliary advertising packet is sent. See @ref BLE_GAP_PHYS. */ +} ble_gap_aux_pointer_t; + +/**@brief Bluetooth Low Energy address. */ +typedef struct { + uint8_t + addr_id_peer : 1; /**< Only valid for peer addresses. + This bit is set by the SoftDevice to indicate whether the address has been resolved from + a Resolvable Private Address (when the peer is using privacy). + If set to 1, @ref addr and @ref addr_type refer to the identity address of the resolved address. + + This bit is ignored when a variable of type @ref ble_gap_addr_t is used as input to API functions. + */ + uint8_t addr_type : 7; /**< See @ref BLE_GAP_ADDR_TYPES. */ + uint8_t addr[BLE_GAP_ADDR_LEN]; /**< 48-bit address, LSB format. + @ref addr is not used if @ref addr_type is @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. */ +} ble_gap_addr_t; + +/**@brief GAP connection parameters. + * + * @note When ble_conn_params_t is received in an event, both min_conn_interval and + * max_conn_interval will be equal to the connection interval set by the central. + * + * @note If both conn_sup_timeout and max_conn_interval are specified, then the following constraint applies: + * conn_sup_timeout * 4 > (1 + slave_latency) * max_conn_interval + * that corresponds to the following Bluetooth Spec requirement: + * The Supervision_Timeout in milliseconds shall be larger than + * (1 + Conn_Latency) * Conn_Interval_Max * 2, where Conn_Interval_Max is given in milliseconds. + */ +typedef struct { + uint16_t min_conn_interval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t max_conn_interval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t slave_latency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t conn_sup_timeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ +} ble_gap_conn_params_t; + +/**@brief GAP connection security modes. + * + * Security Mode 0 Level 0: No access permissions at all (this level is not defined by the Bluetooth Core specification).\n + * Security Mode 1 Level 1: No security is needed (aka open link).\n + * Security Mode 1 Level 2: Encrypted link required, MITM protection not necessary.\n + * Security Mode 1 Level 3: MITM protected encrypted link required.\n + * Security Mode 1 Level 4: LESC MITM protected encrypted link using a 128-bit strength encryption key required.\n + * Security Mode 2 Level 1: Signing or encryption required, MITM protection not necessary.\n + * Security Mode 2 Level 2: MITM protected signing required, unless link is MITM protected encrypted.\n + */ +typedef struct { + uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ + uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */ + +} ble_gap_conn_sec_mode_t; + +/**@brief GAP connection security status.*/ +typedef struct { + ble_gap_conn_sec_mode_t sec_mode; /**< Currently active security mode for this connection.*/ + uint8_t + encr_key_size; /**< Length of currently active encryption key, 7 to 16 octets (only applicable for bonding procedures). */ +} ble_gap_conn_sec_t; + +/**@brief Identity Resolving Key. */ +typedef struct { + uint8_t irk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing IRK. */ +} ble_gap_irk_t; + +/**@brief Channel mask (40 bits). + * Every channel is represented with a bit positioned as per channel index defined in Bluetooth Core Specification v5.0, + * Vol 6, Part B, Section 1.4.1. The LSB contained in array element 0 represents channel index 0, and bit 39 represents + * channel index 39. If a bit is set to 1, the channel is not used. + */ +typedef uint8_t ble_gap_ch_mask_t[5]; + +/**@brief GAP advertising parameters. */ +typedef struct { + ble_gap_adv_properties_t properties; /**< The properties of the advertising events. */ + ble_gap_addr_t const *p_peer_addr; /**< Address of a known peer. + @note ble_gap_addr_t::addr_type cannot be + @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. + - When privacy is enabled and the local device uses + @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE addresses, + the device identity list is searched for a matching entry. If + the local IRK for that device identity is set, the local IRK + for that device will be used to generate the advertiser address + field in the advertising packet. + - If @ref ble_gap_adv_properties_t::type is directed, this must be + set to the targeted scanner or initiator. If the peer address is + in the device identity list, the peer IRK for that device will be + used to generate @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE + target addresses used in the advertising event PDUs. */ + uint32_t interval; /**< Advertising interval in 625 us units. @sa BLE_GAP_ADV_INTERVALS. + @note If @ref ble_gap_adv_properties_t::type is set to + @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE + advertising, this parameter is ignored. */ + uint16_t duration; /**< Advertising duration in 10 ms units. When timeout is reached, + an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. + @sa BLE_GAP_ADV_TIMEOUT_VALUES. + @note The SoftDevice will always complete at least one advertising + event even if the duration is set too low. */ + uint8_t max_adv_evts; /**< Maximum advertising events that shall be sent prior to disabling + advertising. Setting the value to 0 disables the limitation. When + the count of advertising events specified by this parameter + (if not 0) is reached, advertising will be automatically stopped + and an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised + @note If @ref ble_gap_adv_properties_t::type is set to + @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE, + this parameter is ignored. */ + ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. + At least one of the primary channels, that is channel index 37-39, must be used. + Masking away secondary advertising channels is not supported. */ + uint8_t filter_policy; /**< Filter Policy. @sa BLE_GAP_ADV_FILTER_POLICIES. */ + uint8_t primary_phy; /**< Indicates the PHY on which the primary advertising channel packets + are transmitted. If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS + will be used. + Valid values are @ref BLE_GAP_PHY_1MBPS and @ref BLE_GAP_PHY_CODED. + @note The primary_phy shall indicate @ref BLE_GAP_PHY_1MBPS if + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t secondary_phy; /**< Indicates the PHY on which the secondary advertising channel packets + are transmitted. + If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS will be used. + Valid values are + @ref BLE_GAP_PHY_1MBPS, @ref BLE_GAP_PHY_2MBPS, and @ref BLE_GAP_PHY_CODED. + If @ref ble_gap_adv_properties_t::type is an extended advertising type + and connectable, this is the PHY that will be used to establish a + connection and send AUX_ADV_IND packets on. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t set_id : 4; /**< The advertising set identifier distinguishes this advertising set from other + advertising sets transmitted by this and other devices. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t scan_req_notification : 1; /**< Enable scan request notifications for this advertising set. When a + scan request is received and the scanner address is allowed + by the filter policy, @ref BLE_GAP_EVT_SCAN_REQ_REPORT is raised. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is a non-scannable + advertising type. */ +} ble_gap_adv_params_t; + +/**@brief GAP advertising data buffers. + * + * The application must provide the buffers for advertisement. The memory shall reside in application RAM, and + * shall never be modified while advertising. The data shall be kept alive until either: + * - @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. + * - @ref BLE_GAP_EVT_CONNECTED is raised with @ref ble_gap_evt_connected_t::adv_handle set to the corresponding + * advertising handle. + * - Advertising is stopped. + * - Advertising data is changed. + * To update advertising data while advertising, provide new buffers to @ref sd_ble_gap_adv_set_configure. */ +typedef struct { + ble_data_t adv_data; /**< Advertising data. + @note + Advertising data can only be specified for a @ref ble_gap_adv_properties_t::type + that is allowed to contain advertising data. */ + ble_data_t scan_rsp_data; /**< Scan response data. + @note + Scan response data can only be specified for a @ref ble_gap_adv_properties_t::type + that is scannable. */ +} ble_gap_adv_data_t; + +/**@brief GAP scanning parameters. */ +typedef struct { + uint8_t extended : 1; /**< If 1, the scanner will accept extended advertising packets. + If set to 0, the scanner will not receive advertising packets + on secondary advertising channels, and will not be able + to receive long advertising PDUs. */ + uint8_t report_incomplete_evts : 1; /**< If 1, events of type @ref ble_gap_evt_adv_report_t may have + @ref ble_gap_adv_report_type_t::status set to + @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. + This parameter is ignored when used with @ref sd_ble_gap_connect + @note This may be used to abort receiving more packets from an extended + advertising event, and is only available for extended + scanning, see @ref sd_ble_gap_scan_start. + @note This feature is not supported by this SoftDevice. */ + uint8_t active : 1; /**< If 1, perform active scanning by sending scan requests. + This parameter is ignored when used with @ref sd_ble_gap_connect. */ + uint8_t filter_policy : 2; /**< Scanning filter policy. @sa BLE_GAP_SCAN_FILTER_POLICIES. + @note Only @ref BLE_GAP_SCAN_FP_ACCEPT_ALL and + @ref BLE_GAP_SCAN_FP_WHITELIST are valid when used with + @ref sd_ble_gap_connect */ + uint8_t scan_phys; /**< Bitfield of PHYs to scan on. If set to @ref BLE_GAP_PHY_AUTO, + scan_phys will default to @ref BLE_GAP_PHY_1MBPS. + - If @ref ble_gap_scan_params_t::extended is set to 0, the only + supported PHY is @ref BLE_GAP_PHY_1MBPS. + - When used with @ref sd_ble_gap_scan_start, + the bitfield indicates the PHYs the scanner will use for scanning + on primary advertising channels. The scanner will accept + @ref BLE_GAP_PHYS_SUPPORTED as secondary advertising channel PHYs. + - When used with @ref sd_ble_gap_connect, the bitfield indicates + the PHYs the initiator will use for scanning on primary advertising + channels. The initiator will accept connections initiated on either + of the @ref BLE_GAP_PHYS_SUPPORTED PHYs. + If scan_phys contains @ref BLE_GAP_PHY_1MBPS and/or @ref BLE_GAP_PHY_2MBPS, + the primary scan PHY is @ref BLE_GAP_PHY_1MBPS. + If scan_phys also contains @ref BLE_GAP_PHY_CODED, the primary scan + PHY will also contain @ref BLE_GAP_PHY_CODED. If the only scan PHY is + @ref BLE_GAP_PHY_CODED, the primary scan PHY is + @ref BLE_GAP_PHY_CODED only. */ + uint16_t interval; /**< Scan interval in 625 us units. @sa BLE_GAP_SCAN_INTERVALS. */ + uint16_t window; /**< Scan window in 625 us units. @sa BLE_GAP_SCAN_WINDOW. + If scan_phys contains both @ref BLE_GAP_PHY_1MBPS and + @ref BLE_GAP_PHY_CODED interval shall be larger than or + equal to twice the scan window. */ + uint16_t timeout; /**< Scan timeout in 10 ms units. @sa BLE_GAP_SCAN_TIMEOUT. */ + ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. + At least one of the primary channels, that is channel index 37-39, must be + set to 0. + Masking away secondary channels is not supported. */ +} ble_gap_scan_params_t; + +/**@brief Privacy. + * + * The privacy feature provides a way for the device to avoid being tracked over a period of time. + * The privacy feature, when enabled, hides the local device identity and replaces it with a private address + * that is automatically refreshed at a specified interval. + * + * If a device still wants to be recognized by other peers, it needs to share it's Identity Resolving Key (IRK). + * With this key, a device can generate a random private address that can only be recognized by peers in possession of that + * key, and devices can establish connections without revealing their real identities. + * + * Both network privacy (@ref BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY) and device privacy (@ref + * BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY) are supported. + * + * @note If the device IRK is updated, the new IRK becomes the one to be distributed in all + * bonding procedures performed after @ref sd_ble_gap_privacy_set returns. + * The IRK distributed during bonding procedure is the device IRK that is active when @ref sd_ble_gap_sec_params_reply is + * called. + */ +typedef struct { + uint8_t privacy_mode; /**< Privacy mode, see @ref BLE_GAP_PRIVACY_MODES. Default is @ref BLE_GAP_PRIVACY_MODE_OFF. */ + uint8_t private_addr_type; /**< The private address type must be either @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE or + @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE. */ + uint16_t private_addr_cycle_s; /**< Private address cycle interval in seconds. Providing an address cycle value of 0 will use + the default value defined by @ref BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S. */ + ble_gap_irk_t + *p_device_irk; /**< When used as input, pointer to IRK structure that will be used as the default IRK. If NULL, the device + default IRK will be used. When used as output, pointer to IRK structure where the current default IRK + will be written to. If NULL, this argument is ignored. By default, the default IRK is used to generate + random private resolvable addresses for the local device unless instructed otherwise. */ +} ble_gap_privacy_params_t; + +/**@brief PHY preferences for TX and RX + * @note tx_phys and rx_phys are bit fields. Multiple bits can be set in them to indicate multiple preferred PHYs for each + * direction. + * @code + * p_gap_phys->tx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; + * p_gap_phys->rx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; + * @endcode + * + */ +typedef struct { + uint8_t tx_phys; /**< Preferred transmit PHYs, see @ref BLE_GAP_PHYS. */ + uint8_t rx_phys; /**< Preferred receive PHYs, see @ref BLE_GAP_PHYS. */ +} ble_gap_phys_t; + +/** @brief Keys that can be exchanged during a bonding procedure. */ +typedef struct { + uint8_t enc : 1; /**< Long Term Key and Master Identification. */ + uint8_t id : 1; /**< Identity Resolving Key and Identity Address Information. */ + uint8_t sign : 1; /**< Connection Signature Resolving Key. */ + uint8_t link : 1; /**< Derive the Link Key from the LTK. */ +} ble_gap_sec_kdist_t; + +/**@brief GAP security parameters. */ +typedef struct { + uint8_t bond : 1; /**< Perform bonding. */ + uint8_t mitm : 1; /**< Enable Man In The Middle protection. */ + uint8_t lesc : 1; /**< Enable LE Secure Connection pairing. */ + uint8_t keypress : 1; /**< Enable generation of keypress notifications. */ + uint8_t io_caps : 3; /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */ + uint8_t oob : 1; /**< The OOB data flag. + - In LE legacy pairing, this flag is set if a device has out of band authentication data. + The OOB method is used if both of the devices have out of band authentication data. + - In LE Secure Connections pairing, this flag is set if a device has the peer device's out of band + authentication data. The OOB method is used if at least one device has the peer device's OOB data + available. */ + uint8_t + min_key_size; /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */ + uint8_t max_key_size; /**< Maximum encryption key size in octets between min_key_size and 16. */ + ble_gap_sec_kdist_t kdist_own; /**< Key distribution bitmap: keys that the local device will distribute. */ + ble_gap_sec_kdist_t kdist_peer; /**< Key distribution bitmap: keys that the remote device will distribute. */ +} ble_gap_sec_params_t; + +/**@brief GAP Encryption Information. */ +typedef struct { + uint8_t ltk[BLE_GAP_SEC_KEY_LEN]; /**< Long Term Key. */ + uint8_t lesc : 1; /**< Key generated using LE Secure Connections. */ + uint8_t auth : 1; /**< Authenticated Key. */ + uint8_t ltk_len : 6; /**< LTK length in octets. */ +} ble_gap_enc_info_t; + +/**@brief GAP Master Identification. */ +typedef struct { + uint16_t ediv; /**< Encrypted Diversifier. */ + uint8_t rand[BLE_GAP_SEC_RAND_LEN]; /**< Random Number. */ +} ble_gap_master_id_t; + +/**@brief GAP Signing Information. */ +typedef struct { + uint8_t csrk[BLE_GAP_SEC_KEY_LEN]; /**< Connection Signature Resolving Key. */ +} ble_gap_sign_info_t; + +/**@brief GAP LE Secure Connections P-256 Public Key. */ +typedef struct { + uint8_t pk[BLE_GAP_LESC_P256_PK_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key. Stored in the + standard SMP protocol format: {X,Y} both in little-endian. */ +} ble_gap_lesc_p256_pk_t; + +/**@brief GAP LE Secure Connections DHKey. */ +typedef struct { + uint8_t key[BLE_GAP_LESC_DHKEY_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman Key. Stored in little-endian. */ +} ble_gap_lesc_dhkey_t; + +/**@brief GAP LE Secure Connections OOB data. */ +typedef struct { + ble_gap_addr_t addr; /**< Bluetooth address of the device. */ + uint8_t r[BLE_GAP_SEC_KEY_LEN]; /**< Random Number. */ + uint8_t c[BLE_GAP_SEC_KEY_LEN]; /**< Confirm Value. */ +} ble_gap_lesc_oob_data_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONNECTED. */ +typedef struct { + ble_gap_addr_t + peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref + ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ + uint8_t role; /**< BLE role for this connection, see @ref BLE_GAP_ROLES */ + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ + uint8_t adv_handle; /**< Advertising handle in which advertising has ended. + This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ + ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated + advertising set. The advertising buffers provided in + @ref sd_ble_gap_adv_set_configure are now released. + This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ +} ble_gap_evt_connected_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DISCONNECTED. */ +typedef struct { + uint8_t reason; /**< HCI error code, see @ref BLE_HCI_STATUS_CODES. */ +} ble_gap_evt_disconnected_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE. */ +typedef struct { + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ +} ble_gap_evt_conn_param_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST. */ +typedef struct { + ble_gap_phys_t peer_preferred_phys; /**< The PHYs the peer prefers to use. */ +} ble_gap_evt_phy_update_request_t; + +/**@brief Event Structure for @ref BLE_GAP_EVT_PHY_UPDATE. */ +typedef struct { + uint8_t status; /**< Status of the procedure, see @ref BLE_HCI_STATUS_CODES.*/ + uint8_t tx_phy; /**< TX PHY for this connection, see @ref BLE_GAP_PHYS. */ + uint8_t rx_phy; /**< RX PHY for this connection, see @ref BLE_GAP_PHYS. */ +} ble_gap_evt_phy_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. */ +typedef struct { + ble_gap_sec_params_t peer_params; /**< Initiator Security Parameters. */ +} ble_gap_evt_sec_params_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_INFO_REQUEST. */ +typedef struct { + ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. */ + ble_gap_master_id_t master_id; /**< Master Identification for LTK lookup. */ + uint8_t enc_info : 1; /**< If 1, Encryption Information required. */ + uint8_t id_info : 1; /**< If 1, Identity Information required. */ + uint8_t sign_info : 1; /**< If 1, Signing Information required. */ +} ble_gap_evt_sec_info_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_PASSKEY_DISPLAY. */ +typedef struct { + uint8_t passkey[BLE_GAP_PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */ + uint8_t match_request : 1; /**< If 1 requires the application to report the match using @ref sd_ble_gap_auth_key_reply + with either @ref BLE_GAP_AUTH_KEY_TYPE_NONE if there is no match or + @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY if there is a match. */ +} ble_gap_evt_passkey_display_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_KEY_PRESSED. */ +typedef struct { + uint8_t kp_not; /**< Keypress notification type, see @ref BLE_GAP_KP_NOT_TYPES. */ +} ble_gap_evt_key_pressed_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_KEY_REQUEST. */ +typedef struct { + uint8_t key_type; /**< See @ref BLE_GAP_AUTH_KEY_TYPES. */ +} ble_gap_evt_auth_key_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST. */ +typedef struct { + ble_gap_lesc_p256_pk_t + *p_pk_peer; /**< LE Secure Connections remote P-256 Public Key. This will point to the application-supplied memory + inside the keyset during the call to @ref sd_ble_gap_sec_params_reply. */ + uint8_t oobd_req : 1; /**< LESC OOB data required. A call to @ref sd_ble_gap_lesc_oob_data_set is required to complete the + procedure. */ +} ble_gap_evt_lesc_dhkey_request_t; + +/**@brief Security levels supported. + * @note See Bluetooth Specification Version 4.2 Volume 3, Part C, Chapter 10, Section 10.2.1. + */ +typedef struct { + uint8_t lv1 : 1; /**< If 1: Level 1 is supported. */ + uint8_t lv2 : 1; /**< If 1: Level 2 is supported. */ + uint8_t lv3 : 1; /**< If 1: Level 3 is supported. */ + uint8_t lv4 : 1; /**< If 1: Level 4 is supported. */ +} ble_gap_sec_levels_t; + +/**@brief Encryption Key. */ +typedef struct { + ble_gap_enc_info_t enc_info; /**< Encryption Information. */ + ble_gap_master_id_t master_id; /**< Master Identification. */ +} ble_gap_enc_key_t; + +/**@brief Identity Key. */ +typedef struct { + ble_gap_irk_t id_info; /**< Identity Resolving Key. */ + ble_gap_addr_t id_addr_info; /**< Identity Address. */ +} ble_gap_id_key_t; + +/**@brief Security Keys. */ +typedef struct { + ble_gap_enc_key_t *p_enc_key; /**< Encryption Key, or NULL. */ + ble_gap_id_key_t *p_id_key; /**< Identity Key, or NULL. */ + ble_gap_sign_info_t *p_sign_key; /**< Signing Key, or NULL. */ + ble_gap_lesc_p256_pk_t *p_pk; /**< LE Secure Connections P-256 Public Key. When in debug mode the application must use the + value defined in the Core Bluetooth Specification v4.2 Vol.3, Part H, Section 2.3.5.6.1 */ +} ble_gap_sec_keys_t; + +/**@brief Security key set for both local and peer keys. */ +typedef struct { + ble_gap_sec_keys_t keys_own; /**< Keys distributed by the local device. For LE Secure Connections the encryption key will be + generated locally and will always be stored if bonding. */ + ble_gap_sec_keys_t + keys_peer; /**< Keys distributed by the remote device. For LE Secure Connections, p_enc_key must always be NULL. */ +} ble_gap_sec_keyset_t; + +/**@brief Data Length Update Procedure parameters. */ +typedef struct { + uint16_t max_tx_octets; /**< Maximum number of payload octets that a Controller supports for transmission of a single Link + Layer Data Channel PDU. */ + uint16_t max_rx_octets; /**< Maximum number of payload octets that a Controller supports for reception of a single Link Layer + Data Channel PDU. */ + uint16_t max_tx_time_us; /**< Maximum time, in microseconds, that a Controller supports for transmission of a single Link + Layer Data Channel PDU. */ + uint16_t max_rx_time_us; /**< Maximum time, in microseconds, that a Controller supports for reception of a single Link Layer + Data Channel PDU. */ +} ble_gap_data_length_params_t; + +/**@brief Data Length Update Procedure local limitation. */ +typedef struct { + uint16_t tx_payload_limited_octets; /**< If > 0, the requested TX packet length is too long by this many octets. */ + uint16_t rx_payload_limited_octets; /**< If > 0, the requested RX packet length is too long by this many octets. */ + uint16_t tx_rx_time_limited_us; /**< If > 0, the requested combination of TX and RX packet lengths is too long by this many + microseconds. */ +} ble_gap_data_length_limitation_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_STATUS. */ +typedef struct { + uint8_t auth_status; /**< Authentication status, see @ref BLE_GAP_SEC_STATUS. */ + uint8_t error_src : 2; /**< On error, source that caused the failure, see @ref BLE_GAP_SEC_STATUS_SOURCES. */ + uint8_t bonded : 1; /**< Procedure resulted in a bond. */ + uint8_t lesc : 1; /**< Procedure resulted in a LE Secure Connection. */ + ble_gap_sec_levels_t sm1_levels; /**< Levels supported in Security Mode 1. */ + ble_gap_sec_levels_t sm2_levels; /**< Levels supported in Security Mode 2. */ + ble_gap_sec_kdist_t kdist_own; /**< Bitmap stating which keys were exchanged (distributed) by the local device. If bonding + with LE Secure Connections, the enc bit will be always set. */ + ble_gap_sec_kdist_t kdist_peer; /**< Bitmap stating which keys were exchanged (distributed) by the remote device. If bonding + with LE Secure Connections, the enc bit will never be set. */ +} ble_gap_evt_auth_status_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_SEC_UPDATE. */ +typedef struct { + ble_gap_conn_sec_t conn_sec; /**< Connection security level. */ +} ble_gap_evt_conn_sec_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Source of timeout event, see @ref BLE_GAP_TIMEOUT_SOURCES. */ + union { + ble_data_t adv_report_buffer; /**< If source is set to @ref BLE_GAP_TIMEOUT_SRC_SCAN, the released + scan buffer is contained in this field. */ + } params; /**< Event Parameters. */ +} ble_gap_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_RSSI_CHANGED. */ +typedef struct { + int8_t rssi; /**< Received Signal Strength Indication in dBm. + @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature + measurement. */ + uint8_t ch_index; /**< Data Channel Index on which the Signal Strength is measured (0-36). */ +} ble_gap_evt_rssi_changed_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_ADV_SET_TERMINATED */ +typedef struct { + uint8_t reason; /**< Reason for why the advertising set terminated. See + @ref BLE_GAP_EVT_ADV_SET_TERMINATED_REASON. */ + uint8_t adv_handle; /**< Advertising handle in which advertising has ended. */ + uint8_t num_completed_adv_events; /**< If @ref ble_gap_adv_params_t::max_adv_evts was not set to 0, + this field indicates the number of completed advertising events. */ + ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated + advertising set. The advertising buffers provided in + @ref sd_ble_gap_adv_set_configure are now released. */ +} ble_gap_evt_adv_set_terminated_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; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_REQUEST. */ +typedef struct { + uint8_t bond : 1; /**< Perform bonding. */ + uint8_t mitm : 1; /**< Man In The Middle protection requested. */ + uint8_t lesc : 1; /**< LE Secure Connections requested. */ + uint8_t keypress : 1; /**< Generation of keypress notifications requested. */ +} ble_gap_evt_sec_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST. */ +typedef struct { + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ +} ble_gap_evt_conn_param_update_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SCAN_REQ_REPORT. */ +typedef struct { + uint8_t adv_handle; /**< Advertising handle for the advertising set which received the Scan Request */ + int8_t rssi; /**< Received Signal Strength Indication in dBm. + @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature + measurement. */ + ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref + ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ +} ble_gap_evt_scan_req_report_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST. */ +typedef struct { + ble_gap_data_length_params_t peer_params; /**< Peer data length parameters. */ +} ble_gap_evt_data_length_update_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE. + * + * @note This event may also be raised after a PHY Update procedure. + */ +typedef struct { + ble_gap_data_length_params_t effective_params; /**< The effective data length parameters. */ +} ble_gap_evt_data_length_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT. */ +typedef struct { + int8_t + channel_energy[BLE_GAP_CHANNEL_COUNT]; /**< The measured energy on the Bluetooth Low Energy + channels, in dBm, indexed by Channel Index. + If no measurement is available for the given channel, channel_energy is set to + @ref BLE_GAP_POWER_LEVEL_INVALID. */ +} ble_gap_evt_qos_channel_survey_report_t; + +/**@brief GAP event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which event occurred. */ + union /**< union alternative identified by evt_id in enclosing struct. */ + { + ble_gap_evt_connected_t connected; /**< Connected Event Parameters. */ + ble_gap_evt_disconnected_t disconnected; /**< Disconnected Event Parameters. */ + ble_gap_evt_conn_param_update_t conn_param_update; /**< Connection Parameter Update Parameters. */ + ble_gap_evt_sec_params_request_t sec_params_request; /**< Security Parameters Request Event Parameters. */ + ble_gap_evt_sec_info_request_t sec_info_request; /**< Security Information Request Event Parameters. */ + ble_gap_evt_passkey_display_t passkey_display; /**< Passkey Display Event Parameters. */ + ble_gap_evt_key_pressed_t key_pressed; /**< Key Pressed Event Parameters. */ + ble_gap_evt_auth_key_request_t auth_key_request; /**< Authentication Key Request Event Parameters. */ + ble_gap_evt_lesc_dhkey_request_t lesc_dhkey_request; /**< LE Secure Connections DHKey calculation request. */ + ble_gap_evt_auth_status_t auth_status; /**< Authentication Status Event Parameters. */ + ble_gap_evt_conn_sec_update_t conn_sec_update; /**< Connection Security Update Event Parameters. */ + ble_gap_evt_timeout_t timeout; /**< Timeout Event Parameters. */ + ble_gap_evt_rssi_changed_t rssi_changed; /**< RSSI Event Parameters. */ + ble_gap_evt_adv_report_t adv_report; /**< Advertising Report Event Parameters. */ + ble_gap_evt_adv_set_terminated_t adv_set_terminated; /**< Advertising Set Terminated Event Parameters. */ + ble_gap_evt_sec_request_t sec_request; /**< Security Request Event Parameters. */ + ble_gap_evt_conn_param_update_request_t conn_param_update_request; /**< Connection Parameter Update Parameters. */ + ble_gap_evt_scan_req_report_t scan_req_report; /**< Scan Request Report Parameters. */ + ble_gap_evt_phy_update_request_t phy_update_request; /**< PHY Update Request Event Parameters. */ + ble_gap_evt_phy_update_t phy_update; /**< PHY Update Parameters. */ + ble_gap_evt_data_length_update_request_t data_length_update_request; /**< Data Length Update Request Event Parameters. */ + ble_gap_evt_data_length_update_t data_length_update; /**< Data Length Update Event Parameters. */ + ble_gap_evt_qos_channel_survey_report_t + qos_channel_survey_report; /**< Quality of Service (QoS) Channel Survey Report Parameters. */ + } params; /**< Event Parameters. */ +} ble_gap_evt_t; + +/** + * @brief BLE GAP connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_CONN_COUNT The connection count for the connection configurations is zero. + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - The sum of conn_count for all connection configurations combined exceeds UINT8_MAX. + * - The event length is smaller than @ref BLE_GAP_EVENT_LENGTH_MIN. + */ +typedef struct { + uint8_t conn_count; /**< The number of concurrent connections the application can create with this configuration. + The default and minimum value is @ref BLE_GAP_CONN_COUNT_DEFAULT. */ + uint16_t event_length; /**< The time set aside for this connection on every connection interval in 1.25 ms units. + The default value is @ref BLE_GAP_EVENT_LENGTH_DEFAULT, the minimum value is @ref + BLE_GAP_EVENT_LENGTH_MIN. The event length and the connection interval are the primary parameters + for setting the throughput of a connection. + See the SoftDevice Specification for details on throughput. */ +} ble_gap_conn_cfg_t; + +/** + * @brief Configuration of maximum concurrent connections in the different connected roles, set with + * @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_CONN_COUNT The sum of periph_role_count and central_role_count is too + * large. The maximum supported sum of concurrent connections is + * @ref BLE_GAP_ROLE_COUNT_COMBINED_MAX. + * @retval ::NRF_ERROR_INVALID_PARAM central_sec_count is larger than central_role_count. + * @retval ::NRF_ERROR_RESOURCES The adv_set_count is too large. The maximum + * supported advertising handles is + * @ref BLE_GAP_ADV_SET_COUNT_MAX. + */ +typedef struct { + uint8_t adv_set_count; /**< Maximum number of advertising sets. Default value is @ref BLE_GAP_ADV_SET_COUNT_DEFAULT. */ + uint8_t periph_role_count; /**< Maximum number of connections concurrently acting as a peripheral. Default value is @ref + BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT. */ + uint8_t central_role_count; /**< Maximum number of connections concurrently acting as a central. Default value is @ref + BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT. */ + uint8_t central_sec_count; /**< Number of SMP instances shared between all connections acting as a central. Default value is + @ref BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT. */ + uint8_t qos_channel_survey_role_available : 1; /**< If set, the Quality of Service (QoS) channel survey module is available to + the application using @ref sd_ble_gap_qos_channel_survey_start. */ +} ble_gap_cfg_role_count_t; + +/** + * @brief Device name and its properties, set with @ref sd_ble_cfg_set. + * + * @note If the device name is not configured, the default device name will be + * @ref BLE_GAP_DEVNAME_DEFAULT, the maximum device name length will be + * @ref BLE_GAP_DEVNAME_DEFAULT_LEN, vloc will be set to @ref BLE_GATTS_VLOC_STACK and the device name + * will have no write access. + * + * @note If @ref max_len is more than @ref BLE_GAP_DEVNAME_DEFAULT_LEN and vloc is set to @ref BLE_GATTS_VLOC_STACK, + * the attribute table size must be increased to have room for the longer device name (see + * @ref sd_ble_cfg_set and @ref ble_gatts_cfg_attr_tab_size_t). + * + * @note If vloc is @ref BLE_GATTS_VLOC_STACK : + * - p_value must point to non-volatile memory (flash) or be NULL. + * - If p_value is NULL, the device name will initially be empty. + * + * @note If vloc is @ref BLE_GATTS_VLOC_USER : + * - p_value cannot be NULL. + * - If the device name is writable, p_value must point to volatile memory (RAM). + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - Invalid device name location (vloc). + * - Invalid device name security mode. + * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: + * - The device name length is invalid (must be between 0 and @ref BLE_GAP_DEVNAME_MAX_LEN). + * - The device name length is too long for the given Attribute Table. + * @retval ::NRF_ERROR_NOT_SUPPORTED Device name security mode is not supported. + */ +typedef struct { + ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ + uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ + uint8_t *p_value; /**< Pointer to where the value (device name) is stored or will be stored. */ + uint16_t current_len; /**< Current length in bytes of the memory pointed to by p_value.*/ + uint16_t max_len; /**< Maximum length in bytes of the memory pointed to by p_value.*/ +} ble_gap_cfg_device_name_t; + +/**@brief Peripheral Preferred Connection Parameters include configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t include_cfg; /**< Inclusion configuration of the Peripheral Preferred Connection Parameters characteristic. + See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_PPCP_INCL_CONFIG_DEFAULT. */ +} ble_gap_cfg_ppcp_incl_cfg_t; + +/**@brief Central Address Resolution include configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t include_cfg; /**< Inclusion configuration of the Central Address Resolution characteristic. + See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_CAR_INCL_CONFIG_DEFAULT. */ +} ble_gap_cfg_car_incl_cfg_t; + +/**@brief Configuration structure for GAP configurations. */ +typedef union { + ble_gap_cfg_role_count_t role_count_cfg; /**< Role count configuration, cfg_id is @ref BLE_GAP_CFG_ROLE_COUNT. */ + ble_gap_cfg_device_name_t device_name_cfg; /**< Device name configuration, cfg_id is @ref BLE_GAP_CFG_DEVICE_NAME. */ + ble_gap_cfg_ppcp_incl_cfg_t ppcp_include_cfg; /**< Peripheral Preferred Connection Parameters characteristic include + configuration, cfg_id is @ref BLE_GAP_CFG_PPCP_INCL_CONFIG. */ + ble_gap_cfg_car_incl_cfg_t car_include_cfg; /**< Central Address Resolution characteristic include configuration, + cfg_id is @ref BLE_GAP_CFG_CAR_INCL_CONFIG. */ +} ble_gap_cfg_t; + +/**@brief Channel Map option. + * + * @details Used with @ref sd_ble_opt_get to get the current channel map + * or @ref sd_ble_opt_set to set a new channel map. When setting the + * channel map, it applies to all current and future connections. When getting the + * current channel map, it applies to a single connection and the connection handle + * must be supplied. + * + * @note Setting the channel map may take some time, depending on connection parameters. + * The time taken may be different for each connection and the get operation will + * return the previous channel map until the new one has taken effect. + * + * @note After setting the channel map, by spec it can not be set again until at least 1 s has passed. + * See Bluetooth Specification Version 4.1 Volume 2, Part E, Section 7.3.46. + * + * @retval ::NRF_SUCCESS Get or set successful. + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - Less then two bits in @ref ch_map are set. + * - Bits for primary advertising channels (37-39) are set. + * @retval ::NRF_ERROR_BUSY Channel map was set again before enough time had passed. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied for get. + * + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle (only applicable for get) */ + uint8_t ch_map[5]; /**< Channel Map (37-bit). */ +} ble_gap_opt_ch_map_t; + +/**@brief Local connection latency option. + * + * @details Local connection latency is a feature which enables the slave to improve + * current consumption by ignoring the slave latency set by the peer. The + * local connection latency can only be set to a multiple of the slave latency, + * and cannot be longer than half of the supervision timeout. + * + * @details Used with @ref sd_ble_opt_set to set the local connection latency. The + * @ref sd_ble_opt_get is not supported for this option, but the actual + * local connection latency (unless set to NULL) is set as a return parameter + * when setting the option. + * + * @note The latency set will be truncated down to the closest slave latency event + * multiple, or the nearest multiple before half of the supervision timeout. + * + * @note The local connection latency is disabled by default, and needs to be enabled for new + * connections and whenever the connection is updated. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint16_t requested_latency; /**< Requested local connection latency. */ + uint16_t *p_actual_latency; /**< Pointer to storage for the actual local connection latency (can be set to NULL to skip return + value). */ +} ble_gap_opt_local_conn_latency_t; + +/**@brief Disable slave latency + * + * @details Used with @ref sd_ble_opt_set to temporarily disable slave latency of a peripheral connection + * (see @ref ble_gap_conn_params_t::slave_latency). And to re-enable it again. When disabled, the + * peripheral will ignore the slave_latency set by the central. + * + * @note Shall only be called on peripheral links. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint8_t disable; /**< For allowed values see @ref BLE_GAP_SLAVE_LATENCY */ +} ble_gap_opt_slave_latency_disable_t; + +/**@brief Passkey Option. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} + * @endmscs + * + * @details Structure containing the passkey to be used during pairing. This can be used with @ref + * sd_ble_opt_set to make the SoftDevice use a preprogrammed passkey for authentication + * instead of generating a random one. + * + * @note Repeated pairing attempts using the same preprogrammed passkey makes pairing vulnerable to MITM attacks. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * + */ +typedef struct { + uint8_t const *p_passkey; /**< Pointer to 6-digit ASCII string (digit 0..9 only, no NULL termination) passkey to be used + during pairing. If this is NULL, the SoftDevice will generate a random passkey if required.*/ +} ble_gap_opt_passkey_t; + +/**@brief Compatibility mode 1 option. + * + * @details This can be used with @ref sd_ble_opt_set to enable and disable + * compatibility mode 1. Compatibility mode 1 is disabled by default. + * + * @note Compatibility mode 1 enables interoperability with devices that do not support a value of + * 0 for the WinOffset parameter in the Link Layer CONNECT_IND packet. This applies to a + * limited set of legacy peripheral devices from another vendor. Enabling this compatibility + * mode will only have an effect if the local device will act as a central device and + * initiate a connection to a peripheral device. In that case it may lead to the connection + * creation taking up to one connection interval longer to complete for all connections. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_INVALID_STATE When connection creation is ongoing while mode 1 is set. + */ +typedef struct { + uint8_t enable : 1; /**< Enable compatibility mode 1.*/ +} ble_gap_opt_compat_mode_1_t; + +/**@brief Authenticated payload timeout option. + * + * @details This can be used with @ref sd_ble_opt_set to change the Authenticated payload timeout to a value other + * than the default of @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX. + * + * @note The authenticated payload timeout event ::BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD will be generated + * if auth_payload_timeout time has elapsed without receiving a packet with a valid MIC on an encrypted + * link. + * + * @note The LE ping procedure will be initiated before the timer expires to give the peer a chance + * to reset the timer. In addition the stack will try to prioritize running of LE ping over other + * activities to increase chances of finishing LE ping before timer expires. To avoid side-effects + * on other activities, it is recommended to use high timeout values. + * Recommended timeout > 2*(connInterval * (6 + connSlaveLatency)). + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. auth_payload_timeout was outside of allowed range. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint16_t auth_payload_timeout; /**< Requested timeout in 10 ms unit, see @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT. */ +} ble_gap_opt_auth_payload_timeout_t; + +/**@brief Option structure for GAP options. */ +typedef union { + ble_gap_opt_ch_map_t ch_map; /**< Parameters for the Channel Map option. */ + ble_gap_opt_local_conn_latency_t local_conn_latency; /**< Parameters for the Local connection latency option */ + ble_gap_opt_passkey_t passkey; /**< Parameters for the Passkey option.*/ + ble_gap_opt_compat_mode_1_t compat_mode_1; /**< Parameters for the compatibility mode 1 option.*/ + ble_gap_opt_auth_payload_timeout_t auth_payload_timeout; /**< Parameters for the authenticated payload timeout option.*/ + ble_gap_opt_slave_latency_disable_t slave_latency_disable; /**< Parameters for the Disable slave latency option */ +} ble_gap_opt_t; + +/**@brief Connection event triggering parameters. */ +typedef struct { + uint8_t ppi_ch_id; /**< PPI channel to use. This channel should be regarded as reserved until + connection event PPI task triggering is stopped. + The PPI channel ID can not be one of the PPI channels reserved by + the SoftDevice. See @ref NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK. */ + uint32_t task_endpoint; /**< Task Endpoint to trigger. */ + uint16_t conn_evt_counter_start; /**< The connection event on which the task triggering should start. */ + uint16_t period_in_events; /**< Trigger period. Valid range is [1, 32767]. + If the device is in slave role and slave latency is enabled, + this parameter should be set to a multiple of (slave latency + 1) + to ensure low power operation. */ +} ble_gap_conn_event_trigger_t; +/**@} */ + +/**@addtogroup BLE_GAP_FUNCTIONS Functions + * @{ */ + +/**@brief Set the local Bluetooth identity address. + * + * The local Bluetooth identity address is the address that identifies this device to other peers. + * The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. + * + * @note The identity address cannot be changed while advertising, scanning or creating a connection. + * + * @note This address will be distributed to the peer during bonding. + * If the address changes, the address stored in the peer device will not be valid and the ability to + * reconnect using the old address will be lost. + * + * @note By default the SoftDevice will set an address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC upon being + * enabled. The address is a random number populated during the IC manufacturing process and remains unchanged + * for the lifetime of each IC. + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @endmscs + * + * @param[in] p_addr Pointer to address structure. + * + * @retval ::NRF_SUCCESS Address successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_STATE The identity address cannot be changed while advertising, + * scanning or creating a connection. + */ +SVCALL(SD_BLE_GAP_ADDR_SET, uint32_t, sd_ble_gap_addr_set(ble_gap_addr_t const *p_addr)); + +/**@brief Get local Bluetooth identity address. + * + * @note This will always return the identity address irrespective of the privacy settings, + * i.e. the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. + * + * @param[out] p_addr Pointer to address structure to be filled in. + * + * @retval ::NRF_SUCCESS Address successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + */ +SVCALL(SD_BLE_GAP_ADDR_GET, uint32_t, sd_ble_gap_addr_get(ble_gap_addr_t *p_addr)); + +/**@brief Get the Bluetooth device address used by the advertiser. + * + * @note This function will return the local Bluetooth address used in advertising PDUs. When + * using privacy, the SoftDevice will generate a new private address every + * @ref ble_gap_privacy_params_t::private_addr_cycle_s configured using + * @ref sd_ble_gap_privacy_set. Hence depending on when the application calls this API, the + * address returned may not be the latest address that is used in the advertising PDUs. + * + * @param[in] adv_handle The advertising handle to get the address from. + * @param[out] p_addr Pointer to address structure to be filled in. + * + * @retval ::NRF_SUCCESS Address successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. + * @retval ::NRF_ERROR_INVALID_STATE The advertising set is currently not advertising. + */ +SVCALL(SD_BLE_GAP_ADV_ADDR_GET, uint32_t, sd_ble_gap_adv_addr_get(uint8_t adv_handle, ble_gap_addr_t *p_addr)); + +/**@brief Set the active whitelist in the SoftDevice. + * + * @note Only one whitelist can be used at a time and the whitelist is shared between the BLE roles. + * The whitelist cannot be set if a BLE role is using the whitelist. + * + * @note If an address is resolved using the information in the device identity list, then the whitelist + * filter policy applies to the peer identity address and not the resolvable address sent on air. + * + * @mscs + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} + * @endmscs + * + * @param[in] pp_wl_addrs Pointer to a whitelist of peer addresses, if NULL the whitelist will be cleared. + * @param[in] len Length of the whitelist, maximum @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT. + * + * @retval ::NRF_SUCCESS The whitelist is successfully set/cleared. + * @retval ::NRF_ERROR_INVALID_ADDR The whitelist (or one of its entries) provided is invalid. + * @retval ::BLE_ERROR_GAP_WHITELIST_IN_USE The whitelist is in use by a BLE role and cannot be set or cleared. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_DATA_SIZE The given whitelist size is invalid (zero or too large); this can only return when + * pp_wl_addrs is not NULL. + */ +SVCALL(SD_BLE_GAP_WHITELIST_SET, uint32_t, sd_ble_gap_whitelist_set(ble_gap_addr_t const *const *pp_wl_addrs, uint8_t len)); + +/**@brief Set device identity list. + * + * @note Only one device identity list can be used at a time and the list is shared between the BLE roles. + * The device identity list cannot be set if a BLE role is using the list. + * + * @param[in] pp_id_keys Pointer to an array of peer identity addresses and peer IRKs, if NULL the device identity list will + * be cleared. + * @param[in] pp_local_irks Pointer to an array of local IRKs. Each entry in the array maps to the entry in pp_id_keys at the + * same index. To fill in the list with the currently set device IRK for all peers, set to NULL. + * @param[in] len Length of the device identity list, maximum @ref BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT. + * + * @mscs + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS The device identity list successfully set/cleared. + * @retval ::NRF_ERROR_INVALID_ADDR The device identity list (or one of its entries) provided is invalid. + * This code may be returned if the local IRK list also has an invalid entry. + * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE The device identity list is in use and cannot be set or cleared. + * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE The device identity list contains multiple entries with the same identity + * address. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_DATA_SIZE The given device identity list size invalid (zero or too large); this can + * only return when pp_id_keys is not NULL. + */ +SVCALL(SD_BLE_GAP_DEVICE_IDENTITIES_SET, uint32_t, + sd_ble_gap_device_identities_set(ble_gap_id_key_t const *const *pp_id_keys, ble_gap_irk_t const *const *pp_local_irks, + uint8_t len)); + +/**@brief Set privacy settings. + * + * @note Privacy settings cannot be changed while advertising, scanning or creating a connection. + * + * @param[in] p_privacy_params Privacy settings. + * + * @mscs + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_INVALID_ADDR The pointer to privacy settings is NULL or invalid. + * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. + * @retval ::NRF_ERROR_INVALID_PARAM Out of range parameters are provided. + * @retval ::NRF_ERROR_NOT_SUPPORTED The SoftDevice does not support privacy if the Central Address Resolution + characteristic is not configured to be included and the SoftDevice is configured + to support central roles. + See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + * @retval ::NRF_ERROR_INVALID_STATE Privacy settings cannot be changed while advertising, scanning + * or creating a connection. + */ +SVCALL(SD_BLE_GAP_PRIVACY_SET, uint32_t, sd_ble_gap_privacy_set(ble_gap_privacy_params_t const *p_privacy_params)); + +/**@brief Get privacy settings. + * + * @note ::ble_gap_privacy_params_t::p_device_irk must be initialized to NULL or a valid address before this function is called. + * If it is initialized to a valid address, the address pointed to will contain the current device IRK on return. + * + * @param[in,out] p_privacy_params Privacy settings. + * + * @retval ::NRF_SUCCESS Privacy settings read. + * @retval ::NRF_ERROR_INVALID_ADDR The pointer given for returning the privacy settings may be NULL or invalid. + * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. + */ +SVCALL(SD_BLE_GAP_PRIVACY_GET, uint32_t, sd_ble_gap_privacy_get(ble_gap_privacy_params_t *p_privacy_params)); + +/**@brief Configure an advertising set. Set, clear or update advertising and scan response data. + * + * @note The format of the advertising data will be checked by this call to ensure interoperability. + * Limitations imposed by this API call to the data provided include having a flags data type in the scan response data and + * duplicating the local name in the advertising data and scan response data. + * + * @note In order to update advertising data while advertising, new advertising buffers must be provided. + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in,out] p_adv_handle Provide a pointer to a handle containing @ref + * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising set. On success, a new handle is then returned through the + * pointer. Provide a pointer to an existing advertising handle to configure an existing advertising set. + * @param[in] p_adv_data Advertising data. If set to NULL, no advertising data will be used. See + * @ref ble_gap_adv_data_t. + * @param[in] p_adv_params Advertising parameters. When this function is used to update advertising + * data while advertising, this parameter must be NULL. See @ref ble_gap_adv_params_t. + * + * @retval ::NRF_SUCCESS Advertising set successfully configured. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: + * - Invalid advertising data configuration specified. See @ref + * ble_gap_adv_data_t. + * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. + * - Use of whitelist requested but whitelist has not been set, + * see @ref sd_ble_gap_whitelist_set. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR ble_gap_adv_params_t::p_peer_addr is invalid. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - It is invalid to provide non-NULL advertising set parameters while + * advertising. + * - It is invalid to provide the same data buffers while advertising. To + * update advertising data, provide new advertising buffers. + * @retval ::BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST Discoverable mode and whitelist incompatible. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. Use @ref + * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_FLAGS Invalid combination of advertising flags supplied. + * @retval ::NRF_ERROR_INVALID_DATA Invalid data type(s) supplied. Check the advertising data format + * specification given in Bluetooth Specification Version 5.0, Volume 3, Part C, Chapter 11. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid data length(s) supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported data length or advertising parameter configuration. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to configure a new advertising handle. Update an + * existing advertising handle instead. + * @retval ::BLE_ERROR_GAP_UUID_LIST_MISMATCH Invalid UUID list supplied. + */ +SVCALL(SD_BLE_GAP_ADV_SET_CONFIGURE, uint32_t, + sd_ble_gap_adv_set_configure(uint8_t *p_adv_handle, ble_gap_adv_data_t const *p_adv_data, + ble_gap_adv_params_t const *p_adv_params)); + +/**@brief Start advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). + * + * @note Only one advertiser may be active at any time. + * + * @note If privacy is enabled, the advertiser's private address will be refreshed when this function is called. + * See @ref sd_ble_gap_privacy_set(). + * + * @events + * @event{@ref BLE_GAP_EVT_CONNECTED, Generated after connection has been established through connectable advertising.} + * @event{@ref BLE_GAP_EVT_ADV_SET_TERMINATED, Advertising set has terminated.} + * @event{@ref BLE_GAP_EVT_SCAN_REQ_REPORT, A scan request was received.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] adv_handle Advertising handle to advertise on, received from @ref sd_ble_gap_adv_set_configure. + * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or + * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. For non-connectable + * advertising, this is ignored. + * + * @retval ::NRF_SUCCESS The BLE stack has started advertising. + * @retval ::NRF_ERROR_INVALID_STATE adv_handle is not configured or already advertising. + * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration + * tag has been reached; connectable advertiser cannot be started. + * To increase the number of available connections, + * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. Configure a new adveriting handle with @ref + sd_ble_gap_adv_set_configure. + * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: + * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. + * - Use of whitelist requested but whitelist has not been set, see @ref + sd_ble_gap_whitelist_set. + * @retval ::NRF_ERROR_RESOURCES Either: + * - adv_handle is configured with connectable advertising, but the event_length parameter + * associated with conn_cfg_tag is too small to be able to establish a connection on + * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. + * - Not enough BLE role slots available. + Stop one or more currently active roles (Central, Peripheral, Broadcaster or Observer) + and try again. + * - p_adv_params is configured with connectable advertising, but the event_length + parameter + * associated with conn_cfg_tag is too small to be able to establish a connection on + * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. + */ +SVCALL(SD_BLE_GAP_ADV_START, uint32_t, sd_ble_gap_adv_start(uint8_t adv_handle, uint8_t conn_cfg_tag)); + +/**@brief Stop advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] adv_handle The advertising handle that should stop advertising. + * + * @retval ::NRF_SUCCESS The BLE stack has stopped advertising. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Invalid advertising handle. + * @retval ::NRF_ERROR_INVALID_STATE The advertising handle is not advertising. + */ +SVCALL(SD_BLE_GAP_ADV_STOP, uint32_t, sd_ble_gap_adv_stop(uint8_t adv_handle)); + +/**@brief Update connection parameters. + * + * @details In the central role this will initiate a Link Layer connection parameter update procedure, + * otherwise in the peripheral role, this will send the corresponding L2CAP request and wait for + * the central to perform the procedure. In both cases, and regardless of success or failure, the application + * will be informed of the result with a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE event. + * + * @details This function can be used as a central both to reply to a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST or to start the + * procedure unrequested. + * + * @events + * @event{@ref BLE_GAP_EVT_CONN_PARAM_UPDATE, Result of the connection parameter update procedure.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CPU_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CPU_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CPU_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_conn_params Pointer to desired connection parameters. If NULL is provided on a peripheral role, + * the parameters in the PPCP characteristic of the GAP service will be used instead. + * If NULL is provided on a central role and in response to a @ref + * BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST, the peripheral request will be rejected + * + * @retval ::NRF_SUCCESS The Connection Update procedure has been started successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. + * @retval ::NRF_ERROR_BUSY Procedure already in progress, wait for pending procedures to complete and retry. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GAP_CONN_PARAM_UPDATE, uint32_t, + sd_ble_gap_conn_param_update(uint16_t conn_handle, ble_gap_conn_params_t const *p_conn_params)); + +/**@brief Disconnect (GAP Link Termination). + * + * @details This call initiates the disconnection procedure, and its completion will be communicated to the application + * with a @ref BLE_GAP_EVT_DISCONNECTED event. + * + * @events + * @event{@ref BLE_GAP_EVT_DISCONNECTED, Generated when disconnection procedure is complete.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CONN_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] hci_status_code HCI status code, see @ref BLE_HCI_STATUS_CODES (accepted values are @ref + * BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION and @ref BLE_HCI_CONN_INTERVAL_UNACCEPTABLE). + * + * @retval ::NRF_SUCCESS The disconnection procedure has been started successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. + */ +SVCALL(SD_BLE_GAP_DISCONNECT, uint32_t, sd_ble_gap_disconnect(uint16_t conn_handle, uint8_t hci_status_code)); + +/**@brief Set the radio's transmit power. + * + * @param[in] role The role to set the transmit power for, see @ref BLE_GAP_TX_POWER_ROLES for + * possible roles. + * @param[in] handle The handle parameter is interpreted depending on role: + * - If role is @ref BLE_GAP_TX_POWER_ROLE_CONN, this value is the specific connection handle. + * - If role is @ref BLE_GAP_TX_POWER_ROLE_ADV, the advertising set identified with the advertising handle, + * will use the specified transmit power, and include it in the advertising packet headers if + * @ref ble_gap_adv_properties_t::include_tx_power set. + * - For all other roles handle is ignored. + * @param[in] tx_power Radio transmit power in dBm (see note for accepted values). + * + * @note Supported tx_power values: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm and +4dBm. + * In addition, on some chips following values are supported: +2dBm, +5dBm, +6dBm, +7dBm and +8dBm. + * Setting these values on a chip that does not support them will result in undefined behaviour. + * @note The initiator will have the same transmit power as the scanner. + * @note When a connection is created it will inherit the transmit power from the initiator or + * advertiser leading to the connection. + * + * @retval ::NRF_SUCCESS Successfully changed the transmit power. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_TX_POWER_SET, uint32_t, sd_ble_gap_tx_power_set(uint8_t role, uint16_t handle, int8_t tx_power)); + +/**@brief Set GAP Appearance value. + * + * @param[in] appearance Appearance (16-bit), see @ref BLE_APPEARANCES. + * + * @retval ::NRF_SUCCESS Appearance value set successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + */ +SVCALL(SD_BLE_GAP_APPEARANCE_SET, uint32_t, sd_ble_gap_appearance_set(uint16_t appearance)); + +/**@brief Get GAP Appearance value. + * + * @param[out] p_appearance Pointer to appearance (16-bit) to be filled in, see @ref BLE_APPEARANCES. + * + * @retval ::NRF_SUCCESS Appearance value retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GAP_APPEARANCE_GET, uint32_t, sd_ble_gap_appearance_get(uint16_t *p_appearance)); + +/**@brief Set GAP Peripheral Preferred Connection Parameters. + * + * @param[in] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure with the desired parameters. + * + * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, + see @ref ble_gap_cfg_ppcp_incl_cfg_t. + */ +SVCALL(SD_BLE_GAP_PPCP_SET, uint32_t, sd_ble_gap_ppcp_set(ble_gap_conn_params_t const *p_conn_params)); + +/**@brief Get GAP Peripheral Preferred Connection Parameters. + * + * @param[out] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure where the parameters will be stored. + * + * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, + see @ref ble_gap_cfg_ppcp_incl_cfg_t. + */ +SVCALL(SD_BLE_GAP_PPCP_GET, uint32_t, sd_ble_gap_ppcp_get(ble_gap_conn_params_t *p_conn_params)); + +/**@brief Set GAP device name. + * + * @note If the device name is located in application flash memory (see @ref ble_gap_cfg_device_name_t), + * it cannot be changed. Then @ref NRF_ERROR_FORBIDDEN will be returned. + * + * @param[in] p_write_perm Write permissions for the Device Name characteristic, see @ref ble_gap_conn_sec_mode_t. + * @param[in] p_dev_name Pointer to a UTF-8 encoded, non NULL-terminated string. + * @param[in] len Length of the UTF-8, non NULL-terminated string pointed to by p_dev_name in octets (must be smaller or + * equal than @ref BLE_GAP_DEVNAME_MAX_LEN). + * + * @retval ::NRF_SUCCESS GAP device name and permissions set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_FORBIDDEN Device name is not writable. + */ +SVCALL(SD_BLE_GAP_DEVICE_NAME_SET, uint32_t, + sd_ble_gap_device_name_set(ble_gap_conn_sec_mode_t const *p_write_perm, uint8_t const *p_dev_name, uint16_t len)); + +/**@brief Get GAP device name. + * + * @note If the device name is longer than the size of the supplied buffer, + * p_len will return the complete device name length, + * and not the number of bytes actually returned in p_dev_name. + * The application may use this information to allocate a suitable buffer size. + * + * @param[out] p_dev_name Pointer to an empty buffer where the UTF-8 non NULL-terminated string will be placed. Set to + * NULL to obtain the complete device name length. + * @param[in,out] p_len Length of the buffer pointed by p_dev_name, complete device name length on output. + * + * @retval ::NRF_SUCCESS GAP device name retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + */ +SVCALL(SD_BLE_GAP_DEVICE_NAME_GET, uint32_t, sd_ble_gap_device_name_get(uint8_t *p_dev_name, uint16_t *p_len)); + +/**@brief Initiate the GAP Authentication procedure. + * + * @details In the central role, this function will send an SMP Pairing Request (or an SMP Pairing Failed if rejected), + * otherwise in the peripheral role, an SMP Security Request will be sent. + * + * @events + * @event{Depending on the security parameters set and the packet exchanges with the peer\, the following events may be + * generated:} + * @event{@ref BLE_GAP_EVT_SEC_PARAMS_REQUEST} + * @event{@ref BLE_GAP_EVT_SEC_INFO_REQUEST} + * @event{@ref BLE_GAP_EVT_PASSKEY_DISPLAY} + * @event{@ref BLE_GAP_EVT_KEY_PRESSED} + * @event{@ref BLE_GAP_EVT_AUTH_KEY_REQUEST} + * @event{@ref BLE_GAP_EVT_LESC_DHKEY_REQUEST} + * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE} + * @event{@ref BLE_GAP_EVT_AUTH_STATUS} + * @event{@ref BLE_GAP_EVT_TIMEOUT} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_SEC_REQ_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_sec_params Pointer to the @ref ble_gap_sec_params_t structure with the security parameters to be used during the + * pairing or bonding procedure. In the peripheral role, only the bond, mitm, lesc and keypress fields of this structure are used. + * In the central role, this pointer may be NULL to reject a Security Request. + * + * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - No link has been established. + * - An encryption is already executing or queued. + * @retval ::NRF_ERROR_NO_MEM The maximum number of authentication procedures that can run in parallel for the given role is + * reached. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. + * Distribution of own Identity Information is only supported if the Central + * Address Resolution characteristic is configured to be included or + * the Softdevice is configured to support peripheral roles only. + * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + * @retval ::NRF_ERROR_TIMEOUT A SMP timeout has occurred, and further SMP operations on this link is prohibited. + */ +SVCALL(SD_BLE_GAP_AUTHENTICATE, uint32_t, + sd_ble_gap_authenticate(uint16_t conn_handle, ble_gap_sec_params_t const *p_sec_params)); + +/**@brief Reply with GAP security parameters. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST, calling it at other times will result in + * an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_CONFIRM_FAIL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_KS_TOO_SMALL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_APP_ERROR_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_REMOTE_PAIRING_FAIL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_TIMEOUT_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] sec_status Security status, see @ref BLE_GAP_SEC_STATUS. + * @param[in] p_sec_params Pointer to a @ref ble_gap_sec_params_t security parameters structure. In the central role this must be + * set to NULL, as the parameters have already been provided during a previous call to @ref sd_ble_gap_authenticate. + * @param[in,out] p_sec_keyset Pointer to a @ref ble_gap_sec_keyset_t security keyset structure. Any keys generated and/or + * distributed as a result of the ongoing security procedure will be stored into the memory referenced by the pointers inside this + * structure. The keys will be stored and available to the application upon reception of a @ref BLE_GAP_EVT_AUTH_STATUS event. + * Note that the SoftDevice expects the application to provide memory for storing the + * peer's keys. So it must be ensured that the relevant pointers inside this structure are not NULL. The + * pointers to the local key can, however, be NULL, in which case, the local key data will not be available to the application + * upon reception of the + * @ref BLE_GAP_EVT_AUTH_STATUS event. + * + * @retval ::NRF_SUCCESS Successfully accepted security parameter from the application. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Security parameters has not been requested. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. + * Distribution of own Identity Information is only supported if the Central + * Address Resolution characteristic is configured to be included or + * the Softdevice is configured to support peripheral roles only. + * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + */ +SVCALL(SD_BLE_GAP_SEC_PARAMS_REPLY, uint32_t, + sd_ble_gap_sec_params_reply(uint16_t conn_handle, uint8_t sec_status, ble_gap_sec_params_t const *p_sec_params, + ble_gap_sec_keyset_t const *p_sec_keyset)); + +/**@brief Reply with an authentication key. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_AUTH_KEY_REQUEST or a @ref BLE_GAP_EVT_PASSKEY_DISPLAY, + * calling it at other times will result in an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] key_type See @ref BLE_GAP_AUTH_KEY_TYPES. + * @param[in] p_key If key type is @ref BLE_GAP_AUTH_KEY_TYPE_NONE, then NULL. + * If key type is @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY, then a 6-byte ASCII string (digit 0..9 only, no NULL + * termination) or NULL when confirming LE Secure Connections Numeric Comparison. If key type is @ref BLE_GAP_AUTH_KEY_TYPE_OOB, + * then a 16-byte OOB key value in little-endian format. + * + * @retval ::NRF_SUCCESS Authentication key successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Authentication key has not been requested. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_AUTH_KEY_REPLY, uint32_t, + sd_ble_gap_auth_key_reply(uint16_t conn_handle, uint8_t key_type, uint8_t const *p_key)); + +/**@brief Reply with an LE Secure connections DHKey. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST, calling it at other times will result in + * an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_dhkey LE Secure Connections DHKey. + * + * @retval ::NRF_SUCCESS DHKey successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - The peer is not authenticated. + * - The application has not pulled a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_DHKEY_REPLY, uint32_t, + sd_ble_gap_lesc_dhkey_reply(uint16_t conn_handle, ble_gap_lesc_dhkey_t const *p_dhkey)); + +/**@brief Notify the peer of a local keypress. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] kp_not See @ref BLE_GAP_KP_NOT_TYPES. + * + * @retval ::NRF_SUCCESS Keypress notification successfully queued for transmission. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Authentication key not requested. + * - Passkey has not been entered. + * - Keypresses have not been enabled by both peers. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy. Retry at later time. + */ +SVCALL(SD_BLE_GAP_KEYPRESS_NOTIFY, uint32_t, sd_ble_gap_keypress_notify(uint16_t conn_handle, uint8_t kp_not)); + +/**@brief Generate a set of OOB data to send to a peer out of band. + * + * @note The @ref ble_gap_addr_t included in the OOB data returned will be the currently active one (or, if a connection has + * already been established, the one used during connection setup). The application may manually overwrite it with an updated + * value. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. Can be @ref BLE_CONN_HANDLE_INVALID if a BLE connection has not been established yet. + * @param[in] p_pk_own LE Secure Connections local P-256 Public Key. + * @param[out] p_oobd_own The OOB data to be sent out of band to a peer. + * + * @retval ::NRF_SUCCESS OOB data successfully generated. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_OOB_DATA_GET, uint32_t, + sd_ble_gap_lesc_oob_data_get(uint16_t conn_handle, ble_gap_lesc_p256_pk_t const *p_pk_own, + ble_gap_lesc_oob_data_t *p_oobd_own)); + +/**@brief Provide the OOB data sent/received out of band. + * + * @note An authentication procedure with OOB selected as an algorithm must be in progress when calling this function. + * @note A @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event with the oobd_req set to 1 must have been received prior to calling this + * function. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_oobd_own The OOB data sent out of band to a peer or NULL if the peer has not received OOB data. + * Must correspond to @ref ble_gap_sec_params_t::oob flag in @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. + * @param[in] p_oobd_peer The OOB data received out of band from a peer or NULL if none received. + * Must correspond to @ref ble_gap_sec_params_t::oob flag + * in @ref sd_ble_gap_authenticate in the central role or + * in @ref sd_ble_gap_sec_params_reply in the peripheral role. + * + * @retval ::NRF_SUCCESS OOB data accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Authentication key not requested + * - Not expecting LESC OOB data + * - Have not actually exchanged passkeys. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_OOB_DATA_SET, uint32_t, + sd_ble_gap_lesc_oob_data_set(uint16_t conn_handle, ble_gap_lesc_oob_data_t const *p_oobd_own, + ble_gap_lesc_oob_data_t const *p_oobd_peer)); + +/**@brief Initiate GAP Encryption procedure. + * + * @details In the central role, this function will initiate the encryption procedure using the encryption information provided. + * + * @events + * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE, The connection security has been updated.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_master_id Pointer to a @ref ble_gap_master_id_t master identification structure. + * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. + * + * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::BLE_ERROR_INVALID_ROLE Operation is not supported in the Peripheral role. + * @retval ::NRF_ERROR_BUSY Procedure already in progress or not allowed at this time, wait for pending procedures to complete and + * retry. + */ +SVCALL(SD_BLE_GAP_ENCRYPT, uint32_t, + sd_ble_gap_encrypt(uint16_t conn_handle, ble_gap_master_id_t const *p_master_id, ble_gap_enc_info_t const *p_enc_info)); + +/**@brief Reply with GAP security information. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_INFO_REQUEST, calling it at other times will result in + * @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * @note Data signing is not yet supported, and p_sign_info must therefore be NULL. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_ENC_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. May be NULL to signal none is + * available. + * @param[in] p_id_info Pointer to a @ref ble_gap_irk_t identity information structure. May be NULL to signal none is available. + * @param[in] p_sign_info Pointer to a @ref ble_gap_sign_info_t signing information structure. May be NULL to signal none is + * available. + * + * @retval ::NRF_SUCCESS Successfully accepted security information. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - No link has been established. + * - No @ref BLE_GAP_EVT_SEC_INFO_REQUEST pending. + * - Encryption information provided by the app without being requested. See @ref + * ble_gap_evt_sec_info_request_t::enc_info. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_SEC_INFO_REPLY, uint32_t, + sd_ble_gap_sec_info_reply(uint16_t conn_handle, ble_gap_enc_info_t const *p_enc_info, ble_gap_irk_t const *p_id_info, + ble_gap_sign_info_t const *p_sign_info)); + +/**@brief Get the current connection security. + * + * @param[in] conn_handle Connection handle. + * @param[out] p_conn_sec Pointer to a @ref ble_gap_conn_sec_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Current connection security successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_CONN_SEC_GET, uint32_t, sd_ble_gap_conn_sec_get(uint16_t conn_handle, ble_gap_conn_sec_t *p_conn_sec)); + +/**@brief Start reporting the received signal strength to the application. + * + * A new event is reported whenever the RSSI value changes, until @ref sd_ble_gap_rssi_stop is called. + * + * @events + * @event{@ref BLE_GAP_EVT_RSSI_CHANGED, New RSSI data available. How often the event is generated is + * dependent on the settings of the threshold_dbm + * and skip_count input parameters.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] threshold_dbm Minimum change in dBm before triggering the @ref BLE_GAP_EVT_RSSI_CHANGED event. Events are + * disabled if threshold_dbm equals @ref BLE_GAP_RSSI_THRESHOLD_INVALID. + * @param[in] skip_count Number of RSSI samples with a change of threshold_dbm or more before sending a new @ref + * BLE_GAP_EVT_RSSI_CHANGED event. + * + * @retval ::NRF_SUCCESS Successfully activated RSSI reporting. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is already ongoing. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_RSSI_START, uint32_t, sd_ble_gap_rssi_start(uint16_t conn_handle, uint8_t threshold_dbm, uint8_t skip_count)); + +/**@brief Stop reporting the received signal strength. + * + * @note An RSSI change detected before the call but not yet received by the application + * may be reported after @ref sd_ble_gap_rssi_stop has been called. + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * + * @retval ::NRF_SUCCESS Successfully deactivated RSSI reporting. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_RSSI_STOP, uint32_t, sd_ble_gap_rssi_stop(uint16_t conn_handle)); + +/**@brief Get the received signal strength for the last connection event. + * + * @ref sd_ble_gap_rssi_start must be called to start reporting RSSI before using this function. @ref NRF_ERROR_NOT_FOUND + * will be returned until RSSI was sampled for the first time after calling @ref sd_ble_gap_rssi_start. + * @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature measurement. + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[out] p_rssi Pointer to the location where the RSSI measurement shall be stored. + * @param[out] p_ch_index Pointer to the location where Channel Index for the RSSI measurement shall be stored. + * + * @retval ::NRF_SUCCESS Successfully read the RSSI. + * @retval ::NRF_ERROR_NOT_FOUND No sample is available. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. + */ +SVCALL(SD_BLE_GAP_RSSI_GET, uint32_t, sd_ble_gap_rssi_get(uint16_t conn_handle, int8_t *p_rssi, uint8_t *p_ch_index)); + +/**@brief Start or continue scanning (GAP Discovery procedure, Observer Procedure). + * + * @note A call to this function will require the application to keep the memory pointed by + * p_adv_report_buffer alive until the buffer is released. The buffer is released when the scanner is stopped + * or when this function is called with another buffer. + * + * @note The scanner will automatically stop in the following cases: + * - @ref sd_ble_gap_scan_stop is called. + * - @ref sd_ble_gap_connect is called. + * - A @ref BLE_GAP_EVT_TIMEOUT with source set to @ref BLE_GAP_TIMEOUT_SRC_SCAN is received. + * - When a @ref BLE_GAP_EVT_ADV_REPORT event is received and @ref ble_gap_adv_report_type_t::status is not set to + * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. In this case scanning is only paused to let the application + * access received data. The application must call this function to continue scanning, or call @ref + * sd_ble_gap_scan_stop to stop scanning. + * + * @note If a @ref BLE_GAP_EVT_ADV_REPORT event is received with @ref ble_gap_adv_report_type_t::status set to + * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the scanner will continue scanning, and the application will + * receive more reports from this advertising event. The following reports will include the old and new received data. + * + * @events + * @event{@ref BLE_GAP_EVT_ADV_REPORT, An advertising or scan response packet has been received.} + * @event{@ref BLE_GAP_EVT_TIMEOUT, Scanner has timed out.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_SCAN_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] p_scan_params Pointer to scan parameters structure. When this function is used to continue + * scanning, this parameter must be NULL. + * @param[in] p_adv_report_buffer Pointer to buffer used to store incoming advertising data. + * The memory pointed to should be kept alive until the scanning is stopped. + * See @ref BLE_GAP_SCAN_BUFFER_SIZE for minimum and maximum buffer size. + * If the scanner receives advertising data larger than can be stored in the buffer, + * a @ref BLE_GAP_EVT_ADV_REPORT will be raised with @ref ble_gap_adv_report_type_t::status + * set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED. + * + * @retval ::NRF_SUCCESS Successfully initiated scanning procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Scanning is already ongoing and p_scan_params was not NULL + * - Scanning is not running and p_scan_params was NULL. + * - The scanner has timed out when this function is called to continue scanning. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. See @ref ble_gap_scan_params_t. + * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported parameters supplied. See @ref ble_gap_scan_params_t. + * @retval ::NRF_ERROR_INVALID_LENGTH The provided buffer length is invalid. See @ref BLE_GAP_SCAN_BUFFER_MIN. + * @retval ::NRF_ERROR_RESOURCES Not enough BLE role slots available. + * Stop one or more currently active roles (Central, Peripheral or Broadcaster) and try again + */ +SVCALL(SD_BLE_GAP_SCAN_START, uint32_t, + sd_ble_gap_scan_start(ble_gap_scan_params_t const *p_scan_params, ble_data_t const *p_adv_report_buffer)); + +/**@brief Stop scanning (GAP Discovery procedure, Observer Procedure). + * + * @note The buffer provided in @ref sd_ble_gap_scan_start is released. + * + * @mscs + * @mmsc{@ref BLE_GAP_SCAN_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully stopped scanning procedure. + * @retval ::NRF_ERROR_INVALID_STATE Not in the scanning state. + */ +SVCALL(SD_BLE_GAP_SCAN_STOP, uint32_t, sd_ble_gap_scan_stop(void)); + +/**@brief Create a connection (GAP Link Establishment). + * + * @note If a scanning procedure is currently in progress it will be automatically stopped when calling this function. + * The scanning procedure will be stopped even if the function returns an error. + * + * @events + * @event{@ref BLE_GAP_EVT_CONNECTED, A connection was established.} + * @event{@ref BLE_GAP_EVT_TIMEOUT, Failed to establish a connection.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} + * @endmscs + * + * @param[in] p_peer_addr Pointer to peer identity address. If @ref ble_gap_scan_params_t::filter_policy is set to use + * whitelist, then p_peer_addr is ignored. + * @param[in] p_scan_params Pointer to scan parameters structure. + * @param[in] p_conn_params Pointer to desired connection parameters. + * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or + * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. + * + * @retval ::NRF_SUCCESS Successfully initiated connection procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid parameter(s) pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * - Invalid parameter(s) in p_scan_params or p_conn_params. + * - Use of whitelist requested but whitelist has not been set, see @ref + * sd_ble_gap_whitelist_set. + * - Peer address was not present in the device identity list, see @ref + * sd_ble_gap_device_identities_set. + * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. + * @retval ::NRF_ERROR_INVALID_STATE The SoftDevice is in an invalid state to perform this operation. This may be due to an + * existing locally initiated connect procedure, which must complete before initiating again. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid Peer address. + * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration tag has been reached. + * To increase the number of available connections, + * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. + * @retval ::NRF_ERROR_RESOURCES Either: + * - Not enough BLE role slots available. + * Stop one or more currently active roles (Central, Peripheral or Observer) and try again. + * - The event_length parameter associated with conn_cfg_tag is too small to be able to + * establish a connection on the selected @ref ble_gap_scan_params_t::scan_phys. + * Use @ref sd_ble_cfg_set to increase the event length. + */ +SVCALL(SD_BLE_GAP_CONNECT, uint32_t, + sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params, + ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag)); + +/**@brief Cancel a connection establishment. + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully canceled an ongoing connection procedure. + * @retval ::NRF_ERROR_INVALID_STATE No locally initiated connect procedure started or connection + * completed occurred. + */ +SVCALL(SD_BLE_GAP_CONNECT_CANCEL, uint32_t, sd_ble_gap_connect_cancel(void)); + +/**@brief Initiate or respond to a PHY Update Procedure + * + * @details This function is used to initiate or respond to a PHY Update Procedure. It will always + * generate a @ref BLE_GAP_EVT_PHY_UPDATE event if successfully executed. + * If this function is used to initiate a PHY Update procedure and the only option + * provided in @ref ble_gap_phys_t::tx_phys and @ref ble_gap_phys_t::rx_phys is the + * currently active PHYs in the respective directions, the SoftDevice will generate a + * @ref BLE_GAP_EVT_PHY_UPDATE with the current PHYs set and will not initiate the + * procedure in the Link Layer. + * + * If @ref ble_gap_phys_t::tx_phys or @ref ble_gap_phys_t::rx_phys is @ref BLE_GAP_PHY_AUTO, + * then the stack will select PHYs based on the peer's PHY preferences and the local link + * configuration. The PHY Update procedure will for this case result in a PHY combination + * that respects the time constraints configured with @ref sd_ble_cfg_set and the current + * link layer data length. + * + * When acting as a central, the SoftDevice will select the fastest common PHY in each direction. + * + * If the peer does not support the PHY Update Procedure, then the resulting + * @ref BLE_GAP_EVT_PHY_UPDATE event will have a status set to + * @ref BLE_HCI_UNSUPPORTED_REMOTE_FEATURE. + * + * If the PHY Update procedure was rejected by the peer due to a procedure collision, the status + * will be @ref BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION or + * @ref BLE_HCI_DIFFERENT_TRANSACTION_COLLISION. + * If the peer responds to the PHY Update procedure with invalid parameters, the status + * will be @ref BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS. + * If the PHY Update procedure was rejected by the peer for a different reason, the status will + * contain the reason as specified by the peer. + * + * @events + * @event{@ref BLE_GAP_EVT_PHY_UPDATE, Result of the PHY Update Procedure.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_PHY_UPDATE} + * @mmsc{@ref BLE_GAP_PERIPHERAL_PHY_UPDATE} + * @endmscs + * + * @param[in] conn_handle Connection handle to indicate the connection for which the PHY Update is requested. + * @param[in] p_gap_phys Pointer to PHY structure. + * + * @retval ::NRF_SUCCESS Successfully requested a PHY Update. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the combination of + * @ref ble_gap_phys_t::tx_phys, @ref ble_gap_phys_t::rx_phys, and @ref + * ble_gap_data_length_params_t. The connection event length is configured with @ref BLE_CONN_CFG_GAP using @ref sd_ble_cfg_set. + * @retval ::NRF_ERROR_BUSY Procedure is already in progress or not allowed at this time. Process pending events and wait for the + * pending procedure to complete and retry. + * + */ +SVCALL(SD_BLE_GAP_PHY_UPDATE, uint32_t, sd_ble_gap_phy_update(uint16_t conn_handle, ble_gap_phys_t const *p_gap_phys)); + +/**@brief Initiate or respond to a Data Length Update Procedure. + * + * @note If the application uses @ref BLE_GAP_DATA_LENGTH_AUTO for one or more members of + * p_dl_params, the SoftDevice will choose the highest value supported in current + * configuration and connection parameters. + * @note If the link PHY is Coded, the SoftDevice will ensure that the MaxTxTime and/or MaxRxTime + * used in the Data Length Update procedure is at least 2704 us. Otherwise, MaxTxTime and + * MaxRxTime will be limited to maximum 2120 us. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_dl_params Pointer to local parameters to be used in Data Length Update + * Procedure. Set any member to @ref BLE_GAP_DATA_LENGTH_AUTO to let + * the SoftDevice automatically decide the value for that member. + * Set to NULL to use automatic values for all members. + * @param[out] p_dl_limitation Pointer to limitation to be written when local device does not + * have enough resources or does not support the requested Data Length + * Update parameters. Ignored if NULL. + * + * @mscs + * @mmsc{@ref BLE_GAP_DATA_LENGTH_UPDATE_PROCEDURE_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully set Data Length Extension initiation/response parameters. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The requested parameters are not supported by the SoftDevice. Inspect + * p_dl_limitation to see which parameter is not supported. + * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the requested + * parameters. Use @ref sd_ble_cfg_set with @ref BLE_CONN_CFG_GAP to increase the connection event length. Inspect p_dl_limitation + * to see where the limitation is. + * @retval ::NRF_ERROR_BUSY Peer has already initiated a Data Length Update Procedure. Process the + * pending @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event to respond. + */ +SVCALL(SD_BLE_GAP_DATA_LENGTH_UPDATE, uint32_t, + sd_ble_gap_data_length_update(uint16_t conn_handle, ble_gap_data_length_params_t const *p_dl_params, + ble_gap_data_length_limitation_t *p_dl_limitation)); + +/**@brief Start the Quality of Service (QoS) channel survey module. + * + * @details The channel survey module provides measurements of the energy levels on + * the Bluetooth Low Energy channels. When the module is enabled, @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT + * events will periodically report the measured energy levels for each channel. + * + * @note The measurements are scheduled with lower priority than other Bluetooth Low Energy roles, + * Radio Timeslot API events and Flash API events. + * + * @note The channel survey module will attempt to do measurements so that the average interval + * between measurements will be interval_us. However due to the channel survey module + * having the lowest priority of all roles and modules, this may not be possible. In that + * case fewer than expected channel survey reports may be given. + * + * @note In order to use the channel survey module, @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available + * must be set. This is done using @ref sd_ble_cfg_set. + * + * @param[in] interval_us Requested average interval for the measurements and reports. See + * @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS for valid ranges. If set + * to @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS, the channel + * survey role will be scheduled at every available opportunity. + * + * @retval ::NRF_SUCCESS The module is successfully started. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. interval_us is out of the + * allowed range. + * @retval ::NRF_ERROR_INVALID_STATE Trying to start the module when already running. + * @retval ::NRF_ERROR_RESOURCES The channel survey module is not available to the application. + * Set @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available using + * @ref sd_ble_cfg_set. + */ +SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_START, uint32_t, sd_ble_gap_qos_channel_survey_start(uint32_t interval_us)); + +/**@brief Stop the Quality of Service (QoS) channel survey module. + * + * @note The SoftDevice may generate one @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT event after this + * function is called. + * + * @retval ::NRF_SUCCESS The module is successfully stopped. + * @retval ::NRF_ERROR_INVALID_STATE Trying to stop the module when it is not running. + */ +SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP, uint32_t, sd_ble_gap_qos_channel_survey_stop(void)); + +/**@brief Obtain the next connection event counter value. + * + * @details The connection event counter is initialized to zero on the first connection event. The value is incremented + * by one for each connection event. For more information see Bluetooth Core Specification v5.0, Vol 6, Part B, + * Section 4.5.1. + * + * @note The connection event counter obtained through this API will be outdated if this API is called + * at the same time as the connection event counter is incremented. + * + * @note This API will always return the last connection event counter + 1. + * The actual connection event may be multiple connection events later if: + * - Slave latency is enabled and there is no data to transmit or receive. + * - Another role is scheduled with a higher priority at the same time as the next connection event. + * + * @param[in] conn_handle Connection handle. + * @param[out] p_counter Pointer to the variable where the next connection event counter will be written. + * + * @retval ::NRF_SUCCESS The connection event counter was successfully retrieved. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET, uint32_t, + sd_ble_gap_next_conn_evt_counter_get(uint16_t conn_handle, uint16_t *p_counter)); + +/**@brief Start triggering a given task on connection event start. + * + * @details When enabled, this feature will trigger a PPI task at the start of connection events. + * The application can configure the SoftDevice to trigger every N connection events starting from + * a given connection event counter. See also @ref ble_gap_conn_event_trigger_t. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_params Connection event trigger parameters. + * + * @retval ::NRF_SUCCESS Success. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. See @ref ble_gap_conn_event_trigger_t. + * @retval ::NRF_ERROR_INVALID_STATE Either: + * - Trying to start connection event triggering when it is already ongoing. + * - @ref ble_gap_conn_event_trigger_t::conn_evt_counter_start is in the past. + * Use @ref sd_ble_gap_next_conn_evt_counter_get to find a new value + to be used as ble_gap_conn_event_trigger_t::conn_evt_counter_start. + */ +SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_START, uint32_t, + sd_ble_gap_conn_evt_trigger_start(uint16_t conn_handle, ble_gap_conn_event_trigger_t const *p_params)); + +/**@brief Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. + * + * @param[in] conn_handle Connection handle. + * + * @retval ::NRF_SUCCESS Success. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE Trying to stop connection event triggering when it is not enabled. + */ +SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_STOP, uint32_t, sd_ble_gap_conn_evt_trigger_stop(uint16_t conn_handle)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GAP_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gatt.h b/variants/wio-sdk-wm1110/softdevice/ble_gatt.h new file mode 100644 index 0000000000..df0d728fc8 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_gatt.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATT Generic Attribute Profile (GATT) Common + @{ + @brief Common definitions and prototypes for the GATT interfaces. + */ + +#ifndef BLE_GATT_H__ +#define BLE_GATT_H__ + +#include "ble_err.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATT_DEFINES Defines + * @{ */ + +/** @brief Default ATT MTU, in bytes. */ +#define BLE_GATT_ATT_MTU_DEFAULT 23 + +/**@brief Invalid Attribute Handle. */ +#define BLE_GATT_HANDLE_INVALID 0x0000 + +/**@brief First Attribute Handle. */ +#define BLE_GATT_HANDLE_START 0x0001 + +/**@brief Last Attribute Handle. */ +#define BLE_GATT_HANDLE_END 0xFFFF + +/** @defgroup BLE_GATT_TIMEOUT_SOURCES GATT Timeout sources + * @{ */ +#define BLE_GATT_TIMEOUT_SRC_PROTOCOL 0x00 /**< ATT Protocol timeout. */ +/** @} */ + +/** @defgroup BLE_GATT_WRITE_OPS GATT Write operations + * @{ */ +#define BLE_GATT_OP_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATT_OP_WRITE_REQ 0x01 /**< Write Request. */ +#define BLE_GATT_OP_WRITE_CMD 0x02 /**< Write Command. */ +#define BLE_GATT_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ +#define BLE_GATT_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ +#define BLE_GATT_OP_EXEC_WRITE_REQ 0x05 /**< Execute Write Request. */ +/** @} */ + +/** @defgroup BLE_GATT_EXEC_WRITE_FLAGS GATT Execute Write flags + * @{ */ +#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL 0x00 /**< Cancel prepared write. */ +#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE 0x01 /**< Execute prepared write. */ +/** @} */ + +/** @defgroup BLE_GATT_HVX_TYPES GATT Handle Value operations + * @{ */ +#define BLE_GATT_HVX_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATT_HVX_NOTIFICATION 0x01 /**< Handle Value Notification. */ +#define BLE_GATT_HVX_INDICATION 0x02 /**< Handle Value Indication. */ +/** @} */ + +/** @defgroup BLE_GATT_STATUS_CODES GATT Status Codes + * @{ */ +#define BLE_GATT_STATUS_SUCCESS 0x0000 /**< Success. */ +#define BLE_GATT_STATUS_UNKNOWN 0x0001 /**< Unknown or not applicable status. */ +#define BLE_GATT_STATUS_ATTERR_INVALID 0x0100 /**< ATT Error: Invalid Error Code. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_HANDLE 0x0101 /**< ATT Error: Invalid Attribute Handle. */ +#define BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED 0x0102 /**< ATT Error: Read not permitted. */ +#define BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED 0x0103 /**< ATT Error: Write not permitted. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_PDU 0x0104 /**< ATT Error: Used in ATT as Invalid PDU. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION 0x0105 /**< ATT Error: Authenticated link required. */ +#define BLE_GATT_STATUS_ATTERR_REQUEST_NOT_SUPPORTED 0x0106 /**< ATT Error: Used in ATT as Request Not Supported. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_OFFSET 0x0107 /**< ATT Error: Offset specified was past the end of the attribute. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION 0x0108 /**< ATT Error: Used in ATT as Insufficient Authorization. */ +#define BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL 0x0109 /**< ATT Error: Used in ATT as Prepare Queue Full. */ +#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND 0x010A /**< ATT Error: Used in ATT as Attribute not found. */ +#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_LONG \ + 0x010B /**< ATT Error: Attribute cannot be read or written using read/write blob requests. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_ENC_KEY_SIZE 0x010C /**< ATT Error: Encryption key size used is insufficient. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH 0x010D /**< ATT Error: Invalid value size. */ +#define BLE_GATT_STATUS_ATTERR_UNLIKELY_ERROR 0x010E /**< ATT Error: Very unlikely error. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION 0x010F /**< ATT Error: Encrypted link required. */ +#define BLE_GATT_STATUS_ATTERR_UNSUPPORTED_GROUP_TYPE \ + 0x0110 /**< ATT Error: Attribute type is not a supported grouping attribute. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_RESOURCES 0x0111 /**< ATT Error: Insufficient resources. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_BEGIN 0x0112 /**< ATT Error: Reserved for Future Use range #1 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_END 0x017F /**< ATT Error: Reserved for Future Use range #1 end. */ +#define BLE_GATT_STATUS_ATTERR_APP_BEGIN 0x0180 /**< ATT Error: Application range begin. */ +#define BLE_GATT_STATUS_ATTERR_APP_END 0x019F /**< ATT Error: Application range end. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_BEGIN 0x01A0 /**< ATT Error: Reserved for Future Use range #2 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_END 0x01DF /**< ATT Error: Reserved for Future Use range #2 end. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_BEGIN 0x01E0 /**< ATT Error: Reserved for Future Use range #3 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_END 0x01FC /**< ATT Error: Reserved for Future Use range #3 end. */ +#define BLE_GATT_STATUS_ATTERR_CPS_WRITE_REQ_REJECTED \ + 0x01FC /**< ATT Common Profile and Service Error: Write request rejected. \ + */ +#define BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR \ + 0x01FD /**< ATT Common Profile and Service Error: Client Characteristic Configuration Descriptor improperly configured. */ +#define BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG \ + 0x01FE /**< ATT Common Profile and Service Error: Procedure Already in Progress. */ +#define BLE_GATT_STATUS_ATTERR_CPS_OUT_OF_RANGE 0x01FF /**< ATT Common Profile and Service Error: Out Of Range. */ +/** @} */ + +/** @defgroup BLE_GATT_CPF_FORMATS Characteristic Presentation Formats + * @note Found at + * http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml + * @{ */ +#define BLE_GATT_CPF_FORMAT_RFU 0x00 /**< Reserved For Future Use. */ +#define BLE_GATT_CPF_FORMAT_BOOLEAN 0x01 /**< Boolean. */ +#define BLE_GATT_CPF_FORMAT_2BIT 0x02 /**< Unsigned 2-bit integer. */ +#define BLE_GATT_CPF_FORMAT_NIBBLE 0x03 /**< Unsigned 4-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT8 0x04 /**< Unsigned 8-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT12 0x05 /**< Unsigned 12-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT16 0x06 /**< Unsigned 16-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT24 0x07 /**< Unsigned 24-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT32 0x08 /**< Unsigned 32-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT48 0x09 /**< Unsigned 48-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT64 0x0A /**< Unsigned 64-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT128 0x0B /**< Unsigned 128-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT8 0x0C /**< Signed 2-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT12 0x0D /**< Signed 12-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT16 0x0E /**< Signed 16-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT24 0x0F /**< Signed 24-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT32 0x10 /**< Signed 32-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT48 0x11 /**< Signed 48-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT64 0x12 /**< Signed 64-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT128 0x13 /**< Signed 128-bit integer. */ +#define BLE_GATT_CPF_FORMAT_FLOAT32 0x14 /**< IEEE-754 32-bit floating point. */ +#define BLE_GATT_CPF_FORMAT_FLOAT64 0x15 /**< IEEE-754 64-bit floating point. */ +#define BLE_GATT_CPF_FORMAT_SFLOAT 0x16 /**< IEEE-11073 16-bit SFLOAT. */ +#define BLE_GATT_CPF_FORMAT_FLOAT 0x17 /**< IEEE-11073 32-bit FLOAT. */ +#define BLE_GATT_CPF_FORMAT_DUINT16 0x18 /**< IEEE-20601 format. */ +#define BLE_GATT_CPF_FORMAT_UTF8S 0x19 /**< UTF-8 string. */ +#define BLE_GATT_CPF_FORMAT_UTF16S 0x1A /**< UTF-16 string. */ +#define BLE_GATT_CPF_FORMAT_STRUCT 0x1B /**< Opaque Structure. */ +/** @} */ + +/** @defgroup BLE_GATT_CPF_NAMESPACES GATT Bluetooth Namespaces + * @{ + */ +#define BLE_GATT_CPF_NAMESPACE_BTSIG 0x01 /**< Bluetooth SIG defined Namespace. */ +#define BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN 0x0000 /**< Namespace Description Unknown. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATT_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATT connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_PARAM att_mtu is smaller than @ref BLE_GATT_ATT_MTU_DEFAULT. + */ +typedef struct { + uint16_t att_mtu; /**< Maximum size of ATT packet the SoftDevice can send or receive. + The default and minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + @mscs + @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} + @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} + @endmscs + */ +} ble_gatt_conn_cfg_t; + +/**@brief GATT Characteristic Properties. */ +typedef struct { + /* Standard properties */ + uint8_t broadcast : 1; /**< Broadcasting of the value permitted. */ + uint8_t read : 1; /**< Reading the value permitted. */ + uint8_t write_wo_resp : 1; /**< Writing the value with Write Command permitted. */ + uint8_t write : 1; /**< Writing the value with Write Request permitted. */ + uint8_t notify : 1; /**< Notification of the value permitted. */ + uint8_t indicate : 1; /**< Indications of the value permitted. */ + uint8_t auth_signed_wr : 1; /**< Writing the value with Signed Write Command permitted. */ +} ble_gatt_char_props_t; + +/**@brief GATT Characteristic Extended Properties. */ +typedef struct { + /* Extended properties */ + uint8_t reliable_wr : 1; /**< Writing the value with Queued Write operations permitted. */ + uint8_t wr_aux : 1; /**< Writing the Characteristic User Description descriptor permitted. */ +} ble_gatt_char_ext_props_t; + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GATT_H__ + +/** @} */ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gattc.h b/variants/wio-sdk-wm1110/softdevice/ble_gattc.h new file mode 100644 index 0000000000..f1df1782ca --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_gattc.h @@ -0,0 +1,764 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATTC Generic Attribute Profile (GATT) Client + @{ + @brief Definitions and prototypes for the GATT Client interface. + */ + +#ifndef BLE_GATTC_H__ +#define BLE_GATTC_H__ + +#include "ble_err.h" +#include "ble_gatt.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATTC_ENUMERATIONS Enumerations + * @{ */ + +/**@brief GATTC API SVC numbers. */ +enum BLE_GATTC_SVCS { + SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER = BLE_GATTC_SVC_BASE, /**< Primary Service Discovery. */ + SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, /**< Relationship Discovery. */ + SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, /**< Characteristic Discovery. */ + SD_BLE_GATTC_DESCRIPTORS_DISCOVER, /**< Characteristic Descriptor Discovery. */ + SD_BLE_GATTC_ATTR_INFO_DISCOVER, /**< Attribute Information Discovery. */ + SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, /**< Read Characteristic Value by UUID. */ + SD_BLE_GATTC_READ, /**< Generic read. */ + SD_BLE_GATTC_CHAR_VALUES_READ, /**< Read multiple Characteristic Values. */ + SD_BLE_GATTC_WRITE, /**< Generic write. */ + SD_BLE_GATTC_HV_CONFIRM, /**< Handle Value Confirmation. */ + SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. */ +}; + +/** + * @brief GATT Client Event IDs. + */ +enum BLE_GATTC_EVTS { + BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP = BLE_GATTC_EVT_BASE, /**< Primary Service Discovery Response event. \n See @ref + ble_gattc_evt_prim_srvc_disc_rsp_t. */ + BLE_GATTC_EVT_REL_DISC_RSP, /**< Relationship Discovery Response event. \n See @ref ble_gattc_evt_rel_disc_rsp_t. + */ + BLE_GATTC_EVT_CHAR_DISC_RSP, /**< Characteristic Discovery Response event. \n See @ref + ble_gattc_evt_char_disc_rsp_t. */ + BLE_GATTC_EVT_DESC_DISC_RSP, /**< Descriptor Discovery Response event. \n See @ref + ble_gattc_evt_desc_disc_rsp_t. */ + BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, /**< Attribute Information Response event. \n See @ref + ble_gattc_evt_attr_info_disc_rsp_t. */ + BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP, /**< Read By UUID Response event. \n See @ref + ble_gattc_evt_char_val_by_uuid_read_rsp_t. */ + BLE_GATTC_EVT_READ_RSP, /**< Read Response event. \n See @ref ble_gattc_evt_read_rsp_t. */ + BLE_GATTC_EVT_CHAR_VALS_READ_RSP, /**< Read multiple Response event. \n See @ref + ble_gattc_evt_char_vals_read_rsp_t. */ + BLE_GATTC_EVT_WRITE_RSP, /**< Write Response event. \n See @ref ble_gattc_evt_write_rsp_t. */ + BLE_GATTC_EVT_HVX, /**< Handle Value Notification or Indication event. \n Confirm indication with @ref + sd_ble_gattc_hv_confirm. \n See @ref ble_gattc_evt_hvx_t. */ + BLE_GATTC_EVT_EXCHANGE_MTU_RSP, /**< Exchange MTU Response event. \n See @ref + ble_gattc_evt_exchange_mtu_rsp_t. */ + BLE_GATTC_EVT_TIMEOUT, /**< Timeout event. \n See @ref ble_gattc_evt_timeout_t. */ + BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE /**< Write without Response transmission complete. \n See @ref + ble_gattc_evt_write_cmd_tx_complete_t. */ +}; + +/**@brief GATTC Option IDs. + * IDs that uniquely identify a GATTC option. + */ +enum BLE_GATTC_OPTS { + BLE_GATTC_OPT_UUID_DISC = BLE_GATTC_OPT_BASE, /**< UUID discovery. @ref ble_gattc_opt_uuid_disc_t */ +}; + +/** @} */ + +/** @addtogroup BLE_GATTC_DEFINES Defines + * @{ */ + +/** @defgroup BLE_ERRORS_GATTC SVC return values specific to GATTC + * @{ */ +#define BLE_ERROR_GATTC_PROC_NOT_PERMITTED (NRF_GATTC_ERR_BASE + 0x000) /**< Procedure not Permitted. */ +/** @} */ + +/** @defgroup BLE_GATTC_ATTR_INFO_FORMAT Attribute Information Formats + * @{ */ +#define BLE_GATTC_ATTR_INFO_FORMAT_16BIT 1 /**< 16-bit Attribute Information Format. */ +#define BLE_GATTC_ATTR_INFO_FORMAT_128BIT 2 /**< 128-bit Attribute Information Format. */ +/** @} */ + +/** @defgroup BLE_GATTC_DEFAULTS GATT Client defaults + * @{ */ +#define BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT \ + 1 /**< Default number of Write without Response that can be queued for transmission. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATTC_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATTC connection configuration parameters, set with @ref sd_ble_cfg_set. + */ +typedef struct { + uint8_t write_cmd_tx_queue_size; /**< The guaranteed minimum number of Write without Response that can be queued for + transmission. The default value is @ref BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT */ +} ble_gattc_conn_cfg_t; + +/**@brief Operation Handle Range. */ +typedef struct { + uint16_t start_handle; /**< Start Handle. */ + uint16_t end_handle; /**< End Handle. */ +} ble_gattc_handle_range_t; + +/**@brief GATT service. */ +typedef struct { + ble_uuid_t uuid; /**< Service UUID. */ + ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */ +} ble_gattc_service_t; + +/**@brief GATT include. */ +typedef struct { + uint16_t handle; /**< Include Handle. */ + ble_gattc_service_t included_srvc; /**< Handle of the included service. */ +} ble_gattc_include_t; + +/**@brief GATT characteristic. */ +typedef struct { + ble_uuid_t uuid; /**< Characteristic UUID. */ + ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ + uint8_t char_ext_props : 1; /**< Extended properties present. */ + uint16_t handle_decl; /**< Handle of the Characteristic Declaration. */ + uint16_t handle_value; /**< Handle of the Characteristic Value. */ +} ble_gattc_char_t; + +/**@brief GATT descriptor. */ +typedef struct { + uint16_t handle; /**< Descriptor Handle. */ + ble_uuid_t uuid; /**< Descriptor UUID. */ +} ble_gattc_desc_t; + +/**@brief Write Parameters. */ +typedef struct { + uint8_t write_op; /**< Write Operation to be performed, see @ref BLE_GATT_WRITE_OPS. */ + uint8_t flags; /**< Flags, see @ref BLE_GATT_EXEC_WRITE_FLAGS. */ + uint16_t handle; /**< Handle to the attribute to be written. */ + uint16_t offset; /**< Offset in bytes. @note For WRITE_CMD and WRITE_REQ, offset must be 0. */ + uint16_t len; /**< Length of data in bytes. */ + uint8_t const *p_value; /**< Pointer to the value data. */ +} ble_gattc_write_params_t; + +/**@brief Attribute Information for 16-bit Attribute UUID. */ +typedef struct { + uint16_t handle; /**< Attribute handle. */ + ble_uuid_t uuid; /**< 16-bit Attribute UUID. */ +} ble_gattc_attr_info16_t; + +/**@brief Attribute Information for 128-bit Attribute UUID. */ +typedef struct { + uint16_t handle; /**< Attribute handle. */ + ble_uuid128_t uuid; /**< 128-bit Attribute UUID. */ +} ble_gattc_attr_info128_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Service count. */ + ble_gattc_service_t services[1]; /**< Service data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use + event structures with variable length array members. */ +} ble_gattc_evt_prim_srvc_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_REL_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Include count. */ + ble_gattc_include_t includes[1]; /**< Include data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use + event structures with variable length array members. */ +} ble_gattc_evt_rel_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Characteristic count. */ + ble_gattc_char_t chars[1]; /**< Characteristic data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event + structures with variable length array members. */ +} ble_gattc_evt_char_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_DESC_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Descriptor count. */ + ble_gattc_desc_t descs[1]; /**< Descriptor data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event + structures with variable length array members. */ +} ble_gattc_evt_desc_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Attribute count. */ + uint8_t format; /**< Attribute information format, see @ref BLE_GATTC_ATTR_INFO_FORMAT. */ + union { + ble_gattc_attr_info16_t attr_info16[1]; /**< Attribute information for 16-bit Attribute UUID. + @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on + how to use event structures with variable length array members. */ + ble_gattc_attr_info128_t attr_info128[1]; /**< Attribute information for 128-bit Attribute UUID. + @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on + how to use event structures with variable length array members. */ + } info; /**< Attribute information union. */ +} ble_gattc_evt_attr_info_disc_rsp_t; + +/**@brief GATT read by UUID handle value pair. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint8_t *p_value; /**< Pointer to the Attribute Value, length is available in @ref + ble_gattc_evt_char_val_by_uuid_read_rsp_t::value_len. */ +} ble_gattc_handle_value_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP. */ +typedef struct { + uint16_t count; /**< Handle-Value Pair Count. */ + uint16_t value_len; /**< Length of the value in Handle-Value(s) list. */ + uint8_t handle_value[1]; /**< Handle-Value(s) list. To iterate through the list use @ref + sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter. + @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with + variable length array members. */ +} ble_gattc_evt_char_val_by_uuid_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_READ_RSP. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint16_t offset; /**< Offset of the attribute data. */ + uint16_t len; /**< Attribute data length. */ + uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP. */ +typedef struct { + uint16_t len; /**< Concatenated Attribute values length. */ + uint8_t values[1]; /**< Attribute values. @note This is a variable length array. The size of 1 indicated is only a placeholder + for compilation. See @ref sd_ble_evt_get for more information on how to use event structures with + variable length array members. */ +} ble_gattc_evt_char_vals_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_RSP. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint8_t write_op; /**< Type of write operation, see @ref BLE_GATT_WRITE_OPS. */ + uint16_t offset; /**< Data offset. */ + uint16_t len; /**< Data length. */ + uint8_t data[1]; /**< Data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_write_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_HVX. */ +typedef struct { + uint16_t handle; /**< Handle to which the HVx operation applies. */ + uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ + uint16_t len; /**< Attribute data length. */ + uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_hvx_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. */ +typedef struct { + uint16_t server_rx_mtu; /**< Server RX MTU size. */ +} ble_gattc_evt_exchange_mtu_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ +} ble_gattc_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE. */ +typedef struct { + uint8_t count; /**< Number of write without response transmissions completed. */ +} ble_gattc_evt_write_cmd_tx_complete_t; + +/**@brief GATTC event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which event occurred. */ + uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ + uint16_t + error_handle; /**< In case of error: The handle causing the error. In all other cases @ref BLE_GATT_HANDLE_INVALID. */ + union { + ble_gattc_evt_prim_srvc_disc_rsp_t prim_srvc_disc_rsp; /**< Primary Service Discovery Response Event Parameters. */ + ble_gattc_evt_rel_disc_rsp_t rel_disc_rsp; /**< Relationship Discovery Response Event Parameters. */ + ble_gattc_evt_char_disc_rsp_t char_disc_rsp; /**< Characteristic Discovery Response Event Parameters. */ + ble_gattc_evt_desc_disc_rsp_t desc_disc_rsp; /**< Descriptor Discovery Response Event Parameters. */ + ble_gattc_evt_char_val_by_uuid_read_rsp_t + char_val_by_uuid_read_rsp; /**< Characteristic Value Read by UUID Response Event Parameters. */ + ble_gattc_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. */ + ble_gattc_evt_char_vals_read_rsp_t char_vals_read_rsp; /**< Characteristic Values Read Response Event Parameters. */ + ble_gattc_evt_write_rsp_t write_rsp; /**< Write Response Event Parameters. */ + ble_gattc_evt_hvx_t hvx; /**< Handle Value Notification/Indication Event Parameters. */ + ble_gattc_evt_exchange_mtu_rsp_t exchange_mtu_rsp; /**< Exchange MTU Response Event Parameters. */ + ble_gattc_evt_timeout_t timeout; /**< Timeout Event Parameters. */ + ble_gattc_evt_attr_info_disc_rsp_t attr_info_disc_rsp; /**< Attribute Information Discovery Event Parameters. */ + ble_gattc_evt_write_cmd_tx_complete_t + write_cmd_tx_complete; /**< Write without Response transmission complete Event Parameters. */ + } params; /**< Event Parameters. @note Only valid if @ref gatt_status == @ref BLE_GATT_STATUS_SUCCESS. */ +} ble_gattc_evt_t; + +/**@brief UUID discovery option. + * + * @details Used with @ref sd_ble_opt_set to enable and disable automatic insertion of discovered 128-bit UUIDs to the + * Vendor Specific UUID table. Disabled by default. + * - When disabled, if a procedure initiated by + * @ref sd_ble_gattc_primary_services_discover, + * @ref sd_ble_gattc_relationships_discover, + * @ref sd_ble_gattc_characteristics_discover, + * @ref sd_ble_gattc_descriptors_discover + * finds a 128-bit UUID which was not added by @ref sd_ble_uuid_vs_add, @ref ble_uuid_t::type will be set + * to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. + * - When enabled, all found 128-bit UUIDs will be automatically added. The application can use + * @ref sd_ble_uuid_encode to retrieve the 128-bit UUID from @ref ble_uuid_t received in the corresponding + * event. If the total number of Vendor Specific UUIDs exceeds the table capacity, @ref ble_uuid_t::type will + * be set to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. + * See also @ref ble_common_cfg_vs_uuid_t, @ref sd_ble_uuid_vs_remove. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * + * @retval ::NRF_SUCCESS Set successfully. + * + */ +typedef struct { + uint8_t auto_add_vs_enable : 1; /**< Set to 1 to enable (or 0 to disable) automatic insertion of discovered 128-bit UUIDs. */ +} ble_gattc_opt_uuid_disc_t; + +/**@brief Option structure for GATTC options. */ +typedef union { + ble_gattc_opt_uuid_disc_t uuid_disc; /**< Parameters for the UUID discovery option. */ +} ble_gattc_opt_t; + +/** @} */ + +/** @addtogroup BLE_GATTC_FUNCTIONS Functions + * @{ */ + +/**@brief Initiate or continue a GATT Primary Service Discovery procedure. + * + * @details This function initiates or resumes a Primary Service discovery procedure, starting from the supplied handle. + * If the last service has not been reached, this function must be called again with an updated start handle value to + * continue the search. See also @ref ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_PRIM_SRVC_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] start_handle Handle to start searching from. + * @param[in] p_srvc_uuid Pointer to the service UUID to be found. If it is NULL, all primary services will be returned. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Primary Service Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER, uint32_t, + sd_ble_gattc_primary_services_discover(uint16_t conn_handle, uint16_t start_handle, ble_uuid_t const *p_srvc_uuid)); + +/**@brief Initiate or continue a GATT Relationship Discovery procedure. + * + * @details This function initiates or resumes the Find Included Services sub-procedure. If the last included service has not been + * reached, this must be called again with an updated handle range to continue the search. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_REL_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_REL_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Relationship Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, uint32_t, + sd_ble_gattc_relationships_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Characteristic Discovery procedure. + * + * @details This function initiates or resumes a Characteristic discovery procedure. If the last Characteristic has not been + * reached, this must be called again with an updated handle range to continue the discovery. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_CHAR_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Characteristic Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, uint32_t, + sd_ble_gattc_characteristics_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Characteristic Descriptor Discovery procedure. + * + * @details This function initiates or resumes a Characteristic Descriptor discovery procedure. If the last Descriptor has not + * been reached, this must be called again with an updated handle range to continue the discovery. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_DESC_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_DESC_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Characteristic to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Descriptor Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t, + sd_ble_gattc_descriptors_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Read using Characteristic UUID procedure. + * + * @details This function initiates or resumes a Read using Characteristic UUID procedure. If the last Characteristic has not been + * reached, this must be called again with an updated handle range to continue the discovery. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_READ_UUID_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_uuid Pointer to a Characteristic value UUID to read. + * @param[in] p_handle_range A pointer to the range of handles to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Read using Characteristic UUID procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, uint32_t, + sd_ble_gattc_char_value_by_uuid_read(uint16_t conn_handle, ble_uuid_t const *p_uuid, + ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Read (Long) Characteristic or Descriptor procedure. + * + * @details This function initiates or resumes a GATT Read (Long) Characteristic or Descriptor procedure. If the Characteristic or + * Descriptor to be read is longer than ATT_MTU - 1, this function must be called multiple times with appropriate offset to read + * the complete value. + * + * @events + * @event{@ref BLE_GATTC_EVT_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_VALUE_READ_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] handle The handle of the attribute to be read. + * @param[in] offset Offset into the attribute value to be read. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Read (Long) procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_READ, uint32_t, sd_ble_gattc_read(uint16_t conn_handle, uint16_t handle, uint16_t offset)); + +/**@brief Initiate a GATT Read Multiple Characteristic Values procedure. + * + * @details This function initiates a GATT Read Multiple Characteristic Values procedure. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_READ_MULT_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handles A pointer to the handle(s) of the attribute(s) to be read. + * @param[in] handle_count The number of handles in p_handles. + * + * @retval ::NRF_SUCCESS Successfully started the Read Multiple Characteristic Values procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t, + sd_ble_gattc_char_values_read(uint16_t conn_handle, uint16_t const *p_handles, uint16_t handle_count)); + +/**@brief Perform a Write (Characteristic Value or Descriptor, with or without response, signed or not, long or reliable) + * procedure. + * + * @details This function can perform all write procedures described in GATT. + * + * @note Only one write with response procedure can be ongoing per connection at a time. + * If the application tries to write with response while another write with response procedure is ongoing, + * the function call will return @ref NRF_ERROR_BUSY. + * A @ref BLE_GATTC_EVT_WRITE_RSP event will be issued as soon as the write response arrives from the peer. + * + * @note The number of Write without Response that can be queued is configured by @ref + * ble_gattc_conn_cfg_t::write_cmd_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. + * A @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event will be issued as soon as the transmission of the write without + * response is complete. + * + * @note The application can keep track of the available queue element count for writes without responses by following the + * procedure below: + * - Store initial queue element count in a variable. + * - Decrement the variable, which stores the currently available queue element count, by one when a call to this + * function returns @ref NRF_SUCCESS. + * - Increment the variable, which stores the current available queue element count, by the count variable in @ref + * BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event. + * + * @events + * @event{@ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE, Write without response transmission complete.} + * @event{@ref BLE_GATTC_EVT_WRITE_RSP, Write response received from the peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_VALUE_WRITE_WITHOUT_RESP_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_WRITE_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_LONG_WRITE_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_RELIABLE_WRITE_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_write_params A pointer to a write parameters structure. + * + * @retval ::NRF_SUCCESS Successfully started the Write procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_BUSY For write with response, procedure already in progress. Wait for a @ref BLE_GATTC_EVT_WRITE_RSP event + * and retry. + * @retval ::NRF_ERROR_RESOURCES Too many writes without responses queued. + * Wait for a @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event and retry. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_WRITE, uint32_t, sd_ble_gattc_write(uint16_t conn_handle, ble_gattc_write_params_t const *p_write_params)); + +/**@brief Send a Handle Value Confirmation to the GATT Server. + * + * @mscs + * @mmsc{@ref BLE_GATTC_HVI_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] handle The handle of the attribute in the indication. + * + * @retval ::NRF_SUCCESS Successfully queued the Handle Value Confirmation for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no Indication pending to be confirmed. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_HV_CONFIRM, uint32_t, sd_ble_gattc_hv_confirm(uint16_t conn_handle, uint16_t handle)); + +/**@brief Discovers information about a range of attributes on a GATT server. + * + * @events + * @event{@ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, Generated when information about a range of attributes has been received.} + * @endevents + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range The range of handles to request information about. + * + * @retval ::NRF_SUCCESS Successfully started an attribute information discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t, + sd_ble_gattc_attr_info_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Start an ATT_MTU exchange by sending an Exchange MTU Request to the server. + * + * @details The SoftDevice sets ATT_MTU to the minimum of: + * - The Client RX MTU value, and + * - The Server RX MTU value from @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. + * + * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. + * + * @events + * @event{@ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] client_rx_mtu Client RX MTU size. + * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration + used for this connection. + * - The value must be equal to Server RX MTU size given in @ref sd_ble_gatts_exchange_mtu_reply + * if an ATT_MTU exchange has already been performed in the other direction. + * + * @retval ::NRF_SUCCESS Successfully sent request to the server. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state or an ATT_MTU exchange was already requested once. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid Client RX MTU size supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, uint32_t, + sd_ble_gattc_exchange_mtu_request(uint16_t conn_handle, uint16_t client_rx_mtu)); + +/**@brief Iterate through Handle-Value(s) list in @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. + * + * @param[in] p_gattc_evt Pointer to event buffer containing @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. + * @note If the buffer contains different event, behavior is undefined. + * @param[in,out] p_iter Iterator, points to @ref ble_gattc_handle_value_t structure that will be filled in with + * the next Handle-Value pair in each iteration. If the function returns other than + * @ref NRF_SUCCESS, it will not be changed. + * - To start iteration, initialize the structure to zero. + * - To continue, pass the value from previous iteration. + * + * \code + * ble_gattc_handle_value_t iter; + * memset(&iter, 0, sizeof(ble_gattc_handle_value_t)); + * while (sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(&ble_evt.evt.gattc_evt, &iter) == NRF_SUCCESS) + * { + * app_handle = iter.handle; + * memcpy(app_value, iter.p_value, ble_evt.evt.gattc_evt.params.char_val_by_uuid_read_rsp.value_len); + * } + * \endcode + * + * @retval ::NRF_SUCCESS Successfully retrieved the next Handle-Value pair. + * @retval ::NRF_ERROR_NOT_FOUND No more Handle-Value pairs available in the list. + */ +__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, + ble_gattc_handle_value_t *p_iter); + +/** @} */ + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION + +__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, + ble_gattc_handle_value_t *p_iter) +{ + uint32_t value_len = p_gattc_evt->params.char_val_by_uuid_read_rsp.value_len; + uint8_t *p_first = p_gattc_evt->params.char_val_by_uuid_read_rsp.handle_value; + uint8_t *p_next = p_iter->p_value ? p_iter->p_value + value_len : p_first; + + if ((p_next - p_first) / (sizeof(uint16_t) + value_len) < p_gattc_evt->params.char_val_by_uuid_read_rsp.count) { + p_iter->handle = (uint16_t)p_next[1] << 8 | p_next[0]; + p_iter->p_value = p_next + sizeof(uint16_t); + return NRF_SUCCESS; + } else { + return NRF_ERROR_NOT_FOUND; + } +} + +#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ + +#ifdef __cplusplus +} +#endif +#endif /* BLE_GATTC_H__ */ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gatts.h b/variants/wio-sdk-wm1110/softdevice/ble_gatts.h new file mode 100644 index 0000000000..dc94957cd1 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_gatts.h @@ -0,0 +1,904 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATTS Generic Attribute Profile (GATT) Server + @{ + @brief Definitions and prototypes for the GATTS interface. + */ + +#ifndef BLE_GATTS_H__ +#define BLE_GATTS_H__ + +#include "ble_err.h" +#include "ble_gap.h" +#include "ble_gatt.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATTS_ENUMERATIONS Enumerations + * @{ */ + +/** + * @brief GATTS API SVC numbers. + */ +enum BLE_GATTS_SVCS { + SD_BLE_GATTS_SERVICE_ADD = BLE_GATTS_SVC_BASE, /**< Add a service. */ + SD_BLE_GATTS_INCLUDE_ADD, /**< Add an included service. */ + SD_BLE_GATTS_CHARACTERISTIC_ADD, /**< Add a characteristic. */ + SD_BLE_GATTS_DESCRIPTOR_ADD, /**< Add a generic attribute. */ + SD_BLE_GATTS_VALUE_SET, /**< Set an attribute value. */ + SD_BLE_GATTS_VALUE_GET, /**< Get an attribute value. */ + SD_BLE_GATTS_HVX, /**< Handle Value Notification or Indication. */ + SD_BLE_GATTS_SERVICE_CHANGED, /**< Perform a Service Changed Indication to one or more peers. */ + SD_BLE_GATTS_RW_AUTHORIZE_REPLY, /**< Reply to an authorization request for a read or write operation on one or more + attributes. */ + SD_BLE_GATTS_SYS_ATTR_SET, /**< Set the persistent system attributes for a connection. */ + SD_BLE_GATTS_SYS_ATTR_GET, /**< Retrieve the persistent system attributes. */ + SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, /**< Retrieve the first valid user handle. */ + SD_BLE_GATTS_ATTR_GET, /**< Retrieve the UUID and/or metadata of an attribute. */ + SD_BLE_GATTS_EXCHANGE_MTU_REPLY /**< Reply to Exchange MTU Request. */ +}; + +/** + * @brief GATT Server Event IDs. + */ +enum BLE_GATTS_EVTS { + BLE_GATTS_EVT_WRITE = BLE_GATTS_EVT_BASE, /**< Write operation performed. \n See + @ref ble_gatts_evt_write_t. */ + BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST, /**< Read/Write Authorization request. \n Reply with + @ref sd_ble_gatts_rw_authorize_reply. \n See @ref ble_gatts_evt_rw_authorize_request_t. + */ + BLE_GATTS_EVT_SYS_ATTR_MISSING, /**< A persistent system attribute access is pending. \n Respond with @ref + sd_ble_gatts_sys_attr_set. \n See @ref ble_gatts_evt_sys_attr_missing_t. */ + BLE_GATTS_EVT_HVC, /**< Handle Value Confirmation. \n See @ref ble_gatts_evt_hvc_t. + */ + BLE_GATTS_EVT_SC_CONFIRM, /**< Service Changed Confirmation. \n No additional event + structure applies. */ + BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. \n Reply with + @ref sd_ble_gatts_exchange_mtu_reply. \n See @ref ble_gatts_evt_exchange_mtu_request_t. + */ + BLE_GATTS_EVT_TIMEOUT, /**< Peer failed to respond to an ATT request in time. \n See @ref + ble_gatts_evt_timeout_t. */ + BLE_GATTS_EVT_HVN_TX_COMPLETE /**< Handle Value Notification transmission complete. \n See @ref + ble_gatts_evt_hvn_tx_complete_t. */ +}; + +/**@brief GATTS Configuration IDs. + * + * IDs that uniquely identify a GATTS configuration. + */ +enum BLE_GATTS_CFGS { + BLE_GATTS_CFG_SERVICE_CHANGED = BLE_GATTS_CFG_BASE, /**< Service changed configuration. */ + BLE_GATTS_CFG_ATTR_TAB_SIZE, /**< Attribute table size configuration. */ + BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM, /**< Service changed CCCD permission configuration. */ +}; + +/** @} */ + +/** @addtogroup BLE_GATTS_DEFINES Defines + * @{ */ + +/** @defgroup BLE_ERRORS_GATTS SVC return values specific to GATTS + * @{ */ +#define BLE_ERROR_GATTS_INVALID_ATTR_TYPE (NRF_GATTS_ERR_BASE + 0x000) /**< Invalid attribute type. */ +#define BLE_ERROR_GATTS_SYS_ATTR_MISSING (NRF_GATTS_ERR_BASE + 0x001) /**< System Attributes missing. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_LENS_MAX Maximum attribute lengths + * @{ */ +#define BLE_GATTS_FIX_ATTR_LEN_MAX (510) /**< Maximum length for fixed length Attribute Values. */ +#define BLE_GATTS_VAR_ATTR_LEN_MAX (512) /**< Maximum length for variable length Attribute Values. */ +/** @} */ + +/** @defgroup BLE_GATTS_SRVC_TYPES GATT Server Service Types + * @{ */ +#define BLE_GATTS_SRVC_TYPE_INVALID 0x00 /**< Invalid Service Type. */ +#define BLE_GATTS_SRVC_TYPE_PRIMARY 0x01 /**< Primary Service. */ +#define BLE_GATTS_SRVC_TYPE_SECONDARY 0x02 /**< Secondary Type. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_TYPES GATT Server Attribute Types + * @{ */ +#define BLE_GATTS_ATTR_TYPE_INVALID 0x00 /**< Invalid Attribute Type. */ +#define BLE_GATTS_ATTR_TYPE_PRIM_SRVC_DECL 0x01 /**< Primary Service Declaration. */ +#define BLE_GATTS_ATTR_TYPE_SEC_SRVC_DECL 0x02 /**< Secondary Service Declaration. */ +#define BLE_GATTS_ATTR_TYPE_INC_DECL 0x03 /**< Include Declaration. */ +#define BLE_GATTS_ATTR_TYPE_CHAR_DECL 0x04 /**< Characteristic Declaration. */ +#define BLE_GATTS_ATTR_TYPE_CHAR_VAL 0x05 /**< Characteristic Value. */ +#define BLE_GATTS_ATTR_TYPE_DESC 0x06 /**< Descriptor. */ +#define BLE_GATTS_ATTR_TYPE_OTHER 0x07 /**< Other, non-GATT specific type. */ +/** @} */ + +/** @defgroup BLE_GATTS_OPS GATT Server Operations + * @{ */ +#define BLE_GATTS_OP_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATTS_OP_WRITE_REQ 0x01 /**< Write Request. */ +#define BLE_GATTS_OP_WRITE_CMD 0x02 /**< Write Command. */ +#define BLE_GATTS_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ +#define BLE_GATTS_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ +#define BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL 0x05 /**< Execute Write Request: Cancel all prepared writes. */ +#define BLE_GATTS_OP_EXEC_WRITE_REQ_NOW 0x06 /**< Execute Write Request: Immediately execute all prepared writes. */ +/** @} */ + +/** @defgroup BLE_GATTS_VLOCS GATT Value Locations + * @{ */ +#define BLE_GATTS_VLOC_INVALID 0x00 /**< Invalid Location. */ +#define BLE_GATTS_VLOC_STACK 0x01 /**< Attribute Value is located in stack memory, no user memory is required. */ +#define BLE_GATTS_VLOC_USER \ + 0x02 /**< Attribute Value is located in user memory. This requires the user to maintain a valid buffer through the lifetime \ + of the attribute, since the stack will read and write directly to the memory using the pointer provided in the APIs. \ + There are no alignment requirements for the buffer. */ +/** @} */ + +/** @defgroup BLE_GATTS_AUTHORIZE_TYPES GATT Server Authorization Types + * @{ */ +#define BLE_GATTS_AUTHORIZE_TYPE_INVALID 0x00 /**< Invalid Type. */ +#define BLE_GATTS_AUTHORIZE_TYPE_READ 0x01 /**< Authorize a Read Operation. */ +#define BLE_GATTS_AUTHORIZE_TYPE_WRITE 0x02 /**< Authorize a Write Request Operation. */ +/** @} */ + +/** @defgroup BLE_GATTS_SYS_ATTR_FLAGS System Attribute Flags + * @{ */ +#define BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS (1 << 0) /**< Restrict system attributes to system services only. */ +#define BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS (1 << 1) /**< Restrict system attributes to user services only. */ +/** @} */ + +/** @defgroup BLE_GATTS_SERVICE_CHANGED Service Changed Inclusion Values + * @{ + */ +#define BLE_GATTS_SERVICE_CHANGED_DEFAULT \ + (1) /**< Default is to include the Service Changed characteristic in the Attribute Table. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_TAB_SIZE Attribute Table size + * @{ + */ +#define BLE_GATTS_ATTR_TAB_SIZE_MIN (248) /**< Minimum Attribute Table size */ +#define BLE_GATTS_ATTR_TAB_SIZE_DEFAULT (1408) /**< Default Attribute Table size. */ +/** @} */ + +/** @defgroup BLE_GATTS_DEFAULTS GATT Server defaults + * @{ + */ +#define BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT \ + 1 /**< Default number of Handle Value Notifications that can be queued for transmission. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATTS_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATTS connection configuration parameters, set with @ref sd_ble_cfg_set. + */ +typedef struct { + uint8_t hvn_tx_queue_size; /**< Minimum guaranteed number of Handle Value Notifications that can be queued for transmission. + The default value is @ref BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT */ +} ble_gatts_conn_cfg_t; + +/**@brief Attribute metadata. */ +typedef struct { + ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */ + ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ + uint8_t vlen : 1; /**< Variable length attribute. */ + uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ + uint8_t rd_auth : 1; /**< Read authorization and value will be requested from the application on every read operation. */ + uint8_t wr_auth : 1; /**< Write authorization will be requested from the application on every Write Request operation (but not + Write Command). */ +} ble_gatts_attr_md_t; + +/**@brief GATT Attribute. */ +typedef struct { + ble_uuid_t const *p_uuid; /**< Pointer to the attribute UUID. */ + ble_gatts_attr_md_t const *p_attr_md; /**< Pointer to the attribute metadata structure. */ + uint16_t init_len; /**< Initial attribute value length in bytes. */ + uint16_t init_offs; /**< Initial attribute value offset in bytes. If different from zero, the first init_offs bytes of the + attribute value will be left uninitialized. */ + uint16_t max_len; /**< Maximum attribute value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */ + uint8_t *p_value; /**< Pointer to the attribute data. Please note that if the @ref BLE_GATTS_VLOC_USER value location is + selected in the attribute metadata, this will have to point to a buffer that remains valid through the + lifetime of the attribute. This excludes usage of automatic variables that may go out of scope or any + other temporary location. The stack may access that memory directly without the application's + knowledge. For writable characteristics, this value must not be a location in flash memory.*/ +} ble_gatts_attr_t; + +/**@brief GATT Attribute Value. */ +typedef struct { + uint16_t len; /**< Length in bytes to be written or read. Length in bytes written or read after successful return.*/ + uint16_t offset; /**< Attribute value offset. */ + uint8_t *p_value; /**< Pointer to where value is stored or will be stored. + If value is stored in user memory, only the attribute length is updated when p_value == NULL. + Set to NULL when reading to obtain the complete length of the attribute value */ +} ble_gatts_value_t; + +/**@brief GATT Characteristic Presentation Format. */ +typedef struct { + uint8_t format; /**< Format of the value, see @ref BLE_GATT_CPF_FORMATS. */ + int8_t exponent; /**< Exponent for integer data types. */ + uint16_t unit; /**< Unit from Bluetooth Assigned Numbers. */ + uint8_t name_space; /**< Namespace from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ + uint16_t desc; /**< Namespace description from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ +} ble_gatts_char_pf_t; + +/**@brief GATT Characteristic metadata. */ +typedef struct { + ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ + ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic Extended Properties. */ + uint8_t const * + p_char_user_desc; /**< Pointer to a UTF-8 encoded string (non-NULL terminated), NULL if the descriptor is not required. */ + uint16_t char_user_desc_max_size; /**< The maximum size in bytes of the user description descriptor. */ + uint16_t char_user_desc_size; /**< The size of the user description, must be smaller or equal to char_user_desc_max_size. */ + ble_gatts_char_pf_t const + *p_char_pf; /**< Pointer to a presentation format structure or NULL if the CPF descriptor is not required. */ + ble_gatts_attr_md_t const + *p_user_desc_md; /**< Attribute metadata for the User Description descriptor, or NULL for default values. */ + ble_gatts_attr_md_t const + *p_cccd_md; /**< Attribute metadata for the Client Characteristic Configuration Descriptor, or NULL for default values. */ + ble_gatts_attr_md_t const + *p_sccd_md; /**< Attribute metadata for the Server Characteristic Configuration Descriptor, or NULL for default values. */ +} ble_gatts_char_md_t; + +/**@brief GATT Characteristic Definition Handles. */ +typedef struct { + uint16_t value_handle; /**< Handle to the characteristic value. */ + uint16_t user_desc_handle; /**< Handle to the User Description descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */ + uint16_t cccd_handle; /**< Handle to the Client Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if + not present. */ + uint16_t sccd_handle; /**< Handle to the Server Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if + not present. */ +} ble_gatts_char_handles_t; + +/**@brief GATT HVx parameters. */ +typedef struct { + uint16_t handle; /**< Characteristic Value Handle. */ + uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ + uint16_t offset; /**< Offset within the attribute value. */ + uint16_t *p_len; /**< Length in bytes to be written, length in bytes written after return. */ + uint8_t const *p_data; /**< Actual data content, use NULL to use the current attribute value. */ +} ble_gatts_hvx_params_t; + +/**@brief GATT Authorization parameters. */ +typedef struct { + uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ + uint8_t update : 1; /**< If set, data supplied in p_data will be used to update the attribute value. + Please note that for @ref BLE_GATTS_AUTHORIZE_TYPE_WRITE operations this bit must always be set, + as the data to be written needs to be stored and later provided by the application. */ + uint16_t offset; /**< Offset of the attribute value being updated. */ + uint16_t len; /**< Length in bytes of the value in p_data pointer, see @ref BLE_GATTS_ATTR_LENS_MAX. */ + uint8_t const *p_data; /**< Pointer to new value used to update the attribute value. */ +} ble_gatts_authorize_params_t; + +/**@brief GATT Read or Write Authorize Reply parameters. */ +typedef struct { + uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ + union { + ble_gatts_authorize_params_t read; /**< Read authorization parameters. */ + ble_gatts_authorize_params_t write; /**< Write authorization parameters. */ + } params; /**< Reply Parameters. */ +} ble_gatts_rw_authorize_reply_params_t; + +/**@brief Service Changed Inclusion configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t service_changed : 1; /**< If 1, include the Service Changed characteristic in the Attribute Table. Default is @ref + BLE_GATTS_SERVICE_CHANGED_DEFAULT. */ +} ble_gatts_cfg_service_changed_t; + +/**@brief Service Changed CCCD permission configuration parameters, set with @ref sd_ble_cfg_set. + * + * @note @ref ble_gatts_attr_md_t::vlen is ignored and should be set to 0. + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - @ref ble_gatts_attr_md_t::write_perm is out of range. + * - @ref ble_gatts_attr_md_t::write_perm is @ref BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS, that is + * not allowed by the Bluetooth Specification. + * - wrong @ref ble_gatts_attr_md_t::read_perm, only @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN is + * allowed by the Bluetooth Specification. + * - wrong @ref ble_gatts_attr_md_t::vloc, only @ref BLE_GATTS_VLOC_STACK is allowed. + * @retval ::NRF_ERROR_NOT_SUPPORTED Security Mode 2 not supported + */ +typedef struct { + ble_gatts_attr_md_t + perm; /**< Permission for Service Changed CCCD. Default is @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN, no authorization. */ +} ble_gatts_cfg_service_changed_cccd_perm_t; + +/**@brief Attribute table size configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: + * - The specified Attribute Table size is too small. + * The minimum acceptable size is defined by @ref BLE_GATTS_ATTR_TAB_SIZE_MIN. + * - The specified Attribute Table size is not a multiple of 4. + */ +typedef struct { + uint32_t attr_tab_size; /**< Attribute table size. Default is @ref BLE_GATTS_ATTR_TAB_SIZE_DEFAULT, minimum is @ref + BLE_GATTS_ATTR_TAB_SIZE_MIN. */ +} ble_gatts_cfg_attr_tab_size_t; + +/**@brief Config structure for GATTS configurations. */ +typedef union { + ble_gatts_cfg_service_changed_t + service_changed; /**< Include service changed characteristic, cfg_id is @ref BLE_GATTS_CFG_SERVICE_CHANGED. */ + ble_gatts_cfg_service_changed_cccd_perm_t service_changed_cccd_perm; /**< Service changed CCCD permission, cfg_id is @ref + BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM. */ + ble_gatts_cfg_attr_tab_size_t attr_tab_size; /**< Attribute table size, cfg_id is @ref BLE_GATTS_CFG_ATTR_TAB_SIZE. */ +} ble_gatts_cfg_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_WRITE. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + ble_uuid_t uuid; /**< Attribute UUID. */ + uint8_t op; /**< Type of write operation, see @ref BLE_GATTS_OPS. */ + uint8_t auth_required; /**< Writing operation deferred due to authorization requirement. Application may use @ref + sd_ble_gatts_value_set to finalize the writing operation. */ + uint16_t offset; /**< Offset for the write operation. */ + uint16_t len; /**< Length of the received data. */ + uint8_t data[1]; /**< Received data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gatts_evt_write_t; + +/**@brief Event substructure for authorized read requests, see @ref ble_gatts_evt_rw_authorize_request_t. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + ble_uuid_t uuid; /**< Attribute UUID. */ + uint16_t offset; /**< Offset for the read operation. */ +} ble_gatts_evt_read_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST. */ +typedef struct { + uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ + union { + ble_gatts_evt_read_t read; /**< Attribute Read Parameters. */ + ble_gatts_evt_write_t write; /**< Attribute Write Parameters. */ + } request; /**< Request Parameters. */ +} ble_gatts_evt_rw_authorize_request_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. */ +typedef struct { + uint8_t hint; /**< Hint (currently unused). */ +} ble_gatts_evt_sys_attr_missing_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_HVC. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ +} ble_gatts_evt_hvc_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST. */ +typedef struct { + uint16_t client_rx_mtu; /**< Client RX MTU size. */ +} ble_gatts_evt_exchange_mtu_request_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ +} ble_gatts_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_HVN_TX_COMPLETE. */ +typedef struct { + uint8_t count; /**< Number of notification transmissions completed. */ +} ble_gatts_evt_hvn_tx_complete_t; + +/**@brief GATTS event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which the event occurred. */ + union { + ble_gatts_evt_write_t write; /**< Write Event Parameters. */ + ble_gatts_evt_rw_authorize_request_t authorize_request; /**< Read or Write Authorize Request Parameters. */ + ble_gatts_evt_sys_attr_missing_t sys_attr_missing; /**< System attributes missing. */ + ble_gatts_evt_hvc_t hvc; /**< Handle Value Confirmation Event Parameters. */ + ble_gatts_evt_exchange_mtu_request_t exchange_mtu_request; /**< Exchange MTU Request Event Parameters. */ + ble_gatts_evt_timeout_t timeout; /**< Timeout Event. */ + ble_gatts_evt_hvn_tx_complete_t hvn_tx_complete; /**< Handle Value Notification transmission complete Event Parameters. */ + } params; /**< Event Parameters. */ +} ble_gatts_evt_t; + +/** @} */ + +/** @addtogroup BLE_GATTS_FUNCTIONS Functions + * @{ */ + +/**@brief Add a service declaration to the Attribute Table. + * + * @note Secondary Services are only relevant in the context of the entity that references them, it is therefore forbidden to + * add a secondary service declaration that is not referenced by another service later in the Attribute Table. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] type Toggles between primary and secondary services, see @ref BLE_GATTS_SRVC_TYPES. + * @param[in] p_uuid Pointer to service UUID. + * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a service declaration. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, Vendor Specific UUIDs need to be present in the table. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type, ble_uuid_t const *p_uuid, uint16_t *p_handle)); + +/**@brief Add an include declaration to the Attribute Table. + * + * @note It is currently only possible to add an include declaration to the last added service (i.e. only sequential population is + * supported at this time). + * + * @note The included service must already be present in the Attribute Table prior to this call. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] service_handle Handle of the service where the included service is to be placed, if @ref BLE_GATT_HANDLE_INVALID + * is used, it will be placed sequentially. + * @param[in] inc_srvc_handle Handle of the included service. + * @param[out] p_include_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added an include declaration. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, handle values need to match previously added services. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. + * @retval ::NRF_ERROR_NOT_SUPPORTED Feature is not supported, service_handle must be that of the last added service. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, self inclusions are not allowed. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + */ +SVCALL(SD_BLE_GATTS_INCLUDE_ADD, uint32_t, + sd_ble_gatts_include_add(uint16_t service_handle, uint16_t inc_srvc_handle, uint16_t *p_include_handle)); + +/**@brief Add a characteristic declaration, a characteristic value declaration and optional characteristic descriptor declarations + * to the Attribute Table. + * + * @note It is currently only possible to add a characteristic to the last added service (i.e. only sequential population is + * supported at this time). + * + * @note Several restrictions apply to the parameters, such as matching permissions between the user description descriptor and + * the writable auxiliaries bits, readable (no security) and writable (selectable) CCCDs and SCCDs and valid presentation format + * values. + * + * @note If no metadata is provided for the optional descriptors, their permissions will be derived from the characteristic + * permissions. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] service_handle Handle of the service where the characteristic is to be placed, if @ref BLE_GATT_HANDLE_INVALID is + * used, it will be placed sequentially. + * @param[in] p_char_md Characteristic metadata. + * @param[in] p_attr_char_value Pointer to the attribute structure corresponding to the characteristic value. + * @param[out] p_handles Pointer to the structure where the assigned handles will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a characteristic. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, service handle, Vendor Specific UUIDs, lengths, and + * permissions need to adhere to the constraints. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + */ +SVCALL(SD_BLE_GATTS_CHARACTERISTIC_ADD, uint32_t, + sd_ble_gatts_characteristic_add(uint16_t service_handle, ble_gatts_char_md_t const *p_char_md, + ble_gatts_attr_t const *p_attr_char_value, ble_gatts_char_handles_t *p_handles)); + +/**@brief Add a descriptor to the Attribute Table. + * + * @note It is currently only possible to add a descriptor to the last added characteristic (i.e. only sequential population is + * supported at this time). + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] char_handle Handle of the characteristic where the descriptor is to be placed, if @ref BLE_GATT_HANDLE_INVALID is + * used, it will be placed sequentially. + * @param[in] p_attr Pointer to the attribute structure. + * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a descriptor. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, characteristic handle, Vendor Specific UUIDs, lengths, and + * permissions need to adhere to the constraints. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a characteristic context is required. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + */ +SVCALL(SD_BLE_GATTS_DESCRIPTOR_ADD, uint32_t, + sd_ble_gatts_descriptor_add(uint16_t char_handle, ble_gatts_attr_t const *p_attr, uint16_t *p_handle)); + +/**@brief Set the value of a given attribute. + * + * @note Values other than system attributes can be set at any time, regardless of whether any active connections exist. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. + * @param[in] handle Attribute handle. + * @param[in,out] p_value Attribute value information. + * + * @retval ::NRF_SUCCESS Successfully set the value of the attribute. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden handle supplied, certain attributes are not modifiable by the application. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. + */ +SVCALL(SD_BLE_GATTS_VALUE_SET, uint32_t, + sd_ble_gatts_value_set(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); + +/**@brief Get the value of a given attribute. + * + * @note If the attribute value is longer than the size of the supplied buffer, + * @ref ble_gatts_value_t::len will return the total attribute value length (excluding offset), + * and not the number of bytes actually returned in @ref ble_gatts_value_t::p_value. + * The application may use this information to allocate a suitable buffer size. + * + * @note When retrieving system attribute values with this function, the connection handle + * may refer to an already disconnected connection. Refer to the documentation of + * @ref sd_ble_gatts_sys_attr_get for further information. + * + * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. + * @param[in] handle Attribute handle. + * @param[in,out] p_value Attribute value information. + * + * @retval ::NRF_SUCCESS Successfully retrieved the value of the attribute. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid attribute offset supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + */ +SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, + sd_ble_gatts_value_get(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); + +/**@brief Notify or Indicate an attribute value. + * + * @details This function checks for the relevant Client Characteristic Configuration descriptor value to verify that the relevant + * operation (notification or indication) has been enabled by the client. It is also able to update the attribute value before + * issuing the PDU, so that the application can atomically perform a value update and a server initiated transaction with a single + * API call. + * + * @note The local attribute value may be updated even if an outgoing packet is not sent to the peer due to an error during + * execution. The Attribute Table has been updated if one of the following error codes is returned: @ref NRF_ERROR_INVALID_STATE, + * @ref NRF_ERROR_BUSY, + * @ref NRF_ERROR_FORBIDDEN, @ref BLE_ERROR_GATTS_SYS_ATTR_MISSING and @ref NRF_ERROR_RESOURCES. + * The caller can check whether the value has been updated by looking at the contents of *(@ref + * ble_gatts_hvx_params_t::p_len). + * + * @note Only one indication procedure can be ongoing per connection at a time. + * If the application tries to indicate an attribute value while another indication procedure is ongoing, + * the function call will return @ref NRF_ERROR_BUSY. + * A @ref BLE_GATTS_EVT_HVC event will be issued as soon as the confirmation arrives from the peer. + * + * @note The number of Handle Value Notifications that can be queued is configured by @ref + * ble_gatts_conn_cfg_t::hvn_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. A @ref + * BLE_GATTS_EVT_HVN_TX_COMPLETE event will be issued as soon as the transmission of the notification is complete. + * + * @note The application can keep track of the available queue element count for notifications by following the procedure + * below: + * - Store initial queue element count in a variable. + * - Decrement the variable, which stores the currently available queue element count, by one when a call to this + * function returns @ref NRF_SUCCESS. + * - Increment the variable, which stores the current available queue element count, by the count variable in @ref + * BLE_GATTS_EVT_HVN_TX_COMPLETE event. + * + * @events + * @event{@ref BLE_GATTS_EVT_HVN_TX_COMPLETE, Notification transmission complete.} + * @event{@ref BLE_GATTS_EVT_HVC, Confirmation received from the peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} + * @mmsc{@ref BLE_GATTS_HVN_MSC} + * @mmsc{@ref BLE_GATTS_HVI_MSC} + * @mmsc{@ref BLE_GATTS_HVX_DISABLED_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in,out] p_hvx_params Pointer to an HVx parameters structure. If @ref ble_gatts_hvx_params_t::p_data + * contains a non-NULL pointer the attribute value will be updated with the contents + * pointed by it before sending the notification or indication. If the attribute value + * is updated, @ref ble_gatts_hvx_params_t::p_len is updated by the SoftDevice to + * contain the number of actual bytes written, else it will be set to 0. + * + * @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute + * value. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: + * - Invalid Connection State + * - Notifications and/or indications not enabled in the CCCD + * - An ATT_MTU exchange is ongoing + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application + * are available to notify and indicate. + * @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and + * indicated. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_FORBIDDEN The connection's current security level is lower than the one required by the write permissions + * of the CCCD associated with this characteristic. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC + * event and retry. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + * @retval ::NRF_ERROR_RESOURCES Too many notifications queued. + * Wait for a @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event and retry. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_gatts_hvx_params_t const *p_hvx_params)); + +/**@brief Indicate the Service Changed attribute value. + * + * @details This call will send a Handle Value Indication to one or more peers connected to inform them that the Attribute + * Table layout has changed. As soon as the peer has confirmed the indication, a @ref BLE_GATTS_EVT_SC_CONFIRM event will + * be issued. + * + * @note Some of the restrictions and limitations that apply to @ref sd_ble_gatts_hvx also apply here. + * + * @events + * @event{@ref BLE_GATTS_EVT_SC_CONFIRM, Confirmation of attribute table change received from peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTS_SC_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] start_handle Start of affected attribute handle range. + * @param[in] end_handle End of affected attribute handle range. + * + * @retval ::NRF_SUCCESS Successfully queued the Service Changed indication for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_NOT_SUPPORTED Service Changed not enabled at initialization. See @ref + * sd_ble_cfg_set and @ref ble_gatts_cfg_service_changed_t. + * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: + * - Invalid Connection State + * - Notifications and/or indications not enabled in the CCCD + * - An ATT_MTU exchange is ongoing + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied, handles must be in the range populated by the + * application. + * @retval ::NRF_ERROR_BUSY Procedure already in progress. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t, + sd_ble_gatts_service_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle)); + +/**@brief Respond to a Read/Write authorization request. + * + * @note This call should only be used as a response to a @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event issued to the application. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_READ_REQ_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_WRITE_REQ_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_rw_authorize_reply_params Pointer to a structure with the attribute provided by the application. + * + * @note @ref ble_gatts_authorize_params_t::p_data is ignored when this function is used to respond + * to a @ref BLE_GATTS_AUTHORIZE_TYPE_READ event if @ref ble_gatts_authorize_params_t::update + * is set to 0. + * + * @retval ::NRF_SUCCESS Successfully queued a response to the peer, and in the case of a write operation, Attribute + * Table updated. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no authorization request pending. + * @retval ::NRF_ERROR_INVALID_PARAM Authorization op invalid, + * handle supplied does not match requested handle, + * or invalid data to be written provided by the application. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_RW_AUTHORIZE_REPLY, uint32_t, + sd_ble_gatts_rw_authorize_reply(uint16_t conn_handle, + ble_gatts_rw_authorize_reply_params_t const *p_rw_authorize_reply_params)); + +/**@brief Update persistent system attribute information. + * + * @details Supply information about persistent system attributes to the stack, + * previously obtained using @ref sd_ble_gatts_sys_attr_get. + * This call is only allowed for active connections, and is usually + * made immediately after a connection is established with an known bonded device, + * often as a response to a @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. + * + * p_sysattrs may point directly to the application's stored copy of the system attributes + * obtained using @ref sd_ble_gatts_sys_attr_get. + * If the pointer is NULL, the system attribute info is initialized, assuming that + * the application does not have any previously saved system attribute data for this device. + * + * @note The state of persistent system attributes is reset upon connection establishment and then remembered for its duration. + * + * @note If this call returns with an error code different from @ref NRF_SUCCESS, the storage of persistent system attributes may + * have been completed only partially. This means that the state of the attribute table is undefined, and the application should + * either provide a new set of attributes using this same call or reset the SoftDevice to return to a known state. + * + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system + * services will be modified. + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user + * services will be modified. + * + * @mscs + * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_UNK_PEER_MSC} + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_sys_attr_data Pointer to a saved copy of system attributes supplied to the stack, or NULL. + * @param[in] len Size of data pointed by p_sys_attr_data, in octets. + * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS + * + * @retval ::NRF_SUCCESS Successfully set the system attribute information. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. + * @retval ::NRF_ERROR_INVALID_DATA Invalid data supplied, the data should be exactly the same as retrieved with @ref + * sd_ble_gatts_sys_attr_get. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GATTS_SYS_ATTR_SET, uint32_t, + sd_ble_gatts_sys_attr_set(uint16_t conn_handle, uint8_t const *p_sys_attr_data, uint16_t len, uint32_t flags)); + +/**@brief Retrieve persistent system attribute information from the stack. + * + * @details This call is used to retrieve information about values to be stored persistently by the application + * during the lifetime of a connection or after it has been terminated. When a new connection is established with the + * same bonded device, the system attribute information retrieved with this function should be restored using using @ref + * sd_ble_gatts_sys_attr_set. If retrieved after disconnection, the data should be read before a new connection established. The + * connection handle for the previous, now disconnected, connection will remain valid until a new one is created to allow this API + * call to refer to it. Connection handles belonging to active connections can be used as well, but care should be taken since the + * system attributes may be written to at any time by the peer during a connection's lifetime. + * + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system + * services will be returned. + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user + * services will be returned. + * + * @mscs + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle of the recently terminated connection. + * @param[out] p_sys_attr_data Pointer to a buffer where updated information about system attributes will be filled in. The + * format of the data is described in @ref BLE_GATTS_SYS_ATTRS_FORMAT. NULL can be provided to obtain the length of the data. + * @param[in,out] p_len Size of application buffer if p_sys_attr_data is not NULL. Unconditionally updated to actual + * length of system attribute data. + * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS + * + * @retval ::NRF_SUCCESS Successfully retrieved the system attribute information. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. + * @retval ::NRF_ERROR_DATA_SIZE The system attribute information did not fit into the provided buffer. + * @retval ::NRF_ERROR_NOT_FOUND No system attributes found. + */ +SVCALL(SD_BLE_GATTS_SYS_ATTR_GET, uint32_t, + sd_ble_gatts_sys_attr_get(uint16_t conn_handle, uint8_t *p_sys_attr_data, uint16_t *p_len, uint32_t flags)); + +/**@brief Retrieve the first valid user attribute handle. + * + * @param[out] p_handle Pointer to an integer where the handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully retrieved the handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, uint32_t, sd_ble_gatts_initial_user_handle_get(uint16_t *p_handle)); + +/**@brief Retrieve the attribute UUID and/or metadata. + * + * @param[in] handle Attribute handle + * @param[out] p_uuid UUID of the attribute. Use NULL to omit this field. + * @param[out] p_md Metadata of the attribute. Use NULL to omit this field. + * + * @retval ::NRF_SUCCESS Successfully retrieved the attribute metadata, + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. Returned when both @c p_uuid and @c p_md are NULL. + * @retval ::NRF_ERROR_NOT_FOUND Attribute was not found. + */ +SVCALL(SD_BLE_GATTS_ATTR_GET, uint32_t, sd_ble_gatts_attr_get(uint16_t handle, ble_uuid_t *p_uuid, ble_gatts_attr_md_t *p_md)); + +/**@brief Reply to an ATT_MTU exchange request by sending an Exchange MTU Response to the client. + * + * @details This function is only used to reply to a @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event. + * + * @details The SoftDevice sets ATT_MTU to the minimum of: + * - The Client RX MTU value from @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, and + * - The Server RX MTU value. + * + * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. + * + * @mscs + * @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] server_rx_mtu Server RX MTU size. + * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration + * used for this connection. + * - The value must be equal to Client RX MTU size given in @ref sd_ble_gattc_exchange_mtu_request + * if an ATT_MTU exchange has already been performed in the other direction. + * + * @retval ::NRF_SUCCESS Successfully sent response to the client. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no ATT_MTU exchange request pending. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid Server RX MTU size supplied. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_EXCHANGE_MTU_REPLY, uint32_t, sd_ble_gatts_exchange_mtu_reply(uint16_t conn_handle, uint16_t server_rx_mtu)); +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GATTS_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_hci.h b/variants/wio-sdk-wm1110/softdevice/ble_hci.h new file mode 100644 index 0000000000..27f85d52ea --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_hci.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ +*/ + +#ifndef BLE_HCI_H__ +#define BLE_HCI_H__ +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup BLE_HCI_STATUS_CODES Bluetooth status codes + * @{ */ + +#define BLE_HCI_STATUS_CODE_SUCCESS 0x00 /**< Success. */ +#define BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND 0x01 /**< Unknown BLE Command. */ +#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02 /**< Unknown Connection Identifier. */ +/*0x03 Hardware Failure +0x04 Page Timeout +*/ +#define BLE_HCI_AUTHENTICATION_FAILURE 0x05 /**< Authentication Failure. */ +#define BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING 0x06 /**< Pin or Key missing. */ +#define BLE_HCI_MEMORY_CAPACITY_EXCEEDED 0x07 /**< Memory Capacity Exceeded. */ +#define BLE_HCI_CONNECTION_TIMEOUT 0x08 /**< Connection Timeout. */ +/*0x09 Connection Limit Exceeded +0x0A Synchronous Connection Limit To A Device Exceeded +0x0B ACL Connection Already Exists*/ +#define BLE_HCI_STATUS_CODE_COMMAND_DISALLOWED 0x0C /**< Command Disallowed. */ +/*0x0D Connection Rejected due to Limited Resources +0x0E Connection Rejected Due To Security Reasons +0x0F Connection Rejected due to Unacceptable BD_ADDR +0x10 Connection Accept Timeout Exceeded +0x11 Unsupported Feature or Parameter Value*/ +#define BLE_HCI_STATUS_CODE_INVALID_BTLE_COMMAND_PARAMETERS 0x12 /**< Invalid BLE Command Parameters. */ +#define BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION 0x13 /**< Remote User Terminated Connection. */ +#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES \ + 0x14 /**< Remote Device Terminated Connection due to low \ + resources.*/ +#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF 0x15 /**< Remote Device Terminated Connection due to power off. */ +#define BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION 0x16 /**< Local Host Terminated Connection. */ +/* +0x17 Repeated Attempts +0x18 Pairing Not Allowed +0x19 Unknown LMP PDU +*/ +#define BLE_HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A /**< Unsupported Remote Feature. */ +/* +0x1B SCO Offset Rejected +0x1C SCO Interval Rejected +0x1D SCO Air Mode Rejected*/ +#define BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS 0x1E /**< Invalid LMP Parameters. */ +#define BLE_HCI_STATUS_CODE_UNSPECIFIED_ERROR 0x1F /**< Unspecified Error. */ +/*0x20 Unsupported LMP Parameter Value +0x21 Role Change Not Allowed +*/ +#define BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT 0x22 /**< LMP Response Timeout. */ +#define BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION 0x23 /**< LMP Error Transaction Collision/LL Procedure Collision. */ +#define BLE_HCI_STATUS_CODE_LMP_PDU_NOT_ALLOWED 0x24 /**< LMP PDU Not Allowed. */ +/*0x25 Encryption Mode Not Acceptable +0x26 Link Key Can Not be Changed +0x27 Requested QoS Not Supported +*/ +#define BLE_HCI_INSTANT_PASSED 0x28 /**< Instant Passed. */ +#define BLE_HCI_PAIRING_WITH_UNIT_KEY_UNSUPPORTED 0x29 /**< Pairing with Unit Key Unsupported. */ +#define BLE_HCI_DIFFERENT_TRANSACTION_COLLISION 0x2A /**< Different Transaction Collision. */ +/* +0x2B Reserved +0x2C QoS Unacceptable Parameter +0x2D QoS Rejected +0x2E Channel Classification Not Supported +0x2F Insufficient Security +*/ +#define BLE_HCI_PARAMETER_OUT_OF_MANDATORY_RANGE 0x30 /**< Parameter Out Of Mandatory Range. */ +/* +0x31 Reserved +0x32 Role Switch Pending +0x33 Reserved +0x34 Reserved Slot Violation +0x35 Role Switch Failed +0x36 Extended Inquiry Response Too Large +0x37 Secure Simple Pairing Not Supported By Host. +0x38 Host Busy - Pairing +0x39 Connection Rejected due to No Suitable Channel Found*/ +#define BLE_HCI_CONTROLLER_BUSY 0x3A /**< Controller Busy. */ +#define BLE_HCI_CONN_INTERVAL_UNACCEPTABLE 0x3B /**< Connection Interval Unacceptable. */ +#define BLE_HCI_DIRECTED_ADVERTISER_TIMEOUT 0x3C /**< Directed Advertisement Timeout. */ +#define BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE 0x3D /**< Connection Terminated due to MIC Failure. */ +#define BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED 0x3E /**< Connection Failed to be Established. */ + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_HCI_H__ + +/** @} */ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h b/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h new file mode 100644 index 0000000000..5f4bd277d3 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h @@ -0,0 +1,495 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_L2CAP Logical Link Control and Adaptation Protocol (L2CAP) + @{ + @brief Definitions and prototypes for the L2CAP interface. + */ + +#ifndef BLE_L2CAP_H__ +#define BLE_L2CAP_H__ + +#include "ble_err.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup BLE_L2CAP_TERMINOLOGY Terminology + * @{ + * @details + * + * L2CAP SDU + * - A data unit that the application can send/receive to/from a peer. + * + * L2CAP PDU + * - A data unit that is exchanged between local and remote L2CAP entities. + * It consists of L2CAP protocol control information and payload fields. + * The payload field can contain an L2CAP SDU or a part of an L2CAP SDU. + * + * L2CAP MTU + * - The maximum length of an L2CAP SDU. + * + * L2CAP MPS + * - The maximum length of an L2CAP PDU payload field. + * + * Credits + * - A value indicating the number of L2CAP PDUs that the receiver of the credit can send to the peer. + * @} */ + +/**@addtogroup BLE_L2CAP_ENUMERATIONS Enumerations + * @{ */ + +/**@brief L2CAP API SVC numbers. */ +enum BLE_L2CAP_SVCS { + SD_BLE_L2CAP_CH_SETUP = BLE_L2CAP_SVC_BASE + 0, /**< Set up an L2CAP channel. */ + SD_BLE_L2CAP_CH_RELEASE = BLE_L2CAP_SVC_BASE + 1, /**< Release an L2CAP channel. */ + SD_BLE_L2CAP_CH_RX = BLE_L2CAP_SVC_BASE + 2, /**< Receive an SDU on an L2CAP channel. */ + SD_BLE_L2CAP_CH_TX = BLE_L2CAP_SVC_BASE + 3, /**< Transmit an SDU on an L2CAP channel. */ + SD_BLE_L2CAP_CH_FLOW_CONTROL = BLE_L2CAP_SVC_BASE + 4, /**< Advanced SDU reception flow control. */ +}; + +/**@brief L2CAP Event IDs. */ +enum BLE_L2CAP_EVTS { + BLE_L2CAP_EVT_CH_SETUP_REQUEST = BLE_L2CAP_EVT_BASE + 0, /**< L2CAP Channel Setup Request event. + \n Reply with @ref sd_ble_l2cap_ch_setup. + \n See @ref ble_l2cap_evt_ch_setup_request_t. */ + BLE_L2CAP_EVT_CH_SETUP_REFUSED = BLE_L2CAP_EVT_BASE + 1, /**< L2CAP Channel Setup Refused event. + \n See @ref ble_l2cap_evt_ch_setup_refused_t. */ + BLE_L2CAP_EVT_CH_SETUP = BLE_L2CAP_EVT_BASE + 2, /**< L2CAP Channel Setup Completed event. + \n See @ref ble_l2cap_evt_ch_setup_t. */ + BLE_L2CAP_EVT_CH_RELEASED = BLE_L2CAP_EVT_BASE + 3, /**< L2CAP Channel Released event. + \n No additional event structure applies. */ + BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED = BLE_L2CAP_EVT_BASE + 4, /**< L2CAP Channel SDU data buffer released event. + \n See @ref ble_l2cap_evt_ch_sdu_buf_released_t. */ + BLE_L2CAP_EVT_CH_CREDIT = BLE_L2CAP_EVT_BASE + 5, /**< L2CAP Channel Credit received. + \n See @ref ble_l2cap_evt_ch_credit_t. */ + BLE_L2CAP_EVT_CH_RX = BLE_L2CAP_EVT_BASE + 6, /**< L2CAP Channel SDU received. + \n See @ref ble_l2cap_evt_ch_rx_t. */ + BLE_L2CAP_EVT_CH_TX = BLE_L2CAP_EVT_BASE + 7, /**< L2CAP Channel SDU transmitted. + \n See @ref ble_l2cap_evt_ch_tx_t. */ +}; + +/** @} */ + +/**@addtogroup BLE_L2CAP_DEFINES Defines + * @{ */ + +/**@brief Maximum number of L2CAP channels per connection. */ +#define BLE_L2CAP_CH_COUNT_MAX (64) + +/**@brief Minimum L2CAP MTU, in bytes. */ +#define BLE_L2CAP_MTU_MIN (23) + +/**@brief Minimum L2CAP MPS, in bytes. */ +#define BLE_L2CAP_MPS_MIN (23) + +/**@brief Invalid CID. */ +#define BLE_L2CAP_CID_INVALID (0x0000) + +/**@brief Default number of credits for @ref sd_ble_l2cap_ch_flow_control. */ +#define BLE_L2CAP_CREDITS_DEFAULT (1) + +/**@defgroup BLE_L2CAP_CH_SETUP_REFUSED_SRCS L2CAP channel setup refused sources + * @{ */ +#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_LOCAL (0x01) /**< Local. */ +#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_REMOTE (0x02) /**< Remote. */ + /** @} */ + +/** @defgroup BLE_L2CAP_CH_STATUS_CODES L2CAP channel status codes + * @{ */ +#define BLE_L2CAP_CH_STATUS_CODE_SUCCESS (0x0000) /**< Success. */ +#define BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED (0x0002) /**< LE_PSM not supported. */ +#define BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES (0x0004) /**< No resources available. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHENTICATION (0x0005) /**< Insufficient authentication. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHORIZATION (0x0006) /**< Insufficient authorization. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC_KEY_SIZE (0x0007) /**< Insufficient encryption key size. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC (0x0008) /**< Insufficient encryption. */ +#define BLE_L2CAP_CH_STATUS_CODE_INVALID_SCID (0x0009) /**< Invalid Source CID. */ +#define BLE_L2CAP_CH_STATUS_CODE_SCID_ALLOCATED (0x000A) /**< Source CID already allocated. */ +#define BLE_L2CAP_CH_STATUS_CODE_UNACCEPTABLE_PARAMS (0x000B) /**< Unacceptable parameters. */ +#define BLE_L2CAP_CH_STATUS_CODE_NOT_UNDERSTOOD \ + (0x8000) /**< Command Reject received instead of LE Credit Based Connection Response. */ +#define BLE_L2CAP_CH_STATUS_CODE_TIMEOUT (0xC000) /**< Operation timed out. */ +/** @} */ + +/** @} */ + +/**@addtogroup BLE_L2CAP_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE L2CAP connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @note These parameters are set per connection, so all L2CAP channels created on this connection + * will have the same parameters. + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - rx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. + * - tx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. + * - ch_count is greater than @ref BLE_L2CAP_CH_COUNT_MAX. + * @retval ::NRF_ERROR_NO_MEM rx_mps or tx_mps is set too high. + */ +typedef struct { + uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall + be able to receive on L2CAP channels on connections with this + configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ + uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall + be able to transmit on L2CAP channels on connections with this + configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ + uint8_t rx_queue_size; /**< Number of SDU data buffers that can be queued for reception per + L2CAP channel. The minimum value is one. */ + uint8_t tx_queue_size; /**< Number of SDU data buffers that can be queued for transmission + per L2CAP channel. The minimum value is one. */ + uint8_t ch_count; /**< Number of L2CAP channels the application can create per connection + with this configuration. The default value is zero, the maximum + value is @ref BLE_L2CAP_CH_COUNT_MAX. + @note if this parameter is set to zero, all other parameters in + @ref ble_l2cap_conn_cfg_t are ignored. */ +} ble_l2cap_conn_cfg_t; + +/**@brief L2CAP channel RX parameters. */ +typedef struct { + uint16_t rx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP shall be able to + receive on this L2CAP channel. + - Must be equal to or greater than @ref BLE_L2CAP_MTU_MIN. */ + uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall be + able to receive on this L2CAP channel. + - Must be equal to or greater than @ref BLE_L2CAP_MPS_MIN. + - Must be equal to or less than @ref ble_l2cap_conn_cfg_t::rx_mps. */ + ble_data_t sdu_buf; /**< SDU data buffer for reception. + - If @ref ble_data_t::p_data is non-NULL, initial credits are + issued to the peer. + - If @ref ble_data_t::p_data is NULL, no initial credits are + issued to the peer. */ +} ble_l2cap_ch_rx_params_t; + +/**@brief L2CAP channel setup parameters. */ +typedef struct { + ble_l2cap_ch_rx_params_t rx_params; /**< L2CAP channel RX parameters. */ + uint16_t le_psm; /**< LE Protocol/Service Multiplexer. Used when requesting + setup of an L2CAP channel, ignored otherwise. */ + uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES. + Used when replying to a setup request of an L2CAP + channel, ignored otherwise. */ +} ble_l2cap_ch_setup_params_t; + +/**@brief L2CAP channel TX parameters. */ +typedef struct { + uint16_t tx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP is able to + transmit on this L2CAP channel. */ + uint16_t peer_mps; /**< The maximum L2CAP PDU payload size, in bytes, that the peer is + able to receive on this L2CAP channel. */ + uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP is able + to transmit on this L2CAP channel. This is effective tx_mps, + selected by the SoftDevice as + MIN( @ref ble_l2cap_ch_tx_params_t::peer_mps, @ref ble_l2cap_conn_cfg_t::tx_mps ) */ + uint16_t credits; /**< Initial credits given by the peer. */ +} ble_l2cap_ch_tx_params_t; + +/**@brief L2CAP Channel Setup Request event. */ +typedef struct { + ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ + uint16_t le_psm; /**< LE Protocol/Service Multiplexer. */ +} ble_l2cap_evt_ch_setup_request_t; + +/**@brief L2CAP Channel Setup Refused event. */ +typedef struct { + uint8_t source; /**< Source, see @ref BLE_L2CAP_CH_SETUP_REFUSED_SRCS */ + uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES */ +} ble_l2cap_evt_ch_setup_refused_t; + +/**@brief L2CAP Channel Setup Completed event. */ +typedef struct { + ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ +} ble_l2cap_evt_ch_setup_t; + +/**@brief L2CAP Channel SDU Data Buffer Released event. */ +typedef struct { + ble_data_t sdu_buf; /**< Returned reception or transmission SDU data buffer. The SoftDevice + returns SDU data buffers supplied by the application, which have + not yet been returned previously via a @ref BLE_L2CAP_EVT_CH_RX or + @ref BLE_L2CAP_EVT_CH_TX event. */ +} ble_l2cap_evt_ch_sdu_buf_released_t; + +/**@brief L2CAP Channel Credit received event. */ +typedef struct { + uint16_t credits; /**< Additional credits given by the peer. */ +} ble_l2cap_evt_ch_credit_t; + +/**@brief L2CAP Channel received SDU event. */ +typedef struct { + uint16_t sdu_len; /**< Total SDU length, in bytes. */ + ble_data_t sdu_buf; /**< SDU data buffer. + @note If there is not enough space in the buffer + (sdu_buf.len < sdu_len) then the rest of the SDU will be + silently discarded by the SoftDevice. */ +} ble_l2cap_evt_ch_rx_t; + +/**@brief L2CAP Channel transmitted SDU event. */ +typedef struct { + ble_data_t sdu_buf; /**< SDU data buffer. */ +} ble_l2cap_evt_ch_tx_t; + +/**@brief L2CAP event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which the event occured. */ + uint16_t local_cid; /**< Local Channel ID of the L2CAP channel, or + @ref BLE_L2CAP_CID_INVALID if not present. */ + union { + ble_l2cap_evt_ch_setup_request_t ch_setup_request; /**< L2CAP Channel Setup Request Event Parameters. */ + ble_l2cap_evt_ch_setup_refused_t ch_setup_refused; /**< L2CAP Channel Setup Refused Event Parameters. */ + ble_l2cap_evt_ch_setup_t ch_setup; /**< L2CAP Channel Setup Completed Event Parameters. */ + ble_l2cap_evt_ch_sdu_buf_released_t ch_sdu_buf_released; /**< L2CAP Channel SDU Data Buffer Released Event Parameters. */ + ble_l2cap_evt_ch_credit_t credit; /**< L2CAP Channel Credit Received Event Parameters. */ + ble_l2cap_evt_ch_rx_t rx; /**< L2CAP Channel SDU Received Event Parameters. */ + ble_l2cap_evt_ch_tx_t tx; /**< L2CAP Channel SDU Transmitted Event Parameters. */ + } params; /**< Event Parameters. */ +} ble_l2cap_evt_t; + +/** @} */ + +/**@addtogroup BLE_L2CAP_FUNCTIONS Functions + * @{ */ + +/**@brief Set up an L2CAP channel. + * + * @details This function is used to: + * - Request setup of an L2CAP channel: sends an LE Credit Based Connection Request packet to a peer. + * - Reply to a setup request of an L2CAP channel (if called in response to a + * @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST event): sends an LE Credit Based Connection + * Response packet to a peer. + * + * @note A call to this function will require the application to keep the SDU data buffer alive + * until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX or + * @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_SETUP, Setup successful.} + * @event{@ref BLE_L2CAP_EVT_CH_SETUP_REFUSED, Setup failed.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_SETUP_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in,out] p_local_cid Pointer to a uint16_t containing Local Channel ID of the L2CAP channel: + * - As input: @ref BLE_L2CAP_CID_INVALID when requesting setup of an L2CAP + * channel or local_cid provided in the @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST + * event when replying to a setup request of an L2CAP channel. + * - As output: local_cid for this channel. + * @param[in] p_params L2CAP channel parameters. + * + * @retval ::NRF_SUCCESS Successfully queued request or response for transmission. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_LENGTH Supplied higher rx_mps than has been configured on this link. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (L2CAP channel already set up). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_RESOURCES The limit has been reached for available L2CAP channels, + * see @ref ble_l2cap_conn_cfg_t::ch_count. + */ +SVCALL(SD_BLE_L2CAP_CH_SETUP, uint32_t, + sd_ble_l2cap_ch_setup(uint16_t conn_handle, uint16_t *p_local_cid, ble_l2cap_ch_setup_params_t const *p_params)); + +/**@brief Release an L2CAP channel. + * + * @details This sends a Disconnection Request packet to a peer. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_RELEASED, Release complete.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_RELEASE_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * + * @retval ::NRF_SUCCESS Successfully queued request for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for the L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + */ +SVCALL(SD_BLE_L2CAP_CH_RELEASE, uint32_t, sd_ble_l2cap_ch_release(uint16_t conn_handle, uint16_t local_cid)); + +/**@brief Receive an SDU on an L2CAP channel. + * + * @details This may issue additional credits to the peer using an LE Flow Control Credit packet. + * + * @note A call to this function will require the application to keep the memory pointed by + * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX + * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::rx_queue_size SDU data buffers + * for reception per L2CAP channel. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_RX, The SDU is received.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_RX_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * @param[in] p_sdu_buf Pointer to the SDU data buffer. + * + * @retval ::NRF_SUCCESS Buffer accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for an L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_RESOURCES Too many SDU data buffers supplied. Wait for a + * @ref BLE_L2CAP_EVT_CH_RX event and retry. + */ +SVCALL(SD_BLE_L2CAP_CH_RX, uint32_t, sd_ble_l2cap_ch_rx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); + +/**@brief Transmit an SDU on an L2CAP channel. + * + * @note A call to this function will require the application to keep the memory pointed by + * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_TX + * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::tx_queue_size SDUs for + * transmission per L2CAP channel. + * + * @note The application can keep track of the available credits for transmission by following + * the procedure below: + * - Store initial credits given by the peer in a variable. + * (Initial credits are provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) + * - Decrement the variable, which stores the currently available credits, by + * ceiling((@ref ble_data_t::len + 2) / tx_mps) when a call to this function returns + * @ref NRF_SUCCESS. (tx_mps is provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) + * - Increment the variable, which stores the currently available credits, by additional + * credits given by the peer in a @ref BLE_L2CAP_EVT_CH_CREDIT event. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_TX, The SDU is transmitted.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_TX_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * @param[in] p_sdu_buf Pointer to the SDU data buffer. + * + * @retval ::NRF_SUCCESS Successfully queued L2CAP SDU for transmission. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for the L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_DATA_SIZE Invalid SDU length supplied, must not be more than + * @ref ble_l2cap_ch_tx_params_t::tx_mtu provided in + * @ref BLE_L2CAP_EVT_CH_SETUP event. + * @retval ::NRF_ERROR_RESOURCES Too many SDUs queued for transmission. Wait for a + * @ref BLE_L2CAP_EVT_CH_TX event and retry. + */ +SVCALL(SD_BLE_L2CAP_CH_TX, uint32_t, sd_ble_l2cap_ch_tx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); + +/**@brief Advanced SDU reception flow control. + * + * @details Adjust the way the SoftDevice issues credits to the peer. + * This may issue additional credits to the peer using an LE Flow Control Credit packet. + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_FLOW_CONTROL_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel or @ref BLE_L2CAP_CID_INVALID to set + * the value that will be used for newly created channels. + * @param[in] credits Number of credits that the SoftDevice will make sure the peer has every + * time it starts using a new reception buffer. + * - @ref BLE_L2CAP_CREDITS_DEFAULT is the default value the SoftDevice will + * use if this function is not called. + * - If set to zero, the SoftDevice will stop issuing credits for new reception + * buffers the application provides or has provided. SDU reception that is + * currently ongoing will be allowed to complete. + * @param[out] p_credits NULL or pointer to a uint16_t. If a valid pointer is provided, it will be + * written by the SoftDevice with the number of credits that is or will be + * available to the peer. If the value written by the SoftDevice is 0 when + * credits parameter was set to 0, the peer will not be able to send more + * data until more credits are provided by calling this function again with + * credits > 0. This parameter is ignored when local_cid is set to + * @ref BLE_L2CAP_CID_INVALID. + * + * @note Application should take care when setting number of credits higher than default value. In + * this case the application must make sure that the SoftDevice always has reception buffers + * available (see @ref sd_ble_l2cap_ch_rx) for that channel. If the SoftDevice does not have + * such buffers available, packets may be NACKed on the Link Layer and all Bluetooth traffic + * on the connection handle may be stalled until the SoftDevice again has an available + * reception buffer. This applies even if the application has used this call to set the + * credits back to default, or zero. + * + * @retval ::NRF_SUCCESS Flow control parameters accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for an L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + */ +SVCALL(SD_BLE_L2CAP_CH_FLOW_CONTROL, uint32_t, + sd_ble_l2cap_ch_flow_control(uint16_t conn_handle, uint16_t local_cid, uint16_t credits, uint16_t *p_credits)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_L2CAP_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_ranges.h b/variants/wio-sdk-wm1110/softdevice/ble_ranges.h new file mode 100644 index 0000000000..2768e49967 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_ranges.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @defgroup ble_ranges Module specific SVC, event and option number subranges + @{ + + @brief Definition of SVC, event and option number subranges for each API module. + + @note + SVCs, event and option numbers are split into subranges for each API module. + Each module receives its entire allocated range of SVC calls, whether implemented or not, + but return BLE_ERROR_NOT_SUPPORTED for unimplemented or undefined calls in its range. + + Note that the symbols BLE__SVC_LAST is the end of the allocated SVC range, + rather than the last SVC function call actually defined and implemented. + + Specific SVC, event and option values are defined in each module's ble_.h file, + which defines names of each individual SVC code based on the range start value. +*/ + +#ifndef BLE_RANGES_H__ +#define BLE_RANGES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_SVC_BASE 0x60 /**< Common BLE SVC base. */ +#define BLE_SVC_LAST 0x6B /**< Common BLE SVC last. */ + +#define BLE_GAP_SVC_BASE 0x6C /**< GAP BLE SVC base. */ +#define BLE_GAP_SVC_LAST 0x9A /**< GAP BLE SVC last. */ + +#define BLE_GATTC_SVC_BASE 0x9B /**< GATTC BLE SVC base. */ +#define BLE_GATTC_SVC_LAST 0xA7 /**< GATTC BLE SVC last. */ + +#define BLE_GATTS_SVC_BASE 0xA8 /**< GATTS BLE SVC base. */ +#define BLE_GATTS_SVC_LAST 0xB7 /**< GATTS BLE SVC last. */ + +#define BLE_L2CAP_SVC_BASE 0xB8 /**< L2CAP BLE SVC base. */ +#define BLE_L2CAP_SVC_LAST 0xBF /**< L2CAP BLE SVC last. */ + +#define BLE_EVT_INVALID 0x00 /**< Invalid BLE Event. */ + +#define BLE_EVT_BASE 0x01 /**< Common BLE Event base. */ +#define BLE_EVT_LAST 0x0F /**< Common BLE Event last. */ + +#define BLE_GAP_EVT_BASE 0x10 /**< GAP BLE Event base. */ +#define BLE_GAP_EVT_LAST 0x2F /**< GAP BLE Event last. */ + +#define BLE_GATTC_EVT_BASE 0x30 /**< GATTC BLE Event base. */ +#define BLE_GATTC_EVT_LAST 0x4F /**< GATTC BLE Event last. */ + +#define BLE_GATTS_EVT_BASE 0x50 /**< GATTS BLE Event base. */ +#define BLE_GATTS_EVT_LAST 0x6F /**< GATTS BLE Event last. */ + +#define BLE_L2CAP_EVT_BASE 0x70 /**< L2CAP BLE Event base. */ +#define BLE_L2CAP_EVT_LAST 0x8F /**< L2CAP BLE Event last. */ + +#define BLE_OPT_INVALID 0x00 /**< Invalid BLE Option. */ + +#define BLE_OPT_BASE 0x01 /**< Common BLE Option base. */ +#define BLE_OPT_LAST 0x1F /**< Common BLE Option last. */ + +#define BLE_GAP_OPT_BASE 0x20 /**< GAP BLE Option base. */ +#define BLE_GAP_OPT_LAST 0x3F /**< GAP BLE Option last. */ + +#define BLE_GATT_OPT_BASE 0x40 /**< GATT BLE Option base. */ +#define BLE_GATT_OPT_LAST 0x5F /**< GATT BLE Option last. */ + +#define BLE_GATTC_OPT_BASE 0x60 /**< GATTC BLE Option base. */ +#define BLE_GATTC_OPT_LAST 0x7F /**< GATTC BLE Option last. */ + +#define BLE_GATTS_OPT_BASE 0x80 /**< GATTS BLE Option base. */ +#define BLE_GATTS_OPT_LAST 0x9F /**< GATTS BLE Option last. */ + +#define BLE_L2CAP_OPT_BASE 0xA0 /**< L2CAP BLE Option base. */ +#define BLE_L2CAP_OPT_LAST 0xBF /**< L2CAP BLE Option last. */ + +#define BLE_CFG_INVALID 0x00 /**< Invalid BLE configuration. */ + +#define BLE_CFG_BASE 0x01 /**< Common BLE configuration base. */ +#define BLE_CFG_LAST 0x1F /**< Common BLE configuration last. */ + +#define BLE_CONN_CFG_BASE 0x20 /**< BLE connection configuration base. */ +#define BLE_CONN_CFG_LAST 0x3F /**< BLE connection configuration last. */ + +#define BLE_GAP_CFG_BASE 0x40 /**< GAP BLE configuration base. */ +#define BLE_GAP_CFG_LAST 0x5F /**< GAP BLE configuration last. */ + +#define BLE_GATT_CFG_BASE 0x60 /**< GATT BLE configuration base. */ +#define BLE_GATT_CFG_LAST 0x7F /**< GATT BLE configuration last. */ + +#define BLE_GATTC_CFG_BASE 0x80 /**< GATTC BLE configuration base. */ +#define BLE_GATTC_CFG_LAST 0x9F /**< GATTC BLE configuration last. */ + +#define BLE_GATTS_CFG_BASE 0xA0 /**< GATTS BLE configuration base. */ +#define BLE_GATTS_CFG_LAST 0xBF /**< GATTS BLE configuration last. */ + +#define BLE_L2CAP_CFG_BASE 0xC0 /**< L2CAP BLE configuration base. */ +#define BLE_L2CAP_CFG_LAST 0xDF /**< L2CAP BLE configuration last. */ + +#ifdef __cplusplus +} +#endif +#endif /* BLE_RANGES_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_types.h b/variants/wio-sdk-wm1110/softdevice/ble_types.h new file mode 100644 index 0000000000..db3656cfdd --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_types.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @defgroup ble_types Common types and macro definitions + @{ + + @brief Common types and macro definitions for the BLE SoftDevice. + */ + +#ifndef BLE_TYPES_H__ +#define BLE_TYPES_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_TYPES_DEFINES Defines + * @{ */ + +/** @defgroup BLE_CONN_HANDLES BLE Connection Handles + * @{ */ +#define BLE_CONN_HANDLE_INVALID 0xFFFF /**< Invalid Connection Handle. */ +#define BLE_CONN_HANDLE_ALL 0xFFFE /**< Applies to all Connection Handles. */ +/** @} */ + +/** @defgroup BLE_UUID_VALUES Assigned Values for BLE UUIDs + * @{ */ +/* Generic UUIDs, applicable to all services */ +#define BLE_UUID_UNKNOWN 0x0000 /**< Reserved UUID. */ +#define BLE_UUID_SERVICE_PRIMARY 0x2800 /**< Primary Service. */ +#define BLE_UUID_SERVICE_SECONDARY 0x2801 /**< Secondary Service. */ +#define BLE_UUID_SERVICE_INCLUDE 0x2802 /**< Include. */ +#define BLE_UUID_CHARACTERISTIC 0x2803 /**< Characteristic. */ +#define BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP 0x2900 /**< Characteristic Extended Properties Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_USER_DESC 0x2901 /**< Characteristic User Description Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG 0x2902 /**< Client Characteristic Configuration Descriptor. */ +#define BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG 0x2903 /**< Server Characteristic Configuration Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT 0x2904 /**< Characteristic Presentation Format Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_AGGREGATE_FORMAT 0x2905 /**< Characteristic Aggregate Format Descriptor. */ +/* GATT specific UUIDs */ +#define BLE_UUID_GATT 0x1801 /**< Generic Attribute Profile. */ +#define BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED 0x2A05 /**< Service Changed Characteristic. */ +/* GAP specific UUIDs */ +#define BLE_UUID_GAP 0x1800 /**< Generic Access Profile. */ +#define BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME 0x2A00 /**< Device Name Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_APPEARANCE 0x2A01 /**< Appearance Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_RECONN_ADDR 0x2A03 /**< Reconnection Address Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_PPCP 0x2A04 /**< Peripheral Preferred Connection Parameters Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_CAR 0x2AA6 /**< Central Address Resolution Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_RPA_ONLY 0x2AC9 /**< Resolvable Private Address Only Characteristic. */ +/** @} */ + +/** @defgroup BLE_UUID_TYPES Types of UUID + * @{ */ +#define BLE_UUID_TYPE_UNKNOWN 0x00 /**< Invalid UUID type. */ +#define BLE_UUID_TYPE_BLE 0x01 /**< Bluetooth SIG UUID (16-bit). */ +#define BLE_UUID_TYPE_VENDOR_BEGIN 0x02 /**< Vendor UUID types start at this index (128-bit). */ +/** @} */ + +/** @defgroup BLE_APPEARANCES Bluetooth Appearance values + * @note Retrieved from + * http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml + * @{ */ +#define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */ +#define BLE_APPEARANCE_GENERIC_PHONE 64 /**< Generic Phone. */ +#define BLE_APPEARANCE_GENERIC_COMPUTER 128 /**< Generic Computer. */ +#define BLE_APPEARANCE_GENERIC_WATCH 192 /**< Generic Watch. */ +#define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /**< Watch: Sports Watch. */ +#define BLE_APPEARANCE_GENERIC_CLOCK 256 /**< Generic Clock. */ +#define BLE_APPEARANCE_GENERIC_DISPLAY 320 /**< Generic Display. */ +#define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /**< Generic Remote Control. */ +#define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /**< Generic Eye-glasses. */ +#define BLE_APPEARANCE_GENERIC_TAG 512 /**< Generic Tag. */ +#define BLE_APPEARANCE_GENERIC_KEYRING 576 /**< Generic Keyring. */ +#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /**< Generic Media Player. */ +#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /**< Generic Barcode Scanner. */ +#define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /**< Generic Thermometer. */ +#define BLE_APPEARANCE_THERMOMETER_EAR 769 /**< Thermometer: Ear. */ +#define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /**< Generic Heart rate Sensor. */ +#define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /**< Heart Rate Sensor: Heart Rate Belt. */ +#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /**< Generic Blood Pressure. */ +#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /**< Blood Pressure: Arm. */ +#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /**< Blood Pressure: Wrist. */ +#define BLE_APPEARANCE_GENERIC_HID 960 /**< Human Interface Device (HID). */ +#define BLE_APPEARANCE_HID_KEYBOARD 961 /**< Keyboard (HID Subtype). */ +#define BLE_APPEARANCE_HID_MOUSE 962 /**< Mouse (HID Subtype). */ +#define BLE_APPEARANCE_HID_JOYSTICK 963 /**< Joystick (HID Subtype). */ +#define BLE_APPEARANCE_HID_GAMEPAD 964 /**< Gamepad (HID Subtype). */ +#define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /**< Digitizer Tablet (HID Subtype). */ +#define BLE_APPEARANCE_HID_CARD_READER 966 /**< Card Reader (HID Subtype). */ +#define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /**< Digital Pen (HID Subtype). */ +#define BLE_APPEARANCE_HID_BARCODE 968 /**< Barcode Scanner (HID Subtype). */ +#define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /**< Generic Glucose Meter. */ +#define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /**< Generic Running Walking Sensor. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /**< Running Walking Sensor: In-Shoe. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /**< Running Walking Sensor: On-Shoe. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /**< Running Walking Sensor: On-Hip. */ +#define BLE_APPEARANCE_GENERIC_CYCLING 1152 /**< Generic Cycling. */ +#define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /**< Cycling: Cycling Computer. */ +#define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /**< Cycling: Speed Sensor. */ +#define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /**< Cycling: Cadence Sensor. */ +#define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /**< Cycling: Power Sensor. */ +#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /**< Cycling: Speed and Cadence Sensor. */ +#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /**< Generic Pulse Oximeter. */ +#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /**< Fingertip (Pulse Oximeter subtype). */ +#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /**< Wrist Worn(Pulse Oximeter subtype). */ +#define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /**< Generic Weight Scale. */ +#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /**< Generic Outdoor Sports Activity. */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /**< Location Display Device (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP \ + 5186 /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /**< Location Pod (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD \ + 5188 /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */ +/** @} */ + +/** @brief Set .type and .uuid fields of ble_uuid_struct to specified UUID value. */ +#define BLE_UUID_BLE_ASSIGN(instance, value) \ + do { \ + instance.type = BLE_UUID_TYPE_BLE; \ + instance.uuid = value; \ + } while (0) + +/** @brief Copy type and uuid members from src to dst ble_uuid_t pointer. Both pointers must be valid/non-null. */ +#define BLE_UUID_COPY_PTR(dst, src) \ + do { \ + (dst)->type = (src)->type; \ + (dst)->uuid = (src)->uuid; \ + } while (0) + +/** @brief Copy type and uuid members from src to dst ble_uuid_t struct. */ +#define BLE_UUID_COPY_INST(dst, src) \ + do { \ + (dst).type = (src).type; \ + (dst).uuid = (src).uuid; \ + } while (0) + +/** @brief Compare for equality both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ +#define BLE_UUID_EQ(p_uuid1, p_uuid2) (((p_uuid1)->type == (p_uuid2)->type) && ((p_uuid1)->uuid == (p_uuid2)->uuid)) + +/** @brief Compare for difference both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ +#define BLE_UUID_NEQ(p_uuid1, p_uuid2) (((p_uuid1)->type != (p_uuid2)->type) || ((p_uuid1)->uuid != (p_uuid2)->uuid)) + +/** @} */ + +/** @addtogroup BLE_TYPES_STRUCTURES Structures + * @{ */ + +/** @brief 128 bit UUID values. */ +typedef struct { + uint8_t uuid128[16]; /**< Little-Endian UUID bytes. */ +} ble_uuid128_t; + +/** @brief Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */ +typedef struct { + uint16_t uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */ + uint8_t + type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is @ref BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */ +} ble_uuid_t; + +/**@brief Data structure. */ +typedef struct { + uint8_t *p_data; /**< Pointer to the data buffer provided to/from the application. */ + uint16_t len; /**< Length of the data buffer, in bytes. */ +} ble_data_t; + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* BLE_TYPES_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h b/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h new file mode 100644 index 0000000000..4e0bd752ab --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2014 - 2017, Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_mbr_api Master Boot Record API + @{ + + @brief APIs for updating SoftDevice and BootLoader + +*/ + +#ifndef NRF_MBR_H__ +#define NRF_MBR_H__ + +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup NRF_MBR_DEFINES Defines + * @{ */ + +/**@brief MBR SVC Base number. */ +#define MBR_SVC_BASE (0x18) + +/**@brief Page size in words. */ +#define MBR_PAGE_SIZE_IN_WORDS (1024) + +/** @brief The size that must be reserved for the MBR when a SoftDevice is written to flash. +This is the offset where the first byte of the SoftDevice hex file is written. */ +#define MBR_SIZE (0x1000) + +/** @brief Location (in the flash memory) of the bootloader address. */ +#define MBR_BOOTLOADER_ADDR (0xFF8) + +/** @brief Location (in UICR) of the bootloader address. */ +#define MBR_UICR_BOOTLOADER_ADDR (&(NRF_UICR->NRFFW[0])) + +/** @brief Location (in the flash memory) of the address of the MBR parameter page. */ +#define MBR_PARAM_PAGE_ADDR (0xFFC) + +/** @brief Location (in UICR) of the address of the MBR parameter page. */ +#define MBR_UICR_PARAM_PAGE_ADDR (&(NRF_UICR->NRFFW[1])) + +/** @} */ + +/** @addtogroup NRF_MBR_ENUMS Enumerations + * @{ */ + +/**@brief nRF Master Boot Record API SVC numbers. */ +enum NRF_MBR_SVCS { + SD_MBR_COMMAND = MBR_SVC_BASE, /**< ::sd_mbr_command */ +}; + +/**@brief Possible values for ::sd_mbr_command_t.command */ +enum NRF_MBR_COMMANDS { + SD_MBR_COMMAND_COPY_BL, /**< Copy a new BootLoader. @see ::sd_mbr_command_copy_bl_t*/ + SD_MBR_COMMAND_COPY_SD, /**< Copy a new SoftDevice. @see ::sd_mbr_command_copy_sd_t*/ + SD_MBR_COMMAND_INIT_SD, /**< Initialize forwarding interrupts to SD, and run reset function in SD. Does not require any + parameters in ::sd_mbr_command_t params.*/ + SD_MBR_COMMAND_COMPARE, /**< This command works like memcmp. @see ::sd_mbr_command_compare_t*/ + SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET, /**< Change the address the MBR starts after a reset. @see + ::sd_mbr_command_vector_table_base_set_t*/ + SD_MBR_COMMAND_RESERVED, + SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET, /**< Start forwarding all interrupts to this address. @see + ::sd_mbr_command_irq_forward_address_set_t*/ +}; + +/** @} */ + +/** @addtogroup NRF_MBR_TYPES Types + * @{ */ + +/**@brief This command copies part of a new SoftDevice + * + * The destination area is erased before copying. + * If dst is in the middle of a flash page, that whole flash page will be erased. + * If (dst+len) is in the middle of a flash page, that whole flash page will be erased. + * + * The user of this function is responsible for setting the BPROT registers. + * + * @retval ::NRF_SUCCESS indicates that the contents of the memory blocks where copied correctly. + * @retval ::NRF_ERROR_INTERNAL indicates that the contents of the memory blocks where not verified correctly after copying. + */ +typedef struct { + uint32_t *src; /**< Pointer to the source of data to be copied.*/ + uint32_t *dst; /**< Pointer to the destination where the content is to be copied.*/ + uint32_t len; /**< Number of 32 bit words to copy. Must be a multiple of @ref MBR_PAGE_SIZE_IN_WORDS words.*/ +} sd_mbr_command_copy_sd_t; + +/**@brief This command works like memcmp, but takes the length in words. + * + * @retval ::NRF_SUCCESS indicates that the contents of both memory blocks are equal. + * @retval ::NRF_ERROR_NULL indicates that the contents of the memory blocks are not equal. + */ +typedef struct { + uint32_t *ptr1; /**< Pointer to block of memory. */ + uint32_t *ptr2; /**< Pointer to block of memory. */ + uint32_t len; /**< Number of 32 bit words to compare.*/ +} sd_mbr_command_compare_t; + +/**@brief This command copies a new BootLoader. + * + * The MBR assumes that either @ref MBR_BOOTLOADER_ADDR or @ref MBR_UICR_BOOTLOADER_ADDR is set to + * the address where the bootloader will be copied. If both addresses are set, the MBR will prioritize + * @ref MBR_BOOTLOADER_ADDR. + * + * The bootloader destination is erased by this function. + * If (destination+bl_len) is in the middle of a flash page, that whole flash page will be erased. + * + * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, + * see @ref sd_mbr_command. + * + * This command will use the flash protect peripheral (BPROT or ACL) to protect the flash that is + * not intended to be written. + * + * On success, this function will not return. It will start the new bootloader from reset-vector as normal. + * + * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. + * @retval ::NRF_ERROR_FORBIDDEN if the bootloader address is not set. + * @retval ::NRF_ERROR_INVALID_LENGTH if parameters attempts to read or write outside flash area. + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. + */ +typedef struct { + uint32_t *bl_src; /**< Pointer to the source of the bootloader to be be copied.*/ + uint32_t bl_len; /**< Number of 32 bit words to copy for BootLoader. */ +} sd_mbr_command_copy_bl_t; + +/**@brief Change the address the MBR starts after a reset + * + * Once this function has been called, this address is where the MBR will start to forward + * interrupts to after a reset. + * + * To restore default forwarding, this function should be called with @ref address set to 0. If a + * bootloader is present, interrupts will be forwarded to the bootloader. If not, interrupts will + * be forwarded to the SoftDevice. + * + * The location of a bootloader can be specified in @ref MBR_BOOTLOADER_ADDR or + * @ref MBR_UICR_BOOTLOADER_ADDR. If both addresses are set, the MBR will prioritize + * @ref MBR_BOOTLOADER_ADDR. + * + * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, + * see @ref sd_mbr_command. + * + * On success, this function will not return. It will reset the device. + * + * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. + * @retval ::NRF_ERROR_INVALID_ADDR if parameter address is outside of the flash size. + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. + */ +typedef struct { + uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ +} sd_mbr_command_vector_table_base_set_t; + +/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the MBR + * + * Unlike sd_mbr_command_vector_table_base_set_t, this function does not reset, and it does not + * change where the MBR starts after reset. + * + * @retval ::NRF_SUCCESS + */ +typedef struct { + uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ +} sd_mbr_command_irq_forward_address_set_t; + +/**@brief Input structure containing data used when calling ::sd_mbr_command + * + * Depending on what command value that is set, the corresponding params value type must also be + * set. See @ref NRF_MBR_COMMANDS for command types and corresponding params value type. If command + * @ref SD_MBR_COMMAND_INIT_SD is set, it is not necessary to set any values under params. + */ +typedef struct { + uint32_t command; /**< Type of command to be issued. See @ref NRF_MBR_COMMANDS. */ + union { + sd_mbr_command_copy_sd_t copy_sd; /**< Parameters for copy SoftDevice.*/ + sd_mbr_command_compare_t compare; /**< Parameters for verify.*/ + sd_mbr_command_copy_bl_t copy_bl; /**< Parameters for copy BootLoader. Requires parameter page. */ + sd_mbr_command_vector_table_base_set_t base_set; /**< Parameters for vector table base set. Requires parameter page.*/ + sd_mbr_command_irq_forward_address_set_t irq_forward_address_set; /**< Parameters for irq forward address set*/ + } params; /**< Command parameters. */ +} sd_mbr_command_t; + +/** @} */ + +/** @addtogroup NRF_MBR_FUNCTIONS Functions + * @{ */ + +/**@brief Issue Master Boot Record commands + * + * Commands used when updating a SoftDevice and bootloader. + * + * The @ref SD_MBR_COMMAND_COPY_BL and @ref SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET requires + * parameters to be retained by the MBR when resetting the IC. This is done in a separate flash + * page. The location of the flash page should be provided by the application in either + * @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR. If both addresses are set, the MBR + * will prioritize @ref MBR_PARAM_PAGE_ADDR. This page will be cleared by the MBR and is used to + * store the command before reset. When an address is specified, the page it refers to must not be + * used by the application. If no address is provided by the application, i.e. both + * @ref MBR_PARAM_PAGE_ADDR and @ref MBR_UICR_PARAM_PAGE_ADDR is 0xFFFFFFFF, MBR commands which use + * flash will be unavailable and return @ref NRF_ERROR_NO_MEM. + * + * @param[in] param Pointer to a struct describing the command. + * + * @note For a complete set of return values, see ::sd_mbr_command_copy_sd_t, + * ::sd_mbr_command_copy_bl_t, ::sd_mbr_command_compare_t, + * ::sd_mbr_command_vector_table_base_set_t, ::sd_mbr_command_irq_forward_address_set_t + * + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page provided + * @retval ::NRF_ERROR_INVALID_PARAM if an invalid command is given. + */ +SVCALL(SD_MBR_COMMAND, uint32_t, sd_mbr_command(sd_mbr_command_t *param)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_MBR_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error.h b/variants/wio-sdk-wm1110/softdevice/nrf_error.h new file mode 100644 index 0000000000..fb2831e191 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_error.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_error SoftDevice Global Error Codes + @{ + + @brief Global Error definitions +*/ + +/* Header guard */ +#ifndef NRF_ERROR_H__ +#define NRF_ERROR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup NRF_ERRORS_BASE Error Codes Base number definitions + * @{ */ +#define NRF_ERROR_BASE_NUM (0x0) ///< Global error base +#define NRF_ERROR_SDM_BASE_NUM (0x1000) ///< SDM error base +#define NRF_ERROR_SOC_BASE_NUM (0x2000) ///< SoC error base +#define NRF_ERROR_STK_BASE_NUM (0x3000) ///< STK error base +/** @} */ + +#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command +#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing +#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled +#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error +#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation +#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found +#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported +#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter +#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state +#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length +#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags +#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data +#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Invalid Data size +#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out +#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer +#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation +#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address +#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy +#define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded. +#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h b/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h new file mode 100644 index 0000000000..2fd6210576 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup nrf_sdm_api + @{ + @defgroup nrf_sdm_error SoftDevice Manager Error Codes + @{ + + @brief Error definitions for the SDM API +*/ + +/* Header guard */ +#ifndef NRF_ERROR_SDM_H__ +#define NRF_ERROR_SDM_H__ + +#include "nrf_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN (NRF_ERROR_SDM_BASE_NUM + 0) ///< Unknown LFCLK source. +#define NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION \ + (NRF_ERROR_SDM_BASE_NUM + 1) ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having + ///< enabled SoftDevice interrupts). +#define NRF_ERROR_SDM_INCORRECT_CLENR0 \ + (NRF_ERROR_SDM_BASE_NUM + 2) ///< Incorrect CLENR0 (can be caused by erroneous SoftDevice flashing). + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_SDM_H__ + +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h b/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h new file mode 100644 index 0000000000..cbd0ba8ac4 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup nrf_soc_api + @{ + @defgroup nrf_soc_error SoC Library Error Codes + @{ + + @brief Error definitions for the SoC library + +*/ + +/* Header guard */ +#ifndef NRF_ERROR_SOC_H__ +#define NRF_ERROR_SOC_H__ + +#include "nrf_error.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* Mutex Errors */ +#define NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN (NRF_ERROR_SOC_BASE_NUM + 0) ///< Mutex already taken + +/* NVIC errors */ +#define NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE (NRF_ERROR_SOC_BASE_NUM + 1) ///< NVIC interrupt not available +#define NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED (NRF_ERROR_SOC_BASE_NUM + 2) ///< NVIC interrupt priority not allowed +#define NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 3) ///< NVIC should not return + +/* Power errors */ +#define NRF_ERROR_SOC_POWER_MODE_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 4) ///< Power mode unknown +#define NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 5) ///< Power POF threshold unknown +#define NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 6) ///< Power off should not return + +/* Rand errors */ +#define NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES (NRF_ERROR_SOC_BASE_NUM + 7) ///< RAND not enough values + +/* PPI errors */ +#define NRF_ERROR_SOC_PPI_INVALID_CHANNEL (NRF_ERROR_SOC_BASE_NUM + 8) ///< Invalid PPI Channel +#define NRF_ERROR_SOC_PPI_INVALID_GROUP (NRF_ERROR_SOC_BASE_NUM + 9) ///< Invalid PPI Group + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_SOC_H__ +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h b/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h new file mode 100644 index 0000000000..d4ab204d96 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h @@ -0,0 +1,449 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup nrf_nvic_api SoftDevice NVIC API + * @{ + * + * @note In order to use this module, the following code has to be added to a .c file: + * \code + * nrf_nvic_state_t nrf_nvic_state = {0}; + * \endcode + * + * @note Definitions and declarations starting with __ (double underscore) in this header file are + * not intended for direct use by the application. + * + * @brief APIs for the accessing NVIC when using a SoftDevice. + * + */ + +#ifndef NRF_NVIC_H__ +#define NRF_NVIC_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup NRF_NVIC_DEFINES Defines + * @{ */ + +/**@defgroup NRF_NVIC_ISER_DEFINES SoftDevice NVIC internal definitions + * @{ */ + +#define __NRF_NVIC_NVMC_IRQn \ + (30) /**< The peripheral ID of the NVMC. IRQ numbers are used to identify peripherals, but the NVMC doesn't have an IRQ \ + number in the MDK. */ + +#define __NRF_NVIC_ISER_COUNT (2) /**< The number of ISER/ICER registers in the NVIC that are used. */ + +/**@brief Interrupt priority levels used by the SoftDevice. */ +#define __NRF_NVIC_SD_IRQ_PRIOS \ + ((uint8_t)((1U << 0) /**< Priority level high .*/ \ + | (1U << 1) /**< Priority level medium. */ \ + | (1U << 4) /**< Priority level low. */ \ + )) + +/**@brief Interrupt priority levels available to the application. */ +#define __NRF_NVIC_APP_IRQ_PRIOS ((uint8_t)~__NRF_NVIC_SD_IRQ_PRIOS) + +/**@brief Interrupts used by the SoftDevice, with IRQn in the range 0-31. */ +#define __NRF_NVIC_SD_IRQS_0 \ + ((uint32_t)((1U << POWER_CLOCK_IRQn) | (1U << RADIO_IRQn) | (1U << RTC0_IRQn) | (1U << TIMER0_IRQn) | (1U << RNG_IRQn) | \ + (1U << ECB_IRQn) | (1U << CCM_AAR_IRQn) | (1U << TEMP_IRQn) | (1U << __NRF_NVIC_NVMC_IRQn) | \ + (1U << (uint32_t)SWI5_IRQn))) + +/**@brief Interrupts used by the SoftDevice, with IRQn in the range 32-63. */ +#define __NRF_NVIC_SD_IRQS_1 ((uint32_t)0) + +/**@brief Interrupts available for to application, with IRQn in the range 0-31. */ +#define __NRF_NVIC_APP_IRQS_0 (~__NRF_NVIC_SD_IRQS_0) + +/**@brief Interrupts available for to application, with IRQn in the range 32-63. */ +#define __NRF_NVIC_APP_IRQS_1 (~__NRF_NVIC_SD_IRQS_1) + +/**@} */ + +/**@} */ + +/**@addtogroup NRF_NVIC_VARIABLES Variables + * @{ */ + +/**@brief Type representing the state struct for the SoftDevice NVIC module. */ +typedef struct { + uint32_t volatile __irq_masks[__NRF_NVIC_ISER_COUNT]; /**< IRQs enabled by the application in the NVIC. */ + uint32_t volatile __cr_flag; /**< Non-zero if already in a critical region */ +} nrf_nvic_state_t; + +/**@brief Variable keeping the state for the SoftDevice NVIC module. This must be declared in an + * application source file. */ +extern nrf_nvic_state_t nrf_nvic_state; + +/**@} */ + +/**@addtogroup NRF_NVIC_INTERNAL_FUNCTIONS SoftDevice NVIC internal functions + * @{ */ + +/**@brief Disables IRQ interrupts globally, including the SoftDevice's interrupts. + * + * @retval The value of PRIMASK prior to disabling the interrupts. + */ +__STATIC_INLINE int __sd_nvic_irq_disable(void); + +/**@brief Enables IRQ interrupts globally, including the SoftDevice's interrupts. + */ +__STATIC_INLINE void __sd_nvic_irq_enable(void); + +/**@brief Checks if IRQn is available to application + * @param[in] IRQn IRQ to check + * + * @retval 1 (true) if the IRQ to check is available to the application + */ +__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn); + +/**@brief Checks if priority is available to application + * @param[in] priority priority to check + * + * @retval 1 (true) if the priority to check is available to the application + */ +__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority); + +/**@} */ + +/**@addtogroup NRF_NVIC_FUNCTIONS SoftDevice NVIC public functions + * @{ */ + +/**@brief Enable External Interrupt. + * @note Corresponds to NVIC_EnableIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_EnableIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt was enabled. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt has a priority not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn); + +/**@brief Disable External Interrupt. + * @note Corresponds to NVIC_DisableIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_DisableIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt was disabled. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn); + +/**@brief Get Pending Interrupt. + * @note Corresponds to NVIC_GetPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_GetPendingIRQ documentation in CMSIS. + * @param[out] p_pending_irq Return value from NVIC_GetPendingIRQ. + * + * @retval ::NRF_SUCCESS The interrupt is available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq); + +/**@brief Set Pending Interrupt. + * @note Corresponds to NVIC_SetPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_SetPendingIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt is set pending. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn); + +/**@brief Clear Pending Interrupt. + * @note Corresponds to NVIC_ClearPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_ClearPendingIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt pending flag is cleared. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn); + +/**@brief Set Interrupt Priority. + * @note Corresponds to NVIC_SetPriority in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * @pre Priority is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_SetPriority documentation in CMSIS. + * @param[in] priority A valid IRQ priority for use by the application. + * + * @retval ::NRF_SUCCESS The interrupt and priority level is available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt priority is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority); + +/**@brief Get Interrupt Priority. + * @note Corresponds to NVIC_GetPriority in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_GetPriority documentation in CMSIS. + * @param[out] p_priority Return value from NVIC_GetPriority. + * + * @retval ::NRF_SUCCESS The interrupt priority is returned in p_priority. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE - IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority); + +/**@brief System Reset. + * @note Corresponds to NVIC_SystemReset in CMSIS. + * + * @retval ::NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN + */ +__STATIC_INLINE uint32_t sd_nvic_SystemReset(void); + +/**@brief Enter critical region. + * + * @post Application interrupts will be disabled. + * @note sd_nvic_critical_region_enter() and ::sd_nvic_critical_region_exit() must be called in matching pairs inside each + * execution context + * @sa sd_nvic_critical_region_exit + * + * @param[out] p_is_nested_critical_region If 1, the application is now in a nested critical region. + * + * @retval ::NRF_SUCCESS + */ +__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region); + +/**@brief Exit critical region. + * + * @pre Application has entered a critical region using ::sd_nvic_critical_region_enter. + * @post If not in a nested critical region, the application interrupts will restored to the state before + * ::sd_nvic_critical_region_enter was called. + * + * @param[in] is_nested_critical_region If this is set to 1, the critical region won't be exited. @sa + * sd_nvic_critical_region_enter. + * + * @retval ::NRF_SUCCESS + */ +__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region); + +/**@} */ + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION + +__STATIC_INLINE int __sd_nvic_irq_disable(void) +{ + int pm = __get_PRIMASK(); + __disable_irq(); + return pm; +} + +__STATIC_INLINE void __sd_nvic_irq_enable(void) +{ + __enable_irq(); +} + +__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn) +{ + if (IRQn < 32) { + return ((1UL << IRQn) & __NRF_NVIC_APP_IRQS_0) != 0; + } else if (IRQn < 64) { + return ((1UL << (IRQn - 32)) & __NRF_NVIC_APP_IRQS_1) != 0; + } else { + return 1; + } +} + +__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority) +{ + if ((priority >= (1 << __NVIC_PRIO_BITS)) || (((1 << priority) & __NRF_NVIC_APP_IRQ_PRIOS) == 0)) { + return 0; + } + return 1; +} + +__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + if (!__sd_nvic_is_app_accessible_priority(NVIC_GetPriority(IRQn))) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; + } + + if (nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] |= + (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F)); + } else { + NVIC_EnableIRQ(IRQn); + } + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + + if (nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] &= ~(1UL << ((uint32_t)(IRQn)&0x1F)); + } else { + NVIC_DisableIRQ(IRQn); + } + + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + *p_pending_irq = NVIC_GetPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + NVIC_SetPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + NVIC_ClearPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + + if (!__sd_nvic_is_app_accessible_priority(priority)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; + } + + NVIC_SetPriority(IRQn, (uint32_t)priority); + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + *p_priority = (NVIC_GetPriority(IRQn) & 0xFF); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SystemReset(void) +{ + NVIC_SystemReset(); + return NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN; +} + +__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region) +{ + int was_masked = __sd_nvic_irq_disable(); + if (!nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__cr_flag = 1; + nrf_nvic_state.__irq_masks[0] = (NVIC->ICER[0] & __NRF_NVIC_APP_IRQS_0); + NVIC->ICER[0] = __NRF_NVIC_APP_IRQS_0; + nrf_nvic_state.__irq_masks[1] = (NVIC->ICER[1] & __NRF_NVIC_APP_IRQS_1); + NVIC->ICER[1] = __NRF_NVIC_APP_IRQS_1; + *p_is_nested_critical_region = 0; + } else { + *p_is_nested_critical_region = 1; + } + if (!was_masked) { + __sd_nvic_irq_enable(); + } + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region) +{ + if (nrf_nvic_state.__cr_flag && (is_nested_critical_region == 0)) { + int was_masked = __sd_nvic_irq_disable(); + NVIC->ISER[0] = nrf_nvic_state.__irq_masks[0]; + NVIC->ISER[1] = nrf_nvic_state.__irq_masks[1]; + nrf_nvic_state.__cr_flag = 0; + if (!was_masked) { + __sd_nvic_irq_enable(); + } + } + + return NRF_SUCCESS; +} + +#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ + +#ifdef __cplusplus +} +#endif + +#endif // NRF_NVIC_H__ + +/**@} */ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h b/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h new file mode 100644 index 0000000000..2786a86a45 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_sdm_api SoftDevice Manager API + @{ + + @brief APIs for SoftDevice management. + +*/ + +#ifndef NRF_SDM_H__ +#define NRF_SDM_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_sdm.h" +#include "nrf_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup NRF_SDM_DEFINES Defines + * @{ */ +#ifdef NRFSOC_DOXYGEN +/// Declared in nrf_mbr.h +#define MBR_SIZE 0 +#warning test +#endif + +/** @brief The major version for the SoftDevice binary distributed with this header file. */ +#define SD_MAJOR_VERSION (7) + +/** @brief The minor version for the SoftDevice binary distributed with this header file. */ +#define SD_MINOR_VERSION (3) + +/** @brief The bugfix version for the SoftDevice binary distributed with this header file. */ +#define SD_BUGFIX_VERSION (0) + +/** @brief The SoftDevice variant of this firmware. */ +#define SD_VARIANT_ID 140 + +/** @brief The full version number for the SoftDevice binary this header file was distributed + * with, as a decimal number in the form Mmmmbbb, where: + * - M is major version (one or more digits) + * - mmm is minor version (three digits) + * - bbb is bugfix version (three digits). */ +#define SD_VERSION (SD_MAJOR_VERSION * 1000000 + SD_MINOR_VERSION * 1000 + SD_BUGFIX_VERSION) + +/** @brief SoftDevice Manager SVC Base number. */ +#define SDM_SVC_BASE 0x10 + +/** @brief SoftDevice unique string size in bytes. */ +#define SD_UNIQUE_STR_SIZE 20 + +/** @brief Invalid info field. Returned when an info field does not exist. */ +#define SDM_INFO_FIELD_INVALID (0) + +/** @brief Defines the SoftDevice Information Structure location (address) as an offset from +the start of the SoftDevice (without MBR)*/ +#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000) + +/** @brief Defines the absolute SoftDevice Information Structure location (address) when the + * SoftDevice is installed just above the MBR (the usual case). */ +#define SOFTDEVICE_INFO_STRUCT_ADDRESS (SOFTDEVICE_INFO_STRUCT_OFFSET + MBR_SIZE) + +/** @brief Defines the offset for the SoftDevice Information Structure size value relative to the + * SoftDevice base address. The size value is of type uint8_t. */ +#define SD_INFO_STRUCT_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET) + +/** @brief Defines the offset for the SoftDevice size value relative to the SoftDevice base address. + * The size value is of type uint32_t. */ +#define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08) + +/** @brief Defines the offset for FWID value relative to the SoftDevice base address. The FWID value + * is of type uint16_t. */ +#define SD_FWID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x0C) + +/** @brief Defines the offset for the SoftDevice ID relative to the SoftDevice base address. The ID + * is of type uint32_t. */ +#define SD_ID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x10) + +/** @brief Defines the offset for the SoftDevice version relative to the SoftDevice base address in + * the same format as @ref SD_VERSION, stored as an uint32_t. */ +#define SD_VERSION_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x14) + +/** @brief Defines the offset for the SoftDevice unique string relative to the SoftDevice base address. + * The SD_UNIQUE_STR is stored as an array of uint8_t. The size of array is @ref SD_UNIQUE_STR_SIZE. + */ +#define SD_UNIQUE_STR_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x18) + +/** @brief Defines a macro for retrieving the actual SoftDevice Information Structure size value + * from a given base address. Use @ref MBR_SIZE as the argument when the SoftDevice is + * installed just above the MBR (the usual case). */ +#define SD_INFO_STRUCT_SIZE_GET(baseaddr) (*((uint8_t *)((baseaddr) + SD_INFO_STRUCT_SIZE_OFFSET))) + +/** @brief Defines a macro for retrieving the actual SoftDevice size value from a given base + * address. Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above + * the MBR (the usual case). */ +#define SD_SIZE_GET(baseaddr) (*((uint32_t *)((baseaddr) + SD_SIZE_OFFSET))) + +/** @brief Defines the amount of flash that is used by the SoftDevice. + * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed + * just above the MBR (the usual case). + */ +#define SD_FLASH_SIZE 0x26000 + +/** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use + * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual + * case). */ +#define SD_FWID_GET(baseaddr) (*((uint16_t *)((baseaddr) + SD_FWID_OFFSET))) + +/** @brief Defines a macro for retrieving the actual SoftDevice ID from a given base address. Use + * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the + * usual case). */ +#define SD_ID_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_ID_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (*((uint32_t *)((baseaddr) + SD_ID_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/** @brief Defines a macro for retrieving the actual SoftDevice version from a given base address. + * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR + * (the usual case). */ +#define SD_VERSION_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_VERSION_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (*((uint32_t *)((baseaddr) + SD_VERSION_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/** @brief Defines a macro for retrieving the address of SoftDevice unique str based on a given base address. + * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR + * (the usual case). */ +#define SD_UNIQUE_STR_ADDR_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_UNIQUE_STR_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (((uint8_t *)((baseaddr) + SD_UNIQUE_STR_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/**@defgroup NRF_FAULT_ID_RANGES Fault ID ranges + * @{ */ +#define NRF_FAULT_ID_SD_RANGE_START 0x00000000 /**< SoftDevice ID range start. */ +#define NRF_FAULT_ID_APP_RANGE_START 0x00001000 /**< Application ID range start. */ +/**@} */ + +/**@defgroup NRF_FAULT_IDS Fault ID types + * @{ */ +#define NRF_FAULT_ID_SD_ASSERT \ + (NRF_FAULT_ID_SD_RANGE_START + 1) /**< SoftDevice assertion. The info parameter is reserved for future used. */ +#define NRF_FAULT_ID_APP_MEMACC \ + (NRF_FAULT_ID_APP_RANGE_START + 1) /**< Application invalid memory access. The info parameter will contain 0x00000000, \ + in case of SoftDevice RAM access violation. In case of SoftDevice peripheral \ + register violation the info parameter will contain the sub-region number of \ + PREGION[0], on whose address range the disallowed write access caused the \ + memory access fault. */ +/**@} */ + +/** @} */ + +/** @addtogroup NRF_SDM_ENUMS Enumerations + * @{ */ + +/**@brief nRF SoftDevice Manager API SVC numbers. */ +enum NRF_SD_SVCS { + SD_SOFTDEVICE_ENABLE = SDM_SVC_BASE, /**< ::sd_softdevice_enable */ + SD_SOFTDEVICE_DISABLE, /**< ::sd_softdevice_disable */ + SD_SOFTDEVICE_IS_ENABLED, /**< ::sd_softdevice_is_enabled */ + SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, /**< ::sd_softdevice_vector_table_base_set */ + SVC_SDM_LAST /**< Placeholder for last SDM SVC */ +}; + +/** @} */ + +/** @addtogroup NRF_SDM_DEFINES Defines + * @{ */ + +/**@defgroup NRF_CLOCK_LF_ACCURACY Clock accuracy + * @{ */ + +#define NRF_CLOCK_LF_ACCURACY_250_PPM (0) /**< Default: 250 ppm */ +#define NRF_CLOCK_LF_ACCURACY_500_PPM (1) /**< 500 ppm */ +#define NRF_CLOCK_LF_ACCURACY_150_PPM (2) /**< 150 ppm */ +#define NRF_CLOCK_LF_ACCURACY_100_PPM (3) /**< 100 ppm */ +#define NRF_CLOCK_LF_ACCURACY_75_PPM (4) /**< 75 ppm */ +#define NRF_CLOCK_LF_ACCURACY_50_PPM (5) /**< 50 ppm */ +#define NRF_CLOCK_LF_ACCURACY_30_PPM (6) /**< 30 ppm */ +#define NRF_CLOCK_LF_ACCURACY_20_PPM (7) /**< 20 ppm */ +#define NRF_CLOCK_LF_ACCURACY_10_PPM (8) /**< 10 ppm */ +#define NRF_CLOCK_LF_ACCURACY_5_PPM (9) /**< 5 ppm */ +#define NRF_CLOCK_LF_ACCURACY_2_PPM (10) /**< 2 ppm */ +#define NRF_CLOCK_LF_ACCURACY_1_PPM (11) /**< 1 ppm */ + +/** @} */ + +/**@defgroup NRF_CLOCK_LF_SRC Possible LFCLK oscillator sources + * @{ */ + +#define NRF_CLOCK_LF_SRC_RC (0) /**< LFCLK RC oscillator. */ +#define NRF_CLOCK_LF_SRC_XTAL (1) /**< LFCLK crystal oscillator. */ +#define NRF_CLOCK_LF_SRC_SYNTH (2) /**< LFCLK Synthesized from HFCLK. */ + +/** @} */ + +/** @} */ + +/** @addtogroup NRF_SDM_TYPES Types + * @{ */ + +/**@brief Type representing LFCLK oscillator source. */ +typedef struct { + uint8_t source; /**< LF oscillator clock source, see @ref NRF_CLOCK_LF_SRC. */ + uint8_t rc_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: Calibration timer interval in 1/4 second + units (nRF52: 1-32). + @note To avoid excessive clock drift, 0.5 degrees Celsius is the + maximum temperature change allowed in one calibration timer + interval. The interval should be selected to ensure this. + + @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. */ + uint8_t rc_temp_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: How often (in number of calibration + intervals) the RC oscillator shall be calibrated if the temperature + hasn't changed. + 0: Always calibrate even if the temperature hasn't changed. + 1: Only calibrate if the temperature has changed (legacy - nRF51 only). + 2-33: Check the temperature and only calibrate if it has changed, + however calibration will take place every rc_temp_ctiv + intervals in any case. + + @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. + + @note For nRF52, the application must ensure calibration at least once + every 8 seconds to ensure +/-500 ppm clock stability. The + recommended configuration for ::NRF_CLOCK_LF_SRC_RC on nRF52 is + rc_ctiv=16 and rc_temp_ctiv=2. This will ensure calibration at + least once every 8 seconds and for temperature changes of 0.5 + degrees Celsius every 4 seconds. See the Product Specification + for the nRF52 device being used for more information.*/ + uint8_t accuracy; /**< External clock accuracy used in the LL to compute timing + windows, see @ref NRF_CLOCK_LF_ACCURACY.*/ +} nrf_clock_lf_cfg_t; + +/**@brief Fault Handler type. + * + * When certain unrecoverable errors occur within the application or SoftDevice the fault handler will be called back. + * The protocol stack will be in an undefined state when this happens and the only way to recover will be to + * perform a reset, using e.g. CMSIS NVIC_SystemReset(). + * If the application returns from the fault handler the SoftDevice will call NVIC_SystemReset(). + * + * @note It is recommended to either perform a reset in the fault handler or to let the SoftDevice reset the device. + * Otherwise SoC peripherals may behave in an undefined way. For example, the RADIO peripherial may + * continously transmit packets. + * + * @note This callback is executed in HardFault context, thus SVC functions cannot be called from the fault callback. + * + * @param[in] id Fault identifier. See @ref NRF_FAULT_IDS. + * @param[in] pc The program counter of the instruction that triggered the fault. + * @param[in] info Optional additional information regarding the fault. Refer to each Fault identifier for details. + * + * @note When id is set to @ref NRF_FAULT_ID_APP_MEMACC, pc will contain the address of the instruction being executed at the time + * when the fault is detected by the CPU. The CPU program counter may have advanced up to 2 instructions (no branching) after the + * one that triggered the fault. + */ +typedef void (*nrf_fault_handler_t)(uint32_t id, uint32_t pc, uint32_t info); + +/** @} */ + +/** @addtogroup NRF_SDM_FUNCTIONS Functions + * @{ */ + +/**@brief Enables the SoftDevice and by extension the protocol stack. + * + * @note Some care must be taken if a low frequency clock source is already running when calling this function: + * If the LF clock has a different source then the one currently running, it will be stopped. Then, the new + * clock source will be started. + * + * @note This function has no effect when returning with an error. + * + * @post If return code is ::NRF_SUCCESS + * - SoC library and protocol stack APIs are made available. + * - A portion of RAM will be unavailable (see relevant SDS documentation). + * - Some peripherals will be unavailable or available only through the SoC API (see relevant SDS documentation). + * - Interrupts will not arrive from protected peripherals or interrupts. + * - nrf_nvic_ functions must be used instead of CMSIS NVIC_ functions for reliable usage of the SoftDevice. + * - Interrupt latency may be affected by the SoftDevice (see relevant SDS documentation). + * - Chosen low frequency clock source will be running. + * + * @param p_clock_lf_cfg Low frequency clock source and accuracy. + If NULL the clock will be configured as an RC source with rc_ctiv = 16 and .rc_temp_ctiv = 2 + In the case of XTAL source, the PPM accuracy of the chosen clock source must be greater than or equal to + the actual characteristics of your XTAL clock. + * @param fault_handler Callback to be invoked in case of fault, cannot be NULL. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE SoftDevice is already enabled, and the clock source and fault handler cannot be updated. + * @retval ::NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION SoftDevice interrupt is already enabled, or an enabled interrupt has + an illegal priority level. + * @retval ::NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN Unknown low frequency clock source selected. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid clock source configuration supplied in p_clock_lf_cfg. + */ +SVCALL(SD_SOFTDEVICE_ENABLE, uint32_t, + sd_softdevice_enable(nrf_clock_lf_cfg_t const *p_clock_lf_cfg, nrf_fault_handler_t fault_handler)); + +/**@brief Disables the SoftDevice and by extension the protocol stack. + * + * Idempotent function to disable the SoftDevice. + * + * @post SoC library and protocol stack APIs are made unavailable. + * @post All interrupts that was protected by the SoftDevice will be disabled and initialized to priority 0 (highest). + * @post All peripherals used by the SoftDevice will be reset to default values. + * @post All of RAM become available. + * @post All interrupts are forwarded to the application. + * @post LFCLK source chosen in ::sd_softdevice_enable will be left running. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_DISABLE, uint32_t, sd_softdevice_disable(void)); + +/**@brief Check if the SoftDevice is enabled. + * + * @param[out] p_softdevice_enabled If the SoftDevice is enabled: 1 else 0. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_IS_ENABLED, uint32_t, sd_softdevice_is_enabled(uint8_t *p_softdevice_enabled)); + +/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the SoftDevice + * + * This function is only intended to be called when a bootloader is enabled. + * + * @param[in] address The base address of the interrupt vector table for forwarded interrupts. + + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table_base_set(uint32_t address)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_SDM_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_soc.h b/variants/wio-sdk-wm1110/softdevice/nrf_soc.h new file mode 100644 index 0000000000..c649ca836d --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_soc.h @@ -0,0 +1,1046 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup nrf_soc_api SoC Library API + * @{ + * + * @brief APIs for the SoC library. + * + */ + +#ifndef NRF_SOC_H__ +#define NRF_SOC_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup NRF_SOC_DEFINES Defines + * @{ */ + +/**@brief The number of the lowest SVC number reserved for the SoC library. */ +#define SOC_SVC_BASE (0x20) /**< Base value for SVCs that are available when the SoftDevice is disabled. */ +#define SOC_SVC_BASE_NOT_AVAILABLE (0x2C) /**< Base value for SVCs that are not available when the SoftDevice is disabled. */ + +/**@brief Guaranteed time for application to process radio inactive notification. */ +#define NRF_RADIO_NOTIFICATION_INACTIVE_GUARANTEED_TIME_US (62) + +/**@brief The minimum allowed timeslot extension time. */ +#define NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US (200) + +/**@brief The maximum processing time to handle a timeslot extension. */ +#define NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US (20) + +/**@brief The latest time before the end of a timeslot the timeslot can be extended. */ +#define NRF_RADIO_MIN_EXTENSION_MARGIN_US (82) + +#define SOC_ECB_KEY_LENGTH (16) /**< ECB key length. */ +#define SOC_ECB_CLEARTEXT_LENGTH (16) /**< ECB cleartext length. */ +#define SOC_ECB_CIPHERTEXT_LENGTH (SOC_ECB_CLEARTEXT_LENGTH) /**< ECB ciphertext length. */ + +#define SD_EVT_IRQn (SWI2_IRQn) /**< SoftDevice Event IRQ number. Used for both protocol events and SoC events. */ +#define SD_EVT_IRQHandler \ + (SWI2_IRQHandler) /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. \ + The default interrupt priority for this handler is set to 6 */ +#define RADIO_NOTIFICATION_IRQn (SWI1_IRQn) /**< The radio notification IRQ number. */ +#define RADIO_NOTIFICATION_IRQHandler \ + (SWI1_IRQHandler) /**< The radio notification IRQ handler. \ + The default interrupt priority for this handler is set to 6 */ +#define NRF_RADIO_LENGTH_MIN_US (100) /**< The shortest allowed radio timeslot, in microseconds. */ +#define NRF_RADIO_LENGTH_MAX_US (100000) /**< The longest allowed radio timeslot, in microseconds. */ + +#define NRF_RADIO_DISTANCE_MAX_US \ + (128000000UL - 1UL) /**< The longest timeslot distance, in microseconds, allowed for the distance parameter (see @ref \ + nrf_radio_request_normal_t) in the request. */ + +#define NRF_RADIO_EARLIEST_TIMEOUT_MAX_US \ + (128000000UL - 1UL) /**< The longest timeout, in microseconds, allowed when requesting the earliest possible timeslot. */ + +#define NRF_RADIO_START_JITTER_US \ + (2) /**< The maximum jitter in @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START relative to the requested start time. */ + +/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is disabled. */ +#define NRF_SOC_SD_PPI_CHANNELS_SD_DISABLED_MSK ((uint32_t)(0)) + +/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is enabled. */ +#define NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK \ + ((uint32_t)((1U << 17) | (1U << 18) | (1U << 19) | (1U << 20) | (1U << 21) | (1U << 22) | (1U << 23) | (1U << 24) | \ + (1U << 25) | (1U << 26) | (1U << 27) | (1U << 28) | (1U << 29) | (1U << 30) | (1U << 31))) + +/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is disabled. */ +#define NRF_SOC_SD_PPI_GROUPS_SD_DISABLED_MSK ((uint32_t)(0)) + +/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is enabled. */ +#define NRF_SOC_SD_PPI_GROUPS_SD_ENABLED_MSK ((uint32_t)((1U << 4) | (1U << 5))) + +/**@} */ + +/**@addtogroup NRF_SOC_ENUMS Enumerations + * @{ */ + +/**@brief The SVC numbers used by the SVC functions in the SoC library. */ +enum NRF_SOC_SVCS { + SD_PPI_CHANNEL_ENABLE_GET = SOC_SVC_BASE, + SD_PPI_CHANNEL_ENABLE_SET = SOC_SVC_BASE + 1, + SD_PPI_CHANNEL_ENABLE_CLR = SOC_SVC_BASE + 2, + SD_PPI_CHANNEL_ASSIGN = SOC_SVC_BASE + 3, + SD_PPI_GROUP_TASK_ENABLE = SOC_SVC_BASE + 4, + SD_PPI_GROUP_TASK_DISABLE = SOC_SVC_BASE + 5, + SD_PPI_GROUP_ASSIGN = SOC_SVC_BASE + 6, + SD_PPI_GROUP_GET = SOC_SVC_BASE + 7, + SD_FLASH_PAGE_ERASE = SOC_SVC_BASE + 8, + SD_FLASH_WRITE = SOC_SVC_BASE + 9, + SD_PROTECTED_REGISTER_WRITE = SOC_SVC_BASE + 11, + SD_MUTEX_NEW = SOC_SVC_BASE_NOT_AVAILABLE, + SD_MUTEX_ACQUIRE = SOC_SVC_BASE_NOT_AVAILABLE + 1, + SD_MUTEX_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 2, + SD_RAND_APPLICATION_POOL_CAPACITY_GET = SOC_SVC_BASE_NOT_AVAILABLE + 3, + SD_RAND_APPLICATION_BYTES_AVAILABLE_GET = SOC_SVC_BASE_NOT_AVAILABLE + 4, + SD_RAND_APPLICATION_VECTOR_GET = SOC_SVC_BASE_NOT_AVAILABLE + 5, + SD_POWER_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 6, + SD_POWER_SYSTEM_OFF = SOC_SVC_BASE_NOT_AVAILABLE + 7, + SD_POWER_RESET_REASON_GET = SOC_SVC_BASE_NOT_AVAILABLE + 8, + SD_POWER_RESET_REASON_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 9, + SD_POWER_POF_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 10, + SD_POWER_POF_THRESHOLD_SET = SOC_SVC_BASE_NOT_AVAILABLE + 11, + SD_POWER_POF_THRESHOLDVDDH_SET = SOC_SVC_BASE_NOT_AVAILABLE + 12, + SD_POWER_RAM_POWER_SET = SOC_SVC_BASE_NOT_AVAILABLE + 13, + SD_POWER_RAM_POWER_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 14, + SD_POWER_RAM_POWER_GET = SOC_SVC_BASE_NOT_AVAILABLE + 15, + SD_POWER_GPREGRET_SET = SOC_SVC_BASE_NOT_AVAILABLE + 16, + SD_POWER_GPREGRET_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 17, + SD_POWER_GPREGRET_GET = SOC_SVC_BASE_NOT_AVAILABLE + 18, + SD_POWER_DCDC_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 19, + SD_POWER_DCDC0_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 20, + SD_APP_EVT_WAIT = SOC_SVC_BASE_NOT_AVAILABLE + 21, + SD_CLOCK_HFCLK_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 22, + SD_CLOCK_HFCLK_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 23, + SD_CLOCK_HFCLK_IS_RUNNING = SOC_SVC_BASE_NOT_AVAILABLE + 24, + SD_RADIO_NOTIFICATION_CFG_SET = SOC_SVC_BASE_NOT_AVAILABLE + 25, + SD_ECB_BLOCK_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 26, + SD_ECB_BLOCKS_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 27, + SD_RADIO_SESSION_OPEN = SOC_SVC_BASE_NOT_AVAILABLE + 28, + SD_RADIO_SESSION_CLOSE = SOC_SVC_BASE_NOT_AVAILABLE + 29, + SD_RADIO_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 30, + SD_EVT_GET = SOC_SVC_BASE_NOT_AVAILABLE + 31, + SD_TEMP_GET = SOC_SVC_BASE_NOT_AVAILABLE + 32, + SD_POWER_USBPWRRDY_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 33, + SD_POWER_USBDETECTED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 34, + SD_POWER_USBREMOVED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 35, + SD_POWER_USBREGSTATUS_GET = SOC_SVC_BASE_NOT_AVAILABLE + 36, + SVC_SOC_LAST = SOC_SVC_BASE_NOT_AVAILABLE + 37 +}; + +/**@brief Possible values of a ::nrf_mutex_t. */ +enum NRF_MUTEX_VALUES { NRF_MUTEX_FREE, NRF_MUTEX_TAKEN }; + +/**@brief Power modes. */ +enum NRF_POWER_MODES { + NRF_POWER_MODE_CONSTLAT, /**< Constant latency mode. See power management in the reference manual. */ + NRF_POWER_MODE_LOWPWR /**< Low power mode. See power management in the reference manual. */ +}; + +/**@brief Power failure thresholds */ +enum NRF_POWER_THRESHOLDS { + NRF_POWER_THRESHOLD_V17 = 4UL, /**< 1.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V18, /**< 1.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V19, /**< 1.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V20, /**< 2.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V21, /**< 2.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V22, /**< 2.2 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V23, /**< 2.3 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V24, /**< 2.4 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V25, /**< 2.5 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V26, /**< 2.6 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V27, /**< 2.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V28 /**< 2.8 Volts power failure threshold. */ +}; + +/**@brief Power failure thresholds for high voltage */ +enum NRF_POWER_THRESHOLDVDDHS { + NRF_POWER_THRESHOLDVDDH_V27, /**< 2.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V28, /**< 2.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V29, /**< 2.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V30, /**< 3.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V31, /**< 3.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V32, /**< 3.2 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V33, /**< 3.3 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V34, /**< 3.4 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V35, /**< 3.5 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V36, /**< 3.6 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V37, /**< 3.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V38, /**< 3.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V39, /**< 3.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V40, /**< 4.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V41, /**< 4.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V42 /**< 4.2 Volts power failure threshold. */ +}; + +/**@brief DC/DC converter modes. */ +enum NRF_POWER_DCDC_MODES { + NRF_POWER_DCDC_DISABLE, /**< The DCDC is disabled. */ + NRF_POWER_DCDC_ENABLE /**< The DCDC is enabled. */ +}; + +/**@brief Radio notification distances. */ +enum NRF_RADIO_NOTIFICATION_DISTANCES { + NRF_RADIO_NOTIFICATION_DISTANCE_NONE = 0, /**< The event does not have a notification. */ + NRF_RADIO_NOTIFICATION_DISTANCE_800US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_1740US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_2680US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_3620US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_4560US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_5500US /**< The distance from the active notification to start of radio activity. */ +}; + +/**@brief Radio notification types. */ +enum NRF_RADIO_NOTIFICATION_TYPES { + NRF_RADIO_NOTIFICATION_TYPE_NONE = 0, /**< The event does not have a radio notification signal. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, /**< Using interrupt for notification when the radio will be enabled. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, /**< Using interrupt for notification when the radio has been disabled. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, /**< Using interrupt for notification both when the radio will be enabled and + disabled. */ +}; + +/**@brief The Radio signal callback types. */ +enum NRF_RADIO_CALLBACK_SIGNAL_TYPE { + NRF_RADIO_CALLBACK_SIGNAL_TYPE_START, /**< This signal indicates the start of the radio timeslot. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0, /**< This signal indicates the NRF_TIMER0 interrupt. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO, /**< This signal indicates the NRF_RADIO interrupt. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED, /**< This signal indicates extend action failed. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED /**< This signal indicates extend action succeeded. */ +}; + +/**@brief The actions requested by the signal callback. + * + * This code gives the SOC instructions about what action to take when the signal callback has + * returned. + */ +enum NRF_RADIO_SIGNAL_CALLBACK_ACTION { + NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE, /**< Return without action. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND, /**< Request an extension of the current + timeslot. Maximum execution time for this action: + @ref NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US. + This action must be started at least + @ref NRF_RADIO_MIN_EXTENSION_MARGIN_US before + the end of the timeslot. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_END, /**< End the current radio timeslot. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END /**< Request a new radio timeslot and end the current timeslot. */ +}; + +/**@brief Radio timeslot high frequency clock source configuration. */ +enum NRF_RADIO_HFCLK_CFG { + NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED, /**< The SoftDevice will guarantee that the high frequency clock source is the + external crystal for the whole duration of the timeslot. This should be the + preferred option for events that use the radio or require high timing accuracy. + @note The SoftDevice will automatically turn on and off the external crystal, + at the beginning and end of the timeslot, respectively. The crystal may also + intentionally be left running after the timeslot, in cases where it is needed + by the SoftDevice shortly after the end of the timeslot. */ + NRF_RADIO_HFCLK_CFG_NO_GUARANTEE /**< This configuration allows for earlier and tighter scheduling of timeslots. + The RC oscillator may be the clock source in part or for the whole duration of the + timeslot. The RC oscillator's accuracy must therefore be taken into consideration. + @note If the application will use the radio peripheral in timeslots with this + configuration, it must make sure that the crystal is running and stable before + starting the radio. */ +}; + +/**@brief Radio timeslot priorities. */ +enum NRF_RADIO_PRIORITY { + NRF_RADIO_PRIORITY_HIGH, /**< High (equal priority as the normal connection priority of the SoftDevice stack(s)). */ + NRF_RADIO_PRIORITY_NORMAL, /**< Normal (equal priority as the priority of secondary activities of the SoftDevice stack(s)). */ +}; + +/**@brief Radio timeslot request type. */ +enum NRF_RADIO_REQUEST_TYPE { + NRF_RADIO_REQ_TYPE_EARLIEST, /**< Request radio timeslot as early as possible. This should always be used for the first + request in a session. */ + NRF_RADIO_REQ_TYPE_NORMAL /**< Normal radio timeslot request. */ +}; + +/**@brief SoC Events. */ +enum NRF_SOC_EVTS { + NRF_EVT_HFCLKSTARTED, /**< Event indicating that the HFCLK has started. */ + NRF_EVT_POWER_FAILURE_WARNING, /**< Event indicating that a power failure warning has occurred. */ + NRF_EVT_FLASH_OPERATION_SUCCESS, /**< Event indicating that the ongoing flash operation has completed successfully. */ + NRF_EVT_FLASH_OPERATION_ERROR, /**< Event indicating that the ongoing flash operation has timed out with an error. */ + NRF_EVT_RADIO_BLOCKED, /**< Event indicating that a radio timeslot was blocked. */ + NRF_EVT_RADIO_CANCELED, /**< Event indicating that a radio timeslot was canceled by SoftDevice. */ + NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN, /**< Event indicating that a radio timeslot signal callback handler return was + invalid. */ + NRF_EVT_RADIO_SESSION_IDLE, /**< Event indicating that a radio timeslot session is idle. */ + NRF_EVT_RADIO_SESSION_CLOSED, /**< Event indicating that a radio timeslot session is closed. */ + NRF_EVT_POWER_USB_POWER_READY, /**< Event indicating that a USB 3.3 V supply is ready. */ + NRF_EVT_POWER_USB_DETECTED, /**< Event indicating that voltage supply is detected on VBUS. */ + NRF_EVT_POWER_USB_REMOVED, /**< Event indicating that voltage supply is removed from VBUS. */ + NRF_EVT_NUMBER_OF_EVTS +}; + +/**@} */ + +/**@addtogroup NRF_SOC_STRUCTURES Structures + * @{ */ + +/**@brief Represents a mutex for use with the nrf_mutex functions. + * @note Accessing the value directly is not safe, use the mutex functions! + */ +typedef volatile uint8_t nrf_mutex_t; + +/**@brief Parameters for a request for a timeslot as early as possible. */ +typedef struct { + uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ + uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ + uint32_t length_us; /**< The radio timeslot length (in the range 100 to 100,000] microseconds). */ + uint32_t timeout_us; /**< Longest acceptable delay until the start of the requested timeslot (up to @ref + NRF_RADIO_EARLIEST_TIMEOUT_MAX_US microseconds). */ +} nrf_radio_request_earliest_t; + +/**@brief Parameters for a normal radio timeslot request. */ +typedef struct { + uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ + uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ + uint32_t distance_us; /**< Distance from the start of the previous radio timeslot (up to @ref NRF_RADIO_DISTANCE_MAX_US + microseconds). */ + uint32_t length_us; /**< The radio timeslot length (in the range [100..100,000] microseconds). */ +} nrf_radio_request_normal_t; + +/**@brief Radio timeslot request parameters. */ +typedef struct { + uint8_t request_type; /**< Type of request, see @ref NRF_RADIO_REQUEST_TYPE. */ + union { + nrf_radio_request_earliest_t earliest; /**< Parameters for requesting a radio timeslot as early as possible. */ + nrf_radio_request_normal_t normal; /**< Parameters for requesting a normal radio timeslot. */ + } params; /**< Parameter union. */ +} nrf_radio_request_t; + +/**@brief Return parameters of the radio timeslot signal callback. */ +typedef struct { + uint8_t callback_action; /**< The action requested by the application when returning from the signal callback, see @ref + NRF_RADIO_SIGNAL_CALLBACK_ACTION. */ + union { + struct { + nrf_radio_request_t *p_next; /**< The request parameters for the next radio timeslot. */ + } request; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END. */ + struct { + uint32_t length_us; /**< Requested extension of the radio timeslot duration (microseconds) (for minimum time see @ref + NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US). */ + } extend; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND. */ + } params; /**< Parameter union. */ +} nrf_radio_signal_callback_return_param_t; + +/**@brief The radio timeslot signal callback type. + * + * @note In case of invalid return parameters, the radio timeslot will automatically end + * immediately after returning from the signal callback and the + * @ref NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN event will be sent. + * @note The returned struct pointer must remain valid after the signal callback + * function returns. For instance, this means that it must not point to a stack variable. + * + * @param[in] signal_type Type of signal, see @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE. + * + * @return Pointer to structure containing action requested by the application. + */ +typedef nrf_radio_signal_callback_return_param_t *(*nrf_radio_signal_callback_t)(uint8_t signal_type); + +/**@brief AES ECB parameter typedefs */ +typedef uint8_t soc_ecb_key_t[SOC_ECB_KEY_LENGTH]; /**< Encryption key type. */ +typedef uint8_t soc_ecb_cleartext_t[SOC_ECB_CLEARTEXT_LENGTH]; /**< Cleartext data type. */ +typedef uint8_t soc_ecb_ciphertext_t[SOC_ECB_CIPHERTEXT_LENGTH]; /**< Ciphertext data type. */ + +/**@brief AES ECB data structure */ +typedef struct { + soc_ecb_key_t key; /**< Encryption key. */ + soc_ecb_cleartext_t cleartext; /**< Cleartext data. */ + soc_ecb_ciphertext_t ciphertext; /**< Ciphertext data. */ +} nrf_ecb_hal_data_t; + +/**@brief AES ECB block. Used to provide multiple blocks in a single call + to @ref sd_ecb_blocks_encrypt.*/ +typedef struct { + soc_ecb_key_t const *p_key; /**< Pointer to the Encryption key. */ + soc_ecb_cleartext_t const *p_cleartext; /**< Pointer to the Cleartext data. */ + soc_ecb_ciphertext_t *p_ciphertext; /**< Pointer to the Ciphertext data. */ +} nrf_ecb_hal_data_block_t; + +/**@} */ + +/**@addtogroup NRF_SOC_FUNCTIONS Functions + * @{ */ + +/**@brief Initialize a mutex. + * + * @param[in] p_mutex Pointer to the mutex to initialize. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_MUTEX_NEW, uint32_t, sd_mutex_new(nrf_mutex_t *p_mutex)); + +/**@brief Attempt to acquire a mutex. + * + * @param[in] p_mutex Pointer to the mutex to acquire. + * + * @retval ::NRF_SUCCESS The mutex was successfully acquired. + * @retval ::NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN The mutex could not be acquired. + */ +SVCALL(SD_MUTEX_ACQUIRE, uint32_t, sd_mutex_acquire(nrf_mutex_t *p_mutex)); + +/**@brief Release a mutex. + * + * @param[in] p_mutex Pointer to the mutex to release. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_MUTEX_RELEASE, uint32_t, sd_mutex_release(nrf_mutex_t *p_mutex)); + +/**@brief Query the capacity of the application random pool. + * + * @param[out] p_pool_capacity The capacity of the pool. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RAND_APPLICATION_POOL_CAPACITY_GET, uint32_t, sd_rand_application_pool_capacity_get(uint8_t *p_pool_capacity)); + +/**@brief Get number of random bytes available to the application. + * + * @param[out] p_bytes_available The number of bytes currently available in the pool. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RAND_APPLICATION_BYTES_AVAILABLE_GET, uint32_t, sd_rand_application_bytes_available_get(uint8_t *p_bytes_available)); + +/**@brief Get random bytes from the application pool. + * + * @param[out] p_buff Pointer to unit8_t buffer for storing the bytes. + * @param[in] length Number of bytes to take from pool and place in p_buff. + * + * @retval ::NRF_SUCCESS The requested bytes were written to p_buff. + * @retval ::NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES No bytes were written to the buffer, because there were not enough bytes + * available. + */ +SVCALL(SD_RAND_APPLICATION_VECTOR_GET, uint32_t, sd_rand_application_vector_get(uint8_t *p_buff, uint8_t length)); + +/**@brief Gets the reset reason register. + * + * @param[out] p_reset_reason Contents of the NRF_POWER->RESETREAS register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RESET_REASON_GET, uint32_t, sd_power_reset_reason_get(uint32_t *p_reset_reason)); + +/**@brief Clears the bits of the reset reason register. + * + * @param[in] reset_reason_clr_msk Contains the bits to clear from the reset reason register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RESET_REASON_CLR, uint32_t, sd_power_reset_reason_clr(uint32_t reset_reason_clr_msk)); + +/**@brief Sets the power mode when in CPU sleep. + * + * @param[in] power_mode The power mode to use when in CPU sleep, see @ref NRF_POWER_MODES. @sa sd_app_evt_wait + * + * @retval ::NRF_SUCCESS The power mode was set. + * @retval ::NRF_ERROR_SOC_POWER_MODE_UNKNOWN The power mode was unknown. + */ +SVCALL(SD_POWER_MODE_SET, uint32_t, sd_power_mode_set(uint8_t power_mode)); + +/**@brief Puts the chip in System OFF mode. + * + * @retval ::NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN + */ +SVCALL(SD_POWER_SYSTEM_OFF, uint32_t, sd_power_system_off(void)); + +/**@brief Enables or disables the power-fail comparator. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_FAILURE_WARNING) when the power failure warning occurs. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] pof_enable True if the power-fail comparator should be enabled, false if it should be disabled. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_POF_ENABLE, uint32_t, sd_power_pof_enable(uint8_t pof_enable)); + +/**@brief Enables or disables the USB power ready event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_POWER_READY) when a USB 3.3 V supply is ready. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbpwrrdy_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBPWRRDY_ENABLE, uint32_t, sd_power_usbpwrrdy_enable(uint8_t usbpwrrdy_enable)); + +/**@brief Enables or disables the power USB-detected event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_DETECTED) when a voltage supply is detected on VBUS. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbdetected_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBDETECTED_ENABLE, uint32_t, sd_power_usbdetected_enable(uint8_t usbdetected_enable)); + +/**@brief Enables or disables the power USB-removed event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_REMOVED) when a voltage supply is removed from VBUS. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbremoved_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBREMOVED_ENABLE, uint32_t, sd_power_usbremoved_enable(uint8_t usbremoved_enable)); + +/**@brief Get USB supply status register content. + * + * @param[out] usbregstatus The content of USBREGSTATUS register. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBREGSTATUS_GET, uint32_t, sd_power_usbregstatus_get(uint32_t *usbregstatus)); + +/**@brief Sets the power failure comparator threshold value. + * + * @note: Power failure comparator threshold setting. This setting applies both for normal voltage + * mode (supply connected to both VDD and VDDH) and high voltage mode (supply connected to + * VDDH only). + * + * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDS. + * + * @retval ::NRF_SUCCESS The power failure threshold was set. + * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. + */ +SVCALL(SD_POWER_POF_THRESHOLD_SET, uint32_t, sd_power_pof_threshold_set(uint8_t threshold)); + +/**@brief Sets the power failure comparator threshold value for high voltage. + * + * @note: Power failure comparator threshold setting for high voltage mode (supply connected to + * VDDH only). This setting does not apply for normal voltage mode (supply connected to both + * VDD and VDDH). + * + * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDVDDHS. + * + * @retval ::NRF_SUCCESS The power failure threshold was set. + * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. + */ +SVCALL(SD_POWER_POF_THRESHOLDVDDH_SET, uint32_t, sd_power_pof_thresholdvddh_set(uint8_t threshold)); + +/**@brief Writes the NRF_POWER->RAM[index].POWERSET register. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERSET register to write to. + * @param[in] ram_powerset Contains the word to write to the NRF_POWER->RAM[index].POWERSET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_SET, uint32_t, sd_power_ram_power_set(uint8_t index, uint32_t ram_powerset)); + +/**@brief Writes the NRF_POWER->RAM[index].POWERCLR register. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERCLR register to write to. + * @param[in] ram_powerclr Contains the word to write to the NRF_POWER->RAM[index].POWERCLR register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_CLR, uint32_t, sd_power_ram_power_clr(uint8_t index, uint32_t ram_powerclr)); + +/**@brief Get contents of NRF_POWER->RAM[index].POWER register, indicates power status of RAM[index] blocks. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWER register to read from. + * @param[out] p_ram_power Content of NRF_POWER->RAM[index].POWER register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_GET, uint32_t, sd_power_ram_power_get(uint8_t index, uint32_t *p_ram_power)); + +/**@brief Set bits in the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[in] gpregret_msk Bits to be set in the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_SET, uint32_t, sd_power_gpregret_set(uint32_t gpregret_id, uint32_t gpregret_msk)); + +/**@brief Clear bits in the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[in] gpregret_msk Bits to be clear in the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_CLR, uint32_t, sd_power_gpregret_clr(uint32_t gpregret_id, uint32_t gpregret_msk)); + +/**@brief Get contents of the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[out] p_gpregret Contents of the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_GET, uint32_t, sd_power_gpregret_get(uint32_t gpregret_id, uint32_t *p_gpregret)); + +/**@brief Enable or disable the DC/DC regulator for the regulator stage 1 (REG1). + * + * @param[in] dcdc_mode The mode of the DCDC, see @ref NRF_POWER_DCDC_MODES. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_PARAM The DCDC mode is invalid. + */ +SVCALL(SD_POWER_DCDC_MODE_SET, uint32_t, sd_power_dcdc_mode_set(uint8_t dcdc_mode)); + +/**@brief Enable or disable the DC/DC regulator for the regulator stage 0 (REG0). + * + * For more details on the REG0 stage, please see product specification. + * + * @param[in] dcdc_mode The mode of the DCDC0, see @ref NRF_POWER_DCDC_MODES. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_PARAM The dcdc_mode is invalid. + */ +SVCALL(SD_POWER_DCDC0_MODE_SET, uint32_t, sd_power_dcdc0_mode_set(uint8_t dcdc_mode)); + +/**@brief Request the high frequency crystal oscillator. + * + * Will start the high frequency crystal oscillator, the startup time of the crystal varies + * and the ::sd_clock_hfclk_is_running function can be polled to check if it has started. + * + * @see sd_clock_hfclk_is_running + * @see sd_clock_hfclk_release + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_REQUEST, uint32_t, sd_clock_hfclk_request(void)); + +/**@brief Releases the high frequency crystal oscillator. + * + * Will stop the high frequency crystal oscillator, this happens immediately. + * + * @see sd_clock_hfclk_is_running + * @see sd_clock_hfclk_request + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_RELEASE, uint32_t, sd_clock_hfclk_release(void)); + +/**@brief Checks if the high frequency crystal oscillator is running. + * + * @see sd_clock_hfclk_request + * @see sd_clock_hfclk_release + * + * @param[out] p_is_running 1 if the external crystal oscillator is running, 0 if not. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_IS_RUNNING, uint32_t, sd_clock_hfclk_is_running(uint32_t *p_is_running)); + +/**@brief Waits for an application event. + * + * An application event is either an application interrupt or a pended interrupt when the interrupt + * is disabled. + * + * When the application waits for an application event by calling this function, an interrupt that + * is enabled will be taken immediately on pending since this function will wait in thread mode, + * then the execution will return in the application's main thread. + * + * In order to wake up from disabled interrupts, the SEVONPEND flag has to be set in the Cortex-M + * MCU's System Control Register (SCR), CMSIS_SCB. In that case, when a disabled interrupt gets + * pended, this function will return to the application's main thread. + * + * @note The application must ensure that the pended flag is cleared using ::sd_nvic_ClearPendingIRQ + * in order to sleep using this function. This is only necessary for disabled interrupts, as + * the interrupt handler will clear the pending flag automatically for enabled interrupts. + * + * @note If an application interrupt has happened since the last time sd_app_evt_wait was + * called this function will return immediately and not go to sleep. This is to avoid race + * conditions that can occur when a flag is updated in the interrupt handler and processed + * in the main loop. + * + * @post An application interrupt has happened or a interrupt pending flag is set. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_APP_EVT_WAIT, uint32_t, sd_app_evt_wait(void)); + +/**@brief Get PPI channel enable register contents. + * + * @param[out] p_channel_enable The contents of the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_GET, uint32_t, sd_ppi_channel_enable_get(uint32_t *p_channel_enable)); + +/**@brief Set PPI channel enable register. + * + * @param[in] channel_enable_set_msk Mask containing the bits to set in the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_SET, uint32_t, sd_ppi_channel_enable_set(uint32_t channel_enable_set_msk)); + +/**@brief Clear PPI channel enable register. + * + * @param[in] channel_enable_clr_msk Mask containing the bits to clear in the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_CLR, uint32_t, sd_ppi_channel_enable_clr(uint32_t channel_enable_clr_msk)); + +/**@brief Assign endpoints to a PPI channel. + * + * @param[in] channel_num Number of the PPI channel to assign. + * @param[in] evt_endpoint Event endpoint of the PPI channel. + * @param[in] task_endpoint Task endpoint of the PPI channel. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_CHANNEL The channel number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ASSIGN, uint32_t, + sd_ppi_channel_assign(uint8_t channel_num, const volatile void *evt_endpoint, const volatile void *task_endpoint)); + +/**@brief Task to enable a channel group. + * + * @param[in] group_num Number of the channel group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_TASK_ENABLE, uint32_t, sd_ppi_group_task_enable(uint8_t group_num)); + +/**@brief Task to disable a channel group. + * + * @param[in] group_num Number of the PPI group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_TASK_DISABLE, uint32_t, sd_ppi_group_task_disable(uint8_t group_num)); + +/**@brief Assign PPI channels to a channel group. + * + * @param[in] group_num Number of the channel group. + * @param[in] channel_msk Mask of the channels to assign to the group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_ASSIGN, uint32_t, sd_ppi_group_assign(uint8_t group_num, uint32_t channel_msk)); + +/**@brief Gets the PPI channels of a channel group. + * + * @param[in] group_num Number of the channel group. + * @param[out] p_channel_msk Mask of the channels assigned to the group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_GET, uint32_t, sd_ppi_group_get(uint8_t group_num, uint32_t *p_channel_msk)); + +/**@brief Configures the Radio Notification signal. + * + * @note + * - The notification signal latency depends on the interrupt priority settings of SWI used + * for notification signal. + * - To ensure that the radio notification signal behaves in a consistent way, the radio + * notifications must be configured when there is no protocol stack or other SoftDevice + * activity in progress. It is recommended that the radio notification signal is + * configured directly after the SoftDevice has been enabled. + * - In the period between the ACTIVE signal and the start of the Radio Event, the SoftDevice + * will interrupt the application to do Radio Event preparation. + * - Using the Radio Notification feature may limit the bandwidth, as the SoftDevice may have + * to shorten the connection events to have time for the Radio Notification signals. + * + * @param[in] type Type of notification signal, see @ref NRF_RADIO_NOTIFICATION_TYPES. + * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE shall be used to turn off radio + * notification. Using @ref NRF_RADIO_NOTIFICATION_DISTANCE_NONE is + * recommended (but not required) to be used with + * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE. + * + * @param[in] distance Distance between the notification signal and start of radio activity, see @ref + * NRF_RADIO_NOTIFICATION_DISTANCES. This parameter is ignored when @ref NRF_RADIO_NOTIFICATION_TYPE_NONE or + * @ref NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE is used. + * + * @retval ::NRF_ERROR_INVALID_PARAM The group number is invalid. + * @retval ::NRF_ERROR_INVALID_STATE A protocol stack or other SoftDevice is running. Stop all + * running activities and retry. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RADIO_NOTIFICATION_CFG_SET, uint32_t, sd_radio_notification_cfg_set(uint8_t type, uint8_t distance)); + +/**@brief Encrypts a block according to the specified parameters. + * + * 128-bit AES encryption. + * + * @note: + * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while + * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application + * main or low interrupt level. + * + * @param[in, out] p_ecb_data Pointer to the ECB parameters' struct (two input + * parameters and one output parameter). + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_ECB_BLOCK_ENCRYPT, uint32_t, sd_ecb_block_encrypt(nrf_ecb_hal_data_t *p_ecb_data)); + +/**@brief Encrypts multiple data blocks provided as an array of data block structures. + * + * @details: Performs 128-bit AES encryption on multiple data blocks + * + * @note: + * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while + * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application + * main or low interrupt level. + * + * @param[in] block_count Count of blocks in the p_data_blocks array. + * @param[in,out] p_data_blocks Pointer to the first entry in a contiguous array of + * @ref nrf_ecb_hal_data_block_t structures. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_ECB_BLOCKS_ENCRYPT, uint32_t, sd_ecb_blocks_encrypt(uint8_t block_count, nrf_ecb_hal_data_block_t *p_data_blocks)); + +/**@brief Gets any pending events generated by the SoC API. + * + * The application should keep calling this function to get events, until ::NRF_ERROR_NOT_FOUND is returned. + * + * @param[out] p_evt_id Set to one of the values in @ref NRF_SOC_EVTS, if any events are pending. + * + * @retval ::NRF_SUCCESS An event was pending. The event id is written in the p_evt_id parameter. + * @retval ::NRF_ERROR_NOT_FOUND No pending events. + */ +SVCALL(SD_EVT_GET, uint32_t, sd_evt_get(uint32_t *p_evt_id)); + +/**@brief Get the temperature measured on the chip + * + * This function will block until the temperature measurement is done. + * It takes around 50 us from call to return. + * + * @param[out] p_temp Result of temperature measurement. Die temperature in 0.25 degrees Celsius. + * + * @retval ::NRF_SUCCESS A temperature measurement was done, and the temperature was written to temp + */ +SVCALL(SD_TEMP_GET, uint32_t, sd_temp_get(int32_t *p_temp)); + +/**@brief Flash Write + * + * Commands to write a buffer to flash + * + * If the SoftDevice is enabled: + * This call initiates the flash access command, and its completion will be communicated to the + * application with exactly one of the following events: + * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. + * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. + * + * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the + * write has been completed + * + * @note + * - This call takes control over the radio and the CPU during flash erase and write to make sure that + * they will not interfere with the flash access. This means that all interrupts will be blocked + * for a predictable time (depending on the NVMC specification in the device's Product Specification + * and the command parameters). + * - The data in the p_src buffer should not be modified before the @ref NRF_EVT_FLASH_OPERATION_SUCCESS + * or the @ref NRF_EVT_FLASH_OPERATION_ERROR have been received if the SoftDevice is enabled. + * - This call will make the SoftDevice trigger a hardfault when the page is written, if it is + * protected. + * + * + * @param[in] p_dst Pointer to start of flash location to be written. + * @param[in] p_src Pointer to buffer with data to be written. + * @param[in] size Number of 32-bit words to write. Maximum size is the number of words in one + * flash page. See the device's Product Specification for details. + * + * @retval ::NRF_ERROR_INVALID_ADDR Tried to write to a non existing flash address, or p_dst or p_src was unaligned. + * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. + * @retval ::NRF_ERROR_INVALID_LENGTH Size was 0, or higher than the maximum allowed size. + * @retval ::NRF_ERROR_FORBIDDEN Tried to write to an address outside the application flash area. + * @retval ::NRF_SUCCESS The command was accepted. + */ +SVCALL(SD_FLASH_WRITE, uint32_t, sd_flash_write(uint32_t *p_dst, uint32_t const *p_src, uint32_t size)); + +/**@brief Flash Erase page + * + * Commands to erase a flash page + * If the SoftDevice is enabled: + * This call initiates the flash access command, and its completion will be communicated to the + * application with exactly one of the following events: + * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. + * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. + * + * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the + * erase has been completed + * + * @note + * - This call takes control over the radio and the CPU during flash erase and write to make sure that + * they will not interfere with the flash access. This means that all interrupts will be blocked + * for a predictable time (depending on the NVMC specification in the device's Product Specification + * and the command parameters). + * - This call will make the SoftDevice trigger a hardfault when the page is erased, if it is + * protected. + * + * + * @param[in] page_number Page number of the page to erase + * + * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. + * @retval ::NRF_ERROR_INVALID_ADDR Tried to erase to a non existing flash page. + * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. + * @retval ::NRF_ERROR_FORBIDDEN Tried to erase a page outside the application flash area. + * @retval ::NRF_SUCCESS The command was accepted. + */ +SVCALL(SD_FLASH_PAGE_ERASE, uint32_t, sd_flash_page_erase(uint32_t page_number)); + +/**@brief Opens a session for radio timeslot requests. + * + * @note Only one session can be open at a time. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) will be called when the radio timeslot + * starts. From this point the NRF_RADIO and NRF_TIMER0 peripherals can be freely accessed + * by the application. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0) is called whenever the NRF_TIMER0 + * interrupt occurs. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO) is called whenever the NRF_RADIO + * interrupt occurs. + * @note p_radio_signal_callback() will be called at ARM interrupt priority level 0. This + * implies that none of the sd_* API calls can be used from p_radio_signal_callback(). + * + * @param[in] p_radio_signal_callback The signal callback. + * + * @retval ::NRF_ERROR_INVALID_ADDR p_radio_signal_callback is an invalid function pointer. + * @retval ::NRF_ERROR_BUSY If session cannot be opened. + * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_SESSION_OPEN, uint32_t, sd_radio_session_open(nrf_radio_signal_callback_t p_radio_signal_callback)); + +/**@brief Closes a session for radio timeslot requests. + * + * @note Any current radio timeslot will be finished before the session is closed. + * @note If a radio timeslot is scheduled when the session is closed, it will be canceled. + * @note The application cannot consider the session closed until the @ref NRF_EVT_RADIO_SESSION_CLOSED + * event is received. + * + * @retval ::NRF_ERROR_FORBIDDEN If session not opened. + * @retval ::NRF_ERROR_BUSY If session is currently being closed. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_SESSION_CLOSE, uint32_t, sd_radio_session_close(void)); + +/**@brief Requests a radio timeslot. + * + * @note The request type is determined by p_request->request_type, and can be one of @ref NRF_RADIO_REQ_TYPE_EARLIEST + * and @ref NRF_RADIO_REQ_TYPE_NORMAL. The first request in a session must always be of type @ref + * NRF_RADIO_REQ_TYPE_EARLIEST. + * @note For a normal request (@ref NRF_RADIO_REQ_TYPE_NORMAL), the start time of a radio timeslot is specified by + * p_request->distance_us and is given relative to the start of the previous timeslot. + * @note A too small p_request->distance_us will lead to a @ref NRF_EVT_RADIO_BLOCKED event. + * @note Timeslots scheduled too close will lead to a @ref NRF_EVT_RADIO_BLOCKED event. + * @note See the SoftDevice Specification for more on radio timeslot scheduling, distances and lengths. + * @note If an opportunity for the first radio timeslot is not found before 100 ms after the call to this + * function, it is not scheduled, and instead a @ref NRF_EVT_RADIO_BLOCKED event is sent. + * The application may then try to schedule the first radio timeslot again. + * @note Successful requests will result in nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START). + * Unsuccessful requests will result in a @ref NRF_EVT_RADIO_BLOCKED event, see @ref NRF_SOC_EVTS. + * @note The jitter in the start time of the radio timeslots is +/- @ref NRF_RADIO_START_JITTER_US us. + * @note The nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) call has a latency relative to the + * specified radio timeslot start, but this does not affect the actual start time of the timeslot. + * @note NRF_TIMER0 is reset at the start of the radio timeslot, and is clocked at 1MHz from the high frequency + * (16 MHz) clock source. If p_request->hfclk_force_xtal is true, the high frequency clock is + * guaranteed to be clocked from the external crystal. + * @note The SoftDevice will neither access the NRF_RADIO peripheral nor the NRF_TIMER0 peripheral + * during the radio timeslot. + * + * @param[in] p_request Pointer to the request parameters. + * + * @retval ::NRF_ERROR_FORBIDDEN Either: + * - The session is not open. + * - The session is not IDLE. + * - This is the first request and its type is not @ref NRF_RADIO_REQ_TYPE_EARLIEST. + * - The request type was set to @ref NRF_RADIO_REQ_TYPE_NORMAL after a + * @ref NRF_RADIO_REQ_TYPE_EARLIEST request was blocked. + * @retval ::NRF_ERROR_INVALID_ADDR If the p_request pointer is invalid. + * @retval ::NRF_ERROR_INVALID_PARAM If the parameters of p_request are not valid. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_REQUEST, uint32_t, sd_radio_request(nrf_radio_request_t const *p_request)); + +/**@brief Write register protected by the SoftDevice + * + * This function writes to a register that is write-protected by the SoftDevice. Please refer to your + * SoftDevice Specification for more details about which registers that are protected by SoftDevice. + * This function can write to the following protected peripheral: + * - ACL + * + * @note Protected registers may be read directly. + * @note Register that are write-once will return @ref NRF_SUCCESS on second set, even the value in + * the register has not changed. See the Product Specification for more details about register + * properties. + * + * @param[in] p_register Pointer to register to be written. + * @param[in] value Value to be written to the register. + * + * @retval ::NRF_ERROR_INVALID_ADDR This function can not write to the reguested register. + * @retval ::NRF_SUCCESS Value successfully written to register. + * + */ +SVCALL(SD_PROTECTED_REGISTER_WRITE, uint32_t, sd_protected_register_write(volatile uint32_t *p_register, uint32_t value)); + +/**@} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_SOC_H__ + +/**@} */ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_svc.h b/variants/wio-sdk-wm1110/softdevice/nrf_svc.h new file mode 100644 index 0000000000..1de44656f3 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_svc.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NRF_SVC__ +#define NRF_SVC__ + +#include "stdint.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Supervisor call declaration. + * + * A call to a function marked with @ref SVCALL, will trigger a Supervisor Call (SVC) Exception. + * The SVCs with SVC numbers 0x00-0x0F are forwared to the application. All other SVCs are handled by the SoftDevice. + * + * @param[in] number The SVC number to be used. + * @param[in] return_type The return type of the SVC function. + * @param[in] signature Function signature. The function can have at most four arguments. + */ + +#ifdef SVCALL_AS_NORMAL_FUNCTION +#define SVCALL(number, return_type, signature) return_type signature +#else + +#ifndef SVCALL +#if defined(__CC_ARM) +#define SVCALL(number, return_type, signature) return_type __svc(number) signature +#elif defined(__GNUC__) +#ifdef __cplusplus +#define GCC_CAST_CPP (uint16_t) +#else +#define GCC_CAST_CPP +#endif +#define SVCALL(number, return_type, signature) \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") __attribute__((naked)) \ + __attribute__((unused)) static return_type signature \ + { \ + __asm("svc %0\n" \ + "bx r14" \ + : \ + : "I"(GCC_CAST_CPP number) \ + : "r0"); \ + } \ + _Pragma("GCC diagnostic pop") + +#elif defined(__ICCARM__) +#define PRAGMA(x) _Pragma(#x) +#define SVCALL(number, return_type, signature) \ + PRAGMA(swi_number = (number)) \ + __swi return_type signature; +#else +#define SVCALL(number, return_type, signature) return_type signature +#endif +#endif // SVCALL + +#endif // SVCALL_AS_NORMAL_FUNCTION + +#ifdef __cplusplus +} +#endif +#endif // NRF_SVC__ diff --git a/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld b/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld new file mode 100644 index 0000000000..6aaeb4034f --- /dev/null +++ b/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld @@ -0,0 +1,38 @@ +/* Linker script to configure memory regions. */ + +SEARCH_DIR(.) +GROUP(-lgcc -lc -lnosys) + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xED000 - 0x27000 + + /* SRAM required by Softdevice depend on + * - Attribute Table Size (Number of Services and Characteristics) + * - Vendor UUID count + * - Max ATT MTU + * - Concurrent connection peripheral + central + secure links + * - Event Len, HVN queue, Write CMD queue + */ + RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x20040000 - 0x20006000 +} + +SECTIONS +{ + . = ALIGN(4); + .svc_data : + { + PROVIDE(__start_svc_data = .); + KEEP(*(.svc_data)) + PROVIDE(__stop_svc_data = .); + } > RAM + + .fs_data : + { + PROVIDE(__start_fs_data = .); + KEEP(*(.fs_data)) + PROVIDE(__stop_fs_data = .); + } > RAM +} INSERT AFTER .data; + +INCLUDE "nrf52_common.ld" diff --git a/variants/wio-tracker-wm1110/platformio.ini b/variants/wio-tracker-wm1110/platformio.ini index cba1b87414..e8c6811866 100644 --- a/variants/wio-tracker-wm1110/platformio.ini +++ b/variants/wio-tracker-wm1110/platformio.ini @@ -6,9 +6,10 @@ board = wio-tracker-wm1110 build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-tracker-wm1110 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. +board_build.ldscript = variants/wio-tracker-wm1110/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-tracker-wm1110> lib_deps = ${nrf52840_base.lib_deps} debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink \ No newline at end of file +;upload_protocol = jlink diff --git a/variants/wio-tracker-wm1110/softdevice/ble.h b/variants/wio-tracker-wm1110/softdevice/ble.h new file mode 100644 index 0000000000..177b436ad8 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble.h @@ -0,0 +1,652 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON BLE SoftDevice Common + @{ + @defgroup ble_api Events, type definitions and API calls + @{ + + @brief Module independent events, type definitions and API calls for the BLE SoftDevice. + + */ + +#ifndef BLE_H__ +#define BLE_H__ + +#include "ble_err.h" +#include "ble_gap.h" +#include "ble_gatt.h" +#include "ble_gattc.h" +#include "ble_gatts.h" +#include "ble_l2cap.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_COMMON_ENUMERATIONS Enumerations + * @{ */ + +/** + * @brief Common API SVC numbers. + */ +enum BLE_COMMON_SVCS { + SD_BLE_ENABLE = BLE_SVC_BASE, /**< Enable and initialize the BLE stack */ + SD_BLE_EVT_GET, /**< Get an event from the pending events queue. */ + SD_BLE_UUID_VS_ADD, /**< Add a Vendor Specific base UUID. */ + SD_BLE_UUID_DECODE, /**< Decode UUID bytes. */ + SD_BLE_UUID_ENCODE, /**< Encode UUID bytes. */ + SD_BLE_VERSION_GET, /**< Get the local version information (company ID, Link Layer Version, Link Layer Subversion). */ + SD_BLE_USER_MEM_REPLY, /**< User Memory Reply. */ + SD_BLE_OPT_SET, /**< Set a BLE option. */ + SD_BLE_OPT_GET, /**< Get a BLE option. */ + SD_BLE_CFG_SET, /**< Add a configuration to the BLE stack. */ + SD_BLE_UUID_VS_REMOVE, /**< Remove a Vendor Specific base UUID. */ +}; + +/** + * @brief BLE Module Independent Event IDs. + */ +enum BLE_COMMON_EVTS { + BLE_EVT_USER_MEM_REQUEST = BLE_EVT_BASE + 0, /**< User Memory request. See @ref ble_evt_user_mem_request_t + \n Reply with @ref sd_ble_user_mem_reply. */ + BLE_EVT_USER_MEM_RELEASE = BLE_EVT_BASE + 1, /**< User Memory release. See @ref ble_evt_user_mem_release_t */ +}; + +/**@brief BLE Connection Configuration IDs. + * + * IDs that uniquely identify a connection configuration. + */ +enum BLE_CONN_CFGS { + BLE_CONN_CFG_GAP = BLE_CONN_CFG_BASE + 0, /**< BLE GAP specific connection configuration. */ + BLE_CONN_CFG_GATTC = BLE_CONN_CFG_BASE + 1, /**< BLE GATTC specific connection configuration. */ + BLE_CONN_CFG_GATTS = BLE_CONN_CFG_BASE + 2, /**< BLE GATTS specific connection configuration. */ + BLE_CONN_CFG_GATT = BLE_CONN_CFG_BASE + 3, /**< BLE GATT specific connection configuration. */ + BLE_CONN_CFG_L2CAP = BLE_CONN_CFG_BASE + 4, /**< BLE L2CAP specific connection configuration. */ +}; + +/**@brief BLE Common Configuration IDs. + * + * IDs that uniquely identify a common configuration. + */ +enum BLE_COMMON_CFGS { + BLE_COMMON_CFG_VS_UUID = BLE_CFG_BASE, /**< Vendor specific base UUID configuration */ +}; + +/**@brief Common Option IDs. + * IDs that uniquely identify a common option. + */ +enum BLE_COMMON_OPTS { + BLE_COMMON_OPT_PA_LNA = BLE_OPT_BASE + 0, /**< PA and LNA options */ + BLE_COMMON_OPT_CONN_EVT_EXT = BLE_OPT_BASE + 1, /**< Extended connection events option */ + BLE_COMMON_OPT_EXTENDED_RC_CAL = BLE_OPT_BASE + 2, /**< Extended RC calibration option */ +}; + +/** @} */ + +/** @addtogroup BLE_COMMON_DEFINES Defines + * @{ */ + +/** @brief Required pointer alignment for BLE Events. + */ +#define BLE_EVT_PTR_ALIGNMENT 4 + +/** @brief Leaves the maximum of the two arguments. + */ +#define BLE_MAX(a, b) ((a) < (b) ? (b) : (a)) + +/** @brief Maximum possible length for BLE Events. + * @note The highest value used for @ref ble_gatt_conn_cfg_t::att_mtu in any connection configuration shall be used as a + * parameter. If that value has not been configured for any connections then @ref BLE_GATT_ATT_MTU_DEFAULT must be used instead. + */ +#define BLE_EVT_LEN_MAX(ATT_MTU) \ + (offsetof(ble_evt_t, evt.gattc_evt.params.prim_srvc_disc_rsp.services) + ((ATT_MTU)-1) / 4 * sizeof(ble_gattc_service_t)) + +/** @defgroup BLE_USER_MEM_TYPES User Memory Types + * @{ */ +#define BLE_USER_MEM_TYPE_INVALID 0x00 /**< Invalid User Memory Types. */ +#define BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES 0x01 /**< User Memory for GATTS queued writes. */ +/** @} */ + +/** @defgroup BLE_UUID_VS_COUNTS Vendor Specific base UUID counts + * @{ + */ +#define BLE_UUID_VS_COUNT_DEFAULT 10 /**< Default VS UUID count. */ +#define BLE_UUID_VS_COUNT_MAX 254 /**< Maximum VS UUID count. */ +/** @} */ + +/** @defgroup BLE_COMMON_CFG_DEFAULTS Configuration defaults. + * @{ + */ +#define BLE_CONN_CFG_TAG_DEFAULT 0 /**< Default configuration tag, SoftDevice default connection configuration. */ + +/** @} */ + +/** @} */ + +/** @addtogroup BLE_COMMON_STRUCTURES Structures + * @{ */ + +/**@brief User Memory Block. */ +typedef struct { + uint8_t *p_mem; /**< Pointer to the start of the user memory block. */ + uint16_t len; /**< Length in bytes of the user memory block. */ +} ble_user_mem_block_t; + +/**@brief Event structure for @ref BLE_EVT_USER_MEM_REQUEST. */ +typedef struct { + uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ +} ble_evt_user_mem_request_t; + +/**@brief Event structure for @ref BLE_EVT_USER_MEM_RELEASE. */ +typedef struct { + uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ + ble_user_mem_block_t mem_block; /**< User memory block */ +} ble_evt_user_mem_release_t; + +/**@brief Event structure for events not associated with a specific function module. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which this event occurred. */ + union { + ble_evt_user_mem_request_t user_mem_request; /**< User Memory Request Event Parameters. */ + ble_evt_user_mem_release_t user_mem_release; /**< User Memory Release Event Parameters. */ + } params; /**< Event parameter union. */ +} ble_common_evt_t; + +/**@brief BLE Event header. */ +typedef struct { + uint16_t evt_id; /**< Value from a BLE__EVT series. */ + uint16_t evt_len; /**< Length in octets including this header. */ +} ble_evt_hdr_t; + +/**@brief Common BLE Event type, wrapping the module specific event reports. */ +typedef struct { + ble_evt_hdr_t header; /**< Event header. */ + union { + ble_common_evt_t common_evt; /**< Common Event, evt_id in BLE_EVT_* series. */ + ble_gap_evt_t gap_evt; /**< GAP originated event, evt_id in BLE_GAP_EVT_* series. */ + ble_gattc_evt_t gattc_evt; /**< GATT client originated event, evt_id in BLE_GATTC_EVT* series. */ + ble_gatts_evt_t gatts_evt; /**< GATT server originated event, evt_id in BLE_GATTS_EVT* series. */ + ble_l2cap_evt_t l2cap_evt; /**< L2CAP originated event, evt_id in BLE_L2CAP_EVT* series. */ + } evt; /**< Event union. */ +} ble_evt_t; + +/** + * @brief Version Information. + */ +typedef struct { + uint8_t version_number; /**< Link Layer Version number. See + https://www.bluetooth.org/en-us/specification/assigned-numbers/link-layer for assigned values. */ + uint16_t company_id; /**< Company ID, Nordic Semiconductor's company ID is 89 (0x0059) + (https://www.bluetooth.org/apps/content/Default.aspx?doc_id=49708). */ + uint16_t + subversion_number; /**< Link Layer Sub Version number, corresponds to the SoftDevice Config ID or Firmware ID (FWID). */ +} ble_version_t; + +/** + * @brief Configuration parameters for the PA and LNA. + */ +typedef struct { + uint8_t enable : 1; /**< Enable toggling for this amplifier */ + uint8_t active_high : 1; /**< Set the pin to be active high */ + uint8_t gpio_pin : 6; /**< The GPIO pin to toggle for this amplifier */ +} ble_pa_lna_cfg_t; + +/** + * @brief PA & LNA GPIO toggle configuration + * + * This option configures the SoftDevice to toggle pins when the radio is active for use with a power amplifier and/or + * a low noise amplifier. + * + * Toggling the pins is achieved by using two PPI channels and a GPIOTE channel. The hardware channel IDs are provided + * by the application and should be regarded as reserved as long as any PA/LNA toggling is enabled. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * @note Setting this option while the radio is in use (i.e. any of the roles are active) may have undefined consequences + * and must be avoided by the application. + */ +typedef struct { + ble_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */ + ble_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */ + + uint8_t ppi_ch_id_set; /**< PPI channel used for radio pin setting */ + uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */ + uint8_t gpiote_ch_id; /**< GPIOTE channel used for radio pin toggling */ +} ble_common_opt_pa_lna_t; + +/** + * @brief Configuration of extended BLE connection events. + * + * When enabled the SoftDevice will dynamically extend the connection event when possible. + * + * The connection event length is controlled by the connection configuration as set by @ref ble_gap_conn_cfg_t::event_length. + * The connection event can be extended if there is time to send another packet pair before the start of the next connection + * interval, and if there are no conflicts with other BLE roles requesting radio time. + * + * @note @ref sd_ble_opt_get is not supported for this option. + */ +typedef struct { + uint8_t enable : 1; /**< Enable extended BLE connection events, disabled by default. */ +} ble_common_opt_conn_evt_ext_t; + +/** + * @brief Enable/disable extended RC calibration. + * + * If extended RC calibration is enabled and the internal RC oscillator (@ref NRF_CLOCK_LF_SRC_RC) is used as the SoftDevice + * LFCLK source, the SoftDevice as a peripheral will by default try to increase the receive window if two consecutive packets + * are not received. If it turns out that the packets were not received due to clock drift, the RC calibration is started. + * This calibration comes in addition to the periodic calibration that is configured by @ref sd_softdevice_enable(). When + * using only peripheral connections, the periodic calibration can therefore be configured with a much longer interval as the + * peripheral will be able to detect and adjust automatically to clock drift, and calibrate on demand. + * + * If extended RC calibration is disabled and the internal RC oscillator is used as the SoftDevice LFCLK source, the + * RC oscillator is calibrated periodically as configured by @ref sd_softdevice_enable(). + * + * @note @ref sd_ble_opt_get is not supported for this option. + */ +typedef struct { + uint8_t enable : 1; /**< Enable extended RC calibration, enabled by default. */ +} ble_common_opt_extended_rc_cal_t; + +/**@brief Option structure for common options. */ +typedef union { + ble_common_opt_pa_lna_t pa_lna; /**< Parameters for controlling PA and LNA pin toggling. */ + ble_common_opt_conn_evt_ext_t conn_evt_ext; /**< Parameters for enabling extended connection events. */ + ble_common_opt_extended_rc_cal_t extended_rc_cal; /**< Parameters for enabling extended RC calibration. */ +} ble_common_opt_t; + +/**@brief Common BLE Option type, wrapping the module specific options. */ +typedef union { + ble_common_opt_t common_opt; /**< COMMON options, opt_id in @ref BLE_COMMON_OPTS series. */ + ble_gap_opt_t gap_opt; /**< GAP option, opt_id in @ref BLE_GAP_OPTS series. */ + ble_gattc_opt_t gattc_opt; /**< GATTC option, opt_id in @ref BLE_GATTC_OPTS series. */ +} ble_opt_t; + +/**@brief BLE connection configuration type, wrapping the module specific configurations, set with + * @ref sd_ble_cfg_set. + * + * @note Connection configurations don't have to be set. + * In the case that no configurations has been set, or fewer connection configurations has been set than enabled connections, + * the default connection configuration will be automatically added for the remaining connections. + * When creating connections with the default configuration, @ref BLE_CONN_CFG_TAG_DEFAULT should be used in + * place of @ref ble_conn_cfg_t::conn_cfg_tag. + * + * @sa sd_ble_gap_adv_start() + * @sa sd_ble_gap_connect() + * + * @mscs + * @mmsc{@ref BLE_CONN_CFG} + * @endmscs + + */ +typedef struct { + uint8_t conn_cfg_tag; /**< The application chosen tag it can use with the + @ref sd_ble_gap_adv_start() and @ref sd_ble_gap_connect() calls + to select this configuration when creating a connection. + Must be different for all connection configurations added and not @ref BLE_CONN_CFG_TAG_DEFAULT. */ + union { + ble_gap_conn_cfg_t gap_conn_cfg; /**< GAP connection configuration, cfg_id is @ref BLE_CONN_CFG_GAP. */ + ble_gattc_conn_cfg_t gattc_conn_cfg; /**< GATTC connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTC. */ + ble_gatts_conn_cfg_t gatts_conn_cfg; /**< GATTS connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTS. */ + ble_gatt_conn_cfg_t gatt_conn_cfg; /**< GATT connection configuration, cfg_id is @ref BLE_CONN_CFG_GATT. */ + ble_l2cap_conn_cfg_t l2cap_conn_cfg; /**< L2CAP connection configuration, cfg_id is @ref BLE_CONN_CFG_L2CAP. */ + } params; /**< Connection configuration union. */ +} ble_conn_cfg_t; + +/** + * @brief Configuration of Vendor Specific base UUIDs, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_PARAM Too many UUIDs configured. + */ +typedef struct { + uint8_t vs_uuid_count; /**< Number of 128-bit Vendor Specific base UUID bases to allocate memory for. + Default value is @ref BLE_UUID_VS_COUNT_DEFAULT. Maximum value is + @ref BLE_UUID_VS_COUNT_MAX. */ +} ble_common_cfg_vs_uuid_t; + +/**@brief Common BLE Configuration type, wrapping the common configurations. */ +typedef union { + ble_common_cfg_vs_uuid_t vs_uuid_cfg; /**< Vendor Specific base UUID configuration, cfg_id is @ref BLE_COMMON_CFG_VS_UUID. */ +} ble_common_cfg_t; + +/**@brief BLE Configuration type, wrapping the module specific configurations. */ +typedef union { + ble_conn_cfg_t conn_cfg; /**< Connection specific configurations, cfg_id in @ref BLE_CONN_CFGS series. */ + ble_common_cfg_t common_cfg; /**< Global common configurations, cfg_id in @ref BLE_COMMON_CFGS series. */ + ble_gap_cfg_t gap_cfg; /**< Global GAP configurations, cfg_id in @ref BLE_GAP_CFGS series. */ + ble_gatts_cfg_t gatts_cfg; /**< Global GATTS configuration, cfg_id in @ref BLE_GATTS_CFGS series. */ +} ble_cfg_t; + +/** @} */ + +/** @addtogroup BLE_COMMON_FUNCTIONS Functions + * @{ */ + +/**@brief Enable the BLE stack + * + * @param[in, out] p_app_ram_base Pointer to a variable containing the start address of the + * application RAM region (APP_RAM_BASE). On return, this will + * contain the minimum start address of the application RAM region + * required by the SoftDevice for this configuration. + * @warning After this call, the SoftDevice may generate several events. The list of events provided + * below require the application to initiate a SoftDevice API call. The corresponding API call + * is referenced in the event documentation. + * If the application fails to do so, the BLE connection may timeout, or the SoftDevice may stop + * communicating with the peer device. + * - @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST + * - @ref BLE_GAP_EVT_SEC_INFO_REQUEST + * - @ref BLE_GAP_EVT_SEC_REQUEST + * - @ref BLE_GAP_EVT_AUTH_KEY_REQUEST + * - @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST + * - @ref BLE_EVT_USER_MEM_REQUEST + * - @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST + * + * @note The memory requirement for a specific configuration will not increase between SoftDevices + * with the same major version number. + * + * @note At runtime the IC's RAM is split into 2 regions: The SoftDevice RAM region is located + * between 0x20000000 and APP_RAM_BASE-1 and the application's RAM region is located between + * APP_RAM_BASE and the start of the call stack. + * + * @details This call initializes the BLE stack, no BLE related function other than @ref + * sd_ble_cfg_set can be called before this one. + * + * @mscs + * @mmsc{@ref BLE_COMMON_ENABLE} + * @endmscs + * + * @retval ::NRF_SUCCESS The BLE stack has been initialized successfully. + * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized and cannot be reinitialized. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_NO_MEM One or more of the following is true: + * - The amount of memory assigned to the SoftDevice by *p_app_ram_base is not + * large enough to fit this configuration's memory requirement. Check *p_app_ram_base + * and set the start address of the application RAM region accordingly. + * - Dynamic part of the SoftDevice RAM region is larger then 64 kB which + * is currently not supported. + * @retval ::NRF_ERROR_RESOURCES The total number of L2CAP Channels configured using @ref sd_ble_cfg_set is too large. + */ +SVCALL(SD_BLE_ENABLE, uint32_t, sd_ble_enable(uint32_t *p_app_ram_base)); + +/**@brief Add configurations for the BLE stack + * + * @param[in] cfg_id Config ID, see @ref BLE_CONN_CFGS, @ref BLE_COMMON_CFGS, @ref + * BLE_GAP_CFGS or @ref BLE_GATTS_CFGS. + * @param[in] p_cfg Pointer to a ble_cfg_t structure containing the configuration value. + * @param[in] app_ram_base The start address of the application RAM region (APP_RAM_BASE). + * See @ref sd_ble_enable for details about APP_RAM_BASE. + * + * @note The memory requirement for a specific configuration will not increase between SoftDevices + * with the same major version number. + * + * @note If a configuration is set more than once, the last one set is the one that takes effect on + * @ref sd_ble_enable. + * + * @note Any part of the BLE stack that is NOT configured with @ref sd_ble_cfg_set will have default + * configuration. + * + * @note @ref sd_ble_cfg_set may be called at any time when the SoftDevice is enabled (see @ref + * sd_softdevice_enable) while the BLE part of the SoftDevice is not enabled (see @ref + * sd_ble_enable). + * + * @note Error codes for the configurations are described in the configuration structs. + * + * @mscs + * @mmsc{@ref BLE_COMMON_ENABLE} + * @endmscs + * + * @retval ::NRF_SUCCESS The configuration has been added successfully. + * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid cfg_id supplied. + * @retval ::NRF_ERROR_NO_MEM The amount of memory assigned to the SoftDevice by app_ram_base is not + * large enough to fit this configuration's memory requirement. + */ +SVCALL(SD_BLE_CFG_SET, uint32_t, sd_ble_cfg_set(uint32_t cfg_id, ble_cfg_t const *p_cfg, uint32_t app_ram_base)); + +/**@brief Get an event from the pending events queue. + * + * @param[out] p_dest Pointer to buffer to be filled in with an event, or NULL to retrieve the event length. + * This buffer must be aligned to the extend defined by @ref BLE_EVT_PTR_ALIGNMENT. + * The buffer should be interpreted as a @ref ble_evt_t struct. + * @param[in, out] p_len Pointer the length of the buffer, on return it is filled with the event length. + * + * @details This call allows the application to pull a BLE event from the BLE stack. The application is signaled that + * an event is available from the BLE stack by the triggering of the SD_EVT_IRQn interrupt. + * The application is free to choose whether to call this function from thread mode (main context) or directly from the + * Interrupt Service Routine that maps to SD_EVT_IRQn. In any case however, and because the BLE stack runs at a higher + * priority than the application, this function should be called in a loop (until @ref NRF_ERROR_NOT_FOUND is returned) + * every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the BLE stack. Failure to do so + * could potentially leave events in the internal queue without the application being aware of this fact. + * + * Sizing the p_dest buffer is equally important, since the application needs to provide all the memory necessary for the event to + * be copied into application memory. If the buffer provided is not large enough to fit the entire contents of the event, + * @ref NRF_ERROR_DATA_SIZE will be returned and the application can then call again with a larger buffer size. + * The maximum possible event length is defined by @ref BLE_EVT_LEN_MAX. The application may also "peek" the event length + * by providing p_dest as a NULL pointer and inspecting the value of *p_len upon return: + * + * \code + * uint16_t len; + * errcode = sd_ble_evt_get(NULL, &len); + * \endcode + * + * @mscs + * @mmsc{@ref BLE_COMMON_IRQ_EVT_MSC} + * @mmsc{@ref BLE_COMMON_THREAD_EVT_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Event pulled and stored into the supplied buffer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_NOT_FOUND No events ready to be pulled. + * @retval ::NRF_ERROR_DATA_SIZE Event ready but could not fit into the supplied buffer. + */ +SVCALL(SD_BLE_EVT_GET, uint32_t, sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len)); + +/**@brief Add a Vendor Specific base UUID. + * + * @details This call enables the application to add a Vendor Specific base UUID to the BLE stack's table, for later + * use with all other modules and APIs. This then allows the application to use the shorter, 24-bit @ref ble_uuid_t + * format when dealing with both 16-bit and 128-bit UUIDs without having to check for lengths and having split code + * paths. This is accomplished by extending the grouping mechanism that the Bluetooth SIG standard base UUID uses + * for all other 128-bit UUIDs. The type field in the @ref ble_uuid_t structure is an index (relative to + * @ref BLE_UUID_TYPE_VENDOR_BEGIN) to the table populated by multiple calls to this function, and the UUID field + * in the same structure contains the 2 bytes at indexes 12 and 13. The number of possible 128-bit UUIDs available to + * the application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536, + * although restricted to modifying bytes 12 and 13 for each of the entries in the supplied array. + * + * @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by + * the 16-bit uuid field in @ref ble_uuid_t. + * + * @note If a UUID is already present in the BLE stack's internal table, the corresponding index will be returned in + * p_uuid_type along with an @ref NRF_SUCCESS error code. + * + * @param[in] p_vs_uuid Pointer to a 16-octet (128-bit) little endian Vendor Specific base UUID disregarding + * bytes 12 and 13. + * @param[out] p_uuid_type Pointer to a uint8_t where the type field in @ref ble_uuid_t corresponding to this UUID will be + * stored. + * + * @retval ::NRF_SUCCESS Successfully added the Vendor Specific base UUID. + * @retval ::NRF_ERROR_INVALID_ADDR If p_vs_uuid or p_uuid_type is NULL or invalid. + * @retval ::NRF_ERROR_NO_MEM If there are no more free slots for VS UUIDs. + */ +SVCALL(SD_BLE_UUID_VS_ADD, uint32_t, sd_ble_uuid_vs_add(ble_uuid128_t const *p_vs_uuid, uint8_t *p_uuid_type)); + +/**@brief Remove a Vendor Specific base UUID. + * + * @details This call removes a Vendor Specific base UUID. This function allows + * the application to reuse memory allocated for Vendor Specific base UUIDs. + * + * @note Currently this function can only be called with a p_uuid_type set to @ref BLE_UUID_TYPE_UNKNOWN or the last added UUID + * type. + * + * @param[inout] p_uuid_type Pointer to a uint8_t where its value matches the UUID type in @ref ble_uuid_t::type to be removed. + * If the type is set to @ref BLE_UUID_TYPE_UNKNOWN, or the pointer is NULL, the last Vendor Specific + * base UUID will be removed. If the function returns successfully, the UUID type that was removed will + * be written back to @p p_uuid_type. If function returns with a failure, it contains the last type that + * is in use by the ATT Server. + * + * @retval ::NRF_SUCCESS Successfully removed the Vendor Specific base UUID. + * @retval ::NRF_ERROR_INVALID_ADDR If p_uuid_type is invalid. + * @retval ::NRF_ERROR_INVALID_PARAM If p_uuid_type points to a non-valid UUID type. + * @retval ::NRF_ERROR_FORBIDDEN If the Vendor Specific base UUID is in use by the ATT Server. + */ +SVCALL(SD_BLE_UUID_VS_REMOVE, uint32_t, sd_ble_uuid_vs_remove(uint8_t *p_uuid_type)); + +/** @brief Decode little endian raw UUID bytes (16-bit or 128-bit) into a 24 bit @ref ble_uuid_t structure. + * + * @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared + * to the corresponding ones in each entry of the table of Vendor Specific base UUIDs + * to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index + * relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type. + * + * @note If the UUID length supplied is 2, then the type set by this call will always be @ref BLE_UUID_TYPE_BLE. + * + * @param[in] uuid_le_len Length in bytes of the buffer pointed to by p_uuid_le (must be 2 or 16 bytes). + * @param[in] p_uuid_le Pointer pointing to little endian raw UUID bytes. + * @param[out] p_uuid Pointer to a @ref ble_uuid_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Successfully decoded into the @ref ble_uuid_t structure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid UUID length. + * @retval ::NRF_ERROR_NOT_FOUND For a 128-bit UUID, no match in the populated table of UUIDs. + */ +SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uint8_t const *p_uuid_le, ble_uuid_t *p_uuid)); + +/** @brief Encode a @ref ble_uuid_t structure into little endian raw UUID bytes (16-bit or 128-bit). + * + * @note The pointer to the destination buffer p_uuid_le may be NULL, in which case only the validity and size of p_uuid is + * computed. + * + * @param[in] p_uuid Pointer to a @ref ble_uuid_t structure that will be encoded into bytes. + * @param[out] p_uuid_le_len Pointer to a uint8_t that will be filled with the encoded length (2 or 16 bytes). + * @param[out] p_uuid_le Pointer to a buffer where the little endian raw UUID bytes (2 or 16) will be stored. + * + * @retval ::NRF_SUCCESS Successfully encoded into the buffer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid UUID type. + */ +SVCALL(SD_BLE_UUID_ENCODE, uint32_t, sd_ble_uuid_encode(ble_uuid_t const *p_uuid, uint8_t *p_uuid_le_len, uint8_t *p_uuid_le)); + +/**@brief Get Version Information. + * + * @details This call allows the application to get the BLE stack version information. + * + * @param[out] p_version Pointer to a ble_version_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Version information stored successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy (typically doing a locally-initiated disconnection procedure). + */ +SVCALL(SD_BLE_VERSION_GET, uint32_t, sd_ble_version_get(ble_version_t *p_version)); + +/**@brief Provide a user memory block. + * + * @note This call can only be used as a response to a @ref BLE_EVT_USER_MEM_REQUEST event issued to the application. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_block Pointer to a user memory block structure or NULL if memory is managed by the application. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully queued a response to the peer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid user memory block length supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection state or no user memory request pending. + */ +SVCALL(SD_BLE_USER_MEM_REPLY, uint32_t, sd_ble_user_mem_reply(uint16_t conn_handle, ble_user_mem_block_t const *p_block)); + +/**@brief Set a BLE option. + * + * @details This call allows the application to set the value of an option. + * + * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS, @ref BLE_GAP_OPTS, and @ref BLE_GATTC_OPTS. + * @param[in] p_opt Pointer to a @ref ble_opt_t structure containing the option value. + * + * @retval ::NRF_SUCCESS Option set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Unable to set the parameter at this time. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. + */ +SVCALL(SD_BLE_OPT_SET, uint32_t, sd_ble_opt_set(uint32_t opt_id, ble_opt_t const *p_opt)); + +/**@brief Get a BLE option. + * + * @details This call allows the application to retrieve the value of an option. + * + * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS and @ref BLE_GAP_OPTS. + * @param[out] p_opt Pointer to a ble_opt_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Option retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Unable to retrieve the parameter at this time. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. + * @retval ::NRF_ERROR_NOT_SUPPORTED This option is not supported. + * + */ +SVCALL(SD_BLE_OPT_GET, uint32_t, sd_ble_opt_get(uint32_t opt_id, ble_opt_t *p_opt)); + +/** @} */ +#ifdef __cplusplus +} +#endif +#endif /* BLE_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_err.h b/variants/wio-tracker-wm1110/softdevice/ble_err.h new file mode 100644 index 0000000000..d20f6d1416 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_err.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @addtogroup nrf_error + @{ + @ingroup BLE_COMMON + @} + + @defgroup ble_err General error codes + @{ + + @brief General error code definitions for the BLE API. + + @ingroup BLE_COMMON +*/ +#ifndef NRF_BLE_ERR_H__ +#define NRF_BLE_ERR_H__ + +#include "nrf_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* @defgroup BLE_ERRORS Error Codes + * @{ */ +#define BLE_ERROR_NOT_ENABLED (NRF_ERROR_STK_BASE_NUM + 0x001) /**< @ref sd_ble_enable has not been called. */ +#define BLE_ERROR_INVALID_CONN_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x002) /**< Invalid connection handle. */ +#define BLE_ERROR_INVALID_ATTR_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x003) /**< Invalid attribute handle. */ +#define BLE_ERROR_INVALID_ADV_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x004) /**< Invalid advertising handle. */ +#define BLE_ERROR_INVALID_ROLE (NRF_ERROR_STK_BASE_NUM + 0x005) /**< Invalid role. */ +#define BLE_ERROR_BLOCKED_BY_OTHER_LINKS \ + (NRF_ERROR_STK_BASE_NUM + 0x006) /**< The attempt to change link settings failed due to the scheduling of other links. */ +/** @} */ + +/** @defgroup BLE_ERROR_SUBRANGES Module specific error code subranges + * @brief Assignment of subranges for module specific error codes. + * @note For specific error codes, see ble_.h or ble_error_.h. + * @{ */ +#define NRF_L2CAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x100) /**< L2CAP specific errors. */ +#define NRF_GAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x200) /**< GAP specific errors. */ +#define NRF_GATTC_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x300) /**< GATT client specific errors. */ +#define NRF_GATTS_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x400) /**< GATT server specific errors. */ +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif + +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gap.h b/variants/wio-tracker-wm1110/softdevice/ble_gap.h new file mode 100644 index 0000000000..8ebdfa82b0 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_gap.h @@ -0,0 +1,2895 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GAP Generic Access Profile (GAP) + @{ + @brief Definitions and prototypes for the GAP interface. + */ + +#ifndef BLE_GAP_H__ +#define BLE_GAP_H__ + +#include "ble_err.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup BLE_GAP_ENUMERATIONS Enumerations + * @{ */ + +/**@brief GAP API SVC numbers. + */ +enum BLE_GAP_SVCS { + SD_BLE_GAP_ADDR_SET = BLE_GAP_SVC_BASE, /**< Set own Bluetooth Address. */ + SD_BLE_GAP_ADDR_GET = BLE_GAP_SVC_BASE + 1, /**< Get own Bluetooth Address. */ + SD_BLE_GAP_WHITELIST_SET = BLE_GAP_SVC_BASE + 2, /**< Set active whitelist. */ + SD_BLE_GAP_DEVICE_IDENTITIES_SET = BLE_GAP_SVC_BASE + 3, /**< Set device identity list. */ + SD_BLE_GAP_PRIVACY_SET = BLE_GAP_SVC_BASE + 4, /**< Set Privacy settings*/ + SD_BLE_GAP_PRIVACY_GET = BLE_GAP_SVC_BASE + 5, /**< Get Privacy settings*/ + SD_BLE_GAP_ADV_SET_CONFIGURE = BLE_GAP_SVC_BASE + 6, /**< Configure an advertising set. */ + SD_BLE_GAP_ADV_START = BLE_GAP_SVC_BASE + 7, /**< Start Advertising. */ + SD_BLE_GAP_ADV_STOP = BLE_GAP_SVC_BASE + 8, /**< Stop Advertising. */ + SD_BLE_GAP_CONN_PARAM_UPDATE = BLE_GAP_SVC_BASE + 9, /**< Connection Parameter Update. */ + SD_BLE_GAP_DISCONNECT = BLE_GAP_SVC_BASE + 10, /**< Disconnect. */ + SD_BLE_GAP_TX_POWER_SET = BLE_GAP_SVC_BASE + 11, /**< Set TX Power. */ + SD_BLE_GAP_APPEARANCE_SET = BLE_GAP_SVC_BASE + 12, /**< Set Appearance. */ + SD_BLE_GAP_APPEARANCE_GET = BLE_GAP_SVC_BASE + 13, /**< Get Appearance. */ + SD_BLE_GAP_PPCP_SET = BLE_GAP_SVC_BASE + 14, /**< Set PPCP. */ + SD_BLE_GAP_PPCP_GET = BLE_GAP_SVC_BASE + 15, /**< Get PPCP. */ + SD_BLE_GAP_DEVICE_NAME_SET = BLE_GAP_SVC_BASE + 16, /**< Set Device Name. */ + SD_BLE_GAP_DEVICE_NAME_GET = BLE_GAP_SVC_BASE + 17, /**< Get Device Name. */ + SD_BLE_GAP_AUTHENTICATE = BLE_GAP_SVC_BASE + 18, /**< Initiate Pairing/Bonding. */ + SD_BLE_GAP_SEC_PARAMS_REPLY = BLE_GAP_SVC_BASE + 19, /**< Reply with Security Parameters. */ + SD_BLE_GAP_AUTH_KEY_REPLY = BLE_GAP_SVC_BASE + 20, /**< Reply with an authentication key. */ + SD_BLE_GAP_LESC_DHKEY_REPLY = BLE_GAP_SVC_BASE + 21, /**< Reply with an LE Secure Connections DHKey. */ + SD_BLE_GAP_KEYPRESS_NOTIFY = BLE_GAP_SVC_BASE + 22, /**< Notify of a keypress during an authentication procedure. */ + SD_BLE_GAP_LESC_OOB_DATA_GET = BLE_GAP_SVC_BASE + 23, /**< Get the local LE Secure Connections OOB data. */ + SD_BLE_GAP_LESC_OOB_DATA_SET = BLE_GAP_SVC_BASE + 24, /**< Set the remote LE Secure Connections OOB data. */ + SD_BLE_GAP_ENCRYPT = BLE_GAP_SVC_BASE + 25, /**< Initiate encryption procedure. */ + SD_BLE_GAP_SEC_INFO_REPLY = BLE_GAP_SVC_BASE + 26, /**< Reply with Security Information. */ + SD_BLE_GAP_CONN_SEC_GET = BLE_GAP_SVC_BASE + 27, /**< Obtain connection security level. */ + SD_BLE_GAP_RSSI_START = BLE_GAP_SVC_BASE + 28, /**< Start reporting of changes in RSSI. */ + SD_BLE_GAP_RSSI_STOP = BLE_GAP_SVC_BASE + 29, /**< Stop reporting of changes in RSSI. */ + SD_BLE_GAP_SCAN_START = BLE_GAP_SVC_BASE + 30, /**< Start Scanning. */ + SD_BLE_GAP_SCAN_STOP = BLE_GAP_SVC_BASE + 31, /**< Stop Scanning. */ + SD_BLE_GAP_CONNECT = BLE_GAP_SVC_BASE + 32, /**< Connect. */ + SD_BLE_GAP_CONNECT_CANCEL = BLE_GAP_SVC_BASE + 33, /**< Cancel ongoing connection procedure. */ + SD_BLE_GAP_RSSI_GET = BLE_GAP_SVC_BASE + 34, /**< Get the last RSSI sample. */ + SD_BLE_GAP_PHY_UPDATE = BLE_GAP_SVC_BASE + 35, /**< Initiate or respond to a PHY Update Procedure. */ + SD_BLE_GAP_DATA_LENGTH_UPDATE = BLE_GAP_SVC_BASE + 36, /**< Initiate or respond to a Data Length Update Procedure. */ + SD_BLE_GAP_QOS_CHANNEL_SURVEY_START = BLE_GAP_SVC_BASE + 37, /**< Start Quality of Service (QoS) channel survey module. */ + SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP = BLE_GAP_SVC_BASE + 38, /**< Stop Quality of Service (QoS) channel survey module. */ + SD_BLE_GAP_ADV_ADDR_GET = BLE_GAP_SVC_BASE + 39, /**< Get the Address used on air while Advertising. */ + SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET = BLE_GAP_SVC_BASE + 40, /**< Get the next connection event counter. */ + SD_BLE_GAP_CONN_EVT_TRIGGER_START = BLE_GAP_SVC_BASE + 41, /** Start triggering a given task on connection event start. */ + SD_BLE_GAP_CONN_EVT_TRIGGER_STOP = + BLE_GAP_SVC_BASE + 42, /** Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. */ +}; + +/**@brief GAP Event IDs. + * IDs that uniquely identify an event coming from the stack to the application. + */ +enum BLE_GAP_EVTS { + BLE_GAP_EVT_CONNECTED = + BLE_GAP_EVT_BASE, /**< Connected to peer. \n See @ref ble_gap_evt_connected_t */ + BLE_GAP_EVT_DISCONNECTED = + BLE_GAP_EVT_BASE + 1, /**< Disconnected from peer. \n See @ref ble_gap_evt_disconnected_t. */ + BLE_GAP_EVT_CONN_PARAM_UPDATE = + BLE_GAP_EVT_BASE + 2, /**< Connection Parameters updated. \n See @ref ble_gap_evt_conn_param_update_t. */ + BLE_GAP_EVT_SEC_PARAMS_REQUEST = + BLE_GAP_EVT_BASE + 3, /**< Request to provide security parameters. \n Reply with @ref sd_ble_gap_sec_params_reply. + \n See @ref ble_gap_evt_sec_params_request_t. */ + BLE_GAP_EVT_SEC_INFO_REQUEST = + BLE_GAP_EVT_BASE + 4, /**< Request to provide security information. \n Reply with @ref sd_ble_gap_sec_info_reply. + \n See @ref ble_gap_evt_sec_info_request_t. */ + BLE_GAP_EVT_PASSKEY_DISPLAY = + BLE_GAP_EVT_BASE + 5, /**< Request to display a passkey to the user. \n In LESC Numeric Comparison, reply with @ref + sd_ble_gap_auth_key_reply. \n See @ref ble_gap_evt_passkey_display_t. */ + BLE_GAP_EVT_KEY_PRESSED = + BLE_GAP_EVT_BASE + 6, /**< Notification of a keypress on the remote device.\n See @ref ble_gap_evt_key_pressed_t */ + BLE_GAP_EVT_AUTH_KEY_REQUEST = + BLE_GAP_EVT_BASE + 7, /**< Request to provide an authentication key. \n Reply with @ref sd_ble_gap_auth_key_reply. + \n See @ref ble_gap_evt_auth_key_request_t. */ + BLE_GAP_EVT_LESC_DHKEY_REQUEST = + BLE_GAP_EVT_BASE + 8, /**< Request to calculate an LE Secure Connections DHKey. \n Reply with @ref + sd_ble_gap_lesc_dhkey_reply. \n See @ref ble_gap_evt_lesc_dhkey_request_t */ + BLE_GAP_EVT_AUTH_STATUS = + BLE_GAP_EVT_BASE + 9, /**< Authentication procedure completed with status. \n See @ref ble_gap_evt_auth_status_t. */ + BLE_GAP_EVT_CONN_SEC_UPDATE = + BLE_GAP_EVT_BASE + 10, /**< Connection security updated. \n See @ref ble_gap_evt_conn_sec_update_t. */ + BLE_GAP_EVT_TIMEOUT = + BLE_GAP_EVT_BASE + 11, /**< Timeout expired. \n See @ref ble_gap_evt_timeout_t. */ + BLE_GAP_EVT_RSSI_CHANGED = + BLE_GAP_EVT_BASE + 12, /**< RSSI report. \n See @ref ble_gap_evt_rssi_changed_t. */ + BLE_GAP_EVT_ADV_REPORT = + BLE_GAP_EVT_BASE + 13, /**< Advertising report. \n See @ref ble_gap_evt_adv_report_t. */ + BLE_GAP_EVT_SEC_REQUEST = + BLE_GAP_EVT_BASE + 14, /**< Security Request. \n Reply with @ref sd_ble_gap_authenticate +\n or with @ref sd_ble_gap_encrypt if required security information is available +. \n See @ref ble_gap_evt_sec_request_t. */ + BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 15, /**< Connection Parameter Update Request. \n Reply with @ref + sd_ble_gap_conn_param_update. \n See @ref ble_gap_evt_conn_param_update_request_t. */ + BLE_GAP_EVT_SCAN_REQ_REPORT = + BLE_GAP_EVT_BASE + 16, /**< Scan request report. \n See @ref ble_gap_evt_scan_req_report_t. */ + BLE_GAP_EVT_PHY_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 17, /**< PHY Update Request. \n Reply with @ref sd_ble_gap_phy_update. \n + See @ref ble_gap_evt_phy_update_request_t. */ + BLE_GAP_EVT_PHY_UPDATE = + BLE_GAP_EVT_BASE + 18, /**< PHY Update Procedure is complete. \n See @ref ble_gap_evt_phy_update_t. */ + BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 19, /**< Data Length Update Request. \n Reply with @ref + sd_ble_gap_data_length_update. \n See @ref ble_gap_evt_data_length_update_request_t. */ + BLE_GAP_EVT_DATA_LENGTH_UPDATE = + BLE_GAP_EVT_BASE + + 20, /**< LL Data Channel PDU payload length updated. \n See @ref ble_gap_evt_data_length_update_t. */ + BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT = + BLE_GAP_EVT_BASE + + 21, /**< Channel survey report. \n See @ref ble_gap_evt_qos_channel_survey_report_t. */ + BLE_GAP_EVT_ADV_SET_TERMINATED = + BLE_GAP_EVT_BASE + + 22, /**< Advertising set terminated. \n See @ref ble_gap_evt_adv_set_terminated_t. */ +}; + +/**@brief GAP Option IDs. + * IDs that uniquely identify a GAP option. + */ +enum BLE_GAP_OPTS { + BLE_GAP_OPT_CH_MAP = BLE_GAP_OPT_BASE, /**< Channel Map. @ref ble_gap_opt_ch_map_t */ + BLE_GAP_OPT_LOCAL_CONN_LATENCY = BLE_GAP_OPT_BASE + 1, /**< Local connection latency. @ref ble_gap_opt_local_conn_latency_t */ + BLE_GAP_OPT_PASSKEY = BLE_GAP_OPT_BASE + 2, /**< Set passkey. @ref ble_gap_opt_passkey_t */ + BLE_GAP_OPT_COMPAT_MODE_1 = BLE_GAP_OPT_BASE + 3, /**< Compatibility mode. @ref ble_gap_opt_compat_mode_1_t */ + BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT = + BLE_GAP_OPT_BASE + 4, /**< Set Authenticated payload timeout. @ref ble_gap_opt_auth_payload_timeout_t */ + BLE_GAP_OPT_SLAVE_LATENCY_DISABLE = + BLE_GAP_OPT_BASE + 5, /**< Disable slave latency. @ref ble_gap_opt_slave_latency_disable_t */ +}; + +/**@brief GAP Configuration IDs. + * + * IDs that uniquely identify a GAP configuration. + */ +enum BLE_GAP_CFGS { + BLE_GAP_CFG_ROLE_COUNT = BLE_GAP_CFG_BASE, /**< Role count configuration. */ + BLE_GAP_CFG_DEVICE_NAME = BLE_GAP_CFG_BASE + 1, /**< Device name configuration. */ + BLE_GAP_CFG_PPCP_INCL_CONFIG = BLE_GAP_CFG_BASE + 2, /**< Peripheral Preferred Connection Parameters characteristic + inclusion configuration. */ + BLE_GAP_CFG_CAR_INCL_CONFIG = BLE_GAP_CFG_BASE + 3, /**< Central Address Resolution characteristic + inclusion configuration. */ +}; + +/**@brief GAP TX Power roles. + */ +enum BLE_GAP_TX_POWER_ROLES { + BLE_GAP_TX_POWER_ROLE_ADV = 1, /**< Advertiser role. */ + BLE_GAP_TX_POWER_ROLE_SCAN_INIT = 2, /**< Scanner and initiator role. */ + BLE_GAP_TX_POWER_ROLE_CONN = 3, /**< Connection role. */ +}; + +/** @} */ + +/**@addtogroup BLE_GAP_DEFINES Defines + * @{ */ + +/**@defgroup BLE_ERRORS_GAP SVC return values specific to GAP + * @{ */ +#define BLE_ERROR_GAP_UUID_LIST_MISMATCH \ + (NRF_GAP_ERR_BASE + 0x000) /**< UUID list does not contain an integral number of UUIDs. */ +#define BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST \ + (NRF_GAP_ERR_BASE + 0x001) /**< Use of Whitelist not permitted with discoverable advertising. */ +#define BLE_ERROR_GAP_INVALID_BLE_ADDR \ + (NRF_GAP_ERR_BASE + 0x002) /**< The upper two bits of the address do not correspond to the specified address type. */ +#define BLE_ERROR_GAP_WHITELIST_IN_USE \ + (NRF_GAP_ERR_BASE + 0x003) /**< Attempt to modify the whitelist while already in use by another operation. */ +#define BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE \ + (NRF_GAP_ERR_BASE + 0x004) /**< Attempt to modify the device identity list while already in use by another operation. */ +#define BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE \ + (NRF_GAP_ERR_BASE + 0x005) /**< The device identity list contains entries with duplicate identity addresses. */ +/**@} */ + +/**@defgroup BLE_GAP_ROLES GAP Roles + * @{ */ +#define BLE_GAP_ROLE_INVALID 0x0 /**< Invalid Role. */ +#define BLE_GAP_ROLE_PERIPH 0x1 /**< Peripheral Role. */ +#define BLE_GAP_ROLE_CENTRAL 0x2 /**< Central Role. */ +/**@} */ + +/**@defgroup BLE_GAP_TIMEOUT_SOURCES GAP Timeout sources + * @{ */ +#define BLE_GAP_TIMEOUT_SRC_SCAN 0x01 /**< Scanning timeout. */ +#define BLE_GAP_TIMEOUT_SRC_CONN 0x02 /**< Connection timeout. */ +#define BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD 0x03 /**< Authenticated payload timeout. */ +/**@} */ + +/**@defgroup BLE_GAP_ADDR_TYPES GAP Address types + * @{ */ +#define BLE_GAP_ADDR_TYPE_PUBLIC 0x00 /**< Public (identity) address.*/ +#define BLE_GAP_ADDR_TYPE_RANDOM_STATIC 0x01 /**< Random static (identity) address. */ +#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE 0x02 /**< Random private resolvable address. */ +#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE 0x03 /**< Random private non-resolvable address. */ +#define BLE_GAP_ADDR_TYPE_ANONYMOUS \ + 0x7F /**< An advertiser may advertise without its address. \ + This type of advertising is called anonymous. */ +/**@} */ + +/**@brief The default interval in seconds at which a private address is refreshed. */ +#define BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S (900) /* 15 minutes. */ +/**@brief The maximum interval in seconds at which a private address can be refreshed. */ +#define BLE_GAP_MAX_PRIVATE_ADDR_CYCLE_INTERVAL_S (41400) /* 11 hours 30 minutes. */ + +/** @brief BLE address length. */ +#define BLE_GAP_ADDR_LEN (6) + +/**@defgroup BLE_GAP_PRIVACY_MODES Privacy modes + * @{ */ +#define BLE_GAP_PRIVACY_MODE_OFF 0x00 /**< Device will send and accept its identity address for its own address. */ +#define BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY 0x01 /**< Device will send and accept only private addresses for its own address. */ +#define BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY \ + 0x02 /**< Device will send and accept only private addresses for its own address, \ + and will not accept a peer using identity address as sender address when \ + the peer IRK is exchanged, non-zero and added to the identity list. */ +/**@} */ + +/** @brief Invalid power level. */ +#define BLE_GAP_POWER_LEVEL_INVALID 127 + +/** @brief Advertising set handle not set. */ +#define BLE_GAP_ADV_SET_HANDLE_NOT_SET (0xFF) + +/** @brief The default number of advertising sets. */ +#define BLE_GAP_ADV_SET_COUNT_DEFAULT (1) + +/** @brief The maximum number of advertising sets supported by this SoftDevice. */ +#define BLE_GAP_ADV_SET_COUNT_MAX (1) + +/**@defgroup BLE_GAP_ADV_SET_DATA_SIZES Advertising data sizes. + * @{ */ +#define BLE_GAP_ADV_SET_DATA_SIZE_MAX \ + (31) /**< Maximum data length for an advertising set. \ + If more advertising data is required, use extended advertising instead. */ +#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED \ + (255) /**< Maximum supported data length for an extended advertising set. */ + +#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED \ + (238) /**< Maximum supported data length for an extended connectable advertising set. */ +/**@}. */ + +/** @brief Set ID not available in advertising report. */ +#define BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE 0xFF + +/**@defgroup BLE_GAP_EVT_ADV_SET_TERMINATED_REASON GAP Advertising Set Terminated reasons + * @{ */ +#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT 0x01 /**< Timeout value reached. */ +#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED 0x02 /**< @ref ble_gap_adv_params_t::max_adv_evts was reached. */ +/**@} */ + +/**@defgroup BLE_GAP_AD_TYPE_DEFINITIONS GAP Advertising and Scan Response Data format + * @note Found at https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm + * @{ */ +#define BLE_GAP_AD_TYPE_FLAGS 0x01 /**< Flags for discoverability. */ +#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 /**< Partial list of 16 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 /**< Complete list of 16 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 /**< Partial list of 32 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 /**< Complete list of 32 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 /**< Partial list of 128 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 /**< Complete list of 128 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 /**< Short local device name. */ +#define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 /**< Complete local device name. */ +#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A /**< Transmit power level. */ +#define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D /**< Class of device. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E /**< Simple Pairing Hash C. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F /**< Simple Pairing Randomizer R. */ +#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 /**< Security Manager TK Value. */ +#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 /**< Security Manager Out Of Band Flags. */ +#define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 /**< Slave Connection Interval Range. */ +#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 /**< List of 16-bit Service Solicitation UUIDs. */ +#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 /**< List of 128-bit Service Solicitation UUIDs. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 /**< Service Data - 16-bit UUID. */ +#define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 /**< Public Target Address. */ +#define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 /**< Random Target Address. */ +#define BLE_GAP_AD_TYPE_APPEARANCE 0x19 /**< Appearance. */ +#define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A /**< Advertising Interval. */ +#define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B /**< LE Bluetooth Device Address. */ +#define BLE_GAP_AD_TYPE_LE_ROLE 0x1C /**< LE Role. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D /**< Simple Pairing Hash C-256. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E /**< Simple Pairing Randomizer R-256. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 /**< Service Data - 32-bit UUID. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 /**< Service Data - 128-bit UUID. */ +#define BLE_GAP_AD_TYPE_LESC_CONFIRMATION_VALUE 0x22 /**< LE Secure Connections Confirmation Value */ +#define BLE_GAP_AD_TYPE_LESC_RANDOM_VALUE 0x23 /**< LE Secure Connections Random Value */ +#define BLE_GAP_AD_TYPE_URI 0x24 /**< URI */ +#define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D /**< 3D Information Data. */ +#define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF /**< Manufacturer Specific Data. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_FLAGS GAP Advertisement Flags + * @{ */ +#define BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE (0x01) /**< LE Limited Discoverable Mode. */ +#define BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) /**< LE General Discoverable Mode. */ +#define BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) /**< BR/EDR not supported. */ +#define BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER (0x08) /**< Simultaneous LE and BR/EDR, Controller. */ +#define BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST (0x10) /**< Simultaneous LE and BR/EDR, Host. */ +#define BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE \ + (BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE | \ + BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE Limited Discoverable Mode, BR/EDR not supported. */ +#define BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE \ + (BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | \ + BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE General Discoverable Mode, BR/EDR not supported. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_INTERVALS GAP Advertising interval max and min + * @{ */ +#define BLE_GAP_ADV_INTERVAL_MIN 0x000020 /**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */ +#define BLE_GAP_ADV_INTERVAL_MAX 0x004000 /**< Maximum Advertising interval in 625 us units, i.e. 10.24 s. */ + /**@} */ + +/**@defgroup BLE_GAP_SCAN_INTERVALS GAP Scan interval max and min + * @{ */ +#define BLE_GAP_SCAN_INTERVAL_MIN 0x0004 /**< Minimum Scan interval in 625 us units, i.e. 2.5 ms. */ +#define BLE_GAP_SCAN_INTERVAL_MAX 0xFFFF /**< Maximum Scan interval in 625 us units, i.e. 40,959.375 s. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_WINDOW GAP Scan window max and min + * @{ */ +#define BLE_GAP_SCAN_WINDOW_MIN 0x0004 /**< Minimum Scan window in 625 us units, i.e. 2.5 ms. */ +#define BLE_GAP_SCAN_WINDOW_MAX 0xFFFF /**< Maximum Scan window in 625 us units, i.e. 40,959.375 s. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_TIMEOUT GAP Scan timeout max and min + * @{ */ +#define BLE_GAP_SCAN_TIMEOUT_MIN 0x0001 /**< Minimum Scan timeout in 10 ms units, i.e 10 ms. */ +#define BLE_GAP_SCAN_TIMEOUT_UNLIMITED 0x0000 /**< Continue to scan forever. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_BUFFER_SIZE GAP Minimum scanner buffer size + * + * Scan buffers are used for storing advertising data received from an advertiser. + * If ble_gap_scan_params_t::extended is set to 0, @ref BLE_GAP_SCAN_BUFFER_MIN is the minimum scan buffer length. + * else the minimum scan buffer size is @ref BLE_GAP_SCAN_BUFFER_EXTENDED_MIN. + * @{ */ +#define BLE_GAP_SCAN_BUFFER_MIN \ + (31) /**< Minimum data length for an \ + advertising set. */ +#define BLE_GAP_SCAN_BUFFER_MAX \ + (31) /**< Maximum data length for an \ + advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MIN \ + (255) /**< Minimum data length for an \ + extended advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX \ + (1650) /**< Maximum data length for an \ + extended advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED \ + (255) /**< Maximum supported data length for \ + an extended advertising set. */ +/** @} */ + +/**@defgroup BLE_GAP_ADV_TYPES GAP Advertising types + * + * Advertising types defined in Bluetooth Core Specification v5.0, Vol 6, Part B, Section 4.4.2. + * + * The maximum advertising data length is defined by @ref BLE_GAP_ADV_SET_DATA_SIZE_MAX. + * The maximum supported data length for an extended advertiser is defined by + * @ref BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED + * Note that some of the advertising types do not support advertising data. Non-scannable types do not support + * scan response data. + * + * @{ */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x01 /**< Connectable and scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE \ + 0x02 /**< Connectable non-scannable directed advertising \ + events. Advertising interval is less that 3.75 ms. \ + Use this type for fast reconnections. \ + @note Advertising data is not supported. */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x03 /**< Connectable non-scannable directed advertising \ + events. \ + @note Advertising data is not supported. */ +#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x04 /**< Non-connectable scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x05 /**< Non-connectable non-scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x06 /**< Connectable non-scannable undirected advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x07 /**< Connectable non-scannable directed advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x08 /**< Non-connectable scannable undirected advertising \ + events using extended advertising PDUs. \ + @note Only scan response data is supported. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED \ + 0x09 /**< Non-connectable scannable directed advertising \ + events using extended advertising PDUs. \ + @note Only scan response data is supported. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x0A /**< Non-connectable non-scannable undirected advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x0B /**< Non-connectable non-scannable directed advertising \ + events using extended advertising PDUs. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_FILTER_POLICIES GAP Advertising filter policies + * @{ */ +#define BLE_GAP_ADV_FP_ANY 0x00 /**< Allow scan requests and connect requests from any device. */ +#define BLE_GAP_ADV_FP_FILTER_SCANREQ 0x01 /**< Filter scan requests with whitelist. */ +#define BLE_GAP_ADV_FP_FILTER_CONNREQ 0x02 /**< Filter connect requests with whitelist. */ +#define BLE_GAP_ADV_FP_FILTER_BOTH 0x03 /**< Filter both scan and connect requests with whitelist. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_DATA_STATUS GAP Advertising data status + * @{ */ +#define BLE_GAP_ADV_DATA_STATUS_COMPLETE 0x00 /**< All data in the advertising event have been received. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA \ + 0x01 /**< More data to be received. \ + @note This value will only be used if \ + @ref ble_gap_scan_params_t::report_incomplete_evts and \ + @ref ble_gap_adv_report_type_t::extended_pdu are set to true. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED \ + 0x02 /**< Incomplete data. Buffer size insufficient to receive more. \ + @note This value will only be used if \ + @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MISSED \ + 0x03 /**< Failed to receive the remaining data. \ + @note This value will only be used if \ + @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ +/**@} */ + +/**@defgroup BLE_GAP_SCAN_FILTER_POLICIES GAP Scanner filter policies + * @{ */ +#define BLE_GAP_SCAN_FP_ACCEPT_ALL \ + 0x00 /**< Accept all advertising packets except directed advertising packets \ + not addressed to this device. */ +#define BLE_GAP_SCAN_FP_WHITELIST \ + 0x01 /**< Accept advertising packets from devices in the whitelist except directed \ + packets not addressed to this device. */ +#define BLE_GAP_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED \ + 0x02 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL. \ + In addition, accept directed advertising packets, where the advertiser's \ + address is a resolvable private address that cannot be resolved. */ +#define BLE_GAP_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED \ + 0x03 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST. \ + In addition, accept directed advertising packets, where the advertiser's \ + address is a resolvable private address that cannot be resolved. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_TIMEOUT_VALUES GAP Advertising timeout values in 10 ms units + * @{ */ +#define BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX \ + (128) /**< Maximum high duty advertising time in 10 ms units. Corresponds to 1.28 s. \ + */ +#define BLE_GAP_ADV_TIMEOUT_LIMITED_MAX \ + (18000) /**< Maximum advertising time in 10 ms units corresponding to TGAP(lim_adv_timeout) = 180 s in limited discoverable \ + mode. */ +#define BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED \ + (0) /**< Unlimited advertising in general discoverable mode. \ + For high duty cycle advertising, this corresponds to @ref BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX. */ +/**@} */ + +/**@defgroup BLE_GAP_DISC_MODES GAP Discovery modes + * @{ */ +#define BLE_GAP_DISC_MODE_NOT_DISCOVERABLE 0x00 /**< Not discoverable discovery Mode. */ +#define BLE_GAP_DISC_MODE_LIMITED 0x01 /**< Limited Discovery Mode. */ +#define BLE_GAP_DISC_MODE_GENERAL 0x02 /**< General Discovery Mode. */ +/**@} */ + +/**@defgroup BLE_GAP_IO_CAPS GAP IO Capabilities + * @{ */ +#define BLE_GAP_IO_CAPS_DISPLAY_ONLY 0x00 /**< Display Only. */ +#define BLE_GAP_IO_CAPS_DISPLAY_YESNO 0x01 /**< Display and Yes/No entry. */ +#define BLE_GAP_IO_CAPS_KEYBOARD_ONLY 0x02 /**< Keyboard Only. */ +#define BLE_GAP_IO_CAPS_NONE 0x03 /**< No I/O capabilities. */ +#define BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY 0x04 /**< Keyboard and Display. */ +/**@} */ + +/**@defgroup BLE_GAP_AUTH_KEY_TYPES GAP Authentication Key Types + * @{ */ +#define BLE_GAP_AUTH_KEY_TYPE_NONE 0x00 /**< No key (may be used to reject). */ +#define BLE_GAP_AUTH_KEY_TYPE_PASSKEY 0x01 /**< 6-digit Passkey. */ +#define BLE_GAP_AUTH_KEY_TYPE_OOB 0x02 /**< Out Of Band data. */ +/**@} */ + +/**@defgroup BLE_GAP_KP_NOT_TYPES GAP Keypress Notification Types + * @{ */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_START 0x00 /**< Passkey entry started. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_IN 0x01 /**< Passkey digit entered. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_OUT 0x02 /**< Passkey digit erased. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_CLEAR 0x03 /**< Passkey cleared. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_END 0x04 /**< Passkey entry completed. */ +/**@} */ + +/**@defgroup BLE_GAP_SEC_STATUS GAP Security status + * @{ */ +#define BLE_GAP_SEC_STATUS_SUCCESS 0x00 /**< Procedure completed with success. */ +#define BLE_GAP_SEC_STATUS_TIMEOUT 0x01 /**< Procedure timed out. */ +#define BLE_GAP_SEC_STATUS_PDU_INVALID 0x02 /**< Invalid PDU received. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE1_BEGIN 0x03 /**< Reserved for Future Use range #1 begin. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE1_END 0x80 /**< Reserved for Future Use range #1 end. */ +#define BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED 0x81 /**< Passkey entry failed (user canceled or other). */ +#define BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE 0x82 /**< Out of Band Key not available. */ +#define BLE_GAP_SEC_STATUS_AUTH_REQ 0x83 /**< Authentication requirements not met. */ +#define BLE_GAP_SEC_STATUS_CONFIRM_VALUE 0x84 /**< Confirm value failed. */ +#define BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP 0x85 /**< Pairing not supported. */ +#define BLE_GAP_SEC_STATUS_ENC_KEY_SIZE 0x86 /**< Encryption key size. */ +#define BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED 0x87 /**< Unsupported SMP command. */ +#define BLE_GAP_SEC_STATUS_UNSPECIFIED 0x88 /**< Unspecified reason. */ +#define BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS 0x89 /**< Too little time elapsed since last attempt. */ +#define BLE_GAP_SEC_STATUS_INVALID_PARAMS 0x8A /**< Invalid parameters. */ +#define BLE_GAP_SEC_STATUS_DHKEY_FAILURE 0x8B /**< DHKey check failure. */ +#define BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE 0x8C /**< Numeric Comparison failure. */ +#define BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG 0x8D /**< BR/EDR pairing in progress. */ +#define BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED 0x8E /**< BR/EDR Link Key cannot be used for LE keys. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE2_BEGIN 0x8F /**< Reserved for Future Use range #2 begin. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE2_END 0xFF /**< Reserved for Future Use range #2 end. */ +/**@} */ + +/**@defgroup BLE_GAP_SEC_STATUS_SOURCES GAP Security status sources + * @{ */ +#define BLE_GAP_SEC_STATUS_SOURCE_LOCAL 0x00 /**< Local failure. */ +#define BLE_GAP_SEC_STATUS_SOURCE_REMOTE 0x01 /**< Remote failure. */ +/**@} */ + +/**@defgroup BLE_GAP_CP_LIMITS GAP Connection Parameters Limits + * @{ */ +#define BLE_GAP_CP_MIN_CONN_INTVL_NONE 0xFFFF /**< No new minimum connection interval specified in connect parameters. */ +#define BLE_GAP_CP_MIN_CONN_INTVL_MIN \ + 0x0006 /**< Lowest minimum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ +#define BLE_GAP_CP_MIN_CONN_INTVL_MAX \ + 0x0C80 /**< Highest minimum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ + */ +#define BLE_GAP_CP_MAX_CONN_INTVL_NONE 0xFFFF /**< No new maximum connection interval specified in connect parameters. */ +#define BLE_GAP_CP_MAX_CONN_INTVL_MIN \ + 0x0006 /**< Lowest maximum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ +#define BLE_GAP_CP_MAX_CONN_INTVL_MAX \ + 0x0C80 /**< Highest maximum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ + */ +#define BLE_GAP_CP_SLAVE_LATENCY_MAX 0x01F3 /**< Highest slave latency permitted, in connection events. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_NONE 0xFFFF /**< No new supervision timeout specified in connect parameters. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN 0x000A /**< Lowest supervision timeout permitted, in units of 10 ms, i.e. 100 ms. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX 0x0C80 /**< Highest supervision timeout permitted, in units of 10 ms, i.e. 32 s. */ +/**@} */ + +/**@defgroup BLE_GAP_DEVNAME GAP device name defines. + * @{ */ +#define BLE_GAP_DEVNAME_DEFAULT "nRF5x" /**< Default device name value. */ +#define BLE_GAP_DEVNAME_DEFAULT_LEN 31 /**< Default number of octets in device name. */ +#define BLE_GAP_DEVNAME_MAX_LEN 248 /**< Maximum number of octets in device name. */ +/**@} */ + +/**@brief Disable RSSI events for connections */ +#define BLE_GAP_RSSI_THRESHOLD_INVALID 0xFF + +/**@defgroup BLE_GAP_PHYS GAP PHYs + * @{ */ +#define BLE_GAP_PHY_AUTO 0x00 /**< Automatic PHY selection. Refer @ref sd_ble_gap_phy_update for more information.*/ +#define BLE_GAP_PHY_1MBPS 0x01 /**< 1 Mbps PHY. */ +#define BLE_GAP_PHY_2MBPS 0x02 /**< 2 Mbps PHY. */ +#define BLE_GAP_PHY_CODED 0x04 /**< Coded PHY. */ +#define BLE_GAP_PHY_NOT_SET 0xFF /**< PHY is not configured. */ + +/**@brief Supported PHYs in connections, for scanning, and for advertising. */ +#define BLE_GAP_PHYS_SUPPORTED (BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_CODED) /**< All PHYs are supported. */ + +/**@} */ + +/**@defgroup BLE_GAP_CONN_SEC_MODE_SET_MACROS GAP attribute security requirement setters + * + * See @ref ble_gap_conn_sec_mode_t. + * @{ */ +/**@brief Set sec_mode pointed to by ptr to have no access rights.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(ptr) \ + do { \ + (ptr)->sm = 0; \ + (ptr)->lv = 0; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require no protection, open link.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_OPEN(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 1; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require encryption, but no MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 2; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require encryption and MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 3; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require LESC encryption and MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 4; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require signing or encryption, no MITM protection needed.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(ptr) \ + do { \ + (ptr)->sm = 2; \ + (ptr)->lv = 1; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require signing or encryption with MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 2; \ + (ptr)->lv = 2; \ + } while (0) +/**@} */ + +/**@brief GAP Security Random Number Length. */ +#define BLE_GAP_SEC_RAND_LEN 8 + +/**@brief GAP Security Key Length. */ +#define BLE_GAP_SEC_KEY_LEN 16 + +/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key Length. */ +#define BLE_GAP_LESC_P256_PK_LEN 64 + +/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman DHKey Length. */ +#define BLE_GAP_LESC_DHKEY_LEN 32 + +/**@brief GAP Passkey Length. */ +#define BLE_GAP_PASSKEY_LEN 6 + +/**@brief Maximum amount of addresses in the whitelist. */ +#define BLE_GAP_WHITELIST_ADDR_MAX_COUNT (8) + +/**@brief Maximum amount of identities in the device identities list. */ +#define BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT (8) + +/**@brief Default connection count for a configuration. */ +#define BLE_GAP_CONN_COUNT_DEFAULT (1) + +/**@defgroup BLE_GAP_EVENT_LENGTH GAP event length defines. + * @{ */ +#define BLE_GAP_EVENT_LENGTH_MIN (2) /**< Minimum event length, in 1.25 ms units. */ +#define BLE_GAP_EVENT_LENGTH_CODED_PHY_MIN (6) /**< The shortest event length in 1.25 ms units supporting LE Coded PHY. */ +#define BLE_GAP_EVENT_LENGTH_DEFAULT (3) /**< Default event length, in 1.25 ms units. */ +/**@} */ + +/**@defgroup BLE_GAP_ROLE_COUNT GAP concurrent connection count defines. + * @{ */ +#define BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT (1) /**< Default maximum number of connections concurrently acting as peripherals. */ +#define BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT (3) /**< Default maximum number of connections concurrently acting as centrals. */ +#define BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT \ + (1) /**< Default number of SMP instances shared between all connections acting as centrals. */ +#define BLE_GAP_ROLE_COUNT_COMBINED_MAX \ + (20) /**< Maximum supported number of concurrent connections in the peripheral and central roles combined. */ + +/**@} */ + +/**@brief Automatic data length parameter. */ +#define BLE_GAP_DATA_LENGTH_AUTO 0 + +/**@defgroup BLE_GAP_AUTH_PAYLOAD_TIMEOUT Authenticated payload timeout defines. + * @{ */ +#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX (48000) /**< Maximum authenticated payload timeout in 10 ms units, i.e. 8 minutes. */ +#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MIN (1) /**< Minimum authenticated payload timeout in 10 ms units, i.e. 10 ms. */ +/**@} */ + +/**@defgroup GAP_SEC_MODES GAP Security Modes + * @{ */ +#define BLE_GAP_SEC_MODE 0x00 /**< No key (may be used to reject). */ +/**@} */ + +/**@brief The total number of channels in Bluetooth Low Energy. */ +#define BLE_GAP_CHANNEL_COUNT (40) + +/**@defgroup BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS Quality of Service (QoS) Channel survey interval defines + * @{ */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS (0) /**< Continuous channel survey. */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MIN_US (7500) /**< Minimum channel survey interval in microseconds (7.5 ms). */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MAX_US (4000000) /**< Maximum channel survey interval in microseconds (4 s). */ + /**@} */ + +/** @} */ + +/** @defgroup BLE_GAP_CHAR_INCL_CONFIG GAP Characteristic inclusion configurations + * @{ + */ +#define BLE_GAP_CHAR_INCL_CONFIG_INCLUDE (0) /**< Include the characteristic in the Attribute Table */ +#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITH_SPACE \ + (1) /**< Do not include the characteristic in the Attribute table. \ + The SoftDevice will reserve the attribute handles \ + which are otherwise used for this characteristic. \ + By reserving the attribute handles it will be possible \ + to upgrade the SoftDevice without changing handle of the \ + Service Changed characteristic. */ +#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITHOUT_SPACE \ + (2) /**< Do not include the characteristic in the Attribute table. \ + The SoftDevice will not reserve the attribute handles \ + which are otherwise used for this characteristic. */ +/**@} */ + +/** @defgroup BLE_GAP_CHAR_INCL_CONFIG_DEFAULTS Characteristic inclusion default values + * @{ */ +#define BLE_GAP_PPCP_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ +#define BLE_GAP_CAR_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ +/**@} */ + +/** @defgroup BLE_GAP_SLAVE_LATENCY Slave latency configuration options + * @{ */ +#define BLE_GAP_SLAVE_LATENCY_ENABLE \ + (0) /**< Slave latency is enabled. When slave latency is enabled, \ + the slave will wake up every time it has data to send, \ + and/or every slave latency number of connection events. */ +#define BLE_GAP_SLAVE_LATENCY_DISABLE \ + (1) /**< Disable slave latency. The slave will wake up every connection event \ + regardless of the requested slave latency. \ + This option consumes the most power. */ +#define BLE_GAP_SLAVE_LATENCY_WAIT_FOR_ACK \ + (2) /**< The slave will wake up every connection event if it has not received \ + an ACK from the master for at least slave latency events. This \ + configuration may increase the power consumption in environments \ + with a lot of radio activity. */ +/**@} */ + +/**@addtogroup BLE_GAP_STRUCTURES Structures + * @{ */ + +/**@brief Advertising event properties. */ +typedef struct { + uint8_t type; /**< Advertising type. See @ref BLE_GAP_ADV_TYPES. */ + uint8_t anonymous : 1; /**< Omit advertiser's address from all PDUs. + @note Anonymous advertising is only available for + @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED and + @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED. */ + uint8_t include_tx_power : 1; /**< This feature is not supported on this SoftDevice. */ +} ble_gap_adv_properties_t; + +/**@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 Advertising Auxiliary Pointer. */ +typedef struct { + uint16_t aux_offset; /**< Time offset from the beginning of advertising packet to the auxiliary packet in 100 us units. */ + uint8_t aux_phy; /**< Indicates the PHY on which the auxiliary advertising packet is sent. See @ref BLE_GAP_PHYS. */ +} ble_gap_aux_pointer_t; + +/**@brief Bluetooth Low Energy address. */ +typedef struct { + uint8_t + addr_id_peer : 1; /**< Only valid for peer addresses. + This bit is set by the SoftDevice to indicate whether the address has been resolved from + a Resolvable Private Address (when the peer is using privacy). + If set to 1, @ref addr and @ref addr_type refer to the identity address of the resolved address. + + This bit is ignored when a variable of type @ref ble_gap_addr_t is used as input to API functions. + */ + uint8_t addr_type : 7; /**< See @ref BLE_GAP_ADDR_TYPES. */ + uint8_t addr[BLE_GAP_ADDR_LEN]; /**< 48-bit address, LSB format. + @ref addr is not used if @ref addr_type is @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. */ +} ble_gap_addr_t; + +/**@brief GAP connection parameters. + * + * @note When ble_conn_params_t is received in an event, both min_conn_interval and + * max_conn_interval will be equal to the connection interval set by the central. + * + * @note If both conn_sup_timeout and max_conn_interval are specified, then the following constraint applies: + * conn_sup_timeout * 4 > (1 + slave_latency) * max_conn_interval + * that corresponds to the following Bluetooth Spec requirement: + * The Supervision_Timeout in milliseconds shall be larger than + * (1 + Conn_Latency) * Conn_Interval_Max * 2, where Conn_Interval_Max is given in milliseconds. + */ +typedef struct { + uint16_t min_conn_interval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t max_conn_interval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t slave_latency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t conn_sup_timeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ +} ble_gap_conn_params_t; + +/**@brief GAP connection security modes. + * + * Security Mode 0 Level 0: No access permissions at all (this level is not defined by the Bluetooth Core specification).\n + * Security Mode 1 Level 1: No security is needed (aka open link).\n + * Security Mode 1 Level 2: Encrypted link required, MITM protection not necessary.\n + * Security Mode 1 Level 3: MITM protected encrypted link required.\n + * Security Mode 1 Level 4: LESC MITM protected encrypted link using a 128-bit strength encryption key required.\n + * Security Mode 2 Level 1: Signing or encryption required, MITM protection not necessary.\n + * Security Mode 2 Level 2: MITM protected signing required, unless link is MITM protected encrypted.\n + */ +typedef struct { + uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ + uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */ + +} ble_gap_conn_sec_mode_t; + +/**@brief GAP connection security status.*/ +typedef struct { + ble_gap_conn_sec_mode_t sec_mode; /**< Currently active security mode for this connection.*/ + uint8_t + encr_key_size; /**< Length of currently active encryption key, 7 to 16 octets (only applicable for bonding procedures). */ +} ble_gap_conn_sec_t; + +/**@brief Identity Resolving Key. */ +typedef struct { + uint8_t irk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing IRK. */ +} ble_gap_irk_t; + +/**@brief Channel mask (40 bits). + * Every channel is represented with a bit positioned as per channel index defined in Bluetooth Core Specification v5.0, + * Vol 6, Part B, Section 1.4.1. The LSB contained in array element 0 represents channel index 0, and bit 39 represents + * channel index 39. If a bit is set to 1, the channel is not used. + */ +typedef uint8_t ble_gap_ch_mask_t[5]; + +/**@brief GAP advertising parameters. */ +typedef struct { + ble_gap_adv_properties_t properties; /**< The properties of the advertising events. */ + ble_gap_addr_t const *p_peer_addr; /**< Address of a known peer. + @note ble_gap_addr_t::addr_type cannot be + @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. + - When privacy is enabled and the local device uses + @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE addresses, + the device identity list is searched for a matching entry. If + the local IRK for that device identity is set, the local IRK + for that device will be used to generate the advertiser address + field in the advertising packet. + - If @ref ble_gap_adv_properties_t::type is directed, this must be + set to the targeted scanner or initiator. If the peer address is + in the device identity list, the peer IRK for that device will be + used to generate @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE + target addresses used in the advertising event PDUs. */ + uint32_t interval; /**< Advertising interval in 625 us units. @sa BLE_GAP_ADV_INTERVALS. + @note If @ref ble_gap_adv_properties_t::type is set to + @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE + advertising, this parameter is ignored. */ + uint16_t duration; /**< Advertising duration in 10 ms units. When timeout is reached, + an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. + @sa BLE_GAP_ADV_TIMEOUT_VALUES. + @note The SoftDevice will always complete at least one advertising + event even if the duration is set too low. */ + uint8_t max_adv_evts; /**< Maximum advertising events that shall be sent prior to disabling + advertising. Setting the value to 0 disables the limitation. When + the count of advertising events specified by this parameter + (if not 0) is reached, advertising will be automatically stopped + and an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised + @note If @ref ble_gap_adv_properties_t::type is set to + @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE, + this parameter is ignored. */ + ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. + At least one of the primary channels, that is channel index 37-39, must be used. + Masking away secondary advertising channels is not supported. */ + uint8_t filter_policy; /**< Filter Policy. @sa BLE_GAP_ADV_FILTER_POLICIES. */ + uint8_t primary_phy; /**< Indicates the PHY on which the primary advertising channel packets + are transmitted. If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS + will be used. + Valid values are @ref BLE_GAP_PHY_1MBPS and @ref BLE_GAP_PHY_CODED. + @note The primary_phy shall indicate @ref BLE_GAP_PHY_1MBPS if + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t secondary_phy; /**< Indicates the PHY on which the secondary advertising channel packets + are transmitted. + If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS will be used. + Valid values are + @ref BLE_GAP_PHY_1MBPS, @ref BLE_GAP_PHY_2MBPS, and @ref BLE_GAP_PHY_CODED. + If @ref ble_gap_adv_properties_t::type is an extended advertising type + and connectable, this is the PHY that will be used to establish a + connection and send AUX_ADV_IND packets on. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t set_id : 4; /**< The advertising set identifier distinguishes this advertising set from other + advertising sets transmitted by this and other devices. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t scan_req_notification : 1; /**< Enable scan request notifications for this advertising set. When a + scan request is received and the scanner address is allowed + by the filter policy, @ref BLE_GAP_EVT_SCAN_REQ_REPORT is raised. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is a non-scannable + advertising type. */ +} ble_gap_adv_params_t; + +/**@brief GAP advertising data buffers. + * + * The application must provide the buffers for advertisement. The memory shall reside in application RAM, and + * shall never be modified while advertising. The data shall be kept alive until either: + * - @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. + * - @ref BLE_GAP_EVT_CONNECTED is raised with @ref ble_gap_evt_connected_t::adv_handle set to the corresponding + * advertising handle. + * - Advertising is stopped. + * - Advertising data is changed. + * To update advertising data while advertising, provide new buffers to @ref sd_ble_gap_adv_set_configure. */ +typedef struct { + ble_data_t adv_data; /**< Advertising data. + @note + Advertising data can only be specified for a @ref ble_gap_adv_properties_t::type + that is allowed to contain advertising data. */ + ble_data_t scan_rsp_data; /**< Scan response data. + @note + Scan response data can only be specified for a @ref ble_gap_adv_properties_t::type + that is scannable. */ +} ble_gap_adv_data_t; + +/**@brief GAP scanning parameters. */ +typedef struct { + uint8_t extended : 1; /**< If 1, the scanner will accept extended advertising packets. + If set to 0, the scanner will not receive advertising packets + on secondary advertising channels, and will not be able + to receive long advertising PDUs. */ + uint8_t report_incomplete_evts : 1; /**< If 1, events of type @ref ble_gap_evt_adv_report_t may have + @ref ble_gap_adv_report_type_t::status set to + @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. + This parameter is ignored when used with @ref sd_ble_gap_connect + @note This may be used to abort receiving more packets from an extended + advertising event, and is only available for extended + scanning, see @ref sd_ble_gap_scan_start. + @note This feature is not supported by this SoftDevice. */ + uint8_t active : 1; /**< If 1, perform active scanning by sending scan requests. + This parameter is ignored when used with @ref sd_ble_gap_connect. */ + uint8_t filter_policy : 2; /**< Scanning filter policy. @sa BLE_GAP_SCAN_FILTER_POLICIES. + @note Only @ref BLE_GAP_SCAN_FP_ACCEPT_ALL and + @ref BLE_GAP_SCAN_FP_WHITELIST are valid when used with + @ref sd_ble_gap_connect */ + uint8_t scan_phys; /**< Bitfield of PHYs to scan on. If set to @ref BLE_GAP_PHY_AUTO, + scan_phys will default to @ref BLE_GAP_PHY_1MBPS. + - If @ref ble_gap_scan_params_t::extended is set to 0, the only + supported PHY is @ref BLE_GAP_PHY_1MBPS. + - When used with @ref sd_ble_gap_scan_start, + the bitfield indicates the PHYs the scanner will use for scanning + on primary advertising channels. The scanner will accept + @ref BLE_GAP_PHYS_SUPPORTED as secondary advertising channel PHYs. + - When used with @ref sd_ble_gap_connect, the bitfield indicates + the PHYs the initiator will use for scanning on primary advertising + channels. The initiator will accept connections initiated on either + of the @ref BLE_GAP_PHYS_SUPPORTED PHYs. + If scan_phys contains @ref BLE_GAP_PHY_1MBPS and/or @ref BLE_GAP_PHY_2MBPS, + the primary scan PHY is @ref BLE_GAP_PHY_1MBPS. + If scan_phys also contains @ref BLE_GAP_PHY_CODED, the primary scan + PHY will also contain @ref BLE_GAP_PHY_CODED. If the only scan PHY is + @ref BLE_GAP_PHY_CODED, the primary scan PHY is + @ref BLE_GAP_PHY_CODED only. */ + uint16_t interval; /**< Scan interval in 625 us units. @sa BLE_GAP_SCAN_INTERVALS. */ + uint16_t window; /**< Scan window in 625 us units. @sa BLE_GAP_SCAN_WINDOW. + If scan_phys contains both @ref BLE_GAP_PHY_1MBPS and + @ref BLE_GAP_PHY_CODED interval shall be larger than or + equal to twice the scan window. */ + uint16_t timeout; /**< Scan timeout in 10 ms units. @sa BLE_GAP_SCAN_TIMEOUT. */ + ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. + At least one of the primary channels, that is channel index 37-39, must be + set to 0. + Masking away secondary channels is not supported. */ +} ble_gap_scan_params_t; + +/**@brief Privacy. + * + * The privacy feature provides a way for the device to avoid being tracked over a period of time. + * The privacy feature, when enabled, hides the local device identity and replaces it with a private address + * that is automatically refreshed at a specified interval. + * + * If a device still wants to be recognized by other peers, it needs to share it's Identity Resolving Key (IRK). + * With this key, a device can generate a random private address that can only be recognized by peers in possession of that + * key, and devices can establish connections without revealing their real identities. + * + * Both network privacy (@ref BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY) and device privacy (@ref + * BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY) are supported. + * + * @note If the device IRK is updated, the new IRK becomes the one to be distributed in all + * bonding procedures performed after @ref sd_ble_gap_privacy_set returns. + * The IRK distributed during bonding procedure is the device IRK that is active when @ref sd_ble_gap_sec_params_reply is + * called. + */ +typedef struct { + uint8_t privacy_mode; /**< Privacy mode, see @ref BLE_GAP_PRIVACY_MODES. Default is @ref BLE_GAP_PRIVACY_MODE_OFF. */ + uint8_t private_addr_type; /**< The private address type must be either @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE or + @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE. */ + uint16_t private_addr_cycle_s; /**< Private address cycle interval in seconds. Providing an address cycle value of 0 will use + the default value defined by @ref BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S. */ + ble_gap_irk_t + *p_device_irk; /**< When used as input, pointer to IRK structure that will be used as the default IRK. If NULL, the device + default IRK will be used. When used as output, pointer to IRK structure where the current default IRK + will be written to. If NULL, this argument is ignored. By default, the default IRK is used to generate + random private resolvable addresses for the local device unless instructed otherwise. */ +} ble_gap_privacy_params_t; + +/**@brief PHY preferences for TX and RX + * @note tx_phys and rx_phys are bit fields. Multiple bits can be set in them to indicate multiple preferred PHYs for each + * direction. + * @code + * p_gap_phys->tx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; + * p_gap_phys->rx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; + * @endcode + * + */ +typedef struct { + uint8_t tx_phys; /**< Preferred transmit PHYs, see @ref BLE_GAP_PHYS. */ + uint8_t rx_phys; /**< Preferred receive PHYs, see @ref BLE_GAP_PHYS. */ +} ble_gap_phys_t; + +/** @brief Keys that can be exchanged during a bonding procedure. */ +typedef struct { + uint8_t enc : 1; /**< Long Term Key and Master Identification. */ + uint8_t id : 1; /**< Identity Resolving Key and Identity Address Information. */ + uint8_t sign : 1; /**< Connection Signature Resolving Key. */ + uint8_t link : 1; /**< Derive the Link Key from the LTK. */ +} ble_gap_sec_kdist_t; + +/**@brief GAP security parameters. */ +typedef struct { + uint8_t bond : 1; /**< Perform bonding. */ + uint8_t mitm : 1; /**< Enable Man In The Middle protection. */ + uint8_t lesc : 1; /**< Enable LE Secure Connection pairing. */ + uint8_t keypress : 1; /**< Enable generation of keypress notifications. */ + uint8_t io_caps : 3; /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */ + uint8_t oob : 1; /**< The OOB data flag. + - In LE legacy pairing, this flag is set if a device has out of band authentication data. + The OOB method is used if both of the devices have out of band authentication data. + - In LE Secure Connections pairing, this flag is set if a device has the peer device's out of band + authentication data. The OOB method is used if at least one device has the peer device's OOB data + available. */ + uint8_t + min_key_size; /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */ + uint8_t max_key_size; /**< Maximum encryption key size in octets between min_key_size and 16. */ + ble_gap_sec_kdist_t kdist_own; /**< Key distribution bitmap: keys that the local device will distribute. */ + ble_gap_sec_kdist_t kdist_peer; /**< Key distribution bitmap: keys that the remote device will distribute. */ +} ble_gap_sec_params_t; + +/**@brief GAP Encryption Information. */ +typedef struct { + uint8_t ltk[BLE_GAP_SEC_KEY_LEN]; /**< Long Term Key. */ + uint8_t lesc : 1; /**< Key generated using LE Secure Connections. */ + uint8_t auth : 1; /**< Authenticated Key. */ + uint8_t ltk_len : 6; /**< LTK length in octets. */ +} ble_gap_enc_info_t; + +/**@brief GAP Master Identification. */ +typedef struct { + uint16_t ediv; /**< Encrypted Diversifier. */ + uint8_t rand[BLE_GAP_SEC_RAND_LEN]; /**< Random Number. */ +} ble_gap_master_id_t; + +/**@brief GAP Signing Information. */ +typedef struct { + uint8_t csrk[BLE_GAP_SEC_KEY_LEN]; /**< Connection Signature Resolving Key. */ +} ble_gap_sign_info_t; + +/**@brief GAP LE Secure Connections P-256 Public Key. */ +typedef struct { + uint8_t pk[BLE_GAP_LESC_P256_PK_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key. Stored in the + standard SMP protocol format: {X,Y} both in little-endian. */ +} ble_gap_lesc_p256_pk_t; + +/**@brief GAP LE Secure Connections DHKey. */ +typedef struct { + uint8_t key[BLE_GAP_LESC_DHKEY_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman Key. Stored in little-endian. */ +} ble_gap_lesc_dhkey_t; + +/**@brief GAP LE Secure Connections OOB data. */ +typedef struct { + ble_gap_addr_t addr; /**< Bluetooth address of the device. */ + uint8_t r[BLE_GAP_SEC_KEY_LEN]; /**< Random Number. */ + uint8_t c[BLE_GAP_SEC_KEY_LEN]; /**< Confirm Value. */ +} ble_gap_lesc_oob_data_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONNECTED. */ +typedef struct { + ble_gap_addr_t + peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref + ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ + uint8_t role; /**< BLE role for this connection, see @ref BLE_GAP_ROLES */ + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ + uint8_t adv_handle; /**< Advertising handle in which advertising has ended. + This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ + ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated + advertising set. The advertising buffers provided in + @ref sd_ble_gap_adv_set_configure are now released. + This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ +} ble_gap_evt_connected_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DISCONNECTED. */ +typedef struct { + uint8_t reason; /**< HCI error code, see @ref BLE_HCI_STATUS_CODES. */ +} ble_gap_evt_disconnected_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE. */ +typedef struct { + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ +} ble_gap_evt_conn_param_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST. */ +typedef struct { + ble_gap_phys_t peer_preferred_phys; /**< The PHYs the peer prefers to use. */ +} ble_gap_evt_phy_update_request_t; + +/**@brief Event Structure for @ref BLE_GAP_EVT_PHY_UPDATE. */ +typedef struct { + uint8_t status; /**< Status of the procedure, see @ref BLE_HCI_STATUS_CODES.*/ + uint8_t tx_phy; /**< TX PHY for this connection, see @ref BLE_GAP_PHYS. */ + uint8_t rx_phy; /**< RX PHY for this connection, see @ref BLE_GAP_PHYS. */ +} ble_gap_evt_phy_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. */ +typedef struct { + ble_gap_sec_params_t peer_params; /**< Initiator Security Parameters. */ +} ble_gap_evt_sec_params_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_INFO_REQUEST. */ +typedef struct { + ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. */ + ble_gap_master_id_t master_id; /**< Master Identification for LTK lookup. */ + uint8_t enc_info : 1; /**< If 1, Encryption Information required. */ + uint8_t id_info : 1; /**< If 1, Identity Information required. */ + uint8_t sign_info : 1; /**< If 1, Signing Information required. */ +} ble_gap_evt_sec_info_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_PASSKEY_DISPLAY. */ +typedef struct { + uint8_t passkey[BLE_GAP_PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */ + uint8_t match_request : 1; /**< If 1 requires the application to report the match using @ref sd_ble_gap_auth_key_reply + with either @ref BLE_GAP_AUTH_KEY_TYPE_NONE if there is no match or + @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY if there is a match. */ +} ble_gap_evt_passkey_display_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_KEY_PRESSED. */ +typedef struct { + uint8_t kp_not; /**< Keypress notification type, see @ref BLE_GAP_KP_NOT_TYPES. */ +} ble_gap_evt_key_pressed_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_KEY_REQUEST. */ +typedef struct { + uint8_t key_type; /**< See @ref BLE_GAP_AUTH_KEY_TYPES. */ +} ble_gap_evt_auth_key_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST. */ +typedef struct { + ble_gap_lesc_p256_pk_t + *p_pk_peer; /**< LE Secure Connections remote P-256 Public Key. This will point to the application-supplied memory + inside the keyset during the call to @ref sd_ble_gap_sec_params_reply. */ + uint8_t oobd_req : 1; /**< LESC OOB data required. A call to @ref sd_ble_gap_lesc_oob_data_set is required to complete the + procedure. */ +} ble_gap_evt_lesc_dhkey_request_t; + +/**@brief Security levels supported. + * @note See Bluetooth Specification Version 4.2 Volume 3, Part C, Chapter 10, Section 10.2.1. + */ +typedef struct { + uint8_t lv1 : 1; /**< If 1: Level 1 is supported. */ + uint8_t lv2 : 1; /**< If 1: Level 2 is supported. */ + uint8_t lv3 : 1; /**< If 1: Level 3 is supported. */ + uint8_t lv4 : 1; /**< If 1: Level 4 is supported. */ +} ble_gap_sec_levels_t; + +/**@brief Encryption Key. */ +typedef struct { + ble_gap_enc_info_t enc_info; /**< Encryption Information. */ + ble_gap_master_id_t master_id; /**< Master Identification. */ +} ble_gap_enc_key_t; + +/**@brief Identity Key. */ +typedef struct { + ble_gap_irk_t id_info; /**< Identity Resolving Key. */ + ble_gap_addr_t id_addr_info; /**< Identity Address. */ +} ble_gap_id_key_t; + +/**@brief Security Keys. */ +typedef struct { + ble_gap_enc_key_t *p_enc_key; /**< Encryption Key, or NULL. */ + ble_gap_id_key_t *p_id_key; /**< Identity Key, or NULL. */ + ble_gap_sign_info_t *p_sign_key; /**< Signing Key, or NULL. */ + ble_gap_lesc_p256_pk_t *p_pk; /**< LE Secure Connections P-256 Public Key. When in debug mode the application must use the + value defined in the Core Bluetooth Specification v4.2 Vol.3, Part H, Section 2.3.5.6.1 */ +} ble_gap_sec_keys_t; + +/**@brief Security key set for both local and peer keys. */ +typedef struct { + ble_gap_sec_keys_t keys_own; /**< Keys distributed by the local device. For LE Secure Connections the encryption key will be + generated locally and will always be stored if bonding. */ + ble_gap_sec_keys_t + keys_peer; /**< Keys distributed by the remote device. For LE Secure Connections, p_enc_key must always be NULL. */ +} ble_gap_sec_keyset_t; + +/**@brief Data Length Update Procedure parameters. */ +typedef struct { + uint16_t max_tx_octets; /**< Maximum number of payload octets that a Controller supports for transmission of a single Link + Layer Data Channel PDU. */ + uint16_t max_rx_octets; /**< Maximum number of payload octets that a Controller supports for reception of a single Link Layer + Data Channel PDU. */ + uint16_t max_tx_time_us; /**< Maximum time, in microseconds, that a Controller supports for transmission of a single Link + Layer Data Channel PDU. */ + uint16_t max_rx_time_us; /**< Maximum time, in microseconds, that a Controller supports for reception of a single Link Layer + Data Channel PDU. */ +} ble_gap_data_length_params_t; + +/**@brief Data Length Update Procedure local limitation. */ +typedef struct { + uint16_t tx_payload_limited_octets; /**< If > 0, the requested TX packet length is too long by this many octets. */ + uint16_t rx_payload_limited_octets; /**< If > 0, the requested RX packet length is too long by this many octets. */ + uint16_t tx_rx_time_limited_us; /**< If > 0, the requested combination of TX and RX packet lengths is too long by this many + microseconds. */ +} ble_gap_data_length_limitation_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_STATUS. */ +typedef struct { + uint8_t auth_status; /**< Authentication status, see @ref BLE_GAP_SEC_STATUS. */ + uint8_t error_src : 2; /**< On error, source that caused the failure, see @ref BLE_GAP_SEC_STATUS_SOURCES. */ + uint8_t bonded : 1; /**< Procedure resulted in a bond. */ + uint8_t lesc : 1; /**< Procedure resulted in a LE Secure Connection. */ + ble_gap_sec_levels_t sm1_levels; /**< Levels supported in Security Mode 1. */ + ble_gap_sec_levels_t sm2_levels; /**< Levels supported in Security Mode 2. */ + ble_gap_sec_kdist_t kdist_own; /**< Bitmap stating which keys were exchanged (distributed) by the local device. If bonding + with LE Secure Connections, the enc bit will be always set. */ + ble_gap_sec_kdist_t kdist_peer; /**< Bitmap stating which keys were exchanged (distributed) by the remote device. If bonding + with LE Secure Connections, the enc bit will never be set. */ +} ble_gap_evt_auth_status_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_SEC_UPDATE. */ +typedef struct { + ble_gap_conn_sec_t conn_sec; /**< Connection security level. */ +} ble_gap_evt_conn_sec_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Source of timeout event, see @ref BLE_GAP_TIMEOUT_SOURCES. */ + union { + ble_data_t adv_report_buffer; /**< If source is set to @ref BLE_GAP_TIMEOUT_SRC_SCAN, the released + scan buffer is contained in this field. */ + } params; /**< Event Parameters. */ +} ble_gap_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_RSSI_CHANGED. */ +typedef struct { + int8_t rssi; /**< Received Signal Strength Indication in dBm. + @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature + measurement. */ + uint8_t ch_index; /**< Data Channel Index on which the Signal Strength is measured (0-36). */ +} ble_gap_evt_rssi_changed_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_ADV_SET_TERMINATED */ +typedef struct { + uint8_t reason; /**< Reason for why the advertising set terminated. See + @ref BLE_GAP_EVT_ADV_SET_TERMINATED_REASON. */ + uint8_t adv_handle; /**< Advertising handle in which advertising has ended. */ + uint8_t num_completed_adv_events; /**< If @ref ble_gap_adv_params_t::max_adv_evts was not set to 0, + this field indicates the number of completed advertising events. */ + ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated + advertising set. The advertising buffers provided in + @ref sd_ble_gap_adv_set_configure are now released. */ +} ble_gap_evt_adv_set_terminated_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; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_REQUEST. */ +typedef struct { + uint8_t bond : 1; /**< Perform bonding. */ + uint8_t mitm : 1; /**< Man In The Middle protection requested. */ + uint8_t lesc : 1; /**< LE Secure Connections requested. */ + uint8_t keypress : 1; /**< Generation of keypress notifications requested. */ +} ble_gap_evt_sec_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST. */ +typedef struct { + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ +} ble_gap_evt_conn_param_update_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SCAN_REQ_REPORT. */ +typedef struct { + uint8_t adv_handle; /**< Advertising handle for the advertising set which received the Scan Request */ + int8_t rssi; /**< Received Signal Strength Indication in dBm. + @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature + measurement. */ + ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref + ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ +} ble_gap_evt_scan_req_report_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST. */ +typedef struct { + ble_gap_data_length_params_t peer_params; /**< Peer data length parameters. */ +} ble_gap_evt_data_length_update_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE. + * + * @note This event may also be raised after a PHY Update procedure. + */ +typedef struct { + ble_gap_data_length_params_t effective_params; /**< The effective data length parameters. */ +} ble_gap_evt_data_length_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT. */ +typedef struct { + int8_t + channel_energy[BLE_GAP_CHANNEL_COUNT]; /**< The measured energy on the Bluetooth Low Energy + channels, in dBm, indexed by Channel Index. + If no measurement is available for the given channel, channel_energy is set to + @ref BLE_GAP_POWER_LEVEL_INVALID. */ +} ble_gap_evt_qos_channel_survey_report_t; + +/**@brief GAP event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which event occurred. */ + union /**< union alternative identified by evt_id in enclosing struct. */ + { + ble_gap_evt_connected_t connected; /**< Connected Event Parameters. */ + ble_gap_evt_disconnected_t disconnected; /**< Disconnected Event Parameters. */ + ble_gap_evt_conn_param_update_t conn_param_update; /**< Connection Parameter Update Parameters. */ + ble_gap_evt_sec_params_request_t sec_params_request; /**< Security Parameters Request Event Parameters. */ + ble_gap_evt_sec_info_request_t sec_info_request; /**< Security Information Request Event Parameters. */ + ble_gap_evt_passkey_display_t passkey_display; /**< Passkey Display Event Parameters. */ + ble_gap_evt_key_pressed_t key_pressed; /**< Key Pressed Event Parameters. */ + ble_gap_evt_auth_key_request_t auth_key_request; /**< Authentication Key Request Event Parameters. */ + ble_gap_evt_lesc_dhkey_request_t lesc_dhkey_request; /**< LE Secure Connections DHKey calculation request. */ + ble_gap_evt_auth_status_t auth_status; /**< Authentication Status Event Parameters. */ + ble_gap_evt_conn_sec_update_t conn_sec_update; /**< Connection Security Update Event Parameters. */ + ble_gap_evt_timeout_t timeout; /**< Timeout Event Parameters. */ + ble_gap_evt_rssi_changed_t rssi_changed; /**< RSSI Event Parameters. */ + ble_gap_evt_adv_report_t adv_report; /**< Advertising Report Event Parameters. */ + ble_gap_evt_adv_set_terminated_t adv_set_terminated; /**< Advertising Set Terminated Event Parameters. */ + ble_gap_evt_sec_request_t sec_request; /**< Security Request Event Parameters. */ + ble_gap_evt_conn_param_update_request_t conn_param_update_request; /**< Connection Parameter Update Parameters. */ + ble_gap_evt_scan_req_report_t scan_req_report; /**< Scan Request Report Parameters. */ + ble_gap_evt_phy_update_request_t phy_update_request; /**< PHY Update Request Event Parameters. */ + ble_gap_evt_phy_update_t phy_update; /**< PHY Update Parameters. */ + ble_gap_evt_data_length_update_request_t data_length_update_request; /**< Data Length Update Request Event Parameters. */ + ble_gap_evt_data_length_update_t data_length_update; /**< Data Length Update Event Parameters. */ + ble_gap_evt_qos_channel_survey_report_t + qos_channel_survey_report; /**< Quality of Service (QoS) Channel Survey Report Parameters. */ + } params; /**< Event Parameters. */ +} ble_gap_evt_t; + +/** + * @brief BLE GAP connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_CONN_COUNT The connection count for the connection configurations is zero. + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - The sum of conn_count for all connection configurations combined exceeds UINT8_MAX. + * - The event length is smaller than @ref BLE_GAP_EVENT_LENGTH_MIN. + */ +typedef struct { + uint8_t conn_count; /**< The number of concurrent connections the application can create with this configuration. + The default and minimum value is @ref BLE_GAP_CONN_COUNT_DEFAULT. */ + uint16_t event_length; /**< The time set aside for this connection on every connection interval in 1.25 ms units. + The default value is @ref BLE_GAP_EVENT_LENGTH_DEFAULT, the minimum value is @ref + BLE_GAP_EVENT_LENGTH_MIN. The event length and the connection interval are the primary parameters + for setting the throughput of a connection. + See the SoftDevice Specification for details on throughput. */ +} ble_gap_conn_cfg_t; + +/** + * @brief Configuration of maximum concurrent connections in the different connected roles, set with + * @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_CONN_COUNT The sum of periph_role_count and central_role_count is too + * large. The maximum supported sum of concurrent connections is + * @ref BLE_GAP_ROLE_COUNT_COMBINED_MAX. + * @retval ::NRF_ERROR_INVALID_PARAM central_sec_count is larger than central_role_count. + * @retval ::NRF_ERROR_RESOURCES The adv_set_count is too large. The maximum + * supported advertising handles is + * @ref BLE_GAP_ADV_SET_COUNT_MAX. + */ +typedef struct { + uint8_t adv_set_count; /**< Maximum number of advertising sets. Default value is @ref BLE_GAP_ADV_SET_COUNT_DEFAULT. */ + uint8_t periph_role_count; /**< Maximum number of connections concurrently acting as a peripheral. Default value is @ref + BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT. */ + uint8_t central_role_count; /**< Maximum number of connections concurrently acting as a central. Default value is @ref + BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT. */ + uint8_t central_sec_count; /**< Number of SMP instances shared between all connections acting as a central. Default value is + @ref BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT. */ + uint8_t qos_channel_survey_role_available : 1; /**< If set, the Quality of Service (QoS) channel survey module is available to + the application using @ref sd_ble_gap_qos_channel_survey_start. */ +} ble_gap_cfg_role_count_t; + +/** + * @brief Device name and its properties, set with @ref sd_ble_cfg_set. + * + * @note If the device name is not configured, the default device name will be + * @ref BLE_GAP_DEVNAME_DEFAULT, the maximum device name length will be + * @ref BLE_GAP_DEVNAME_DEFAULT_LEN, vloc will be set to @ref BLE_GATTS_VLOC_STACK and the device name + * will have no write access. + * + * @note If @ref max_len is more than @ref BLE_GAP_DEVNAME_DEFAULT_LEN and vloc is set to @ref BLE_GATTS_VLOC_STACK, + * the attribute table size must be increased to have room for the longer device name (see + * @ref sd_ble_cfg_set and @ref ble_gatts_cfg_attr_tab_size_t). + * + * @note If vloc is @ref BLE_GATTS_VLOC_STACK : + * - p_value must point to non-volatile memory (flash) or be NULL. + * - If p_value is NULL, the device name will initially be empty. + * + * @note If vloc is @ref BLE_GATTS_VLOC_USER : + * - p_value cannot be NULL. + * - If the device name is writable, p_value must point to volatile memory (RAM). + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - Invalid device name location (vloc). + * - Invalid device name security mode. + * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: + * - The device name length is invalid (must be between 0 and @ref BLE_GAP_DEVNAME_MAX_LEN). + * - The device name length is too long for the given Attribute Table. + * @retval ::NRF_ERROR_NOT_SUPPORTED Device name security mode is not supported. + */ +typedef struct { + ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ + uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ + uint8_t *p_value; /**< Pointer to where the value (device name) is stored or will be stored. */ + uint16_t current_len; /**< Current length in bytes of the memory pointed to by p_value.*/ + uint16_t max_len; /**< Maximum length in bytes of the memory pointed to by p_value.*/ +} ble_gap_cfg_device_name_t; + +/**@brief Peripheral Preferred Connection Parameters include configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t include_cfg; /**< Inclusion configuration of the Peripheral Preferred Connection Parameters characteristic. + See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_PPCP_INCL_CONFIG_DEFAULT. */ +} ble_gap_cfg_ppcp_incl_cfg_t; + +/**@brief Central Address Resolution include configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t include_cfg; /**< Inclusion configuration of the Central Address Resolution characteristic. + See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_CAR_INCL_CONFIG_DEFAULT. */ +} ble_gap_cfg_car_incl_cfg_t; + +/**@brief Configuration structure for GAP configurations. */ +typedef union { + ble_gap_cfg_role_count_t role_count_cfg; /**< Role count configuration, cfg_id is @ref BLE_GAP_CFG_ROLE_COUNT. */ + ble_gap_cfg_device_name_t device_name_cfg; /**< Device name configuration, cfg_id is @ref BLE_GAP_CFG_DEVICE_NAME. */ + ble_gap_cfg_ppcp_incl_cfg_t ppcp_include_cfg; /**< Peripheral Preferred Connection Parameters characteristic include + configuration, cfg_id is @ref BLE_GAP_CFG_PPCP_INCL_CONFIG. */ + ble_gap_cfg_car_incl_cfg_t car_include_cfg; /**< Central Address Resolution characteristic include configuration, + cfg_id is @ref BLE_GAP_CFG_CAR_INCL_CONFIG. */ +} ble_gap_cfg_t; + +/**@brief Channel Map option. + * + * @details Used with @ref sd_ble_opt_get to get the current channel map + * or @ref sd_ble_opt_set to set a new channel map. When setting the + * channel map, it applies to all current and future connections. When getting the + * current channel map, it applies to a single connection and the connection handle + * must be supplied. + * + * @note Setting the channel map may take some time, depending on connection parameters. + * The time taken may be different for each connection and the get operation will + * return the previous channel map until the new one has taken effect. + * + * @note After setting the channel map, by spec it can not be set again until at least 1 s has passed. + * See Bluetooth Specification Version 4.1 Volume 2, Part E, Section 7.3.46. + * + * @retval ::NRF_SUCCESS Get or set successful. + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - Less then two bits in @ref ch_map are set. + * - Bits for primary advertising channels (37-39) are set. + * @retval ::NRF_ERROR_BUSY Channel map was set again before enough time had passed. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied for get. + * + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle (only applicable for get) */ + uint8_t ch_map[5]; /**< Channel Map (37-bit). */ +} ble_gap_opt_ch_map_t; + +/**@brief Local connection latency option. + * + * @details Local connection latency is a feature which enables the slave to improve + * current consumption by ignoring the slave latency set by the peer. The + * local connection latency can only be set to a multiple of the slave latency, + * and cannot be longer than half of the supervision timeout. + * + * @details Used with @ref sd_ble_opt_set to set the local connection latency. The + * @ref sd_ble_opt_get is not supported for this option, but the actual + * local connection latency (unless set to NULL) is set as a return parameter + * when setting the option. + * + * @note The latency set will be truncated down to the closest slave latency event + * multiple, or the nearest multiple before half of the supervision timeout. + * + * @note The local connection latency is disabled by default, and needs to be enabled for new + * connections and whenever the connection is updated. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint16_t requested_latency; /**< Requested local connection latency. */ + uint16_t *p_actual_latency; /**< Pointer to storage for the actual local connection latency (can be set to NULL to skip return + value). */ +} ble_gap_opt_local_conn_latency_t; + +/**@brief Disable slave latency + * + * @details Used with @ref sd_ble_opt_set to temporarily disable slave latency of a peripheral connection + * (see @ref ble_gap_conn_params_t::slave_latency). And to re-enable it again. When disabled, the + * peripheral will ignore the slave_latency set by the central. + * + * @note Shall only be called on peripheral links. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint8_t disable; /**< For allowed values see @ref BLE_GAP_SLAVE_LATENCY */ +} ble_gap_opt_slave_latency_disable_t; + +/**@brief Passkey Option. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} + * @endmscs + * + * @details Structure containing the passkey to be used during pairing. This can be used with @ref + * sd_ble_opt_set to make the SoftDevice use a preprogrammed passkey for authentication + * instead of generating a random one. + * + * @note Repeated pairing attempts using the same preprogrammed passkey makes pairing vulnerable to MITM attacks. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * + */ +typedef struct { + uint8_t const *p_passkey; /**< Pointer to 6-digit ASCII string (digit 0..9 only, no NULL termination) passkey to be used + during pairing. If this is NULL, the SoftDevice will generate a random passkey if required.*/ +} ble_gap_opt_passkey_t; + +/**@brief Compatibility mode 1 option. + * + * @details This can be used with @ref sd_ble_opt_set to enable and disable + * compatibility mode 1. Compatibility mode 1 is disabled by default. + * + * @note Compatibility mode 1 enables interoperability with devices that do not support a value of + * 0 for the WinOffset parameter in the Link Layer CONNECT_IND packet. This applies to a + * limited set of legacy peripheral devices from another vendor. Enabling this compatibility + * mode will only have an effect if the local device will act as a central device and + * initiate a connection to a peripheral device. In that case it may lead to the connection + * creation taking up to one connection interval longer to complete for all connections. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_INVALID_STATE When connection creation is ongoing while mode 1 is set. + */ +typedef struct { + uint8_t enable : 1; /**< Enable compatibility mode 1.*/ +} ble_gap_opt_compat_mode_1_t; + +/**@brief Authenticated payload timeout option. + * + * @details This can be used with @ref sd_ble_opt_set to change the Authenticated payload timeout to a value other + * than the default of @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX. + * + * @note The authenticated payload timeout event ::BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD will be generated + * if auth_payload_timeout time has elapsed without receiving a packet with a valid MIC on an encrypted + * link. + * + * @note The LE ping procedure will be initiated before the timer expires to give the peer a chance + * to reset the timer. In addition the stack will try to prioritize running of LE ping over other + * activities to increase chances of finishing LE ping before timer expires. To avoid side-effects + * on other activities, it is recommended to use high timeout values. + * Recommended timeout > 2*(connInterval * (6 + connSlaveLatency)). + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. auth_payload_timeout was outside of allowed range. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint16_t auth_payload_timeout; /**< Requested timeout in 10 ms unit, see @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT. */ +} ble_gap_opt_auth_payload_timeout_t; + +/**@brief Option structure for GAP options. */ +typedef union { + ble_gap_opt_ch_map_t ch_map; /**< Parameters for the Channel Map option. */ + ble_gap_opt_local_conn_latency_t local_conn_latency; /**< Parameters for the Local connection latency option */ + ble_gap_opt_passkey_t passkey; /**< Parameters for the Passkey option.*/ + ble_gap_opt_compat_mode_1_t compat_mode_1; /**< Parameters for the compatibility mode 1 option.*/ + ble_gap_opt_auth_payload_timeout_t auth_payload_timeout; /**< Parameters for the authenticated payload timeout option.*/ + ble_gap_opt_slave_latency_disable_t slave_latency_disable; /**< Parameters for the Disable slave latency option */ +} ble_gap_opt_t; + +/**@brief Connection event triggering parameters. */ +typedef struct { + uint8_t ppi_ch_id; /**< PPI channel to use. This channel should be regarded as reserved until + connection event PPI task triggering is stopped. + The PPI channel ID can not be one of the PPI channels reserved by + the SoftDevice. See @ref NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK. */ + uint32_t task_endpoint; /**< Task Endpoint to trigger. */ + uint16_t conn_evt_counter_start; /**< The connection event on which the task triggering should start. */ + uint16_t period_in_events; /**< Trigger period. Valid range is [1, 32767]. + If the device is in slave role and slave latency is enabled, + this parameter should be set to a multiple of (slave latency + 1) + to ensure low power operation. */ +} ble_gap_conn_event_trigger_t; +/**@} */ + +/**@addtogroup BLE_GAP_FUNCTIONS Functions + * @{ */ + +/**@brief Set the local Bluetooth identity address. + * + * The local Bluetooth identity address is the address that identifies this device to other peers. + * The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. + * + * @note The identity address cannot be changed while advertising, scanning or creating a connection. + * + * @note This address will be distributed to the peer during bonding. + * If the address changes, the address stored in the peer device will not be valid and the ability to + * reconnect using the old address will be lost. + * + * @note By default the SoftDevice will set an address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC upon being + * enabled. The address is a random number populated during the IC manufacturing process and remains unchanged + * for the lifetime of each IC. + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @endmscs + * + * @param[in] p_addr Pointer to address structure. + * + * @retval ::NRF_SUCCESS Address successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_STATE The identity address cannot be changed while advertising, + * scanning or creating a connection. + */ +SVCALL(SD_BLE_GAP_ADDR_SET, uint32_t, sd_ble_gap_addr_set(ble_gap_addr_t const *p_addr)); + +/**@brief Get local Bluetooth identity address. + * + * @note This will always return the identity address irrespective of the privacy settings, + * i.e. the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. + * + * @param[out] p_addr Pointer to address structure to be filled in. + * + * @retval ::NRF_SUCCESS Address successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + */ +SVCALL(SD_BLE_GAP_ADDR_GET, uint32_t, sd_ble_gap_addr_get(ble_gap_addr_t *p_addr)); + +/**@brief Get the Bluetooth device address used by the advertiser. + * + * @note This function will return the local Bluetooth address used in advertising PDUs. When + * using privacy, the SoftDevice will generate a new private address every + * @ref ble_gap_privacy_params_t::private_addr_cycle_s configured using + * @ref sd_ble_gap_privacy_set. Hence depending on when the application calls this API, the + * address returned may not be the latest address that is used in the advertising PDUs. + * + * @param[in] adv_handle The advertising handle to get the address from. + * @param[out] p_addr Pointer to address structure to be filled in. + * + * @retval ::NRF_SUCCESS Address successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. + * @retval ::NRF_ERROR_INVALID_STATE The advertising set is currently not advertising. + */ +SVCALL(SD_BLE_GAP_ADV_ADDR_GET, uint32_t, sd_ble_gap_adv_addr_get(uint8_t adv_handle, ble_gap_addr_t *p_addr)); + +/**@brief Set the active whitelist in the SoftDevice. + * + * @note Only one whitelist can be used at a time and the whitelist is shared between the BLE roles. + * The whitelist cannot be set if a BLE role is using the whitelist. + * + * @note If an address is resolved using the information in the device identity list, then the whitelist + * filter policy applies to the peer identity address and not the resolvable address sent on air. + * + * @mscs + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} + * @endmscs + * + * @param[in] pp_wl_addrs Pointer to a whitelist of peer addresses, if NULL the whitelist will be cleared. + * @param[in] len Length of the whitelist, maximum @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT. + * + * @retval ::NRF_SUCCESS The whitelist is successfully set/cleared. + * @retval ::NRF_ERROR_INVALID_ADDR The whitelist (or one of its entries) provided is invalid. + * @retval ::BLE_ERROR_GAP_WHITELIST_IN_USE The whitelist is in use by a BLE role and cannot be set or cleared. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_DATA_SIZE The given whitelist size is invalid (zero or too large); this can only return when + * pp_wl_addrs is not NULL. + */ +SVCALL(SD_BLE_GAP_WHITELIST_SET, uint32_t, sd_ble_gap_whitelist_set(ble_gap_addr_t const *const *pp_wl_addrs, uint8_t len)); + +/**@brief Set device identity list. + * + * @note Only one device identity list can be used at a time and the list is shared between the BLE roles. + * The device identity list cannot be set if a BLE role is using the list. + * + * @param[in] pp_id_keys Pointer to an array of peer identity addresses and peer IRKs, if NULL the device identity list will + * be cleared. + * @param[in] pp_local_irks Pointer to an array of local IRKs. Each entry in the array maps to the entry in pp_id_keys at the + * same index. To fill in the list with the currently set device IRK for all peers, set to NULL. + * @param[in] len Length of the device identity list, maximum @ref BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT. + * + * @mscs + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS The device identity list successfully set/cleared. + * @retval ::NRF_ERROR_INVALID_ADDR The device identity list (or one of its entries) provided is invalid. + * This code may be returned if the local IRK list also has an invalid entry. + * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE The device identity list is in use and cannot be set or cleared. + * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE The device identity list contains multiple entries with the same identity + * address. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_DATA_SIZE The given device identity list size invalid (zero or too large); this can + * only return when pp_id_keys is not NULL. + */ +SVCALL(SD_BLE_GAP_DEVICE_IDENTITIES_SET, uint32_t, + sd_ble_gap_device_identities_set(ble_gap_id_key_t const *const *pp_id_keys, ble_gap_irk_t const *const *pp_local_irks, + uint8_t len)); + +/**@brief Set privacy settings. + * + * @note Privacy settings cannot be changed while advertising, scanning or creating a connection. + * + * @param[in] p_privacy_params Privacy settings. + * + * @mscs + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_INVALID_ADDR The pointer to privacy settings is NULL or invalid. + * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. + * @retval ::NRF_ERROR_INVALID_PARAM Out of range parameters are provided. + * @retval ::NRF_ERROR_NOT_SUPPORTED The SoftDevice does not support privacy if the Central Address Resolution + characteristic is not configured to be included and the SoftDevice is configured + to support central roles. + See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + * @retval ::NRF_ERROR_INVALID_STATE Privacy settings cannot be changed while advertising, scanning + * or creating a connection. + */ +SVCALL(SD_BLE_GAP_PRIVACY_SET, uint32_t, sd_ble_gap_privacy_set(ble_gap_privacy_params_t const *p_privacy_params)); + +/**@brief Get privacy settings. + * + * @note ::ble_gap_privacy_params_t::p_device_irk must be initialized to NULL or a valid address before this function is called. + * If it is initialized to a valid address, the address pointed to will contain the current device IRK on return. + * + * @param[in,out] p_privacy_params Privacy settings. + * + * @retval ::NRF_SUCCESS Privacy settings read. + * @retval ::NRF_ERROR_INVALID_ADDR The pointer given for returning the privacy settings may be NULL or invalid. + * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. + */ +SVCALL(SD_BLE_GAP_PRIVACY_GET, uint32_t, sd_ble_gap_privacy_get(ble_gap_privacy_params_t *p_privacy_params)); + +/**@brief Configure an advertising set. Set, clear or update advertising and scan response data. + * + * @note The format of the advertising data will be checked by this call to ensure interoperability. + * Limitations imposed by this API call to the data provided include having a flags data type in the scan response data and + * duplicating the local name in the advertising data and scan response data. + * + * @note In order to update advertising data while advertising, new advertising buffers must be provided. + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in,out] p_adv_handle Provide a pointer to a handle containing @ref + * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising set. On success, a new handle is then returned through the + * pointer. Provide a pointer to an existing advertising handle to configure an existing advertising set. + * @param[in] p_adv_data Advertising data. If set to NULL, no advertising data will be used. See + * @ref ble_gap_adv_data_t. + * @param[in] p_adv_params Advertising parameters. When this function is used to update advertising + * data while advertising, this parameter must be NULL. See @ref ble_gap_adv_params_t. + * + * @retval ::NRF_SUCCESS Advertising set successfully configured. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: + * - Invalid advertising data configuration specified. See @ref + * ble_gap_adv_data_t. + * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. + * - Use of whitelist requested but whitelist has not been set, + * see @ref sd_ble_gap_whitelist_set. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR ble_gap_adv_params_t::p_peer_addr is invalid. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - It is invalid to provide non-NULL advertising set parameters while + * advertising. + * - It is invalid to provide the same data buffers while advertising. To + * update advertising data, provide new advertising buffers. + * @retval ::BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST Discoverable mode and whitelist incompatible. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. Use @ref + * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_FLAGS Invalid combination of advertising flags supplied. + * @retval ::NRF_ERROR_INVALID_DATA Invalid data type(s) supplied. Check the advertising data format + * specification given in Bluetooth Specification Version 5.0, Volume 3, Part C, Chapter 11. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid data length(s) supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported data length or advertising parameter configuration. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to configure a new advertising handle. Update an + * existing advertising handle instead. + * @retval ::BLE_ERROR_GAP_UUID_LIST_MISMATCH Invalid UUID list supplied. + */ +SVCALL(SD_BLE_GAP_ADV_SET_CONFIGURE, uint32_t, + sd_ble_gap_adv_set_configure(uint8_t *p_adv_handle, ble_gap_adv_data_t const *p_adv_data, + ble_gap_adv_params_t const *p_adv_params)); + +/**@brief Start advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). + * + * @note Only one advertiser may be active at any time. + * + * @note If privacy is enabled, the advertiser's private address will be refreshed when this function is called. + * See @ref sd_ble_gap_privacy_set(). + * + * @events + * @event{@ref BLE_GAP_EVT_CONNECTED, Generated after connection has been established through connectable advertising.} + * @event{@ref BLE_GAP_EVT_ADV_SET_TERMINATED, Advertising set has terminated.} + * @event{@ref BLE_GAP_EVT_SCAN_REQ_REPORT, A scan request was received.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] adv_handle Advertising handle to advertise on, received from @ref sd_ble_gap_adv_set_configure. + * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or + * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. For non-connectable + * advertising, this is ignored. + * + * @retval ::NRF_SUCCESS The BLE stack has started advertising. + * @retval ::NRF_ERROR_INVALID_STATE adv_handle is not configured or already advertising. + * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration + * tag has been reached; connectable advertiser cannot be started. + * To increase the number of available connections, + * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. Configure a new adveriting handle with @ref + sd_ble_gap_adv_set_configure. + * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: + * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. + * - Use of whitelist requested but whitelist has not been set, see @ref + sd_ble_gap_whitelist_set. + * @retval ::NRF_ERROR_RESOURCES Either: + * - adv_handle is configured with connectable advertising, but the event_length parameter + * associated with conn_cfg_tag is too small to be able to establish a connection on + * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. + * - Not enough BLE role slots available. + Stop one or more currently active roles (Central, Peripheral, Broadcaster or Observer) + and try again. + * - p_adv_params is configured with connectable advertising, but the event_length + parameter + * associated with conn_cfg_tag is too small to be able to establish a connection on + * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. + */ +SVCALL(SD_BLE_GAP_ADV_START, uint32_t, sd_ble_gap_adv_start(uint8_t adv_handle, uint8_t conn_cfg_tag)); + +/**@brief Stop advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] adv_handle The advertising handle that should stop advertising. + * + * @retval ::NRF_SUCCESS The BLE stack has stopped advertising. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Invalid advertising handle. + * @retval ::NRF_ERROR_INVALID_STATE The advertising handle is not advertising. + */ +SVCALL(SD_BLE_GAP_ADV_STOP, uint32_t, sd_ble_gap_adv_stop(uint8_t adv_handle)); + +/**@brief Update connection parameters. + * + * @details In the central role this will initiate a Link Layer connection parameter update procedure, + * otherwise in the peripheral role, this will send the corresponding L2CAP request and wait for + * the central to perform the procedure. In both cases, and regardless of success or failure, the application + * will be informed of the result with a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE event. + * + * @details This function can be used as a central both to reply to a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST or to start the + * procedure unrequested. + * + * @events + * @event{@ref BLE_GAP_EVT_CONN_PARAM_UPDATE, Result of the connection parameter update procedure.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CPU_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CPU_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CPU_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_conn_params Pointer to desired connection parameters. If NULL is provided on a peripheral role, + * the parameters in the PPCP characteristic of the GAP service will be used instead. + * If NULL is provided on a central role and in response to a @ref + * BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST, the peripheral request will be rejected + * + * @retval ::NRF_SUCCESS The Connection Update procedure has been started successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. + * @retval ::NRF_ERROR_BUSY Procedure already in progress, wait for pending procedures to complete and retry. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GAP_CONN_PARAM_UPDATE, uint32_t, + sd_ble_gap_conn_param_update(uint16_t conn_handle, ble_gap_conn_params_t const *p_conn_params)); + +/**@brief Disconnect (GAP Link Termination). + * + * @details This call initiates the disconnection procedure, and its completion will be communicated to the application + * with a @ref BLE_GAP_EVT_DISCONNECTED event. + * + * @events + * @event{@ref BLE_GAP_EVT_DISCONNECTED, Generated when disconnection procedure is complete.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CONN_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] hci_status_code HCI status code, see @ref BLE_HCI_STATUS_CODES (accepted values are @ref + * BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION and @ref BLE_HCI_CONN_INTERVAL_UNACCEPTABLE). + * + * @retval ::NRF_SUCCESS The disconnection procedure has been started successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. + */ +SVCALL(SD_BLE_GAP_DISCONNECT, uint32_t, sd_ble_gap_disconnect(uint16_t conn_handle, uint8_t hci_status_code)); + +/**@brief Set the radio's transmit power. + * + * @param[in] role The role to set the transmit power for, see @ref BLE_GAP_TX_POWER_ROLES for + * possible roles. + * @param[in] handle The handle parameter is interpreted depending on role: + * - If role is @ref BLE_GAP_TX_POWER_ROLE_CONN, this value is the specific connection handle. + * - If role is @ref BLE_GAP_TX_POWER_ROLE_ADV, the advertising set identified with the advertising handle, + * will use the specified transmit power, and include it in the advertising packet headers if + * @ref ble_gap_adv_properties_t::include_tx_power set. + * - For all other roles handle is ignored. + * @param[in] tx_power Radio transmit power in dBm (see note for accepted values). + * + * @note Supported tx_power values: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm and +4dBm. + * In addition, on some chips following values are supported: +2dBm, +5dBm, +6dBm, +7dBm and +8dBm. + * Setting these values on a chip that does not support them will result in undefined behaviour. + * @note The initiator will have the same transmit power as the scanner. + * @note When a connection is created it will inherit the transmit power from the initiator or + * advertiser leading to the connection. + * + * @retval ::NRF_SUCCESS Successfully changed the transmit power. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_TX_POWER_SET, uint32_t, sd_ble_gap_tx_power_set(uint8_t role, uint16_t handle, int8_t tx_power)); + +/**@brief Set GAP Appearance value. + * + * @param[in] appearance Appearance (16-bit), see @ref BLE_APPEARANCES. + * + * @retval ::NRF_SUCCESS Appearance value set successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + */ +SVCALL(SD_BLE_GAP_APPEARANCE_SET, uint32_t, sd_ble_gap_appearance_set(uint16_t appearance)); + +/**@brief Get GAP Appearance value. + * + * @param[out] p_appearance Pointer to appearance (16-bit) to be filled in, see @ref BLE_APPEARANCES. + * + * @retval ::NRF_SUCCESS Appearance value retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GAP_APPEARANCE_GET, uint32_t, sd_ble_gap_appearance_get(uint16_t *p_appearance)); + +/**@brief Set GAP Peripheral Preferred Connection Parameters. + * + * @param[in] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure with the desired parameters. + * + * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, + see @ref ble_gap_cfg_ppcp_incl_cfg_t. + */ +SVCALL(SD_BLE_GAP_PPCP_SET, uint32_t, sd_ble_gap_ppcp_set(ble_gap_conn_params_t const *p_conn_params)); + +/**@brief Get GAP Peripheral Preferred Connection Parameters. + * + * @param[out] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure where the parameters will be stored. + * + * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, + see @ref ble_gap_cfg_ppcp_incl_cfg_t. + */ +SVCALL(SD_BLE_GAP_PPCP_GET, uint32_t, sd_ble_gap_ppcp_get(ble_gap_conn_params_t *p_conn_params)); + +/**@brief Set GAP device name. + * + * @note If the device name is located in application flash memory (see @ref ble_gap_cfg_device_name_t), + * it cannot be changed. Then @ref NRF_ERROR_FORBIDDEN will be returned. + * + * @param[in] p_write_perm Write permissions for the Device Name characteristic, see @ref ble_gap_conn_sec_mode_t. + * @param[in] p_dev_name Pointer to a UTF-8 encoded, non NULL-terminated string. + * @param[in] len Length of the UTF-8, non NULL-terminated string pointed to by p_dev_name in octets (must be smaller or + * equal than @ref BLE_GAP_DEVNAME_MAX_LEN). + * + * @retval ::NRF_SUCCESS GAP device name and permissions set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_FORBIDDEN Device name is not writable. + */ +SVCALL(SD_BLE_GAP_DEVICE_NAME_SET, uint32_t, + sd_ble_gap_device_name_set(ble_gap_conn_sec_mode_t const *p_write_perm, uint8_t const *p_dev_name, uint16_t len)); + +/**@brief Get GAP device name. + * + * @note If the device name is longer than the size of the supplied buffer, + * p_len will return the complete device name length, + * and not the number of bytes actually returned in p_dev_name. + * The application may use this information to allocate a suitable buffer size. + * + * @param[out] p_dev_name Pointer to an empty buffer where the UTF-8 non NULL-terminated string will be placed. Set to + * NULL to obtain the complete device name length. + * @param[in,out] p_len Length of the buffer pointed by p_dev_name, complete device name length on output. + * + * @retval ::NRF_SUCCESS GAP device name retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + */ +SVCALL(SD_BLE_GAP_DEVICE_NAME_GET, uint32_t, sd_ble_gap_device_name_get(uint8_t *p_dev_name, uint16_t *p_len)); + +/**@brief Initiate the GAP Authentication procedure. + * + * @details In the central role, this function will send an SMP Pairing Request (or an SMP Pairing Failed if rejected), + * otherwise in the peripheral role, an SMP Security Request will be sent. + * + * @events + * @event{Depending on the security parameters set and the packet exchanges with the peer\, the following events may be + * generated:} + * @event{@ref BLE_GAP_EVT_SEC_PARAMS_REQUEST} + * @event{@ref BLE_GAP_EVT_SEC_INFO_REQUEST} + * @event{@ref BLE_GAP_EVT_PASSKEY_DISPLAY} + * @event{@ref BLE_GAP_EVT_KEY_PRESSED} + * @event{@ref BLE_GAP_EVT_AUTH_KEY_REQUEST} + * @event{@ref BLE_GAP_EVT_LESC_DHKEY_REQUEST} + * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE} + * @event{@ref BLE_GAP_EVT_AUTH_STATUS} + * @event{@ref BLE_GAP_EVT_TIMEOUT} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_SEC_REQ_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_sec_params Pointer to the @ref ble_gap_sec_params_t structure with the security parameters to be used during the + * pairing or bonding procedure. In the peripheral role, only the bond, mitm, lesc and keypress fields of this structure are used. + * In the central role, this pointer may be NULL to reject a Security Request. + * + * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - No link has been established. + * - An encryption is already executing or queued. + * @retval ::NRF_ERROR_NO_MEM The maximum number of authentication procedures that can run in parallel for the given role is + * reached. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. + * Distribution of own Identity Information is only supported if the Central + * Address Resolution characteristic is configured to be included or + * the Softdevice is configured to support peripheral roles only. + * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + * @retval ::NRF_ERROR_TIMEOUT A SMP timeout has occurred, and further SMP operations on this link is prohibited. + */ +SVCALL(SD_BLE_GAP_AUTHENTICATE, uint32_t, + sd_ble_gap_authenticate(uint16_t conn_handle, ble_gap_sec_params_t const *p_sec_params)); + +/**@brief Reply with GAP security parameters. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST, calling it at other times will result in + * an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_CONFIRM_FAIL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_KS_TOO_SMALL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_APP_ERROR_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_REMOTE_PAIRING_FAIL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_TIMEOUT_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] sec_status Security status, see @ref BLE_GAP_SEC_STATUS. + * @param[in] p_sec_params Pointer to a @ref ble_gap_sec_params_t security parameters structure. In the central role this must be + * set to NULL, as the parameters have already been provided during a previous call to @ref sd_ble_gap_authenticate. + * @param[in,out] p_sec_keyset Pointer to a @ref ble_gap_sec_keyset_t security keyset structure. Any keys generated and/or + * distributed as a result of the ongoing security procedure will be stored into the memory referenced by the pointers inside this + * structure. The keys will be stored and available to the application upon reception of a @ref BLE_GAP_EVT_AUTH_STATUS event. + * Note that the SoftDevice expects the application to provide memory for storing the + * peer's keys. So it must be ensured that the relevant pointers inside this structure are not NULL. The + * pointers to the local key can, however, be NULL, in which case, the local key data will not be available to the application + * upon reception of the + * @ref BLE_GAP_EVT_AUTH_STATUS event. + * + * @retval ::NRF_SUCCESS Successfully accepted security parameter from the application. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Security parameters has not been requested. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. + * Distribution of own Identity Information is only supported if the Central + * Address Resolution characteristic is configured to be included or + * the Softdevice is configured to support peripheral roles only. + * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + */ +SVCALL(SD_BLE_GAP_SEC_PARAMS_REPLY, uint32_t, + sd_ble_gap_sec_params_reply(uint16_t conn_handle, uint8_t sec_status, ble_gap_sec_params_t const *p_sec_params, + ble_gap_sec_keyset_t const *p_sec_keyset)); + +/**@brief Reply with an authentication key. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_AUTH_KEY_REQUEST or a @ref BLE_GAP_EVT_PASSKEY_DISPLAY, + * calling it at other times will result in an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] key_type See @ref BLE_GAP_AUTH_KEY_TYPES. + * @param[in] p_key If key type is @ref BLE_GAP_AUTH_KEY_TYPE_NONE, then NULL. + * If key type is @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY, then a 6-byte ASCII string (digit 0..9 only, no NULL + * termination) or NULL when confirming LE Secure Connections Numeric Comparison. If key type is @ref BLE_GAP_AUTH_KEY_TYPE_OOB, + * then a 16-byte OOB key value in little-endian format. + * + * @retval ::NRF_SUCCESS Authentication key successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Authentication key has not been requested. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_AUTH_KEY_REPLY, uint32_t, + sd_ble_gap_auth_key_reply(uint16_t conn_handle, uint8_t key_type, uint8_t const *p_key)); + +/**@brief Reply with an LE Secure connections DHKey. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST, calling it at other times will result in + * an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_dhkey LE Secure Connections DHKey. + * + * @retval ::NRF_SUCCESS DHKey successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - The peer is not authenticated. + * - The application has not pulled a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_DHKEY_REPLY, uint32_t, + sd_ble_gap_lesc_dhkey_reply(uint16_t conn_handle, ble_gap_lesc_dhkey_t const *p_dhkey)); + +/**@brief Notify the peer of a local keypress. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] kp_not See @ref BLE_GAP_KP_NOT_TYPES. + * + * @retval ::NRF_SUCCESS Keypress notification successfully queued for transmission. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Authentication key not requested. + * - Passkey has not been entered. + * - Keypresses have not been enabled by both peers. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy. Retry at later time. + */ +SVCALL(SD_BLE_GAP_KEYPRESS_NOTIFY, uint32_t, sd_ble_gap_keypress_notify(uint16_t conn_handle, uint8_t kp_not)); + +/**@brief Generate a set of OOB data to send to a peer out of band. + * + * @note The @ref ble_gap_addr_t included in the OOB data returned will be the currently active one (or, if a connection has + * already been established, the one used during connection setup). The application may manually overwrite it with an updated + * value. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. Can be @ref BLE_CONN_HANDLE_INVALID if a BLE connection has not been established yet. + * @param[in] p_pk_own LE Secure Connections local P-256 Public Key. + * @param[out] p_oobd_own The OOB data to be sent out of band to a peer. + * + * @retval ::NRF_SUCCESS OOB data successfully generated. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_OOB_DATA_GET, uint32_t, + sd_ble_gap_lesc_oob_data_get(uint16_t conn_handle, ble_gap_lesc_p256_pk_t const *p_pk_own, + ble_gap_lesc_oob_data_t *p_oobd_own)); + +/**@brief Provide the OOB data sent/received out of band. + * + * @note An authentication procedure with OOB selected as an algorithm must be in progress when calling this function. + * @note A @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event with the oobd_req set to 1 must have been received prior to calling this + * function. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_oobd_own The OOB data sent out of band to a peer or NULL if the peer has not received OOB data. + * Must correspond to @ref ble_gap_sec_params_t::oob flag in @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. + * @param[in] p_oobd_peer The OOB data received out of band from a peer or NULL if none received. + * Must correspond to @ref ble_gap_sec_params_t::oob flag + * in @ref sd_ble_gap_authenticate in the central role or + * in @ref sd_ble_gap_sec_params_reply in the peripheral role. + * + * @retval ::NRF_SUCCESS OOB data accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Authentication key not requested + * - Not expecting LESC OOB data + * - Have not actually exchanged passkeys. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_OOB_DATA_SET, uint32_t, + sd_ble_gap_lesc_oob_data_set(uint16_t conn_handle, ble_gap_lesc_oob_data_t const *p_oobd_own, + ble_gap_lesc_oob_data_t const *p_oobd_peer)); + +/**@brief Initiate GAP Encryption procedure. + * + * @details In the central role, this function will initiate the encryption procedure using the encryption information provided. + * + * @events + * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE, The connection security has been updated.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_master_id Pointer to a @ref ble_gap_master_id_t master identification structure. + * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. + * + * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::BLE_ERROR_INVALID_ROLE Operation is not supported in the Peripheral role. + * @retval ::NRF_ERROR_BUSY Procedure already in progress or not allowed at this time, wait for pending procedures to complete and + * retry. + */ +SVCALL(SD_BLE_GAP_ENCRYPT, uint32_t, + sd_ble_gap_encrypt(uint16_t conn_handle, ble_gap_master_id_t const *p_master_id, ble_gap_enc_info_t const *p_enc_info)); + +/**@brief Reply with GAP security information. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_INFO_REQUEST, calling it at other times will result in + * @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * @note Data signing is not yet supported, and p_sign_info must therefore be NULL. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_ENC_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. May be NULL to signal none is + * available. + * @param[in] p_id_info Pointer to a @ref ble_gap_irk_t identity information structure. May be NULL to signal none is available. + * @param[in] p_sign_info Pointer to a @ref ble_gap_sign_info_t signing information structure. May be NULL to signal none is + * available. + * + * @retval ::NRF_SUCCESS Successfully accepted security information. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - No link has been established. + * - No @ref BLE_GAP_EVT_SEC_INFO_REQUEST pending. + * - Encryption information provided by the app without being requested. See @ref + * ble_gap_evt_sec_info_request_t::enc_info. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_SEC_INFO_REPLY, uint32_t, + sd_ble_gap_sec_info_reply(uint16_t conn_handle, ble_gap_enc_info_t const *p_enc_info, ble_gap_irk_t const *p_id_info, + ble_gap_sign_info_t const *p_sign_info)); + +/**@brief Get the current connection security. + * + * @param[in] conn_handle Connection handle. + * @param[out] p_conn_sec Pointer to a @ref ble_gap_conn_sec_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Current connection security successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_CONN_SEC_GET, uint32_t, sd_ble_gap_conn_sec_get(uint16_t conn_handle, ble_gap_conn_sec_t *p_conn_sec)); + +/**@brief Start reporting the received signal strength to the application. + * + * A new event is reported whenever the RSSI value changes, until @ref sd_ble_gap_rssi_stop is called. + * + * @events + * @event{@ref BLE_GAP_EVT_RSSI_CHANGED, New RSSI data available. How often the event is generated is + * dependent on the settings of the threshold_dbm + * and skip_count input parameters.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] threshold_dbm Minimum change in dBm before triggering the @ref BLE_GAP_EVT_RSSI_CHANGED event. Events are + * disabled if threshold_dbm equals @ref BLE_GAP_RSSI_THRESHOLD_INVALID. + * @param[in] skip_count Number of RSSI samples with a change of threshold_dbm or more before sending a new @ref + * BLE_GAP_EVT_RSSI_CHANGED event. + * + * @retval ::NRF_SUCCESS Successfully activated RSSI reporting. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is already ongoing. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_RSSI_START, uint32_t, sd_ble_gap_rssi_start(uint16_t conn_handle, uint8_t threshold_dbm, uint8_t skip_count)); + +/**@brief Stop reporting the received signal strength. + * + * @note An RSSI change detected before the call but not yet received by the application + * may be reported after @ref sd_ble_gap_rssi_stop has been called. + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * + * @retval ::NRF_SUCCESS Successfully deactivated RSSI reporting. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_RSSI_STOP, uint32_t, sd_ble_gap_rssi_stop(uint16_t conn_handle)); + +/**@brief Get the received signal strength for the last connection event. + * + * @ref sd_ble_gap_rssi_start must be called to start reporting RSSI before using this function. @ref NRF_ERROR_NOT_FOUND + * will be returned until RSSI was sampled for the first time after calling @ref sd_ble_gap_rssi_start. + * @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature measurement. + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[out] p_rssi Pointer to the location where the RSSI measurement shall be stored. + * @param[out] p_ch_index Pointer to the location where Channel Index for the RSSI measurement shall be stored. + * + * @retval ::NRF_SUCCESS Successfully read the RSSI. + * @retval ::NRF_ERROR_NOT_FOUND No sample is available. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. + */ +SVCALL(SD_BLE_GAP_RSSI_GET, uint32_t, sd_ble_gap_rssi_get(uint16_t conn_handle, int8_t *p_rssi, uint8_t *p_ch_index)); + +/**@brief Start or continue scanning (GAP Discovery procedure, Observer Procedure). + * + * @note A call to this function will require the application to keep the memory pointed by + * p_adv_report_buffer alive until the buffer is released. The buffer is released when the scanner is stopped + * or when this function is called with another buffer. + * + * @note The scanner will automatically stop in the following cases: + * - @ref sd_ble_gap_scan_stop is called. + * - @ref sd_ble_gap_connect is called. + * - A @ref BLE_GAP_EVT_TIMEOUT with source set to @ref BLE_GAP_TIMEOUT_SRC_SCAN is received. + * - When a @ref BLE_GAP_EVT_ADV_REPORT event is received and @ref ble_gap_adv_report_type_t::status is not set to + * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. In this case scanning is only paused to let the application + * access received data. The application must call this function to continue scanning, or call @ref + * sd_ble_gap_scan_stop to stop scanning. + * + * @note If a @ref BLE_GAP_EVT_ADV_REPORT event is received with @ref ble_gap_adv_report_type_t::status set to + * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the scanner will continue scanning, and the application will + * receive more reports from this advertising event. The following reports will include the old and new received data. + * + * @events + * @event{@ref BLE_GAP_EVT_ADV_REPORT, An advertising or scan response packet has been received.} + * @event{@ref BLE_GAP_EVT_TIMEOUT, Scanner has timed out.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_SCAN_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] p_scan_params Pointer to scan parameters structure. When this function is used to continue + * scanning, this parameter must be NULL. + * @param[in] p_adv_report_buffer Pointer to buffer used to store incoming advertising data. + * The memory pointed to should be kept alive until the scanning is stopped. + * See @ref BLE_GAP_SCAN_BUFFER_SIZE for minimum and maximum buffer size. + * If the scanner receives advertising data larger than can be stored in the buffer, + * a @ref BLE_GAP_EVT_ADV_REPORT will be raised with @ref ble_gap_adv_report_type_t::status + * set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED. + * + * @retval ::NRF_SUCCESS Successfully initiated scanning procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Scanning is already ongoing and p_scan_params was not NULL + * - Scanning is not running and p_scan_params was NULL. + * - The scanner has timed out when this function is called to continue scanning. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. See @ref ble_gap_scan_params_t. + * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported parameters supplied. See @ref ble_gap_scan_params_t. + * @retval ::NRF_ERROR_INVALID_LENGTH The provided buffer length is invalid. See @ref BLE_GAP_SCAN_BUFFER_MIN. + * @retval ::NRF_ERROR_RESOURCES Not enough BLE role slots available. + * Stop one or more currently active roles (Central, Peripheral or Broadcaster) and try again + */ +SVCALL(SD_BLE_GAP_SCAN_START, uint32_t, + sd_ble_gap_scan_start(ble_gap_scan_params_t const *p_scan_params, ble_data_t const *p_adv_report_buffer)); + +/**@brief Stop scanning (GAP Discovery procedure, Observer Procedure). + * + * @note The buffer provided in @ref sd_ble_gap_scan_start is released. + * + * @mscs + * @mmsc{@ref BLE_GAP_SCAN_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully stopped scanning procedure. + * @retval ::NRF_ERROR_INVALID_STATE Not in the scanning state. + */ +SVCALL(SD_BLE_GAP_SCAN_STOP, uint32_t, sd_ble_gap_scan_stop(void)); + +/**@brief Create a connection (GAP Link Establishment). + * + * @note If a scanning procedure is currently in progress it will be automatically stopped when calling this function. + * The scanning procedure will be stopped even if the function returns an error. + * + * @events + * @event{@ref BLE_GAP_EVT_CONNECTED, A connection was established.} + * @event{@ref BLE_GAP_EVT_TIMEOUT, Failed to establish a connection.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} + * @endmscs + * + * @param[in] p_peer_addr Pointer to peer identity address. If @ref ble_gap_scan_params_t::filter_policy is set to use + * whitelist, then p_peer_addr is ignored. + * @param[in] p_scan_params Pointer to scan parameters structure. + * @param[in] p_conn_params Pointer to desired connection parameters. + * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or + * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. + * + * @retval ::NRF_SUCCESS Successfully initiated connection procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid parameter(s) pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * - Invalid parameter(s) in p_scan_params or p_conn_params. + * - Use of whitelist requested but whitelist has not been set, see @ref + * sd_ble_gap_whitelist_set. + * - Peer address was not present in the device identity list, see @ref + * sd_ble_gap_device_identities_set. + * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. + * @retval ::NRF_ERROR_INVALID_STATE The SoftDevice is in an invalid state to perform this operation. This may be due to an + * existing locally initiated connect procedure, which must complete before initiating again. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid Peer address. + * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration tag has been reached. + * To increase the number of available connections, + * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. + * @retval ::NRF_ERROR_RESOURCES Either: + * - Not enough BLE role slots available. + * Stop one or more currently active roles (Central, Peripheral or Observer) and try again. + * - The event_length parameter associated with conn_cfg_tag is too small to be able to + * establish a connection on the selected @ref ble_gap_scan_params_t::scan_phys. + * Use @ref sd_ble_cfg_set to increase the event length. + */ +SVCALL(SD_BLE_GAP_CONNECT, uint32_t, + sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params, + ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag)); + +/**@brief Cancel a connection establishment. + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully canceled an ongoing connection procedure. + * @retval ::NRF_ERROR_INVALID_STATE No locally initiated connect procedure started or connection + * completed occurred. + */ +SVCALL(SD_BLE_GAP_CONNECT_CANCEL, uint32_t, sd_ble_gap_connect_cancel(void)); + +/**@brief Initiate or respond to a PHY Update Procedure + * + * @details This function is used to initiate or respond to a PHY Update Procedure. It will always + * generate a @ref BLE_GAP_EVT_PHY_UPDATE event if successfully executed. + * If this function is used to initiate a PHY Update procedure and the only option + * provided in @ref ble_gap_phys_t::tx_phys and @ref ble_gap_phys_t::rx_phys is the + * currently active PHYs in the respective directions, the SoftDevice will generate a + * @ref BLE_GAP_EVT_PHY_UPDATE with the current PHYs set and will not initiate the + * procedure in the Link Layer. + * + * If @ref ble_gap_phys_t::tx_phys or @ref ble_gap_phys_t::rx_phys is @ref BLE_GAP_PHY_AUTO, + * then the stack will select PHYs based on the peer's PHY preferences and the local link + * configuration. The PHY Update procedure will for this case result in a PHY combination + * that respects the time constraints configured with @ref sd_ble_cfg_set and the current + * link layer data length. + * + * When acting as a central, the SoftDevice will select the fastest common PHY in each direction. + * + * If the peer does not support the PHY Update Procedure, then the resulting + * @ref BLE_GAP_EVT_PHY_UPDATE event will have a status set to + * @ref BLE_HCI_UNSUPPORTED_REMOTE_FEATURE. + * + * If the PHY Update procedure was rejected by the peer due to a procedure collision, the status + * will be @ref BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION or + * @ref BLE_HCI_DIFFERENT_TRANSACTION_COLLISION. + * If the peer responds to the PHY Update procedure with invalid parameters, the status + * will be @ref BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS. + * If the PHY Update procedure was rejected by the peer for a different reason, the status will + * contain the reason as specified by the peer. + * + * @events + * @event{@ref BLE_GAP_EVT_PHY_UPDATE, Result of the PHY Update Procedure.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_PHY_UPDATE} + * @mmsc{@ref BLE_GAP_PERIPHERAL_PHY_UPDATE} + * @endmscs + * + * @param[in] conn_handle Connection handle to indicate the connection for which the PHY Update is requested. + * @param[in] p_gap_phys Pointer to PHY structure. + * + * @retval ::NRF_SUCCESS Successfully requested a PHY Update. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the combination of + * @ref ble_gap_phys_t::tx_phys, @ref ble_gap_phys_t::rx_phys, and @ref + * ble_gap_data_length_params_t. The connection event length is configured with @ref BLE_CONN_CFG_GAP using @ref sd_ble_cfg_set. + * @retval ::NRF_ERROR_BUSY Procedure is already in progress or not allowed at this time. Process pending events and wait for the + * pending procedure to complete and retry. + * + */ +SVCALL(SD_BLE_GAP_PHY_UPDATE, uint32_t, sd_ble_gap_phy_update(uint16_t conn_handle, ble_gap_phys_t const *p_gap_phys)); + +/**@brief Initiate or respond to a Data Length Update Procedure. + * + * @note If the application uses @ref BLE_GAP_DATA_LENGTH_AUTO for one or more members of + * p_dl_params, the SoftDevice will choose the highest value supported in current + * configuration and connection parameters. + * @note If the link PHY is Coded, the SoftDevice will ensure that the MaxTxTime and/or MaxRxTime + * used in the Data Length Update procedure is at least 2704 us. Otherwise, MaxTxTime and + * MaxRxTime will be limited to maximum 2120 us. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_dl_params Pointer to local parameters to be used in Data Length Update + * Procedure. Set any member to @ref BLE_GAP_DATA_LENGTH_AUTO to let + * the SoftDevice automatically decide the value for that member. + * Set to NULL to use automatic values for all members. + * @param[out] p_dl_limitation Pointer to limitation to be written when local device does not + * have enough resources or does not support the requested Data Length + * Update parameters. Ignored if NULL. + * + * @mscs + * @mmsc{@ref BLE_GAP_DATA_LENGTH_UPDATE_PROCEDURE_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully set Data Length Extension initiation/response parameters. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The requested parameters are not supported by the SoftDevice. Inspect + * p_dl_limitation to see which parameter is not supported. + * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the requested + * parameters. Use @ref sd_ble_cfg_set with @ref BLE_CONN_CFG_GAP to increase the connection event length. Inspect p_dl_limitation + * to see where the limitation is. + * @retval ::NRF_ERROR_BUSY Peer has already initiated a Data Length Update Procedure. Process the + * pending @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event to respond. + */ +SVCALL(SD_BLE_GAP_DATA_LENGTH_UPDATE, uint32_t, + sd_ble_gap_data_length_update(uint16_t conn_handle, ble_gap_data_length_params_t const *p_dl_params, + ble_gap_data_length_limitation_t *p_dl_limitation)); + +/**@brief Start the Quality of Service (QoS) channel survey module. + * + * @details The channel survey module provides measurements of the energy levels on + * the Bluetooth Low Energy channels. When the module is enabled, @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT + * events will periodically report the measured energy levels for each channel. + * + * @note The measurements are scheduled with lower priority than other Bluetooth Low Energy roles, + * Radio Timeslot API events and Flash API events. + * + * @note The channel survey module will attempt to do measurements so that the average interval + * between measurements will be interval_us. However due to the channel survey module + * having the lowest priority of all roles and modules, this may not be possible. In that + * case fewer than expected channel survey reports may be given. + * + * @note In order to use the channel survey module, @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available + * must be set. This is done using @ref sd_ble_cfg_set. + * + * @param[in] interval_us Requested average interval for the measurements and reports. See + * @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS for valid ranges. If set + * to @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS, the channel + * survey role will be scheduled at every available opportunity. + * + * @retval ::NRF_SUCCESS The module is successfully started. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. interval_us is out of the + * allowed range. + * @retval ::NRF_ERROR_INVALID_STATE Trying to start the module when already running. + * @retval ::NRF_ERROR_RESOURCES The channel survey module is not available to the application. + * Set @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available using + * @ref sd_ble_cfg_set. + */ +SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_START, uint32_t, sd_ble_gap_qos_channel_survey_start(uint32_t interval_us)); + +/**@brief Stop the Quality of Service (QoS) channel survey module. + * + * @note The SoftDevice may generate one @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT event after this + * function is called. + * + * @retval ::NRF_SUCCESS The module is successfully stopped. + * @retval ::NRF_ERROR_INVALID_STATE Trying to stop the module when it is not running. + */ +SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP, uint32_t, sd_ble_gap_qos_channel_survey_stop(void)); + +/**@brief Obtain the next connection event counter value. + * + * @details The connection event counter is initialized to zero on the first connection event. The value is incremented + * by one for each connection event. For more information see Bluetooth Core Specification v5.0, Vol 6, Part B, + * Section 4.5.1. + * + * @note The connection event counter obtained through this API will be outdated if this API is called + * at the same time as the connection event counter is incremented. + * + * @note This API will always return the last connection event counter + 1. + * The actual connection event may be multiple connection events later if: + * - Slave latency is enabled and there is no data to transmit or receive. + * - Another role is scheduled with a higher priority at the same time as the next connection event. + * + * @param[in] conn_handle Connection handle. + * @param[out] p_counter Pointer to the variable where the next connection event counter will be written. + * + * @retval ::NRF_SUCCESS The connection event counter was successfully retrieved. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET, uint32_t, + sd_ble_gap_next_conn_evt_counter_get(uint16_t conn_handle, uint16_t *p_counter)); + +/**@brief Start triggering a given task on connection event start. + * + * @details When enabled, this feature will trigger a PPI task at the start of connection events. + * The application can configure the SoftDevice to trigger every N connection events starting from + * a given connection event counter. See also @ref ble_gap_conn_event_trigger_t. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_params Connection event trigger parameters. + * + * @retval ::NRF_SUCCESS Success. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. See @ref ble_gap_conn_event_trigger_t. + * @retval ::NRF_ERROR_INVALID_STATE Either: + * - Trying to start connection event triggering when it is already ongoing. + * - @ref ble_gap_conn_event_trigger_t::conn_evt_counter_start is in the past. + * Use @ref sd_ble_gap_next_conn_evt_counter_get to find a new value + to be used as ble_gap_conn_event_trigger_t::conn_evt_counter_start. + */ +SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_START, uint32_t, + sd_ble_gap_conn_evt_trigger_start(uint16_t conn_handle, ble_gap_conn_event_trigger_t const *p_params)); + +/**@brief Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. + * + * @param[in] conn_handle Connection handle. + * + * @retval ::NRF_SUCCESS Success. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE Trying to stop connection event triggering when it is not enabled. + */ +SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_STOP, uint32_t, sd_ble_gap_conn_evt_trigger_stop(uint16_t conn_handle)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GAP_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gatt.h b/variants/wio-tracker-wm1110/softdevice/ble_gatt.h new file mode 100644 index 0000000000..df0d728fc8 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_gatt.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATT Generic Attribute Profile (GATT) Common + @{ + @brief Common definitions and prototypes for the GATT interfaces. + */ + +#ifndef BLE_GATT_H__ +#define BLE_GATT_H__ + +#include "ble_err.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATT_DEFINES Defines + * @{ */ + +/** @brief Default ATT MTU, in bytes. */ +#define BLE_GATT_ATT_MTU_DEFAULT 23 + +/**@brief Invalid Attribute Handle. */ +#define BLE_GATT_HANDLE_INVALID 0x0000 + +/**@brief First Attribute Handle. */ +#define BLE_GATT_HANDLE_START 0x0001 + +/**@brief Last Attribute Handle. */ +#define BLE_GATT_HANDLE_END 0xFFFF + +/** @defgroup BLE_GATT_TIMEOUT_SOURCES GATT Timeout sources + * @{ */ +#define BLE_GATT_TIMEOUT_SRC_PROTOCOL 0x00 /**< ATT Protocol timeout. */ +/** @} */ + +/** @defgroup BLE_GATT_WRITE_OPS GATT Write operations + * @{ */ +#define BLE_GATT_OP_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATT_OP_WRITE_REQ 0x01 /**< Write Request. */ +#define BLE_GATT_OP_WRITE_CMD 0x02 /**< Write Command. */ +#define BLE_GATT_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ +#define BLE_GATT_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ +#define BLE_GATT_OP_EXEC_WRITE_REQ 0x05 /**< Execute Write Request. */ +/** @} */ + +/** @defgroup BLE_GATT_EXEC_WRITE_FLAGS GATT Execute Write flags + * @{ */ +#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL 0x00 /**< Cancel prepared write. */ +#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE 0x01 /**< Execute prepared write. */ +/** @} */ + +/** @defgroup BLE_GATT_HVX_TYPES GATT Handle Value operations + * @{ */ +#define BLE_GATT_HVX_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATT_HVX_NOTIFICATION 0x01 /**< Handle Value Notification. */ +#define BLE_GATT_HVX_INDICATION 0x02 /**< Handle Value Indication. */ +/** @} */ + +/** @defgroup BLE_GATT_STATUS_CODES GATT Status Codes + * @{ */ +#define BLE_GATT_STATUS_SUCCESS 0x0000 /**< Success. */ +#define BLE_GATT_STATUS_UNKNOWN 0x0001 /**< Unknown or not applicable status. */ +#define BLE_GATT_STATUS_ATTERR_INVALID 0x0100 /**< ATT Error: Invalid Error Code. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_HANDLE 0x0101 /**< ATT Error: Invalid Attribute Handle. */ +#define BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED 0x0102 /**< ATT Error: Read not permitted. */ +#define BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED 0x0103 /**< ATT Error: Write not permitted. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_PDU 0x0104 /**< ATT Error: Used in ATT as Invalid PDU. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION 0x0105 /**< ATT Error: Authenticated link required. */ +#define BLE_GATT_STATUS_ATTERR_REQUEST_NOT_SUPPORTED 0x0106 /**< ATT Error: Used in ATT as Request Not Supported. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_OFFSET 0x0107 /**< ATT Error: Offset specified was past the end of the attribute. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION 0x0108 /**< ATT Error: Used in ATT as Insufficient Authorization. */ +#define BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL 0x0109 /**< ATT Error: Used in ATT as Prepare Queue Full. */ +#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND 0x010A /**< ATT Error: Used in ATT as Attribute not found. */ +#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_LONG \ + 0x010B /**< ATT Error: Attribute cannot be read or written using read/write blob requests. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_ENC_KEY_SIZE 0x010C /**< ATT Error: Encryption key size used is insufficient. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH 0x010D /**< ATT Error: Invalid value size. */ +#define BLE_GATT_STATUS_ATTERR_UNLIKELY_ERROR 0x010E /**< ATT Error: Very unlikely error. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION 0x010F /**< ATT Error: Encrypted link required. */ +#define BLE_GATT_STATUS_ATTERR_UNSUPPORTED_GROUP_TYPE \ + 0x0110 /**< ATT Error: Attribute type is not a supported grouping attribute. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_RESOURCES 0x0111 /**< ATT Error: Insufficient resources. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_BEGIN 0x0112 /**< ATT Error: Reserved for Future Use range #1 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_END 0x017F /**< ATT Error: Reserved for Future Use range #1 end. */ +#define BLE_GATT_STATUS_ATTERR_APP_BEGIN 0x0180 /**< ATT Error: Application range begin. */ +#define BLE_GATT_STATUS_ATTERR_APP_END 0x019F /**< ATT Error: Application range end. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_BEGIN 0x01A0 /**< ATT Error: Reserved for Future Use range #2 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_END 0x01DF /**< ATT Error: Reserved for Future Use range #2 end. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_BEGIN 0x01E0 /**< ATT Error: Reserved for Future Use range #3 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_END 0x01FC /**< ATT Error: Reserved for Future Use range #3 end. */ +#define BLE_GATT_STATUS_ATTERR_CPS_WRITE_REQ_REJECTED \ + 0x01FC /**< ATT Common Profile and Service Error: Write request rejected. \ + */ +#define BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR \ + 0x01FD /**< ATT Common Profile and Service Error: Client Characteristic Configuration Descriptor improperly configured. */ +#define BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG \ + 0x01FE /**< ATT Common Profile and Service Error: Procedure Already in Progress. */ +#define BLE_GATT_STATUS_ATTERR_CPS_OUT_OF_RANGE 0x01FF /**< ATT Common Profile and Service Error: Out Of Range. */ +/** @} */ + +/** @defgroup BLE_GATT_CPF_FORMATS Characteristic Presentation Formats + * @note Found at + * http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml + * @{ */ +#define BLE_GATT_CPF_FORMAT_RFU 0x00 /**< Reserved For Future Use. */ +#define BLE_GATT_CPF_FORMAT_BOOLEAN 0x01 /**< Boolean. */ +#define BLE_GATT_CPF_FORMAT_2BIT 0x02 /**< Unsigned 2-bit integer. */ +#define BLE_GATT_CPF_FORMAT_NIBBLE 0x03 /**< Unsigned 4-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT8 0x04 /**< Unsigned 8-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT12 0x05 /**< Unsigned 12-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT16 0x06 /**< Unsigned 16-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT24 0x07 /**< Unsigned 24-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT32 0x08 /**< Unsigned 32-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT48 0x09 /**< Unsigned 48-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT64 0x0A /**< Unsigned 64-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT128 0x0B /**< Unsigned 128-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT8 0x0C /**< Signed 2-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT12 0x0D /**< Signed 12-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT16 0x0E /**< Signed 16-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT24 0x0F /**< Signed 24-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT32 0x10 /**< Signed 32-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT48 0x11 /**< Signed 48-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT64 0x12 /**< Signed 64-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT128 0x13 /**< Signed 128-bit integer. */ +#define BLE_GATT_CPF_FORMAT_FLOAT32 0x14 /**< IEEE-754 32-bit floating point. */ +#define BLE_GATT_CPF_FORMAT_FLOAT64 0x15 /**< IEEE-754 64-bit floating point. */ +#define BLE_GATT_CPF_FORMAT_SFLOAT 0x16 /**< IEEE-11073 16-bit SFLOAT. */ +#define BLE_GATT_CPF_FORMAT_FLOAT 0x17 /**< IEEE-11073 32-bit FLOAT. */ +#define BLE_GATT_CPF_FORMAT_DUINT16 0x18 /**< IEEE-20601 format. */ +#define BLE_GATT_CPF_FORMAT_UTF8S 0x19 /**< UTF-8 string. */ +#define BLE_GATT_CPF_FORMAT_UTF16S 0x1A /**< UTF-16 string. */ +#define BLE_GATT_CPF_FORMAT_STRUCT 0x1B /**< Opaque Structure. */ +/** @} */ + +/** @defgroup BLE_GATT_CPF_NAMESPACES GATT Bluetooth Namespaces + * @{ + */ +#define BLE_GATT_CPF_NAMESPACE_BTSIG 0x01 /**< Bluetooth SIG defined Namespace. */ +#define BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN 0x0000 /**< Namespace Description Unknown. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATT_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATT connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_PARAM att_mtu is smaller than @ref BLE_GATT_ATT_MTU_DEFAULT. + */ +typedef struct { + uint16_t att_mtu; /**< Maximum size of ATT packet the SoftDevice can send or receive. + The default and minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + @mscs + @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} + @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} + @endmscs + */ +} ble_gatt_conn_cfg_t; + +/**@brief GATT Characteristic Properties. */ +typedef struct { + /* Standard properties */ + uint8_t broadcast : 1; /**< Broadcasting of the value permitted. */ + uint8_t read : 1; /**< Reading the value permitted. */ + uint8_t write_wo_resp : 1; /**< Writing the value with Write Command permitted. */ + uint8_t write : 1; /**< Writing the value with Write Request permitted. */ + uint8_t notify : 1; /**< Notification of the value permitted. */ + uint8_t indicate : 1; /**< Indications of the value permitted. */ + uint8_t auth_signed_wr : 1; /**< Writing the value with Signed Write Command permitted. */ +} ble_gatt_char_props_t; + +/**@brief GATT Characteristic Extended Properties. */ +typedef struct { + /* Extended properties */ + uint8_t reliable_wr : 1; /**< Writing the value with Queued Write operations permitted. */ + uint8_t wr_aux : 1; /**< Writing the Characteristic User Description descriptor permitted. */ +} ble_gatt_char_ext_props_t; + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GATT_H__ + +/** @} */ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gattc.h b/variants/wio-tracker-wm1110/softdevice/ble_gattc.h new file mode 100644 index 0000000000..f1df1782ca --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_gattc.h @@ -0,0 +1,764 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATTC Generic Attribute Profile (GATT) Client + @{ + @brief Definitions and prototypes for the GATT Client interface. + */ + +#ifndef BLE_GATTC_H__ +#define BLE_GATTC_H__ + +#include "ble_err.h" +#include "ble_gatt.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATTC_ENUMERATIONS Enumerations + * @{ */ + +/**@brief GATTC API SVC numbers. */ +enum BLE_GATTC_SVCS { + SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER = BLE_GATTC_SVC_BASE, /**< Primary Service Discovery. */ + SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, /**< Relationship Discovery. */ + SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, /**< Characteristic Discovery. */ + SD_BLE_GATTC_DESCRIPTORS_DISCOVER, /**< Characteristic Descriptor Discovery. */ + SD_BLE_GATTC_ATTR_INFO_DISCOVER, /**< Attribute Information Discovery. */ + SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, /**< Read Characteristic Value by UUID. */ + SD_BLE_GATTC_READ, /**< Generic read. */ + SD_BLE_GATTC_CHAR_VALUES_READ, /**< Read multiple Characteristic Values. */ + SD_BLE_GATTC_WRITE, /**< Generic write. */ + SD_BLE_GATTC_HV_CONFIRM, /**< Handle Value Confirmation. */ + SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. */ +}; + +/** + * @brief GATT Client Event IDs. + */ +enum BLE_GATTC_EVTS { + BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP = BLE_GATTC_EVT_BASE, /**< Primary Service Discovery Response event. \n See @ref + ble_gattc_evt_prim_srvc_disc_rsp_t. */ + BLE_GATTC_EVT_REL_DISC_RSP, /**< Relationship Discovery Response event. \n See @ref ble_gattc_evt_rel_disc_rsp_t. + */ + BLE_GATTC_EVT_CHAR_DISC_RSP, /**< Characteristic Discovery Response event. \n See @ref + ble_gattc_evt_char_disc_rsp_t. */ + BLE_GATTC_EVT_DESC_DISC_RSP, /**< Descriptor Discovery Response event. \n See @ref + ble_gattc_evt_desc_disc_rsp_t. */ + BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, /**< Attribute Information Response event. \n See @ref + ble_gattc_evt_attr_info_disc_rsp_t. */ + BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP, /**< Read By UUID Response event. \n See @ref + ble_gattc_evt_char_val_by_uuid_read_rsp_t. */ + BLE_GATTC_EVT_READ_RSP, /**< Read Response event. \n See @ref ble_gattc_evt_read_rsp_t. */ + BLE_GATTC_EVT_CHAR_VALS_READ_RSP, /**< Read multiple Response event. \n See @ref + ble_gattc_evt_char_vals_read_rsp_t. */ + BLE_GATTC_EVT_WRITE_RSP, /**< Write Response event. \n See @ref ble_gattc_evt_write_rsp_t. */ + BLE_GATTC_EVT_HVX, /**< Handle Value Notification or Indication event. \n Confirm indication with @ref + sd_ble_gattc_hv_confirm. \n See @ref ble_gattc_evt_hvx_t. */ + BLE_GATTC_EVT_EXCHANGE_MTU_RSP, /**< Exchange MTU Response event. \n See @ref + ble_gattc_evt_exchange_mtu_rsp_t. */ + BLE_GATTC_EVT_TIMEOUT, /**< Timeout event. \n See @ref ble_gattc_evt_timeout_t. */ + BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE /**< Write without Response transmission complete. \n See @ref + ble_gattc_evt_write_cmd_tx_complete_t. */ +}; + +/**@brief GATTC Option IDs. + * IDs that uniquely identify a GATTC option. + */ +enum BLE_GATTC_OPTS { + BLE_GATTC_OPT_UUID_DISC = BLE_GATTC_OPT_BASE, /**< UUID discovery. @ref ble_gattc_opt_uuid_disc_t */ +}; + +/** @} */ + +/** @addtogroup BLE_GATTC_DEFINES Defines + * @{ */ + +/** @defgroup BLE_ERRORS_GATTC SVC return values specific to GATTC + * @{ */ +#define BLE_ERROR_GATTC_PROC_NOT_PERMITTED (NRF_GATTC_ERR_BASE + 0x000) /**< Procedure not Permitted. */ +/** @} */ + +/** @defgroup BLE_GATTC_ATTR_INFO_FORMAT Attribute Information Formats + * @{ */ +#define BLE_GATTC_ATTR_INFO_FORMAT_16BIT 1 /**< 16-bit Attribute Information Format. */ +#define BLE_GATTC_ATTR_INFO_FORMAT_128BIT 2 /**< 128-bit Attribute Information Format. */ +/** @} */ + +/** @defgroup BLE_GATTC_DEFAULTS GATT Client defaults + * @{ */ +#define BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT \ + 1 /**< Default number of Write without Response that can be queued for transmission. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATTC_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATTC connection configuration parameters, set with @ref sd_ble_cfg_set. + */ +typedef struct { + uint8_t write_cmd_tx_queue_size; /**< The guaranteed minimum number of Write without Response that can be queued for + transmission. The default value is @ref BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT */ +} ble_gattc_conn_cfg_t; + +/**@brief Operation Handle Range. */ +typedef struct { + uint16_t start_handle; /**< Start Handle. */ + uint16_t end_handle; /**< End Handle. */ +} ble_gattc_handle_range_t; + +/**@brief GATT service. */ +typedef struct { + ble_uuid_t uuid; /**< Service UUID. */ + ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */ +} ble_gattc_service_t; + +/**@brief GATT include. */ +typedef struct { + uint16_t handle; /**< Include Handle. */ + ble_gattc_service_t included_srvc; /**< Handle of the included service. */ +} ble_gattc_include_t; + +/**@brief GATT characteristic. */ +typedef struct { + ble_uuid_t uuid; /**< Characteristic UUID. */ + ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ + uint8_t char_ext_props : 1; /**< Extended properties present. */ + uint16_t handle_decl; /**< Handle of the Characteristic Declaration. */ + uint16_t handle_value; /**< Handle of the Characteristic Value. */ +} ble_gattc_char_t; + +/**@brief GATT descriptor. */ +typedef struct { + uint16_t handle; /**< Descriptor Handle. */ + ble_uuid_t uuid; /**< Descriptor UUID. */ +} ble_gattc_desc_t; + +/**@brief Write Parameters. */ +typedef struct { + uint8_t write_op; /**< Write Operation to be performed, see @ref BLE_GATT_WRITE_OPS. */ + uint8_t flags; /**< Flags, see @ref BLE_GATT_EXEC_WRITE_FLAGS. */ + uint16_t handle; /**< Handle to the attribute to be written. */ + uint16_t offset; /**< Offset in bytes. @note For WRITE_CMD and WRITE_REQ, offset must be 0. */ + uint16_t len; /**< Length of data in bytes. */ + uint8_t const *p_value; /**< Pointer to the value data. */ +} ble_gattc_write_params_t; + +/**@brief Attribute Information for 16-bit Attribute UUID. */ +typedef struct { + uint16_t handle; /**< Attribute handle. */ + ble_uuid_t uuid; /**< 16-bit Attribute UUID. */ +} ble_gattc_attr_info16_t; + +/**@brief Attribute Information for 128-bit Attribute UUID. */ +typedef struct { + uint16_t handle; /**< Attribute handle. */ + ble_uuid128_t uuid; /**< 128-bit Attribute UUID. */ +} ble_gattc_attr_info128_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Service count. */ + ble_gattc_service_t services[1]; /**< Service data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use + event structures with variable length array members. */ +} ble_gattc_evt_prim_srvc_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_REL_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Include count. */ + ble_gattc_include_t includes[1]; /**< Include data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use + event structures with variable length array members. */ +} ble_gattc_evt_rel_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Characteristic count. */ + ble_gattc_char_t chars[1]; /**< Characteristic data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event + structures with variable length array members. */ +} ble_gattc_evt_char_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_DESC_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Descriptor count. */ + ble_gattc_desc_t descs[1]; /**< Descriptor data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event + structures with variable length array members. */ +} ble_gattc_evt_desc_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Attribute count. */ + uint8_t format; /**< Attribute information format, see @ref BLE_GATTC_ATTR_INFO_FORMAT. */ + union { + ble_gattc_attr_info16_t attr_info16[1]; /**< Attribute information for 16-bit Attribute UUID. + @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on + how to use event structures with variable length array members. */ + ble_gattc_attr_info128_t attr_info128[1]; /**< Attribute information for 128-bit Attribute UUID. + @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on + how to use event structures with variable length array members. */ + } info; /**< Attribute information union. */ +} ble_gattc_evt_attr_info_disc_rsp_t; + +/**@brief GATT read by UUID handle value pair. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint8_t *p_value; /**< Pointer to the Attribute Value, length is available in @ref + ble_gattc_evt_char_val_by_uuid_read_rsp_t::value_len. */ +} ble_gattc_handle_value_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP. */ +typedef struct { + uint16_t count; /**< Handle-Value Pair Count. */ + uint16_t value_len; /**< Length of the value in Handle-Value(s) list. */ + uint8_t handle_value[1]; /**< Handle-Value(s) list. To iterate through the list use @ref + sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter. + @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with + variable length array members. */ +} ble_gattc_evt_char_val_by_uuid_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_READ_RSP. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint16_t offset; /**< Offset of the attribute data. */ + uint16_t len; /**< Attribute data length. */ + uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP. */ +typedef struct { + uint16_t len; /**< Concatenated Attribute values length. */ + uint8_t values[1]; /**< Attribute values. @note This is a variable length array. The size of 1 indicated is only a placeholder + for compilation. See @ref sd_ble_evt_get for more information on how to use event structures with + variable length array members. */ +} ble_gattc_evt_char_vals_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_RSP. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint8_t write_op; /**< Type of write operation, see @ref BLE_GATT_WRITE_OPS. */ + uint16_t offset; /**< Data offset. */ + uint16_t len; /**< Data length. */ + uint8_t data[1]; /**< Data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_write_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_HVX. */ +typedef struct { + uint16_t handle; /**< Handle to which the HVx operation applies. */ + uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ + uint16_t len; /**< Attribute data length. */ + uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_hvx_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. */ +typedef struct { + uint16_t server_rx_mtu; /**< Server RX MTU size. */ +} ble_gattc_evt_exchange_mtu_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ +} ble_gattc_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE. */ +typedef struct { + uint8_t count; /**< Number of write without response transmissions completed. */ +} ble_gattc_evt_write_cmd_tx_complete_t; + +/**@brief GATTC event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which event occurred. */ + uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ + uint16_t + error_handle; /**< In case of error: The handle causing the error. In all other cases @ref BLE_GATT_HANDLE_INVALID. */ + union { + ble_gattc_evt_prim_srvc_disc_rsp_t prim_srvc_disc_rsp; /**< Primary Service Discovery Response Event Parameters. */ + ble_gattc_evt_rel_disc_rsp_t rel_disc_rsp; /**< Relationship Discovery Response Event Parameters. */ + ble_gattc_evt_char_disc_rsp_t char_disc_rsp; /**< Characteristic Discovery Response Event Parameters. */ + ble_gattc_evt_desc_disc_rsp_t desc_disc_rsp; /**< Descriptor Discovery Response Event Parameters. */ + ble_gattc_evt_char_val_by_uuid_read_rsp_t + char_val_by_uuid_read_rsp; /**< Characteristic Value Read by UUID Response Event Parameters. */ + ble_gattc_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. */ + ble_gattc_evt_char_vals_read_rsp_t char_vals_read_rsp; /**< Characteristic Values Read Response Event Parameters. */ + ble_gattc_evt_write_rsp_t write_rsp; /**< Write Response Event Parameters. */ + ble_gattc_evt_hvx_t hvx; /**< Handle Value Notification/Indication Event Parameters. */ + ble_gattc_evt_exchange_mtu_rsp_t exchange_mtu_rsp; /**< Exchange MTU Response Event Parameters. */ + ble_gattc_evt_timeout_t timeout; /**< Timeout Event Parameters. */ + ble_gattc_evt_attr_info_disc_rsp_t attr_info_disc_rsp; /**< Attribute Information Discovery Event Parameters. */ + ble_gattc_evt_write_cmd_tx_complete_t + write_cmd_tx_complete; /**< Write without Response transmission complete Event Parameters. */ + } params; /**< Event Parameters. @note Only valid if @ref gatt_status == @ref BLE_GATT_STATUS_SUCCESS. */ +} ble_gattc_evt_t; + +/**@brief UUID discovery option. + * + * @details Used with @ref sd_ble_opt_set to enable and disable automatic insertion of discovered 128-bit UUIDs to the + * Vendor Specific UUID table. Disabled by default. + * - When disabled, if a procedure initiated by + * @ref sd_ble_gattc_primary_services_discover, + * @ref sd_ble_gattc_relationships_discover, + * @ref sd_ble_gattc_characteristics_discover, + * @ref sd_ble_gattc_descriptors_discover + * finds a 128-bit UUID which was not added by @ref sd_ble_uuid_vs_add, @ref ble_uuid_t::type will be set + * to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. + * - When enabled, all found 128-bit UUIDs will be automatically added. The application can use + * @ref sd_ble_uuid_encode to retrieve the 128-bit UUID from @ref ble_uuid_t received in the corresponding + * event. If the total number of Vendor Specific UUIDs exceeds the table capacity, @ref ble_uuid_t::type will + * be set to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. + * See also @ref ble_common_cfg_vs_uuid_t, @ref sd_ble_uuid_vs_remove. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * + * @retval ::NRF_SUCCESS Set successfully. + * + */ +typedef struct { + uint8_t auto_add_vs_enable : 1; /**< Set to 1 to enable (or 0 to disable) automatic insertion of discovered 128-bit UUIDs. */ +} ble_gattc_opt_uuid_disc_t; + +/**@brief Option structure for GATTC options. */ +typedef union { + ble_gattc_opt_uuid_disc_t uuid_disc; /**< Parameters for the UUID discovery option. */ +} ble_gattc_opt_t; + +/** @} */ + +/** @addtogroup BLE_GATTC_FUNCTIONS Functions + * @{ */ + +/**@brief Initiate or continue a GATT Primary Service Discovery procedure. + * + * @details This function initiates or resumes a Primary Service discovery procedure, starting from the supplied handle. + * If the last service has not been reached, this function must be called again with an updated start handle value to + * continue the search. See also @ref ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_PRIM_SRVC_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] start_handle Handle to start searching from. + * @param[in] p_srvc_uuid Pointer to the service UUID to be found. If it is NULL, all primary services will be returned. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Primary Service Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER, uint32_t, + sd_ble_gattc_primary_services_discover(uint16_t conn_handle, uint16_t start_handle, ble_uuid_t const *p_srvc_uuid)); + +/**@brief Initiate or continue a GATT Relationship Discovery procedure. + * + * @details This function initiates or resumes the Find Included Services sub-procedure. If the last included service has not been + * reached, this must be called again with an updated handle range to continue the search. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_REL_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_REL_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Relationship Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, uint32_t, + sd_ble_gattc_relationships_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Characteristic Discovery procedure. + * + * @details This function initiates or resumes a Characteristic discovery procedure. If the last Characteristic has not been + * reached, this must be called again with an updated handle range to continue the discovery. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_CHAR_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Characteristic Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, uint32_t, + sd_ble_gattc_characteristics_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Characteristic Descriptor Discovery procedure. + * + * @details This function initiates or resumes a Characteristic Descriptor discovery procedure. If the last Descriptor has not + * been reached, this must be called again with an updated handle range to continue the discovery. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_DESC_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_DESC_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Characteristic to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Descriptor Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t, + sd_ble_gattc_descriptors_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Read using Characteristic UUID procedure. + * + * @details This function initiates or resumes a Read using Characteristic UUID procedure. If the last Characteristic has not been + * reached, this must be called again with an updated handle range to continue the discovery. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_READ_UUID_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_uuid Pointer to a Characteristic value UUID to read. + * @param[in] p_handle_range A pointer to the range of handles to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Read using Characteristic UUID procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, uint32_t, + sd_ble_gattc_char_value_by_uuid_read(uint16_t conn_handle, ble_uuid_t const *p_uuid, + ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Read (Long) Characteristic or Descriptor procedure. + * + * @details This function initiates or resumes a GATT Read (Long) Characteristic or Descriptor procedure. If the Characteristic or + * Descriptor to be read is longer than ATT_MTU - 1, this function must be called multiple times with appropriate offset to read + * the complete value. + * + * @events + * @event{@ref BLE_GATTC_EVT_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_VALUE_READ_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] handle The handle of the attribute to be read. + * @param[in] offset Offset into the attribute value to be read. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Read (Long) procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_READ, uint32_t, sd_ble_gattc_read(uint16_t conn_handle, uint16_t handle, uint16_t offset)); + +/**@brief Initiate a GATT Read Multiple Characteristic Values procedure. + * + * @details This function initiates a GATT Read Multiple Characteristic Values procedure. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_READ_MULT_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handles A pointer to the handle(s) of the attribute(s) to be read. + * @param[in] handle_count The number of handles in p_handles. + * + * @retval ::NRF_SUCCESS Successfully started the Read Multiple Characteristic Values procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t, + sd_ble_gattc_char_values_read(uint16_t conn_handle, uint16_t const *p_handles, uint16_t handle_count)); + +/**@brief Perform a Write (Characteristic Value or Descriptor, with or without response, signed or not, long or reliable) + * procedure. + * + * @details This function can perform all write procedures described in GATT. + * + * @note Only one write with response procedure can be ongoing per connection at a time. + * If the application tries to write with response while another write with response procedure is ongoing, + * the function call will return @ref NRF_ERROR_BUSY. + * A @ref BLE_GATTC_EVT_WRITE_RSP event will be issued as soon as the write response arrives from the peer. + * + * @note The number of Write without Response that can be queued is configured by @ref + * ble_gattc_conn_cfg_t::write_cmd_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. + * A @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event will be issued as soon as the transmission of the write without + * response is complete. + * + * @note The application can keep track of the available queue element count for writes without responses by following the + * procedure below: + * - Store initial queue element count in a variable. + * - Decrement the variable, which stores the currently available queue element count, by one when a call to this + * function returns @ref NRF_SUCCESS. + * - Increment the variable, which stores the current available queue element count, by the count variable in @ref + * BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event. + * + * @events + * @event{@ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE, Write without response transmission complete.} + * @event{@ref BLE_GATTC_EVT_WRITE_RSP, Write response received from the peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_VALUE_WRITE_WITHOUT_RESP_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_WRITE_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_LONG_WRITE_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_RELIABLE_WRITE_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_write_params A pointer to a write parameters structure. + * + * @retval ::NRF_SUCCESS Successfully started the Write procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_BUSY For write with response, procedure already in progress. Wait for a @ref BLE_GATTC_EVT_WRITE_RSP event + * and retry. + * @retval ::NRF_ERROR_RESOURCES Too many writes without responses queued. + * Wait for a @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event and retry. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_WRITE, uint32_t, sd_ble_gattc_write(uint16_t conn_handle, ble_gattc_write_params_t const *p_write_params)); + +/**@brief Send a Handle Value Confirmation to the GATT Server. + * + * @mscs + * @mmsc{@ref BLE_GATTC_HVI_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] handle The handle of the attribute in the indication. + * + * @retval ::NRF_SUCCESS Successfully queued the Handle Value Confirmation for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no Indication pending to be confirmed. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_HV_CONFIRM, uint32_t, sd_ble_gattc_hv_confirm(uint16_t conn_handle, uint16_t handle)); + +/**@brief Discovers information about a range of attributes on a GATT server. + * + * @events + * @event{@ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, Generated when information about a range of attributes has been received.} + * @endevents + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range The range of handles to request information about. + * + * @retval ::NRF_SUCCESS Successfully started an attribute information discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t, + sd_ble_gattc_attr_info_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Start an ATT_MTU exchange by sending an Exchange MTU Request to the server. + * + * @details The SoftDevice sets ATT_MTU to the minimum of: + * - The Client RX MTU value, and + * - The Server RX MTU value from @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. + * + * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. + * + * @events + * @event{@ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] client_rx_mtu Client RX MTU size. + * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration + used for this connection. + * - The value must be equal to Server RX MTU size given in @ref sd_ble_gatts_exchange_mtu_reply + * if an ATT_MTU exchange has already been performed in the other direction. + * + * @retval ::NRF_SUCCESS Successfully sent request to the server. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state or an ATT_MTU exchange was already requested once. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid Client RX MTU size supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, uint32_t, + sd_ble_gattc_exchange_mtu_request(uint16_t conn_handle, uint16_t client_rx_mtu)); + +/**@brief Iterate through Handle-Value(s) list in @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. + * + * @param[in] p_gattc_evt Pointer to event buffer containing @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. + * @note If the buffer contains different event, behavior is undefined. + * @param[in,out] p_iter Iterator, points to @ref ble_gattc_handle_value_t structure that will be filled in with + * the next Handle-Value pair in each iteration. If the function returns other than + * @ref NRF_SUCCESS, it will not be changed. + * - To start iteration, initialize the structure to zero. + * - To continue, pass the value from previous iteration. + * + * \code + * ble_gattc_handle_value_t iter; + * memset(&iter, 0, sizeof(ble_gattc_handle_value_t)); + * while (sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(&ble_evt.evt.gattc_evt, &iter) == NRF_SUCCESS) + * { + * app_handle = iter.handle; + * memcpy(app_value, iter.p_value, ble_evt.evt.gattc_evt.params.char_val_by_uuid_read_rsp.value_len); + * } + * \endcode + * + * @retval ::NRF_SUCCESS Successfully retrieved the next Handle-Value pair. + * @retval ::NRF_ERROR_NOT_FOUND No more Handle-Value pairs available in the list. + */ +__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, + ble_gattc_handle_value_t *p_iter); + +/** @} */ + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION + +__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, + ble_gattc_handle_value_t *p_iter) +{ + uint32_t value_len = p_gattc_evt->params.char_val_by_uuid_read_rsp.value_len; + uint8_t *p_first = p_gattc_evt->params.char_val_by_uuid_read_rsp.handle_value; + uint8_t *p_next = p_iter->p_value ? p_iter->p_value + value_len : p_first; + + if ((p_next - p_first) / (sizeof(uint16_t) + value_len) < p_gattc_evt->params.char_val_by_uuid_read_rsp.count) { + p_iter->handle = (uint16_t)p_next[1] << 8 | p_next[0]; + p_iter->p_value = p_next + sizeof(uint16_t); + return NRF_SUCCESS; + } else { + return NRF_ERROR_NOT_FOUND; + } +} + +#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ + +#ifdef __cplusplus +} +#endif +#endif /* BLE_GATTC_H__ */ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gatts.h b/variants/wio-tracker-wm1110/softdevice/ble_gatts.h new file mode 100644 index 0000000000..dc94957cd1 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_gatts.h @@ -0,0 +1,904 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATTS Generic Attribute Profile (GATT) Server + @{ + @brief Definitions and prototypes for the GATTS interface. + */ + +#ifndef BLE_GATTS_H__ +#define BLE_GATTS_H__ + +#include "ble_err.h" +#include "ble_gap.h" +#include "ble_gatt.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATTS_ENUMERATIONS Enumerations + * @{ */ + +/** + * @brief GATTS API SVC numbers. + */ +enum BLE_GATTS_SVCS { + SD_BLE_GATTS_SERVICE_ADD = BLE_GATTS_SVC_BASE, /**< Add a service. */ + SD_BLE_GATTS_INCLUDE_ADD, /**< Add an included service. */ + SD_BLE_GATTS_CHARACTERISTIC_ADD, /**< Add a characteristic. */ + SD_BLE_GATTS_DESCRIPTOR_ADD, /**< Add a generic attribute. */ + SD_BLE_GATTS_VALUE_SET, /**< Set an attribute value. */ + SD_BLE_GATTS_VALUE_GET, /**< Get an attribute value. */ + SD_BLE_GATTS_HVX, /**< Handle Value Notification or Indication. */ + SD_BLE_GATTS_SERVICE_CHANGED, /**< Perform a Service Changed Indication to one or more peers. */ + SD_BLE_GATTS_RW_AUTHORIZE_REPLY, /**< Reply to an authorization request for a read or write operation on one or more + attributes. */ + SD_BLE_GATTS_SYS_ATTR_SET, /**< Set the persistent system attributes for a connection. */ + SD_BLE_GATTS_SYS_ATTR_GET, /**< Retrieve the persistent system attributes. */ + SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, /**< Retrieve the first valid user handle. */ + SD_BLE_GATTS_ATTR_GET, /**< Retrieve the UUID and/or metadata of an attribute. */ + SD_BLE_GATTS_EXCHANGE_MTU_REPLY /**< Reply to Exchange MTU Request. */ +}; + +/** + * @brief GATT Server Event IDs. + */ +enum BLE_GATTS_EVTS { + BLE_GATTS_EVT_WRITE = BLE_GATTS_EVT_BASE, /**< Write operation performed. \n See + @ref ble_gatts_evt_write_t. */ + BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST, /**< Read/Write Authorization request. \n Reply with + @ref sd_ble_gatts_rw_authorize_reply. \n See @ref ble_gatts_evt_rw_authorize_request_t. + */ + BLE_GATTS_EVT_SYS_ATTR_MISSING, /**< A persistent system attribute access is pending. \n Respond with @ref + sd_ble_gatts_sys_attr_set. \n See @ref ble_gatts_evt_sys_attr_missing_t. */ + BLE_GATTS_EVT_HVC, /**< Handle Value Confirmation. \n See @ref ble_gatts_evt_hvc_t. + */ + BLE_GATTS_EVT_SC_CONFIRM, /**< Service Changed Confirmation. \n No additional event + structure applies. */ + BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. \n Reply with + @ref sd_ble_gatts_exchange_mtu_reply. \n See @ref ble_gatts_evt_exchange_mtu_request_t. + */ + BLE_GATTS_EVT_TIMEOUT, /**< Peer failed to respond to an ATT request in time. \n See @ref + ble_gatts_evt_timeout_t. */ + BLE_GATTS_EVT_HVN_TX_COMPLETE /**< Handle Value Notification transmission complete. \n See @ref + ble_gatts_evt_hvn_tx_complete_t. */ +}; + +/**@brief GATTS Configuration IDs. + * + * IDs that uniquely identify a GATTS configuration. + */ +enum BLE_GATTS_CFGS { + BLE_GATTS_CFG_SERVICE_CHANGED = BLE_GATTS_CFG_BASE, /**< Service changed configuration. */ + BLE_GATTS_CFG_ATTR_TAB_SIZE, /**< Attribute table size configuration. */ + BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM, /**< Service changed CCCD permission configuration. */ +}; + +/** @} */ + +/** @addtogroup BLE_GATTS_DEFINES Defines + * @{ */ + +/** @defgroup BLE_ERRORS_GATTS SVC return values specific to GATTS + * @{ */ +#define BLE_ERROR_GATTS_INVALID_ATTR_TYPE (NRF_GATTS_ERR_BASE + 0x000) /**< Invalid attribute type. */ +#define BLE_ERROR_GATTS_SYS_ATTR_MISSING (NRF_GATTS_ERR_BASE + 0x001) /**< System Attributes missing. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_LENS_MAX Maximum attribute lengths + * @{ */ +#define BLE_GATTS_FIX_ATTR_LEN_MAX (510) /**< Maximum length for fixed length Attribute Values. */ +#define BLE_GATTS_VAR_ATTR_LEN_MAX (512) /**< Maximum length for variable length Attribute Values. */ +/** @} */ + +/** @defgroup BLE_GATTS_SRVC_TYPES GATT Server Service Types + * @{ */ +#define BLE_GATTS_SRVC_TYPE_INVALID 0x00 /**< Invalid Service Type. */ +#define BLE_GATTS_SRVC_TYPE_PRIMARY 0x01 /**< Primary Service. */ +#define BLE_GATTS_SRVC_TYPE_SECONDARY 0x02 /**< Secondary Type. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_TYPES GATT Server Attribute Types + * @{ */ +#define BLE_GATTS_ATTR_TYPE_INVALID 0x00 /**< Invalid Attribute Type. */ +#define BLE_GATTS_ATTR_TYPE_PRIM_SRVC_DECL 0x01 /**< Primary Service Declaration. */ +#define BLE_GATTS_ATTR_TYPE_SEC_SRVC_DECL 0x02 /**< Secondary Service Declaration. */ +#define BLE_GATTS_ATTR_TYPE_INC_DECL 0x03 /**< Include Declaration. */ +#define BLE_GATTS_ATTR_TYPE_CHAR_DECL 0x04 /**< Characteristic Declaration. */ +#define BLE_GATTS_ATTR_TYPE_CHAR_VAL 0x05 /**< Characteristic Value. */ +#define BLE_GATTS_ATTR_TYPE_DESC 0x06 /**< Descriptor. */ +#define BLE_GATTS_ATTR_TYPE_OTHER 0x07 /**< Other, non-GATT specific type. */ +/** @} */ + +/** @defgroup BLE_GATTS_OPS GATT Server Operations + * @{ */ +#define BLE_GATTS_OP_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATTS_OP_WRITE_REQ 0x01 /**< Write Request. */ +#define BLE_GATTS_OP_WRITE_CMD 0x02 /**< Write Command. */ +#define BLE_GATTS_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ +#define BLE_GATTS_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ +#define BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL 0x05 /**< Execute Write Request: Cancel all prepared writes. */ +#define BLE_GATTS_OP_EXEC_WRITE_REQ_NOW 0x06 /**< Execute Write Request: Immediately execute all prepared writes. */ +/** @} */ + +/** @defgroup BLE_GATTS_VLOCS GATT Value Locations + * @{ */ +#define BLE_GATTS_VLOC_INVALID 0x00 /**< Invalid Location. */ +#define BLE_GATTS_VLOC_STACK 0x01 /**< Attribute Value is located in stack memory, no user memory is required. */ +#define BLE_GATTS_VLOC_USER \ + 0x02 /**< Attribute Value is located in user memory. This requires the user to maintain a valid buffer through the lifetime \ + of the attribute, since the stack will read and write directly to the memory using the pointer provided in the APIs. \ + There are no alignment requirements for the buffer. */ +/** @} */ + +/** @defgroup BLE_GATTS_AUTHORIZE_TYPES GATT Server Authorization Types + * @{ */ +#define BLE_GATTS_AUTHORIZE_TYPE_INVALID 0x00 /**< Invalid Type. */ +#define BLE_GATTS_AUTHORIZE_TYPE_READ 0x01 /**< Authorize a Read Operation. */ +#define BLE_GATTS_AUTHORIZE_TYPE_WRITE 0x02 /**< Authorize a Write Request Operation. */ +/** @} */ + +/** @defgroup BLE_GATTS_SYS_ATTR_FLAGS System Attribute Flags + * @{ */ +#define BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS (1 << 0) /**< Restrict system attributes to system services only. */ +#define BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS (1 << 1) /**< Restrict system attributes to user services only. */ +/** @} */ + +/** @defgroup BLE_GATTS_SERVICE_CHANGED Service Changed Inclusion Values + * @{ + */ +#define BLE_GATTS_SERVICE_CHANGED_DEFAULT \ + (1) /**< Default is to include the Service Changed characteristic in the Attribute Table. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_TAB_SIZE Attribute Table size + * @{ + */ +#define BLE_GATTS_ATTR_TAB_SIZE_MIN (248) /**< Minimum Attribute Table size */ +#define BLE_GATTS_ATTR_TAB_SIZE_DEFAULT (1408) /**< Default Attribute Table size. */ +/** @} */ + +/** @defgroup BLE_GATTS_DEFAULTS GATT Server defaults + * @{ + */ +#define BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT \ + 1 /**< Default number of Handle Value Notifications that can be queued for transmission. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATTS_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATTS connection configuration parameters, set with @ref sd_ble_cfg_set. + */ +typedef struct { + uint8_t hvn_tx_queue_size; /**< Minimum guaranteed number of Handle Value Notifications that can be queued for transmission. + The default value is @ref BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT */ +} ble_gatts_conn_cfg_t; + +/**@brief Attribute metadata. */ +typedef struct { + ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */ + ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ + uint8_t vlen : 1; /**< Variable length attribute. */ + uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ + uint8_t rd_auth : 1; /**< Read authorization and value will be requested from the application on every read operation. */ + uint8_t wr_auth : 1; /**< Write authorization will be requested from the application on every Write Request operation (but not + Write Command). */ +} ble_gatts_attr_md_t; + +/**@brief GATT Attribute. */ +typedef struct { + ble_uuid_t const *p_uuid; /**< Pointer to the attribute UUID. */ + ble_gatts_attr_md_t const *p_attr_md; /**< Pointer to the attribute metadata structure. */ + uint16_t init_len; /**< Initial attribute value length in bytes. */ + uint16_t init_offs; /**< Initial attribute value offset in bytes. If different from zero, the first init_offs bytes of the + attribute value will be left uninitialized. */ + uint16_t max_len; /**< Maximum attribute value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */ + uint8_t *p_value; /**< Pointer to the attribute data. Please note that if the @ref BLE_GATTS_VLOC_USER value location is + selected in the attribute metadata, this will have to point to a buffer that remains valid through the + lifetime of the attribute. This excludes usage of automatic variables that may go out of scope or any + other temporary location. The stack may access that memory directly without the application's + knowledge. For writable characteristics, this value must not be a location in flash memory.*/ +} ble_gatts_attr_t; + +/**@brief GATT Attribute Value. */ +typedef struct { + uint16_t len; /**< Length in bytes to be written or read. Length in bytes written or read after successful return.*/ + uint16_t offset; /**< Attribute value offset. */ + uint8_t *p_value; /**< Pointer to where value is stored or will be stored. + If value is stored in user memory, only the attribute length is updated when p_value == NULL. + Set to NULL when reading to obtain the complete length of the attribute value */ +} ble_gatts_value_t; + +/**@brief GATT Characteristic Presentation Format. */ +typedef struct { + uint8_t format; /**< Format of the value, see @ref BLE_GATT_CPF_FORMATS. */ + int8_t exponent; /**< Exponent for integer data types. */ + uint16_t unit; /**< Unit from Bluetooth Assigned Numbers. */ + uint8_t name_space; /**< Namespace from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ + uint16_t desc; /**< Namespace description from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ +} ble_gatts_char_pf_t; + +/**@brief GATT Characteristic metadata. */ +typedef struct { + ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ + ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic Extended Properties. */ + uint8_t const * + p_char_user_desc; /**< Pointer to a UTF-8 encoded string (non-NULL terminated), NULL if the descriptor is not required. */ + uint16_t char_user_desc_max_size; /**< The maximum size in bytes of the user description descriptor. */ + uint16_t char_user_desc_size; /**< The size of the user description, must be smaller or equal to char_user_desc_max_size. */ + ble_gatts_char_pf_t const + *p_char_pf; /**< Pointer to a presentation format structure or NULL if the CPF descriptor is not required. */ + ble_gatts_attr_md_t const + *p_user_desc_md; /**< Attribute metadata for the User Description descriptor, or NULL for default values. */ + ble_gatts_attr_md_t const + *p_cccd_md; /**< Attribute metadata for the Client Characteristic Configuration Descriptor, or NULL for default values. */ + ble_gatts_attr_md_t const + *p_sccd_md; /**< Attribute metadata for the Server Characteristic Configuration Descriptor, or NULL for default values. */ +} ble_gatts_char_md_t; + +/**@brief GATT Characteristic Definition Handles. */ +typedef struct { + uint16_t value_handle; /**< Handle to the characteristic value. */ + uint16_t user_desc_handle; /**< Handle to the User Description descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */ + uint16_t cccd_handle; /**< Handle to the Client Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if + not present. */ + uint16_t sccd_handle; /**< Handle to the Server Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if + not present. */ +} ble_gatts_char_handles_t; + +/**@brief GATT HVx parameters. */ +typedef struct { + uint16_t handle; /**< Characteristic Value Handle. */ + uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ + uint16_t offset; /**< Offset within the attribute value. */ + uint16_t *p_len; /**< Length in bytes to be written, length in bytes written after return. */ + uint8_t const *p_data; /**< Actual data content, use NULL to use the current attribute value. */ +} ble_gatts_hvx_params_t; + +/**@brief GATT Authorization parameters. */ +typedef struct { + uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ + uint8_t update : 1; /**< If set, data supplied in p_data will be used to update the attribute value. + Please note that for @ref BLE_GATTS_AUTHORIZE_TYPE_WRITE operations this bit must always be set, + as the data to be written needs to be stored and later provided by the application. */ + uint16_t offset; /**< Offset of the attribute value being updated. */ + uint16_t len; /**< Length in bytes of the value in p_data pointer, see @ref BLE_GATTS_ATTR_LENS_MAX. */ + uint8_t const *p_data; /**< Pointer to new value used to update the attribute value. */ +} ble_gatts_authorize_params_t; + +/**@brief GATT Read or Write Authorize Reply parameters. */ +typedef struct { + uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ + union { + ble_gatts_authorize_params_t read; /**< Read authorization parameters. */ + ble_gatts_authorize_params_t write; /**< Write authorization parameters. */ + } params; /**< Reply Parameters. */ +} ble_gatts_rw_authorize_reply_params_t; + +/**@brief Service Changed Inclusion configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t service_changed : 1; /**< If 1, include the Service Changed characteristic in the Attribute Table. Default is @ref + BLE_GATTS_SERVICE_CHANGED_DEFAULT. */ +} ble_gatts_cfg_service_changed_t; + +/**@brief Service Changed CCCD permission configuration parameters, set with @ref sd_ble_cfg_set. + * + * @note @ref ble_gatts_attr_md_t::vlen is ignored and should be set to 0. + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - @ref ble_gatts_attr_md_t::write_perm is out of range. + * - @ref ble_gatts_attr_md_t::write_perm is @ref BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS, that is + * not allowed by the Bluetooth Specification. + * - wrong @ref ble_gatts_attr_md_t::read_perm, only @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN is + * allowed by the Bluetooth Specification. + * - wrong @ref ble_gatts_attr_md_t::vloc, only @ref BLE_GATTS_VLOC_STACK is allowed. + * @retval ::NRF_ERROR_NOT_SUPPORTED Security Mode 2 not supported + */ +typedef struct { + ble_gatts_attr_md_t + perm; /**< Permission for Service Changed CCCD. Default is @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN, no authorization. */ +} ble_gatts_cfg_service_changed_cccd_perm_t; + +/**@brief Attribute table size configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: + * - The specified Attribute Table size is too small. + * The minimum acceptable size is defined by @ref BLE_GATTS_ATTR_TAB_SIZE_MIN. + * - The specified Attribute Table size is not a multiple of 4. + */ +typedef struct { + uint32_t attr_tab_size; /**< Attribute table size. Default is @ref BLE_GATTS_ATTR_TAB_SIZE_DEFAULT, minimum is @ref + BLE_GATTS_ATTR_TAB_SIZE_MIN. */ +} ble_gatts_cfg_attr_tab_size_t; + +/**@brief Config structure for GATTS configurations. */ +typedef union { + ble_gatts_cfg_service_changed_t + service_changed; /**< Include service changed characteristic, cfg_id is @ref BLE_GATTS_CFG_SERVICE_CHANGED. */ + ble_gatts_cfg_service_changed_cccd_perm_t service_changed_cccd_perm; /**< Service changed CCCD permission, cfg_id is @ref + BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM. */ + ble_gatts_cfg_attr_tab_size_t attr_tab_size; /**< Attribute table size, cfg_id is @ref BLE_GATTS_CFG_ATTR_TAB_SIZE. */ +} ble_gatts_cfg_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_WRITE. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + ble_uuid_t uuid; /**< Attribute UUID. */ + uint8_t op; /**< Type of write operation, see @ref BLE_GATTS_OPS. */ + uint8_t auth_required; /**< Writing operation deferred due to authorization requirement. Application may use @ref + sd_ble_gatts_value_set to finalize the writing operation. */ + uint16_t offset; /**< Offset for the write operation. */ + uint16_t len; /**< Length of the received data. */ + uint8_t data[1]; /**< Received data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gatts_evt_write_t; + +/**@brief Event substructure for authorized read requests, see @ref ble_gatts_evt_rw_authorize_request_t. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + ble_uuid_t uuid; /**< Attribute UUID. */ + uint16_t offset; /**< Offset for the read operation. */ +} ble_gatts_evt_read_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST. */ +typedef struct { + uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ + union { + ble_gatts_evt_read_t read; /**< Attribute Read Parameters. */ + ble_gatts_evt_write_t write; /**< Attribute Write Parameters. */ + } request; /**< Request Parameters. */ +} ble_gatts_evt_rw_authorize_request_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. */ +typedef struct { + uint8_t hint; /**< Hint (currently unused). */ +} ble_gatts_evt_sys_attr_missing_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_HVC. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ +} ble_gatts_evt_hvc_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST. */ +typedef struct { + uint16_t client_rx_mtu; /**< Client RX MTU size. */ +} ble_gatts_evt_exchange_mtu_request_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ +} ble_gatts_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_HVN_TX_COMPLETE. */ +typedef struct { + uint8_t count; /**< Number of notification transmissions completed. */ +} ble_gatts_evt_hvn_tx_complete_t; + +/**@brief GATTS event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which the event occurred. */ + union { + ble_gatts_evt_write_t write; /**< Write Event Parameters. */ + ble_gatts_evt_rw_authorize_request_t authorize_request; /**< Read or Write Authorize Request Parameters. */ + ble_gatts_evt_sys_attr_missing_t sys_attr_missing; /**< System attributes missing. */ + ble_gatts_evt_hvc_t hvc; /**< Handle Value Confirmation Event Parameters. */ + ble_gatts_evt_exchange_mtu_request_t exchange_mtu_request; /**< Exchange MTU Request Event Parameters. */ + ble_gatts_evt_timeout_t timeout; /**< Timeout Event. */ + ble_gatts_evt_hvn_tx_complete_t hvn_tx_complete; /**< Handle Value Notification transmission complete Event Parameters. */ + } params; /**< Event Parameters. */ +} ble_gatts_evt_t; + +/** @} */ + +/** @addtogroup BLE_GATTS_FUNCTIONS Functions + * @{ */ + +/**@brief Add a service declaration to the Attribute Table. + * + * @note Secondary Services are only relevant in the context of the entity that references them, it is therefore forbidden to + * add a secondary service declaration that is not referenced by another service later in the Attribute Table. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] type Toggles between primary and secondary services, see @ref BLE_GATTS_SRVC_TYPES. + * @param[in] p_uuid Pointer to service UUID. + * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a service declaration. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, Vendor Specific UUIDs need to be present in the table. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type, ble_uuid_t const *p_uuid, uint16_t *p_handle)); + +/**@brief Add an include declaration to the Attribute Table. + * + * @note It is currently only possible to add an include declaration to the last added service (i.e. only sequential population is + * supported at this time). + * + * @note The included service must already be present in the Attribute Table prior to this call. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] service_handle Handle of the service where the included service is to be placed, if @ref BLE_GATT_HANDLE_INVALID + * is used, it will be placed sequentially. + * @param[in] inc_srvc_handle Handle of the included service. + * @param[out] p_include_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added an include declaration. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, handle values need to match previously added services. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. + * @retval ::NRF_ERROR_NOT_SUPPORTED Feature is not supported, service_handle must be that of the last added service. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, self inclusions are not allowed. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + */ +SVCALL(SD_BLE_GATTS_INCLUDE_ADD, uint32_t, + sd_ble_gatts_include_add(uint16_t service_handle, uint16_t inc_srvc_handle, uint16_t *p_include_handle)); + +/**@brief Add a characteristic declaration, a characteristic value declaration and optional characteristic descriptor declarations + * to the Attribute Table. + * + * @note It is currently only possible to add a characteristic to the last added service (i.e. only sequential population is + * supported at this time). + * + * @note Several restrictions apply to the parameters, such as matching permissions between the user description descriptor and + * the writable auxiliaries bits, readable (no security) and writable (selectable) CCCDs and SCCDs and valid presentation format + * values. + * + * @note If no metadata is provided for the optional descriptors, their permissions will be derived from the characteristic + * permissions. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] service_handle Handle of the service where the characteristic is to be placed, if @ref BLE_GATT_HANDLE_INVALID is + * used, it will be placed sequentially. + * @param[in] p_char_md Characteristic metadata. + * @param[in] p_attr_char_value Pointer to the attribute structure corresponding to the characteristic value. + * @param[out] p_handles Pointer to the structure where the assigned handles will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a characteristic. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, service handle, Vendor Specific UUIDs, lengths, and + * permissions need to adhere to the constraints. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + */ +SVCALL(SD_BLE_GATTS_CHARACTERISTIC_ADD, uint32_t, + sd_ble_gatts_characteristic_add(uint16_t service_handle, ble_gatts_char_md_t const *p_char_md, + ble_gatts_attr_t const *p_attr_char_value, ble_gatts_char_handles_t *p_handles)); + +/**@brief Add a descriptor to the Attribute Table. + * + * @note It is currently only possible to add a descriptor to the last added characteristic (i.e. only sequential population is + * supported at this time). + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] char_handle Handle of the characteristic where the descriptor is to be placed, if @ref BLE_GATT_HANDLE_INVALID is + * used, it will be placed sequentially. + * @param[in] p_attr Pointer to the attribute structure. + * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a descriptor. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, characteristic handle, Vendor Specific UUIDs, lengths, and + * permissions need to adhere to the constraints. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a characteristic context is required. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + */ +SVCALL(SD_BLE_GATTS_DESCRIPTOR_ADD, uint32_t, + sd_ble_gatts_descriptor_add(uint16_t char_handle, ble_gatts_attr_t const *p_attr, uint16_t *p_handle)); + +/**@brief Set the value of a given attribute. + * + * @note Values other than system attributes can be set at any time, regardless of whether any active connections exist. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. + * @param[in] handle Attribute handle. + * @param[in,out] p_value Attribute value information. + * + * @retval ::NRF_SUCCESS Successfully set the value of the attribute. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden handle supplied, certain attributes are not modifiable by the application. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. + */ +SVCALL(SD_BLE_GATTS_VALUE_SET, uint32_t, + sd_ble_gatts_value_set(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); + +/**@brief Get the value of a given attribute. + * + * @note If the attribute value is longer than the size of the supplied buffer, + * @ref ble_gatts_value_t::len will return the total attribute value length (excluding offset), + * and not the number of bytes actually returned in @ref ble_gatts_value_t::p_value. + * The application may use this information to allocate a suitable buffer size. + * + * @note When retrieving system attribute values with this function, the connection handle + * may refer to an already disconnected connection. Refer to the documentation of + * @ref sd_ble_gatts_sys_attr_get for further information. + * + * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. + * @param[in] handle Attribute handle. + * @param[in,out] p_value Attribute value information. + * + * @retval ::NRF_SUCCESS Successfully retrieved the value of the attribute. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid attribute offset supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + */ +SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, + sd_ble_gatts_value_get(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); + +/**@brief Notify or Indicate an attribute value. + * + * @details This function checks for the relevant Client Characteristic Configuration descriptor value to verify that the relevant + * operation (notification or indication) has been enabled by the client. It is also able to update the attribute value before + * issuing the PDU, so that the application can atomically perform a value update and a server initiated transaction with a single + * API call. + * + * @note The local attribute value may be updated even if an outgoing packet is not sent to the peer due to an error during + * execution. The Attribute Table has been updated if one of the following error codes is returned: @ref NRF_ERROR_INVALID_STATE, + * @ref NRF_ERROR_BUSY, + * @ref NRF_ERROR_FORBIDDEN, @ref BLE_ERROR_GATTS_SYS_ATTR_MISSING and @ref NRF_ERROR_RESOURCES. + * The caller can check whether the value has been updated by looking at the contents of *(@ref + * ble_gatts_hvx_params_t::p_len). + * + * @note Only one indication procedure can be ongoing per connection at a time. + * If the application tries to indicate an attribute value while another indication procedure is ongoing, + * the function call will return @ref NRF_ERROR_BUSY. + * A @ref BLE_GATTS_EVT_HVC event will be issued as soon as the confirmation arrives from the peer. + * + * @note The number of Handle Value Notifications that can be queued is configured by @ref + * ble_gatts_conn_cfg_t::hvn_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. A @ref + * BLE_GATTS_EVT_HVN_TX_COMPLETE event will be issued as soon as the transmission of the notification is complete. + * + * @note The application can keep track of the available queue element count for notifications by following the procedure + * below: + * - Store initial queue element count in a variable. + * - Decrement the variable, which stores the currently available queue element count, by one when a call to this + * function returns @ref NRF_SUCCESS. + * - Increment the variable, which stores the current available queue element count, by the count variable in @ref + * BLE_GATTS_EVT_HVN_TX_COMPLETE event. + * + * @events + * @event{@ref BLE_GATTS_EVT_HVN_TX_COMPLETE, Notification transmission complete.} + * @event{@ref BLE_GATTS_EVT_HVC, Confirmation received from the peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} + * @mmsc{@ref BLE_GATTS_HVN_MSC} + * @mmsc{@ref BLE_GATTS_HVI_MSC} + * @mmsc{@ref BLE_GATTS_HVX_DISABLED_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in,out] p_hvx_params Pointer to an HVx parameters structure. If @ref ble_gatts_hvx_params_t::p_data + * contains a non-NULL pointer the attribute value will be updated with the contents + * pointed by it before sending the notification or indication. If the attribute value + * is updated, @ref ble_gatts_hvx_params_t::p_len is updated by the SoftDevice to + * contain the number of actual bytes written, else it will be set to 0. + * + * @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute + * value. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: + * - Invalid Connection State + * - Notifications and/or indications not enabled in the CCCD + * - An ATT_MTU exchange is ongoing + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application + * are available to notify and indicate. + * @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and + * indicated. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_FORBIDDEN The connection's current security level is lower than the one required by the write permissions + * of the CCCD associated with this characteristic. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC + * event and retry. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + * @retval ::NRF_ERROR_RESOURCES Too many notifications queued. + * Wait for a @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event and retry. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_gatts_hvx_params_t const *p_hvx_params)); + +/**@brief Indicate the Service Changed attribute value. + * + * @details This call will send a Handle Value Indication to one or more peers connected to inform them that the Attribute + * Table layout has changed. As soon as the peer has confirmed the indication, a @ref BLE_GATTS_EVT_SC_CONFIRM event will + * be issued. + * + * @note Some of the restrictions and limitations that apply to @ref sd_ble_gatts_hvx also apply here. + * + * @events + * @event{@ref BLE_GATTS_EVT_SC_CONFIRM, Confirmation of attribute table change received from peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTS_SC_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] start_handle Start of affected attribute handle range. + * @param[in] end_handle End of affected attribute handle range. + * + * @retval ::NRF_SUCCESS Successfully queued the Service Changed indication for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_NOT_SUPPORTED Service Changed not enabled at initialization. See @ref + * sd_ble_cfg_set and @ref ble_gatts_cfg_service_changed_t. + * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: + * - Invalid Connection State + * - Notifications and/or indications not enabled in the CCCD + * - An ATT_MTU exchange is ongoing + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied, handles must be in the range populated by the + * application. + * @retval ::NRF_ERROR_BUSY Procedure already in progress. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t, + sd_ble_gatts_service_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle)); + +/**@brief Respond to a Read/Write authorization request. + * + * @note This call should only be used as a response to a @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event issued to the application. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_READ_REQ_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_WRITE_REQ_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_rw_authorize_reply_params Pointer to a structure with the attribute provided by the application. + * + * @note @ref ble_gatts_authorize_params_t::p_data is ignored when this function is used to respond + * to a @ref BLE_GATTS_AUTHORIZE_TYPE_READ event if @ref ble_gatts_authorize_params_t::update + * is set to 0. + * + * @retval ::NRF_SUCCESS Successfully queued a response to the peer, and in the case of a write operation, Attribute + * Table updated. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no authorization request pending. + * @retval ::NRF_ERROR_INVALID_PARAM Authorization op invalid, + * handle supplied does not match requested handle, + * or invalid data to be written provided by the application. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_RW_AUTHORIZE_REPLY, uint32_t, + sd_ble_gatts_rw_authorize_reply(uint16_t conn_handle, + ble_gatts_rw_authorize_reply_params_t const *p_rw_authorize_reply_params)); + +/**@brief Update persistent system attribute information. + * + * @details Supply information about persistent system attributes to the stack, + * previously obtained using @ref sd_ble_gatts_sys_attr_get. + * This call is only allowed for active connections, and is usually + * made immediately after a connection is established with an known bonded device, + * often as a response to a @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. + * + * p_sysattrs may point directly to the application's stored copy of the system attributes + * obtained using @ref sd_ble_gatts_sys_attr_get. + * If the pointer is NULL, the system attribute info is initialized, assuming that + * the application does not have any previously saved system attribute data for this device. + * + * @note The state of persistent system attributes is reset upon connection establishment and then remembered for its duration. + * + * @note If this call returns with an error code different from @ref NRF_SUCCESS, the storage of persistent system attributes may + * have been completed only partially. This means that the state of the attribute table is undefined, and the application should + * either provide a new set of attributes using this same call or reset the SoftDevice to return to a known state. + * + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system + * services will be modified. + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user + * services will be modified. + * + * @mscs + * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_UNK_PEER_MSC} + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_sys_attr_data Pointer to a saved copy of system attributes supplied to the stack, or NULL. + * @param[in] len Size of data pointed by p_sys_attr_data, in octets. + * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS + * + * @retval ::NRF_SUCCESS Successfully set the system attribute information. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. + * @retval ::NRF_ERROR_INVALID_DATA Invalid data supplied, the data should be exactly the same as retrieved with @ref + * sd_ble_gatts_sys_attr_get. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GATTS_SYS_ATTR_SET, uint32_t, + sd_ble_gatts_sys_attr_set(uint16_t conn_handle, uint8_t const *p_sys_attr_data, uint16_t len, uint32_t flags)); + +/**@brief Retrieve persistent system attribute information from the stack. + * + * @details This call is used to retrieve information about values to be stored persistently by the application + * during the lifetime of a connection or after it has been terminated. When a new connection is established with the + * same bonded device, the system attribute information retrieved with this function should be restored using using @ref + * sd_ble_gatts_sys_attr_set. If retrieved after disconnection, the data should be read before a new connection established. The + * connection handle for the previous, now disconnected, connection will remain valid until a new one is created to allow this API + * call to refer to it. Connection handles belonging to active connections can be used as well, but care should be taken since the + * system attributes may be written to at any time by the peer during a connection's lifetime. + * + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system + * services will be returned. + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user + * services will be returned. + * + * @mscs + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle of the recently terminated connection. + * @param[out] p_sys_attr_data Pointer to a buffer where updated information about system attributes will be filled in. The + * format of the data is described in @ref BLE_GATTS_SYS_ATTRS_FORMAT. NULL can be provided to obtain the length of the data. + * @param[in,out] p_len Size of application buffer if p_sys_attr_data is not NULL. Unconditionally updated to actual + * length of system attribute data. + * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS + * + * @retval ::NRF_SUCCESS Successfully retrieved the system attribute information. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. + * @retval ::NRF_ERROR_DATA_SIZE The system attribute information did not fit into the provided buffer. + * @retval ::NRF_ERROR_NOT_FOUND No system attributes found. + */ +SVCALL(SD_BLE_GATTS_SYS_ATTR_GET, uint32_t, + sd_ble_gatts_sys_attr_get(uint16_t conn_handle, uint8_t *p_sys_attr_data, uint16_t *p_len, uint32_t flags)); + +/**@brief Retrieve the first valid user attribute handle. + * + * @param[out] p_handle Pointer to an integer where the handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully retrieved the handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, uint32_t, sd_ble_gatts_initial_user_handle_get(uint16_t *p_handle)); + +/**@brief Retrieve the attribute UUID and/or metadata. + * + * @param[in] handle Attribute handle + * @param[out] p_uuid UUID of the attribute. Use NULL to omit this field. + * @param[out] p_md Metadata of the attribute. Use NULL to omit this field. + * + * @retval ::NRF_SUCCESS Successfully retrieved the attribute metadata, + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. Returned when both @c p_uuid and @c p_md are NULL. + * @retval ::NRF_ERROR_NOT_FOUND Attribute was not found. + */ +SVCALL(SD_BLE_GATTS_ATTR_GET, uint32_t, sd_ble_gatts_attr_get(uint16_t handle, ble_uuid_t *p_uuid, ble_gatts_attr_md_t *p_md)); + +/**@brief Reply to an ATT_MTU exchange request by sending an Exchange MTU Response to the client. + * + * @details This function is only used to reply to a @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event. + * + * @details The SoftDevice sets ATT_MTU to the minimum of: + * - The Client RX MTU value from @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, and + * - The Server RX MTU value. + * + * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. + * + * @mscs + * @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] server_rx_mtu Server RX MTU size. + * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration + * used for this connection. + * - The value must be equal to Client RX MTU size given in @ref sd_ble_gattc_exchange_mtu_request + * if an ATT_MTU exchange has already been performed in the other direction. + * + * @retval ::NRF_SUCCESS Successfully sent response to the client. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no ATT_MTU exchange request pending. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid Server RX MTU size supplied. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_EXCHANGE_MTU_REPLY, uint32_t, sd_ble_gatts_exchange_mtu_reply(uint16_t conn_handle, uint16_t server_rx_mtu)); +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GATTS_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_hci.h b/variants/wio-tracker-wm1110/softdevice/ble_hci.h new file mode 100644 index 0000000000..27f85d52ea --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_hci.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ +*/ + +#ifndef BLE_HCI_H__ +#define BLE_HCI_H__ +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup BLE_HCI_STATUS_CODES Bluetooth status codes + * @{ */ + +#define BLE_HCI_STATUS_CODE_SUCCESS 0x00 /**< Success. */ +#define BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND 0x01 /**< Unknown BLE Command. */ +#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02 /**< Unknown Connection Identifier. */ +/*0x03 Hardware Failure +0x04 Page Timeout +*/ +#define BLE_HCI_AUTHENTICATION_FAILURE 0x05 /**< Authentication Failure. */ +#define BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING 0x06 /**< Pin or Key missing. */ +#define BLE_HCI_MEMORY_CAPACITY_EXCEEDED 0x07 /**< Memory Capacity Exceeded. */ +#define BLE_HCI_CONNECTION_TIMEOUT 0x08 /**< Connection Timeout. */ +/*0x09 Connection Limit Exceeded +0x0A Synchronous Connection Limit To A Device Exceeded +0x0B ACL Connection Already Exists*/ +#define BLE_HCI_STATUS_CODE_COMMAND_DISALLOWED 0x0C /**< Command Disallowed. */ +/*0x0D Connection Rejected due to Limited Resources +0x0E Connection Rejected Due To Security Reasons +0x0F Connection Rejected due to Unacceptable BD_ADDR +0x10 Connection Accept Timeout Exceeded +0x11 Unsupported Feature or Parameter Value*/ +#define BLE_HCI_STATUS_CODE_INVALID_BTLE_COMMAND_PARAMETERS 0x12 /**< Invalid BLE Command Parameters. */ +#define BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION 0x13 /**< Remote User Terminated Connection. */ +#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES \ + 0x14 /**< Remote Device Terminated Connection due to low \ + resources.*/ +#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF 0x15 /**< Remote Device Terminated Connection due to power off. */ +#define BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION 0x16 /**< Local Host Terminated Connection. */ +/* +0x17 Repeated Attempts +0x18 Pairing Not Allowed +0x19 Unknown LMP PDU +*/ +#define BLE_HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A /**< Unsupported Remote Feature. */ +/* +0x1B SCO Offset Rejected +0x1C SCO Interval Rejected +0x1D SCO Air Mode Rejected*/ +#define BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS 0x1E /**< Invalid LMP Parameters. */ +#define BLE_HCI_STATUS_CODE_UNSPECIFIED_ERROR 0x1F /**< Unspecified Error. */ +/*0x20 Unsupported LMP Parameter Value +0x21 Role Change Not Allowed +*/ +#define BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT 0x22 /**< LMP Response Timeout. */ +#define BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION 0x23 /**< LMP Error Transaction Collision/LL Procedure Collision. */ +#define BLE_HCI_STATUS_CODE_LMP_PDU_NOT_ALLOWED 0x24 /**< LMP PDU Not Allowed. */ +/*0x25 Encryption Mode Not Acceptable +0x26 Link Key Can Not be Changed +0x27 Requested QoS Not Supported +*/ +#define BLE_HCI_INSTANT_PASSED 0x28 /**< Instant Passed. */ +#define BLE_HCI_PAIRING_WITH_UNIT_KEY_UNSUPPORTED 0x29 /**< Pairing with Unit Key Unsupported. */ +#define BLE_HCI_DIFFERENT_TRANSACTION_COLLISION 0x2A /**< Different Transaction Collision. */ +/* +0x2B Reserved +0x2C QoS Unacceptable Parameter +0x2D QoS Rejected +0x2E Channel Classification Not Supported +0x2F Insufficient Security +*/ +#define BLE_HCI_PARAMETER_OUT_OF_MANDATORY_RANGE 0x30 /**< Parameter Out Of Mandatory Range. */ +/* +0x31 Reserved +0x32 Role Switch Pending +0x33 Reserved +0x34 Reserved Slot Violation +0x35 Role Switch Failed +0x36 Extended Inquiry Response Too Large +0x37 Secure Simple Pairing Not Supported By Host. +0x38 Host Busy - Pairing +0x39 Connection Rejected due to No Suitable Channel Found*/ +#define BLE_HCI_CONTROLLER_BUSY 0x3A /**< Controller Busy. */ +#define BLE_HCI_CONN_INTERVAL_UNACCEPTABLE 0x3B /**< Connection Interval Unacceptable. */ +#define BLE_HCI_DIRECTED_ADVERTISER_TIMEOUT 0x3C /**< Directed Advertisement Timeout. */ +#define BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE 0x3D /**< Connection Terminated due to MIC Failure. */ +#define BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED 0x3E /**< Connection Failed to be Established. */ + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_HCI_H__ + +/** @} */ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h b/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h new file mode 100644 index 0000000000..5f4bd277d3 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h @@ -0,0 +1,495 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_L2CAP Logical Link Control and Adaptation Protocol (L2CAP) + @{ + @brief Definitions and prototypes for the L2CAP interface. + */ + +#ifndef BLE_L2CAP_H__ +#define BLE_L2CAP_H__ + +#include "ble_err.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup BLE_L2CAP_TERMINOLOGY Terminology + * @{ + * @details + * + * L2CAP SDU + * - A data unit that the application can send/receive to/from a peer. + * + * L2CAP PDU + * - A data unit that is exchanged between local and remote L2CAP entities. + * It consists of L2CAP protocol control information and payload fields. + * The payload field can contain an L2CAP SDU or a part of an L2CAP SDU. + * + * L2CAP MTU + * - The maximum length of an L2CAP SDU. + * + * L2CAP MPS + * - The maximum length of an L2CAP PDU payload field. + * + * Credits + * - A value indicating the number of L2CAP PDUs that the receiver of the credit can send to the peer. + * @} */ + +/**@addtogroup BLE_L2CAP_ENUMERATIONS Enumerations + * @{ */ + +/**@brief L2CAP API SVC numbers. */ +enum BLE_L2CAP_SVCS { + SD_BLE_L2CAP_CH_SETUP = BLE_L2CAP_SVC_BASE + 0, /**< Set up an L2CAP channel. */ + SD_BLE_L2CAP_CH_RELEASE = BLE_L2CAP_SVC_BASE + 1, /**< Release an L2CAP channel. */ + SD_BLE_L2CAP_CH_RX = BLE_L2CAP_SVC_BASE + 2, /**< Receive an SDU on an L2CAP channel. */ + SD_BLE_L2CAP_CH_TX = BLE_L2CAP_SVC_BASE + 3, /**< Transmit an SDU on an L2CAP channel. */ + SD_BLE_L2CAP_CH_FLOW_CONTROL = BLE_L2CAP_SVC_BASE + 4, /**< Advanced SDU reception flow control. */ +}; + +/**@brief L2CAP Event IDs. */ +enum BLE_L2CAP_EVTS { + BLE_L2CAP_EVT_CH_SETUP_REQUEST = BLE_L2CAP_EVT_BASE + 0, /**< L2CAP Channel Setup Request event. + \n Reply with @ref sd_ble_l2cap_ch_setup. + \n See @ref ble_l2cap_evt_ch_setup_request_t. */ + BLE_L2CAP_EVT_CH_SETUP_REFUSED = BLE_L2CAP_EVT_BASE + 1, /**< L2CAP Channel Setup Refused event. + \n See @ref ble_l2cap_evt_ch_setup_refused_t. */ + BLE_L2CAP_EVT_CH_SETUP = BLE_L2CAP_EVT_BASE + 2, /**< L2CAP Channel Setup Completed event. + \n See @ref ble_l2cap_evt_ch_setup_t. */ + BLE_L2CAP_EVT_CH_RELEASED = BLE_L2CAP_EVT_BASE + 3, /**< L2CAP Channel Released event. + \n No additional event structure applies. */ + BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED = BLE_L2CAP_EVT_BASE + 4, /**< L2CAP Channel SDU data buffer released event. + \n See @ref ble_l2cap_evt_ch_sdu_buf_released_t. */ + BLE_L2CAP_EVT_CH_CREDIT = BLE_L2CAP_EVT_BASE + 5, /**< L2CAP Channel Credit received. + \n See @ref ble_l2cap_evt_ch_credit_t. */ + BLE_L2CAP_EVT_CH_RX = BLE_L2CAP_EVT_BASE + 6, /**< L2CAP Channel SDU received. + \n See @ref ble_l2cap_evt_ch_rx_t. */ + BLE_L2CAP_EVT_CH_TX = BLE_L2CAP_EVT_BASE + 7, /**< L2CAP Channel SDU transmitted. + \n See @ref ble_l2cap_evt_ch_tx_t. */ +}; + +/** @} */ + +/**@addtogroup BLE_L2CAP_DEFINES Defines + * @{ */ + +/**@brief Maximum number of L2CAP channels per connection. */ +#define BLE_L2CAP_CH_COUNT_MAX (64) + +/**@brief Minimum L2CAP MTU, in bytes. */ +#define BLE_L2CAP_MTU_MIN (23) + +/**@brief Minimum L2CAP MPS, in bytes. */ +#define BLE_L2CAP_MPS_MIN (23) + +/**@brief Invalid CID. */ +#define BLE_L2CAP_CID_INVALID (0x0000) + +/**@brief Default number of credits for @ref sd_ble_l2cap_ch_flow_control. */ +#define BLE_L2CAP_CREDITS_DEFAULT (1) + +/**@defgroup BLE_L2CAP_CH_SETUP_REFUSED_SRCS L2CAP channel setup refused sources + * @{ */ +#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_LOCAL (0x01) /**< Local. */ +#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_REMOTE (0x02) /**< Remote. */ + /** @} */ + +/** @defgroup BLE_L2CAP_CH_STATUS_CODES L2CAP channel status codes + * @{ */ +#define BLE_L2CAP_CH_STATUS_CODE_SUCCESS (0x0000) /**< Success. */ +#define BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED (0x0002) /**< LE_PSM not supported. */ +#define BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES (0x0004) /**< No resources available. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHENTICATION (0x0005) /**< Insufficient authentication. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHORIZATION (0x0006) /**< Insufficient authorization. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC_KEY_SIZE (0x0007) /**< Insufficient encryption key size. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC (0x0008) /**< Insufficient encryption. */ +#define BLE_L2CAP_CH_STATUS_CODE_INVALID_SCID (0x0009) /**< Invalid Source CID. */ +#define BLE_L2CAP_CH_STATUS_CODE_SCID_ALLOCATED (0x000A) /**< Source CID already allocated. */ +#define BLE_L2CAP_CH_STATUS_CODE_UNACCEPTABLE_PARAMS (0x000B) /**< Unacceptable parameters. */ +#define BLE_L2CAP_CH_STATUS_CODE_NOT_UNDERSTOOD \ + (0x8000) /**< Command Reject received instead of LE Credit Based Connection Response. */ +#define BLE_L2CAP_CH_STATUS_CODE_TIMEOUT (0xC000) /**< Operation timed out. */ +/** @} */ + +/** @} */ + +/**@addtogroup BLE_L2CAP_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE L2CAP connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @note These parameters are set per connection, so all L2CAP channels created on this connection + * will have the same parameters. + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - rx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. + * - tx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. + * - ch_count is greater than @ref BLE_L2CAP_CH_COUNT_MAX. + * @retval ::NRF_ERROR_NO_MEM rx_mps or tx_mps is set too high. + */ +typedef struct { + uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall + be able to receive on L2CAP channels on connections with this + configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ + uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall + be able to transmit on L2CAP channels on connections with this + configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ + uint8_t rx_queue_size; /**< Number of SDU data buffers that can be queued for reception per + L2CAP channel. The minimum value is one. */ + uint8_t tx_queue_size; /**< Number of SDU data buffers that can be queued for transmission + per L2CAP channel. The minimum value is one. */ + uint8_t ch_count; /**< Number of L2CAP channels the application can create per connection + with this configuration. The default value is zero, the maximum + value is @ref BLE_L2CAP_CH_COUNT_MAX. + @note if this parameter is set to zero, all other parameters in + @ref ble_l2cap_conn_cfg_t are ignored. */ +} ble_l2cap_conn_cfg_t; + +/**@brief L2CAP channel RX parameters. */ +typedef struct { + uint16_t rx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP shall be able to + receive on this L2CAP channel. + - Must be equal to or greater than @ref BLE_L2CAP_MTU_MIN. */ + uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall be + able to receive on this L2CAP channel. + - Must be equal to or greater than @ref BLE_L2CAP_MPS_MIN. + - Must be equal to or less than @ref ble_l2cap_conn_cfg_t::rx_mps. */ + ble_data_t sdu_buf; /**< SDU data buffer for reception. + - If @ref ble_data_t::p_data is non-NULL, initial credits are + issued to the peer. + - If @ref ble_data_t::p_data is NULL, no initial credits are + issued to the peer. */ +} ble_l2cap_ch_rx_params_t; + +/**@brief L2CAP channel setup parameters. */ +typedef struct { + ble_l2cap_ch_rx_params_t rx_params; /**< L2CAP channel RX parameters. */ + uint16_t le_psm; /**< LE Protocol/Service Multiplexer. Used when requesting + setup of an L2CAP channel, ignored otherwise. */ + uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES. + Used when replying to a setup request of an L2CAP + channel, ignored otherwise. */ +} ble_l2cap_ch_setup_params_t; + +/**@brief L2CAP channel TX parameters. */ +typedef struct { + uint16_t tx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP is able to + transmit on this L2CAP channel. */ + uint16_t peer_mps; /**< The maximum L2CAP PDU payload size, in bytes, that the peer is + able to receive on this L2CAP channel. */ + uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP is able + to transmit on this L2CAP channel. This is effective tx_mps, + selected by the SoftDevice as + MIN( @ref ble_l2cap_ch_tx_params_t::peer_mps, @ref ble_l2cap_conn_cfg_t::tx_mps ) */ + uint16_t credits; /**< Initial credits given by the peer. */ +} ble_l2cap_ch_tx_params_t; + +/**@brief L2CAP Channel Setup Request event. */ +typedef struct { + ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ + uint16_t le_psm; /**< LE Protocol/Service Multiplexer. */ +} ble_l2cap_evt_ch_setup_request_t; + +/**@brief L2CAP Channel Setup Refused event. */ +typedef struct { + uint8_t source; /**< Source, see @ref BLE_L2CAP_CH_SETUP_REFUSED_SRCS */ + uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES */ +} ble_l2cap_evt_ch_setup_refused_t; + +/**@brief L2CAP Channel Setup Completed event. */ +typedef struct { + ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ +} ble_l2cap_evt_ch_setup_t; + +/**@brief L2CAP Channel SDU Data Buffer Released event. */ +typedef struct { + ble_data_t sdu_buf; /**< Returned reception or transmission SDU data buffer. The SoftDevice + returns SDU data buffers supplied by the application, which have + not yet been returned previously via a @ref BLE_L2CAP_EVT_CH_RX or + @ref BLE_L2CAP_EVT_CH_TX event. */ +} ble_l2cap_evt_ch_sdu_buf_released_t; + +/**@brief L2CAP Channel Credit received event. */ +typedef struct { + uint16_t credits; /**< Additional credits given by the peer. */ +} ble_l2cap_evt_ch_credit_t; + +/**@brief L2CAP Channel received SDU event. */ +typedef struct { + uint16_t sdu_len; /**< Total SDU length, in bytes. */ + ble_data_t sdu_buf; /**< SDU data buffer. + @note If there is not enough space in the buffer + (sdu_buf.len < sdu_len) then the rest of the SDU will be + silently discarded by the SoftDevice. */ +} ble_l2cap_evt_ch_rx_t; + +/**@brief L2CAP Channel transmitted SDU event. */ +typedef struct { + ble_data_t sdu_buf; /**< SDU data buffer. */ +} ble_l2cap_evt_ch_tx_t; + +/**@brief L2CAP event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which the event occured. */ + uint16_t local_cid; /**< Local Channel ID of the L2CAP channel, or + @ref BLE_L2CAP_CID_INVALID if not present. */ + union { + ble_l2cap_evt_ch_setup_request_t ch_setup_request; /**< L2CAP Channel Setup Request Event Parameters. */ + ble_l2cap_evt_ch_setup_refused_t ch_setup_refused; /**< L2CAP Channel Setup Refused Event Parameters. */ + ble_l2cap_evt_ch_setup_t ch_setup; /**< L2CAP Channel Setup Completed Event Parameters. */ + ble_l2cap_evt_ch_sdu_buf_released_t ch_sdu_buf_released; /**< L2CAP Channel SDU Data Buffer Released Event Parameters. */ + ble_l2cap_evt_ch_credit_t credit; /**< L2CAP Channel Credit Received Event Parameters. */ + ble_l2cap_evt_ch_rx_t rx; /**< L2CAP Channel SDU Received Event Parameters. */ + ble_l2cap_evt_ch_tx_t tx; /**< L2CAP Channel SDU Transmitted Event Parameters. */ + } params; /**< Event Parameters. */ +} ble_l2cap_evt_t; + +/** @} */ + +/**@addtogroup BLE_L2CAP_FUNCTIONS Functions + * @{ */ + +/**@brief Set up an L2CAP channel. + * + * @details This function is used to: + * - Request setup of an L2CAP channel: sends an LE Credit Based Connection Request packet to a peer. + * - Reply to a setup request of an L2CAP channel (if called in response to a + * @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST event): sends an LE Credit Based Connection + * Response packet to a peer. + * + * @note A call to this function will require the application to keep the SDU data buffer alive + * until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX or + * @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_SETUP, Setup successful.} + * @event{@ref BLE_L2CAP_EVT_CH_SETUP_REFUSED, Setup failed.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_SETUP_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in,out] p_local_cid Pointer to a uint16_t containing Local Channel ID of the L2CAP channel: + * - As input: @ref BLE_L2CAP_CID_INVALID when requesting setup of an L2CAP + * channel or local_cid provided in the @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST + * event when replying to a setup request of an L2CAP channel. + * - As output: local_cid for this channel. + * @param[in] p_params L2CAP channel parameters. + * + * @retval ::NRF_SUCCESS Successfully queued request or response for transmission. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_LENGTH Supplied higher rx_mps than has been configured on this link. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (L2CAP channel already set up). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_RESOURCES The limit has been reached for available L2CAP channels, + * see @ref ble_l2cap_conn_cfg_t::ch_count. + */ +SVCALL(SD_BLE_L2CAP_CH_SETUP, uint32_t, + sd_ble_l2cap_ch_setup(uint16_t conn_handle, uint16_t *p_local_cid, ble_l2cap_ch_setup_params_t const *p_params)); + +/**@brief Release an L2CAP channel. + * + * @details This sends a Disconnection Request packet to a peer. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_RELEASED, Release complete.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_RELEASE_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * + * @retval ::NRF_SUCCESS Successfully queued request for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for the L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + */ +SVCALL(SD_BLE_L2CAP_CH_RELEASE, uint32_t, sd_ble_l2cap_ch_release(uint16_t conn_handle, uint16_t local_cid)); + +/**@brief Receive an SDU on an L2CAP channel. + * + * @details This may issue additional credits to the peer using an LE Flow Control Credit packet. + * + * @note A call to this function will require the application to keep the memory pointed by + * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX + * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::rx_queue_size SDU data buffers + * for reception per L2CAP channel. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_RX, The SDU is received.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_RX_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * @param[in] p_sdu_buf Pointer to the SDU data buffer. + * + * @retval ::NRF_SUCCESS Buffer accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for an L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_RESOURCES Too many SDU data buffers supplied. Wait for a + * @ref BLE_L2CAP_EVT_CH_RX event and retry. + */ +SVCALL(SD_BLE_L2CAP_CH_RX, uint32_t, sd_ble_l2cap_ch_rx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); + +/**@brief Transmit an SDU on an L2CAP channel. + * + * @note A call to this function will require the application to keep the memory pointed by + * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_TX + * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::tx_queue_size SDUs for + * transmission per L2CAP channel. + * + * @note The application can keep track of the available credits for transmission by following + * the procedure below: + * - Store initial credits given by the peer in a variable. + * (Initial credits are provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) + * - Decrement the variable, which stores the currently available credits, by + * ceiling((@ref ble_data_t::len + 2) / tx_mps) when a call to this function returns + * @ref NRF_SUCCESS. (tx_mps is provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) + * - Increment the variable, which stores the currently available credits, by additional + * credits given by the peer in a @ref BLE_L2CAP_EVT_CH_CREDIT event. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_TX, The SDU is transmitted.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_TX_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * @param[in] p_sdu_buf Pointer to the SDU data buffer. + * + * @retval ::NRF_SUCCESS Successfully queued L2CAP SDU for transmission. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for the L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_DATA_SIZE Invalid SDU length supplied, must not be more than + * @ref ble_l2cap_ch_tx_params_t::tx_mtu provided in + * @ref BLE_L2CAP_EVT_CH_SETUP event. + * @retval ::NRF_ERROR_RESOURCES Too many SDUs queued for transmission. Wait for a + * @ref BLE_L2CAP_EVT_CH_TX event and retry. + */ +SVCALL(SD_BLE_L2CAP_CH_TX, uint32_t, sd_ble_l2cap_ch_tx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); + +/**@brief Advanced SDU reception flow control. + * + * @details Adjust the way the SoftDevice issues credits to the peer. + * This may issue additional credits to the peer using an LE Flow Control Credit packet. + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_FLOW_CONTROL_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel or @ref BLE_L2CAP_CID_INVALID to set + * the value that will be used for newly created channels. + * @param[in] credits Number of credits that the SoftDevice will make sure the peer has every + * time it starts using a new reception buffer. + * - @ref BLE_L2CAP_CREDITS_DEFAULT is the default value the SoftDevice will + * use if this function is not called. + * - If set to zero, the SoftDevice will stop issuing credits for new reception + * buffers the application provides or has provided. SDU reception that is + * currently ongoing will be allowed to complete. + * @param[out] p_credits NULL or pointer to a uint16_t. If a valid pointer is provided, it will be + * written by the SoftDevice with the number of credits that is or will be + * available to the peer. If the value written by the SoftDevice is 0 when + * credits parameter was set to 0, the peer will not be able to send more + * data until more credits are provided by calling this function again with + * credits > 0. This parameter is ignored when local_cid is set to + * @ref BLE_L2CAP_CID_INVALID. + * + * @note Application should take care when setting number of credits higher than default value. In + * this case the application must make sure that the SoftDevice always has reception buffers + * available (see @ref sd_ble_l2cap_ch_rx) for that channel. If the SoftDevice does not have + * such buffers available, packets may be NACKed on the Link Layer and all Bluetooth traffic + * on the connection handle may be stalled until the SoftDevice again has an available + * reception buffer. This applies even if the application has used this call to set the + * credits back to default, or zero. + * + * @retval ::NRF_SUCCESS Flow control parameters accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for an L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + */ +SVCALL(SD_BLE_L2CAP_CH_FLOW_CONTROL, uint32_t, + sd_ble_l2cap_ch_flow_control(uint16_t conn_handle, uint16_t local_cid, uint16_t credits, uint16_t *p_credits)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_L2CAP_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_ranges.h b/variants/wio-tracker-wm1110/softdevice/ble_ranges.h new file mode 100644 index 0000000000..2768e49967 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_ranges.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @defgroup ble_ranges Module specific SVC, event and option number subranges + @{ + + @brief Definition of SVC, event and option number subranges for each API module. + + @note + SVCs, event and option numbers are split into subranges for each API module. + Each module receives its entire allocated range of SVC calls, whether implemented or not, + but return BLE_ERROR_NOT_SUPPORTED for unimplemented or undefined calls in its range. + + Note that the symbols BLE__SVC_LAST is the end of the allocated SVC range, + rather than the last SVC function call actually defined and implemented. + + Specific SVC, event and option values are defined in each module's ble_.h file, + which defines names of each individual SVC code based on the range start value. +*/ + +#ifndef BLE_RANGES_H__ +#define BLE_RANGES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_SVC_BASE 0x60 /**< Common BLE SVC base. */ +#define BLE_SVC_LAST 0x6B /**< Common BLE SVC last. */ + +#define BLE_GAP_SVC_BASE 0x6C /**< GAP BLE SVC base. */ +#define BLE_GAP_SVC_LAST 0x9A /**< GAP BLE SVC last. */ + +#define BLE_GATTC_SVC_BASE 0x9B /**< GATTC BLE SVC base. */ +#define BLE_GATTC_SVC_LAST 0xA7 /**< GATTC BLE SVC last. */ + +#define BLE_GATTS_SVC_BASE 0xA8 /**< GATTS BLE SVC base. */ +#define BLE_GATTS_SVC_LAST 0xB7 /**< GATTS BLE SVC last. */ + +#define BLE_L2CAP_SVC_BASE 0xB8 /**< L2CAP BLE SVC base. */ +#define BLE_L2CAP_SVC_LAST 0xBF /**< L2CAP BLE SVC last. */ + +#define BLE_EVT_INVALID 0x00 /**< Invalid BLE Event. */ + +#define BLE_EVT_BASE 0x01 /**< Common BLE Event base. */ +#define BLE_EVT_LAST 0x0F /**< Common BLE Event last. */ + +#define BLE_GAP_EVT_BASE 0x10 /**< GAP BLE Event base. */ +#define BLE_GAP_EVT_LAST 0x2F /**< GAP BLE Event last. */ + +#define BLE_GATTC_EVT_BASE 0x30 /**< GATTC BLE Event base. */ +#define BLE_GATTC_EVT_LAST 0x4F /**< GATTC BLE Event last. */ + +#define BLE_GATTS_EVT_BASE 0x50 /**< GATTS BLE Event base. */ +#define BLE_GATTS_EVT_LAST 0x6F /**< GATTS BLE Event last. */ + +#define BLE_L2CAP_EVT_BASE 0x70 /**< L2CAP BLE Event base. */ +#define BLE_L2CAP_EVT_LAST 0x8F /**< L2CAP BLE Event last. */ + +#define BLE_OPT_INVALID 0x00 /**< Invalid BLE Option. */ + +#define BLE_OPT_BASE 0x01 /**< Common BLE Option base. */ +#define BLE_OPT_LAST 0x1F /**< Common BLE Option last. */ + +#define BLE_GAP_OPT_BASE 0x20 /**< GAP BLE Option base. */ +#define BLE_GAP_OPT_LAST 0x3F /**< GAP BLE Option last. */ + +#define BLE_GATT_OPT_BASE 0x40 /**< GATT BLE Option base. */ +#define BLE_GATT_OPT_LAST 0x5F /**< GATT BLE Option last. */ + +#define BLE_GATTC_OPT_BASE 0x60 /**< GATTC BLE Option base. */ +#define BLE_GATTC_OPT_LAST 0x7F /**< GATTC BLE Option last. */ + +#define BLE_GATTS_OPT_BASE 0x80 /**< GATTS BLE Option base. */ +#define BLE_GATTS_OPT_LAST 0x9F /**< GATTS BLE Option last. */ + +#define BLE_L2CAP_OPT_BASE 0xA0 /**< L2CAP BLE Option base. */ +#define BLE_L2CAP_OPT_LAST 0xBF /**< L2CAP BLE Option last. */ + +#define BLE_CFG_INVALID 0x00 /**< Invalid BLE configuration. */ + +#define BLE_CFG_BASE 0x01 /**< Common BLE configuration base. */ +#define BLE_CFG_LAST 0x1F /**< Common BLE configuration last. */ + +#define BLE_CONN_CFG_BASE 0x20 /**< BLE connection configuration base. */ +#define BLE_CONN_CFG_LAST 0x3F /**< BLE connection configuration last. */ + +#define BLE_GAP_CFG_BASE 0x40 /**< GAP BLE configuration base. */ +#define BLE_GAP_CFG_LAST 0x5F /**< GAP BLE configuration last. */ + +#define BLE_GATT_CFG_BASE 0x60 /**< GATT BLE configuration base. */ +#define BLE_GATT_CFG_LAST 0x7F /**< GATT BLE configuration last. */ + +#define BLE_GATTC_CFG_BASE 0x80 /**< GATTC BLE configuration base. */ +#define BLE_GATTC_CFG_LAST 0x9F /**< GATTC BLE configuration last. */ + +#define BLE_GATTS_CFG_BASE 0xA0 /**< GATTS BLE configuration base. */ +#define BLE_GATTS_CFG_LAST 0xBF /**< GATTS BLE configuration last. */ + +#define BLE_L2CAP_CFG_BASE 0xC0 /**< L2CAP BLE configuration base. */ +#define BLE_L2CAP_CFG_LAST 0xDF /**< L2CAP BLE configuration last. */ + +#ifdef __cplusplus +} +#endif +#endif /* BLE_RANGES_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_types.h b/variants/wio-tracker-wm1110/softdevice/ble_types.h new file mode 100644 index 0000000000..db3656cfdd --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_types.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @defgroup ble_types Common types and macro definitions + @{ + + @brief Common types and macro definitions for the BLE SoftDevice. + */ + +#ifndef BLE_TYPES_H__ +#define BLE_TYPES_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_TYPES_DEFINES Defines + * @{ */ + +/** @defgroup BLE_CONN_HANDLES BLE Connection Handles + * @{ */ +#define BLE_CONN_HANDLE_INVALID 0xFFFF /**< Invalid Connection Handle. */ +#define BLE_CONN_HANDLE_ALL 0xFFFE /**< Applies to all Connection Handles. */ +/** @} */ + +/** @defgroup BLE_UUID_VALUES Assigned Values for BLE UUIDs + * @{ */ +/* Generic UUIDs, applicable to all services */ +#define BLE_UUID_UNKNOWN 0x0000 /**< Reserved UUID. */ +#define BLE_UUID_SERVICE_PRIMARY 0x2800 /**< Primary Service. */ +#define BLE_UUID_SERVICE_SECONDARY 0x2801 /**< Secondary Service. */ +#define BLE_UUID_SERVICE_INCLUDE 0x2802 /**< Include. */ +#define BLE_UUID_CHARACTERISTIC 0x2803 /**< Characteristic. */ +#define BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP 0x2900 /**< Characteristic Extended Properties Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_USER_DESC 0x2901 /**< Characteristic User Description Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG 0x2902 /**< Client Characteristic Configuration Descriptor. */ +#define BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG 0x2903 /**< Server Characteristic Configuration Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT 0x2904 /**< Characteristic Presentation Format Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_AGGREGATE_FORMAT 0x2905 /**< Characteristic Aggregate Format Descriptor. */ +/* GATT specific UUIDs */ +#define BLE_UUID_GATT 0x1801 /**< Generic Attribute Profile. */ +#define BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED 0x2A05 /**< Service Changed Characteristic. */ +/* GAP specific UUIDs */ +#define BLE_UUID_GAP 0x1800 /**< Generic Access Profile. */ +#define BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME 0x2A00 /**< Device Name Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_APPEARANCE 0x2A01 /**< Appearance Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_RECONN_ADDR 0x2A03 /**< Reconnection Address Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_PPCP 0x2A04 /**< Peripheral Preferred Connection Parameters Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_CAR 0x2AA6 /**< Central Address Resolution Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_RPA_ONLY 0x2AC9 /**< Resolvable Private Address Only Characteristic. */ +/** @} */ + +/** @defgroup BLE_UUID_TYPES Types of UUID + * @{ */ +#define BLE_UUID_TYPE_UNKNOWN 0x00 /**< Invalid UUID type. */ +#define BLE_UUID_TYPE_BLE 0x01 /**< Bluetooth SIG UUID (16-bit). */ +#define BLE_UUID_TYPE_VENDOR_BEGIN 0x02 /**< Vendor UUID types start at this index (128-bit). */ +/** @} */ + +/** @defgroup BLE_APPEARANCES Bluetooth Appearance values + * @note Retrieved from + * http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml + * @{ */ +#define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */ +#define BLE_APPEARANCE_GENERIC_PHONE 64 /**< Generic Phone. */ +#define BLE_APPEARANCE_GENERIC_COMPUTER 128 /**< Generic Computer. */ +#define BLE_APPEARANCE_GENERIC_WATCH 192 /**< Generic Watch. */ +#define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /**< Watch: Sports Watch. */ +#define BLE_APPEARANCE_GENERIC_CLOCK 256 /**< Generic Clock. */ +#define BLE_APPEARANCE_GENERIC_DISPLAY 320 /**< Generic Display. */ +#define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /**< Generic Remote Control. */ +#define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /**< Generic Eye-glasses. */ +#define BLE_APPEARANCE_GENERIC_TAG 512 /**< Generic Tag. */ +#define BLE_APPEARANCE_GENERIC_KEYRING 576 /**< Generic Keyring. */ +#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /**< Generic Media Player. */ +#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /**< Generic Barcode Scanner. */ +#define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /**< Generic Thermometer. */ +#define BLE_APPEARANCE_THERMOMETER_EAR 769 /**< Thermometer: Ear. */ +#define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /**< Generic Heart rate Sensor. */ +#define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /**< Heart Rate Sensor: Heart Rate Belt. */ +#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /**< Generic Blood Pressure. */ +#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /**< Blood Pressure: Arm. */ +#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /**< Blood Pressure: Wrist. */ +#define BLE_APPEARANCE_GENERIC_HID 960 /**< Human Interface Device (HID). */ +#define BLE_APPEARANCE_HID_KEYBOARD 961 /**< Keyboard (HID Subtype). */ +#define BLE_APPEARANCE_HID_MOUSE 962 /**< Mouse (HID Subtype). */ +#define BLE_APPEARANCE_HID_JOYSTICK 963 /**< Joystick (HID Subtype). */ +#define BLE_APPEARANCE_HID_GAMEPAD 964 /**< Gamepad (HID Subtype). */ +#define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /**< Digitizer Tablet (HID Subtype). */ +#define BLE_APPEARANCE_HID_CARD_READER 966 /**< Card Reader (HID Subtype). */ +#define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /**< Digital Pen (HID Subtype). */ +#define BLE_APPEARANCE_HID_BARCODE 968 /**< Barcode Scanner (HID Subtype). */ +#define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /**< Generic Glucose Meter. */ +#define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /**< Generic Running Walking Sensor. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /**< Running Walking Sensor: In-Shoe. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /**< Running Walking Sensor: On-Shoe. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /**< Running Walking Sensor: On-Hip. */ +#define BLE_APPEARANCE_GENERIC_CYCLING 1152 /**< Generic Cycling. */ +#define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /**< Cycling: Cycling Computer. */ +#define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /**< Cycling: Speed Sensor. */ +#define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /**< Cycling: Cadence Sensor. */ +#define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /**< Cycling: Power Sensor. */ +#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /**< Cycling: Speed and Cadence Sensor. */ +#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /**< Generic Pulse Oximeter. */ +#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /**< Fingertip (Pulse Oximeter subtype). */ +#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /**< Wrist Worn(Pulse Oximeter subtype). */ +#define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /**< Generic Weight Scale. */ +#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /**< Generic Outdoor Sports Activity. */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /**< Location Display Device (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP \ + 5186 /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /**< Location Pod (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD \ + 5188 /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */ +/** @} */ + +/** @brief Set .type and .uuid fields of ble_uuid_struct to specified UUID value. */ +#define BLE_UUID_BLE_ASSIGN(instance, value) \ + do { \ + instance.type = BLE_UUID_TYPE_BLE; \ + instance.uuid = value; \ + } while (0) + +/** @brief Copy type and uuid members from src to dst ble_uuid_t pointer. Both pointers must be valid/non-null. */ +#define BLE_UUID_COPY_PTR(dst, src) \ + do { \ + (dst)->type = (src)->type; \ + (dst)->uuid = (src)->uuid; \ + } while (0) + +/** @brief Copy type and uuid members from src to dst ble_uuid_t struct. */ +#define BLE_UUID_COPY_INST(dst, src) \ + do { \ + (dst).type = (src).type; \ + (dst).uuid = (src).uuid; \ + } while (0) + +/** @brief Compare for equality both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ +#define BLE_UUID_EQ(p_uuid1, p_uuid2) (((p_uuid1)->type == (p_uuid2)->type) && ((p_uuid1)->uuid == (p_uuid2)->uuid)) + +/** @brief Compare for difference both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ +#define BLE_UUID_NEQ(p_uuid1, p_uuid2) (((p_uuid1)->type != (p_uuid2)->type) || ((p_uuid1)->uuid != (p_uuid2)->uuid)) + +/** @} */ + +/** @addtogroup BLE_TYPES_STRUCTURES Structures + * @{ */ + +/** @brief 128 bit UUID values. */ +typedef struct { + uint8_t uuid128[16]; /**< Little-Endian UUID bytes. */ +} ble_uuid128_t; + +/** @brief Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */ +typedef struct { + uint16_t uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */ + uint8_t + type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is @ref BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */ +} ble_uuid_t; + +/**@brief Data structure. */ +typedef struct { + uint8_t *p_data; /**< Pointer to the data buffer provided to/from the application. */ + uint16_t len; /**< Length of the data buffer, in bytes. */ +} ble_data_t; + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* BLE_TYPES_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h b/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h new file mode 100644 index 0000000000..4e0bd752ab --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2014 - 2017, Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_mbr_api Master Boot Record API + @{ + + @brief APIs for updating SoftDevice and BootLoader + +*/ + +#ifndef NRF_MBR_H__ +#define NRF_MBR_H__ + +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup NRF_MBR_DEFINES Defines + * @{ */ + +/**@brief MBR SVC Base number. */ +#define MBR_SVC_BASE (0x18) + +/**@brief Page size in words. */ +#define MBR_PAGE_SIZE_IN_WORDS (1024) + +/** @brief The size that must be reserved for the MBR when a SoftDevice is written to flash. +This is the offset where the first byte of the SoftDevice hex file is written. */ +#define MBR_SIZE (0x1000) + +/** @brief Location (in the flash memory) of the bootloader address. */ +#define MBR_BOOTLOADER_ADDR (0xFF8) + +/** @brief Location (in UICR) of the bootloader address. */ +#define MBR_UICR_BOOTLOADER_ADDR (&(NRF_UICR->NRFFW[0])) + +/** @brief Location (in the flash memory) of the address of the MBR parameter page. */ +#define MBR_PARAM_PAGE_ADDR (0xFFC) + +/** @brief Location (in UICR) of the address of the MBR parameter page. */ +#define MBR_UICR_PARAM_PAGE_ADDR (&(NRF_UICR->NRFFW[1])) + +/** @} */ + +/** @addtogroup NRF_MBR_ENUMS Enumerations + * @{ */ + +/**@brief nRF Master Boot Record API SVC numbers. */ +enum NRF_MBR_SVCS { + SD_MBR_COMMAND = MBR_SVC_BASE, /**< ::sd_mbr_command */ +}; + +/**@brief Possible values for ::sd_mbr_command_t.command */ +enum NRF_MBR_COMMANDS { + SD_MBR_COMMAND_COPY_BL, /**< Copy a new BootLoader. @see ::sd_mbr_command_copy_bl_t*/ + SD_MBR_COMMAND_COPY_SD, /**< Copy a new SoftDevice. @see ::sd_mbr_command_copy_sd_t*/ + SD_MBR_COMMAND_INIT_SD, /**< Initialize forwarding interrupts to SD, and run reset function in SD. Does not require any + parameters in ::sd_mbr_command_t params.*/ + SD_MBR_COMMAND_COMPARE, /**< This command works like memcmp. @see ::sd_mbr_command_compare_t*/ + SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET, /**< Change the address the MBR starts after a reset. @see + ::sd_mbr_command_vector_table_base_set_t*/ + SD_MBR_COMMAND_RESERVED, + SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET, /**< Start forwarding all interrupts to this address. @see + ::sd_mbr_command_irq_forward_address_set_t*/ +}; + +/** @} */ + +/** @addtogroup NRF_MBR_TYPES Types + * @{ */ + +/**@brief This command copies part of a new SoftDevice + * + * The destination area is erased before copying. + * If dst is in the middle of a flash page, that whole flash page will be erased. + * If (dst+len) is in the middle of a flash page, that whole flash page will be erased. + * + * The user of this function is responsible for setting the BPROT registers. + * + * @retval ::NRF_SUCCESS indicates that the contents of the memory blocks where copied correctly. + * @retval ::NRF_ERROR_INTERNAL indicates that the contents of the memory blocks where not verified correctly after copying. + */ +typedef struct { + uint32_t *src; /**< Pointer to the source of data to be copied.*/ + uint32_t *dst; /**< Pointer to the destination where the content is to be copied.*/ + uint32_t len; /**< Number of 32 bit words to copy. Must be a multiple of @ref MBR_PAGE_SIZE_IN_WORDS words.*/ +} sd_mbr_command_copy_sd_t; + +/**@brief This command works like memcmp, but takes the length in words. + * + * @retval ::NRF_SUCCESS indicates that the contents of both memory blocks are equal. + * @retval ::NRF_ERROR_NULL indicates that the contents of the memory blocks are not equal. + */ +typedef struct { + uint32_t *ptr1; /**< Pointer to block of memory. */ + uint32_t *ptr2; /**< Pointer to block of memory. */ + uint32_t len; /**< Number of 32 bit words to compare.*/ +} sd_mbr_command_compare_t; + +/**@brief This command copies a new BootLoader. + * + * The MBR assumes that either @ref MBR_BOOTLOADER_ADDR or @ref MBR_UICR_BOOTLOADER_ADDR is set to + * the address where the bootloader will be copied. If both addresses are set, the MBR will prioritize + * @ref MBR_BOOTLOADER_ADDR. + * + * The bootloader destination is erased by this function. + * If (destination+bl_len) is in the middle of a flash page, that whole flash page will be erased. + * + * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, + * see @ref sd_mbr_command. + * + * This command will use the flash protect peripheral (BPROT or ACL) to protect the flash that is + * not intended to be written. + * + * On success, this function will not return. It will start the new bootloader from reset-vector as normal. + * + * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. + * @retval ::NRF_ERROR_FORBIDDEN if the bootloader address is not set. + * @retval ::NRF_ERROR_INVALID_LENGTH if parameters attempts to read or write outside flash area. + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. + */ +typedef struct { + uint32_t *bl_src; /**< Pointer to the source of the bootloader to be be copied.*/ + uint32_t bl_len; /**< Number of 32 bit words to copy for BootLoader. */ +} sd_mbr_command_copy_bl_t; + +/**@brief Change the address the MBR starts after a reset + * + * Once this function has been called, this address is where the MBR will start to forward + * interrupts to after a reset. + * + * To restore default forwarding, this function should be called with @ref address set to 0. If a + * bootloader is present, interrupts will be forwarded to the bootloader. If not, interrupts will + * be forwarded to the SoftDevice. + * + * The location of a bootloader can be specified in @ref MBR_BOOTLOADER_ADDR or + * @ref MBR_UICR_BOOTLOADER_ADDR. If both addresses are set, the MBR will prioritize + * @ref MBR_BOOTLOADER_ADDR. + * + * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, + * see @ref sd_mbr_command. + * + * On success, this function will not return. It will reset the device. + * + * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. + * @retval ::NRF_ERROR_INVALID_ADDR if parameter address is outside of the flash size. + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. + */ +typedef struct { + uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ +} sd_mbr_command_vector_table_base_set_t; + +/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the MBR + * + * Unlike sd_mbr_command_vector_table_base_set_t, this function does not reset, and it does not + * change where the MBR starts after reset. + * + * @retval ::NRF_SUCCESS + */ +typedef struct { + uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ +} sd_mbr_command_irq_forward_address_set_t; + +/**@brief Input structure containing data used when calling ::sd_mbr_command + * + * Depending on what command value that is set, the corresponding params value type must also be + * set. See @ref NRF_MBR_COMMANDS for command types and corresponding params value type. If command + * @ref SD_MBR_COMMAND_INIT_SD is set, it is not necessary to set any values under params. + */ +typedef struct { + uint32_t command; /**< Type of command to be issued. See @ref NRF_MBR_COMMANDS. */ + union { + sd_mbr_command_copy_sd_t copy_sd; /**< Parameters for copy SoftDevice.*/ + sd_mbr_command_compare_t compare; /**< Parameters for verify.*/ + sd_mbr_command_copy_bl_t copy_bl; /**< Parameters for copy BootLoader. Requires parameter page. */ + sd_mbr_command_vector_table_base_set_t base_set; /**< Parameters for vector table base set. Requires parameter page.*/ + sd_mbr_command_irq_forward_address_set_t irq_forward_address_set; /**< Parameters for irq forward address set*/ + } params; /**< Command parameters. */ +} sd_mbr_command_t; + +/** @} */ + +/** @addtogroup NRF_MBR_FUNCTIONS Functions + * @{ */ + +/**@brief Issue Master Boot Record commands + * + * Commands used when updating a SoftDevice and bootloader. + * + * The @ref SD_MBR_COMMAND_COPY_BL and @ref SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET requires + * parameters to be retained by the MBR when resetting the IC. This is done in a separate flash + * page. The location of the flash page should be provided by the application in either + * @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR. If both addresses are set, the MBR + * will prioritize @ref MBR_PARAM_PAGE_ADDR. This page will be cleared by the MBR and is used to + * store the command before reset. When an address is specified, the page it refers to must not be + * used by the application. If no address is provided by the application, i.e. both + * @ref MBR_PARAM_PAGE_ADDR and @ref MBR_UICR_PARAM_PAGE_ADDR is 0xFFFFFFFF, MBR commands which use + * flash will be unavailable and return @ref NRF_ERROR_NO_MEM. + * + * @param[in] param Pointer to a struct describing the command. + * + * @note For a complete set of return values, see ::sd_mbr_command_copy_sd_t, + * ::sd_mbr_command_copy_bl_t, ::sd_mbr_command_compare_t, + * ::sd_mbr_command_vector_table_base_set_t, ::sd_mbr_command_irq_forward_address_set_t + * + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page provided + * @retval ::NRF_ERROR_INVALID_PARAM if an invalid command is given. + */ +SVCALL(SD_MBR_COMMAND, uint32_t, sd_mbr_command(sd_mbr_command_t *param)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_MBR_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error.h b/variants/wio-tracker-wm1110/softdevice/nrf_error.h new file mode 100644 index 0000000000..fb2831e191 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_error.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_error SoftDevice Global Error Codes + @{ + + @brief Global Error definitions +*/ + +/* Header guard */ +#ifndef NRF_ERROR_H__ +#define NRF_ERROR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup NRF_ERRORS_BASE Error Codes Base number definitions + * @{ */ +#define NRF_ERROR_BASE_NUM (0x0) ///< Global error base +#define NRF_ERROR_SDM_BASE_NUM (0x1000) ///< SDM error base +#define NRF_ERROR_SOC_BASE_NUM (0x2000) ///< SoC error base +#define NRF_ERROR_STK_BASE_NUM (0x3000) ///< STK error base +/** @} */ + +#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command +#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing +#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled +#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error +#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation +#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found +#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported +#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter +#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state +#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length +#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags +#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data +#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Invalid Data size +#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out +#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer +#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation +#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address +#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy +#define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded. +#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h b/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h new file mode 100644 index 0000000000..2fd6210576 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup nrf_sdm_api + @{ + @defgroup nrf_sdm_error SoftDevice Manager Error Codes + @{ + + @brief Error definitions for the SDM API +*/ + +/* Header guard */ +#ifndef NRF_ERROR_SDM_H__ +#define NRF_ERROR_SDM_H__ + +#include "nrf_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN (NRF_ERROR_SDM_BASE_NUM + 0) ///< Unknown LFCLK source. +#define NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION \ + (NRF_ERROR_SDM_BASE_NUM + 1) ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having + ///< enabled SoftDevice interrupts). +#define NRF_ERROR_SDM_INCORRECT_CLENR0 \ + (NRF_ERROR_SDM_BASE_NUM + 2) ///< Incorrect CLENR0 (can be caused by erroneous SoftDevice flashing). + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_SDM_H__ + +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h b/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h new file mode 100644 index 0000000000..cbd0ba8ac4 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup nrf_soc_api + @{ + @defgroup nrf_soc_error SoC Library Error Codes + @{ + + @brief Error definitions for the SoC library + +*/ + +/* Header guard */ +#ifndef NRF_ERROR_SOC_H__ +#define NRF_ERROR_SOC_H__ + +#include "nrf_error.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* Mutex Errors */ +#define NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN (NRF_ERROR_SOC_BASE_NUM + 0) ///< Mutex already taken + +/* NVIC errors */ +#define NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE (NRF_ERROR_SOC_BASE_NUM + 1) ///< NVIC interrupt not available +#define NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED (NRF_ERROR_SOC_BASE_NUM + 2) ///< NVIC interrupt priority not allowed +#define NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 3) ///< NVIC should not return + +/* Power errors */ +#define NRF_ERROR_SOC_POWER_MODE_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 4) ///< Power mode unknown +#define NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 5) ///< Power POF threshold unknown +#define NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 6) ///< Power off should not return + +/* Rand errors */ +#define NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES (NRF_ERROR_SOC_BASE_NUM + 7) ///< RAND not enough values + +/* PPI errors */ +#define NRF_ERROR_SOC_PPI_INVALID_CHANNEL (NRF_ERROR_SOC_BASE_NUM + 8) ///< Invalid PPI Channel +#define NRF_ERROR_SOC_PPI_INVALID_GROUP (NRF_ERROR_SOC_BASE_NUM + 9) ///< Invalid PPI Group + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_SOC_H__ +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h b/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h new file mode 100644 index 0000000000..d4ab204d96 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h @@ -0,0 +1,449 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup nrf_nvic_api SoftDevice NVIC API + * @{ + * + * @note In order to use this module, the following code has to be added to a .c file: + * \code + * nrf_nvic_state_t nrf_nvic_state = {0}; + * \endcode + * + * @note Definitions and declarations starting with __ (double underscore) in this header file are + * not intended for direct use by the application. + * + * @brief APIs for the accessing NVIC when using a SoftDevice. + * + */ + +#ifndef NRF_NVIC_H__ +#define NRF_NVIC_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup NRF_NVIC_DEFINES Defines + * @{ */ + +/**@defgroup NRF_NVIC_ISER_DEFINES SoftDevice NVIC internal definitions + * @{ */ + +#define __NRF_NVIC_NVMC_IRQn \ + (30) /**< The peripheral ID of the NVMC. IRQ numbers are used to identify peripherals, but the NVMC doesn't have an IRQ \ + number in the MDK. */ + +#define __NRF_NVIC_ISER_COUNT (2) /**< The number of ISER/ICER registers in the NVIC that are used. */ + +/**@brief Interrupt priority levels used by the SoftDevice. */ +#define __NRF_NVIC_SD_IRQ_PRIOS \ + ((uint8_t)((1U << 0) /**< Priority level high .*/ \ + | (1U << 1) /**< Priority level medium. */ \ + | (1U << 4) /**< Priority level low. */ \ + )) + +/**@brief Interrupt priority levels available to the application. */ +#define __NRF_NVIC_APP_IRQ_PRIOS ((uint8_t)~__NRF_NVIC_SD_IRQ_PRIOS) + +/**@brief Interrupts used by the SoftDevice, with IRQn in the range 0-31. */ +#define __NRF_NVIC_SD_IRQS_0 \ + ((uint32_t)((1U << POWER_CLOCK_IRQn) | (1U << RADIO_IRQn) | (1U << RTC0_IRQn) | (1U << TIMER0_IRQn) | (1U << RNG_IRQn) | \ + (1U << ECB_IRQn) | (1U << CCM_AAR_IRQn) | (1U << TEMP_IRQn) | (1U << __NRF_NVIC_NVMC_IRQn) | \ + (1U << (uint32_t)SWI5_IRQn))) + +/**@brief Interrupts used by the SoftDevice, with IRQn in the range 32-63. */ +#define __NRF_NVIC_SD_IRQS_1 ((uint32_t)0) + +/**@brief Interrupts available for to application, with IRQn in the range 0-31. */ +#define __NRF_NVIC_APP_IRQS_0 (~__NRF_NVIC_SD_IRQS_0) + +/**@brief Interrupts available for to application, with IRQn in the range 32-63. */ +#define __NRF_NVIC_APP_IRQS_1 (~__NRF_NVIC_SD_IRQS_1) + +/**@} */ + +/**@} */ + +/**@addtogroup NRF_NVIC_VARIABLES Variables + * @{ */ + +/**@brief Type representing the state struct for the SoftDevice NVIC module. */ +typedef struct { + uint32_t volatile __irq_masks[__NRF_NVIC_ISER_COUNT]; /**< IRQs enabled by the application in the NVIC. */ + uint32_t volatile __cr_flag; /**< Non-zero if already in a critical region */ +} nrf_nvic_state_t; + +/**@brief Variable keeping the state for the SoftDevice NVIC module. This must be declared in an + * application source file. */ +extern nrf_nvic_state_t nrf_nvic_state; + +/**@} */ + +/**@addtogroup NRF_NVIC_INTERNAL_FUNCTIONS SoftDevice NVIC internal functions + * @{ */ + +/**@brief Disables IRQ interrupts globally, including the SoftDevice's interrupts. + * + * @retval The value of PRIMASK prior to disabling the interrupts. + */ +__STATIC_INLINE int __sd_nvic_irq_disable(void); + +/**@brief Enables IRQ interrupts globally, including the SoftDevice's interrupts. + */ +__STATIC_INLINE void __sd_nvic_irq_enable(void); + +/**@brief Checks if IRQn is available to application + * @param[in] IRQn IRQ to check + * + * @retval 1 (true) if the IRQ to check is available to the application + */ +__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn); + +/**@brief Checks if priority is available to application + * @param[in] priority priority to check + * + * @retval 1 (true) if the priority to check is available to the application + */ +__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority); + +/**@} */ + +/**@addtogroup NRF_NVIC_FUNCTIONS SoftDevice NVIC public functions + * @{ */ + +/**@brief Enable External Interrupt. + * @note Corresponds to NVIC_EnableIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_EnableIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt was enabled. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt has a priority not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn); + +/**@brief Disable External Interrupt. + * @note Corresponds to NVIC_DisableIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_DisableIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt was disabled. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn); + +/**@brief Get Pending Interrupt. + * @note Corresponds to NVIC_GetPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_GetPendingIRQ documentation in CMSIS. + * @param[out] p_pending_irq Return value from NVIC_GetPendingIRQ. + * + * @retval ::NRF_SUCCESS The interrupt is available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq); + +/**@brief Set Pending Interrupt. + * @note Corresponds to NVIC_SetPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_SetPendingIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt is set pending. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn); + +/**@brief Clear Pending Interrupt. + * @note Corresponds to NVIC_ClearPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_ClearPendingIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt pending flag is cleared. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn); + +/**@brief Set Interrupt Priority. + * @note Corresponds to NVIC_SetPriority in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * @pre Priority is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_SetPriority documentation in CMSIS. + * @param[in] priority A valid IRQ priority for use by the application. + * + * @retval ::NRF_SUCCESS The interrupt and priority level is available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt priority is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority); + +/**@brief Get Interrupt Priority. + * @note Corresponds to NVIC_GetPriority in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_GetPriority documentation in CMSIS. + * @param[out] p_priority Return value from NVIC_GetPriority. + * + * @retval ::NRF_SUCCESS The interrupt priority is returned in p_priority. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE - IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority); + +/**@brief System Reset. + * @note Corresponds to NVIC_SystemReset in CMSIS. + * + * @retval ::NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN + */ +__STATIC_INLINE uint32_t sd_nvic_SystemReset(void); + +/**@brief Enter critical region. + * + * @post Application interrupts will be disabled. + * @note sd_nvic_critical_region_enter() and ::sd_nvic_critical_region_exit() must be called in matching pairs inside each + * execution context + * @sa sd_nvic_critical_region_exit + * + * @param[out] p_is_nested_critical_region If 1, the application is now in a nested critical region. + * + * @retval ::NRF_SUCCESS + */ +__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region); + +/**@brief Exit critical region. + * + * @pre Application has entered a critical region using ::sd_nvic_critical_region_enter. + * @post If not in a nested critical region, the application interrupts will restored to the state before + * ::sd_nvic_critical_region_enter was called. + * + * @param[in] is_nested_critical_region If this is set to 1, the critical region won't be exited. @sa + * sd_nvic_critical_region_enter. + * + * @retval ::NRF_SUCCESS + */ +__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region); + +/**@} */ + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION + +__STATIC_INLINE int __sd_nvic_irq_disable(void) +{ + int pm = __get_PRIMASK(); + __disable_irq(); + return pm; +} + +__STATIC_INLINE void __sd_nvic_irq_enable(void) +{ + __enable_irq(); +} + +__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn) +{ + if (IRQn < 32) { + return ((1UL << IRQn) & __NRF_NVIC_APP_IRQS_0) != 0; + } else if (IRQn < 64) { + return ((1UL << (IRQn - 32)) & __NRF_NVIC_APP_IRQS_1) != 0; + } else { + return 1; + } +} + +__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority) +{ + if ((priority >= (1 << __NVIC_PRIO_BITS)) || (((1 << priority) & __NRF_NVIC_APP_IRQ_PRIOS) == 0)) { + return 0; + } + return 1; +} + +__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + if (!__sd_nvic_is_app_accessible_priority(NVIC_GetPriority(IRQn))) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; + } + + if (nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] |= + (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F)); + } else { + NVIC_EnableIRQ(IRQn); + } + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + + if (nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] &= ~(1UL << ((uint32_t)(IRQn)&0x1F)); + } else { + NVIC_DisableIRQ(IRQn); + } + + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + *p_pending_irq = NVIC_GetPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + NVIC_SetPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + NVIC_ClearPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + + if (!__sd_nvic_is_app_accessible_priority(priority)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; + } + + NVIC_SetPriority(IRQn, (uint32_t)priority); + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + *p_priority = (NVIC_GetPriority(IRQn) & 0xFF); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SystemReset(void) +{ + NVIC_SystemReset(); + return NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN; +} + +__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region) +{ + int was_masked = __sd_nvic_irq_disable(); + if (!nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__cr_flag = 1; + nrf_nvic_state.__irq_masks[0] = (NVIC->ICER[0] & __NRF_NVIC_APP_IRQS_0); + NVIC->ICER[0] = __NRF_NVIC_APP_IRQS_0; + nrf_nvic_state.__irq_masks[1] = (NVIC->ICER[1] & __NRF_NVIC_APP_IRQS_1); + NVIC->ICER[1] = __NRF_NVIC_APP_IRQS_1; + *p_is_nested_critical_region = 0; + } else { + *p_is_nested_critical_region = 1; + } + if (!was_masked) { + __sd_nvic_irq_enable(); + } + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region) +{ + if (nrf_nvic_state.__cr_flag && (is_nested_critical_region == 0)) { + int was_masked = __sd_nvic_irq_disable(); + NVIC->ISER[0] = nrf_nvic_state.__irq_masks[0]; + NVIC->ISER[1] = nrf_nvic_state.__irq_masks[1]; + nrf_nvic_state.__cr_flag = 0; + if (!was_masked) { + __sd_nvic_irq_enable(); + } + } + + return NRF_SUCCESS; +} + +#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ + +#ifdef __cplusplus +} +#endif + +#endif // NRF_NVIC_H__ + +/**@} */ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h b/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h new file mode 100644 index 0000000000..2786a86a45 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_sdm_api SoftDevice Manager API + @{ + + @brief APIs for SoftDevice management. + +*/ + +#ifndef NRF_SDM_H__ +#define NRF_SDM_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_sdm.h" +#include "nrf_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup NRF_SDM_DEFINES Defines + * @{ */ +#ifdef NRFSOC_DOXYGEN +/// Declared in nrf_mbr.h +#define MBR_SIZE 0 +#warning test +#endif + +/** @brief The major version for the SoftDevice binary distributed with this header file. */ +#define SD_MAJOR_VERSION (7) + +/** @brief The minor version for the SoftDevice binary distributed with this header file. */ +#define SD_MINOR_VERSION (3) + +/** @brief The bugfix version for the SoftDevice binary distributed with this header file. */ +#define SD_BUGFIX_VERSION (0) + +/** @brief The SoftDevice variant of this firmware. */ +#define SD_VARIANT_ID 140 + +/** @brief The full version number for the SoftDevice binary this header file was distributed + * with, as a decimal number in the form Mmmmbbb, where: + * - M is major version (one or more digits) + * - mmm is minor version (three digits) + * - bbb is bugfix version (three digits). */ +#define SD_VERSION (SD_MAJOR_VERSION * 1000000 + SD_MINOR_VERSION * 1000 + SD_BUGFIX_VERSION) + +/** @brief SoftDevice Manager SVC Base number. */ +#define SDM_SVC_BASE 0x10 + +/** @brief SoftDevice unique string size in bytes. */ +#define SD_UNIQUE_STR_SIZE 20 + +/** @brief Invalid info field. Returned when an info field does not exist. */ +#define SDM_INFO_FIELD_INVALID (0) + +/** @brief Defines the SoftDevice Information Structure location (address) as an offset from +the start of the SoftDevice (without MBR)*/ +#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000) + +/** @brief Defines the absolute SoftDevice Information Structure location (address) when the + * SoftDevice is installed just above the MBR (the usual case). */ +#define SOFTDEVICE_INFO_STRUCT_ADDRESS (SOFTDEVICE_INFO_STRUCT_OFFSET + MBR_SIZE) + +/** @brief Defines the offset for the SoftDevice Information Structure size value relative to the + * SoftDevice base address. The size value is of type uint8_t. */ +#define SD_INFO_STRUCT_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET) + +/** @brief Defines the offset for the SoftDevice size value relative to the SoftDevice base address. + * The size value is of type uint32_t. */ +#define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08) + +/** @brief Defines the offset for FWID value relative to the SoftDevice base address. The FWID value + * is of type uint16_t. */ +#define SD_FWID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x0C) + +/** @brief Defines the offset for the SoftDevice ID relative to the SoftDevice base address. The ID + * is of type uint32_t. */ +#define SD_ID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x10) + +/** @brief Defines the offset for the SoftDevice version relative to the SoftDevice base address in + * the same format as @ref SD_VERSION, stored as an uint32_t. */ +#define SD_VERSION_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x14) + +/** @brief Defines the offset for the SoftDevice unique string relative to the SoftDevice base address. + * The SD_UNIQUE_STR is stored as an array of uint8_t. The size of array is @ref SD_UNIQUE_STR_SIZE. + */ +#define SD_UNIQUE_STR_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x18) + +/** @brief Defines a macro for retrieving the actual SoftDevice Information Structure size value + * from a given base address. Use @ref MBR_SIZE as the argument when the SoftDevice is + * installed just above the MBR (the usual case). */ +#define SD_INFO_STRUCT_SIZE_GET(baseaddr) (*((uint8_t *)((baseaddr) + SD_INFO_STRUCT_SIZE_OFFSET))) + +/** @brief Defines a macro for retrieving the actual SoftDevice size value from a given base + * address. Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above + * the MBR (the usual case). */ +#define SD_SIZE_GET(baseaddr) (*((uint32_t *)((baseaddr) + SD_SIZE_OFFSET))) + +/** @brief Defines the amount of flash that is used by the SoftDevice. + * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed + * just above the MBR (the usual case). + */ +#define SD_FLASH_SIZE 0x26000 + +/** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use + * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual + * case). */ +#define SD_FWID_GET(baseaddr) (*((uint16_t *)((baseaddr) + SD_FWID_OFFSET))) + +/** @brief Defines a macro for retrieving the actual SoftDevice ID from a given base address. Use + * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the + * usual case). */ +#define SD_ID_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_ID_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (*((uint32_t *)((baseaddr) + SD_ID_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/** @brief Defines a macro for retrieving the actual SoftDevice version from a given base address. + * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR + * (the usual case). */ +#define SD_VERSION_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_VERSION_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (*((uint32_t *)((baseaddr) + SD_VERSION_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/** @brief Defines a macro for retrieving the address of SoftDevice unique str based on a given base address. + * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR + * (the usual case). */ +#define SD_UNIQUE_STR_ADDR_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_UNIQUE_STR_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (((uint8_t *)((baseaddr) + SD_UNIQUE_STR_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/**@defgroup NRF_FAULT_ID_RANGES Fault ID ranges + * @{ */ +#define NRF_FAULT_ID_SD_RANGE_START 0x00000000 /**< SoftDevice ID range start. */ +#define NRF_FAULT_ID_APP_RANGE_START 0x00001000 /**< Application ID range start. */ +/**@} */ + +/**@defgroup NRF_FAULT_IDS Fault ID types + * @{ */ +#define NRF_FAULT_ID_SD_ASSERT \ + (NRF_FAULT_ID_SD_RANGE_START + 1) /**< SoftDevice assertion. The info parameter is reserved for future used. */ +#define NRF_FAULT_ID_APP_MEMACC \ + (NRF_FAULT_ID_APP_RANGE_START + 1) /**< Application invalid memory access. The info parameter will contain 0x00000000, \ + in case of SoftDevice RAM access violation. In case of SoftDevice peripheral \ + register violation the info parameter will contain the sub-region number of \ + PREGION[0], on whose address range the disallowed write access caused the \ + memory access fault. */ +/**@} */ + +/** @} */ + +/** @addtogroup NRF_SDM_ENUMS Enumerations + * @{ */ + +/**@brief nRF SoftDevice Manager API SVC numbers. */ +enum NRF_SD_SVCS { + SD_SOFTDEVICE_ENABLE = SDM_SVC_BASE, /**< ::sd_softdevice_enable */ + SD_SOFTDEVICE_DISABLE, /**< ::sd_softdevice_disable */ + SD_SOFTDEVICE_IS_ENABLED, /**< ::sd_softdevice_is_enabled */ + SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, /**< ::sd_softdevice_vector_table_base_set */ + SVC_SDM_LAST /**< Placeholder for last SDM SVC */ +}; + +/** @} */ + +/** @addtogroup NRF_SDM_DEFINES Defines + * @{ */ + +/**@defgroup NRF_CLOCK_LF_ACCURACY Clock accuracy + * @{ */ + +#define NRF_CLOCK_LF_ACCURACY_250_PPM (0) /**< Default: 250 ppm */ +#define NRF_CLOCK_LF_ACCURACY_500_PPM (1) /**< 500 ppm */ +#define NRF_CLOCK_LF_ACCURACY_150_PPM (2) /**< 150 ppm */ +#define NRF_CLOCK_LF_ACCURACY_100_PPM (3) /**< 100 ppm */ +#define NRF_CLOCK_LF_ACCURACY_75_PPM (4) /**< 75 ppm */ +#define NRF_CLOCK_LF_ACCURACY_50_PPM (5) /**< 50 ppm */ +#define NRF_CLOCK_LF_ACCURACY_30_PPM (6) /**< 30 ppm */ +#define NRF_CLOCK_LF_ACCURACY_20_PPM (7) /**< 20 ppm */ +#define NRF_CLOCK_LF_ACCURACY_10_PPM (8) /**< 10 ppm */ +#define NRF_CLOCK_LF_ACCURACY_5_PPM (9) /**< 5 ppm */ +#define NRF_CLOCK_LF_ACCURACY_2_PPM (10) /**< 2 ppm */ +#define NRF_CLOCK_LF_ACCURACY_1_PPM (11) /**< 1 ppm */ + +/** @} */ + +/**@defgroup NRF_CLOCK_LF_SRC Possible LFCLK oscillator sources + * @{ */ + +#define NRF_CLOCK_LF_SRC_RC (0) /**< LFCLK RC oscillator. */ +#define NRF_CLOCK_LF_SRC_XTAL (1) /**< LFCLK crystal oscillator. */ +#define NRF_CLOCK_LF_SRC_SYNTH (2) /**< LFCLK Synthesized from HFCLK. */ + +/** @} */ + +/** @} */ + +/** @addtogroup NRF_SDM_TYPES Types + * @{ */ + +/**@brief Type representing LFCLK oscillator source. */ +typedef struct { + uint8_t source; /**< LF oscillator clock source, see @ref NRF_CLOCK_LF_SRC. */ + uint8_t rc_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: Calibration timer interval in 1/4 second + units (nRF52: 1-32). + @note To avoid excessive clock drift, 0.5 degrees Celsius is the + maximum temperature change allowed in one calibration timer + interval. The interval should be selected to ensure this. + + @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. */ + uint8_t rc_temp_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: How often (in number of calibration + intervals) the RC oscillator shall be calibrated if the temperature + hasn't changed. + 0: Always calibrate even if the temperature hasn't changed. + 1: Only calibrate if the temperature has changed (legacy - nRF51 only). + 2-33: Check the temperature and only calibrate if it has changed, + however calibration will take place every rc_temp_ctiv + intervals in any case. + + @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. + + @note For nRF52, the application must ensure calibration at least once + every 8 seconds to ensure +/-500 ppm clock stability. The + recommended configuration for ::NRF_CLOCK_LF_SRC_RC on nRF52 is + rc_ctiv=16 and rc_temp_ctiv=2. This will ensure calibration at + least once every 8 seconds and for temperature changes of 0.5 + degrees Celsius every 4 seconds. See the Product Specification + for the nRF52 device being used for more information.*/ + uint8_t accuracy; /**< External clock accuracy used in the LL to compute timing + windows, see @ref NRF_CLOCK_LF_ACCURACY.*/ +} nrf_clock_lf_cfg_t; + +/**@brief Fault Handler type. + * + * When certain unrecoverable errors occur within the application or SoftDevice the fault handler will be called back. + * The protocol stack will be in an undefined state when this happens and the only way to recover will be to + * perform a reset, using e.g. CMSIS NVIC_SystemReset(). + * If the application returns from the fault handler the SoftDevice will call NVIC_SystemReset(). + * + * @note It is recommended to either perform a reset in the fault handler or to let the SoftDevice reset the device. + * Otherwise SoC peripherals may behave in an undefined way. For example, the RADIO peripherial may + * continously transmit packets. + * + * @note This callback is executed in HardFault context, thus SVC functions cannot be called from the fault callback. + * + * @param[in] id Fault identifier. See @ref NRF_FAULT_IDS. + * @param[in] pc The program counter of the instruction that triggered the fault. + * @param[in] info Optional additional information regarding the fault. Refer to each Fault identifier for details. + * + * @note When id is set to @ref NRF_FAULT_ID_APP_MEMACC, pc will contain the address of the instruction being executed at the time + * when the fault is detected by the CPU. The CPU program counter may have advanced up to 2 instructions (no branching) after the + * one that triggered the fault. + */ +typedef void (*nrf_fault_handler_t)(uint32_t id, uint32_t pc, uint32_t info); + +/** @} */ + +/** @addtogroup NRF_SDM_FUNCTIONS Functions + * @{ */ + +/**@brief Enables the SoftDevice and by extension the protocol stack. + * + * @note Some care must be taken if a low frequency clock source is already running when calling this function: + * If the LF clock has a different source then the one currently running, it will be stopped. Then, the new + * clock source will be started. + * + * @note This function has no effect when returning with an error. + * + * @post If return code is ::NRF_SUCCESS + * - SoC library and protocol stack APIs are made available. + * - A portion of RAM will be unavailable (see relevant SDS documentation). + * - Some peripherals will be unavailable or available only through the SoC API (see relevant SDS documentation). + * - Interrupts will not arrive from protected peripherals or interrupts. + * - nrf_nvic_ functions must be used instead of CMSIS NVIC_ functions for reliable usage of the SoftDevice. + * - Interrupt latency may be affected by the SoftDevice (see relevant SDS documentation). + * - Chosen low frequency clock source will be running. + * + * @param p_clock_lf_cfg Low frequency clock source and accuracy. + If NULL the clock will be configured as an RC source with rc_ctiv = 16 and .rc_temp_ctiv = 2 + In the case of XTAL source, the PPM accuracy of the chosen clock source must be greater than or equal to + the actual characteristics of your XTAL clock. + * @param fault_handler Callback to be invoked in case of fault, cannot be NULL. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE SoftDevice is already enabled, and the clock source and fault handler cannot be updated. + * @retval ::NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION SoftDevice interrupt is already enabled, or an enabled interrupt has + an illegal priority level. + * @retval ::NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN Unknown low frequency clock source selected. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid clock source configuration supplied in p_clock_lf_cfg. + */ +SVCALL(SD_SOFTDEVICE_ENABLE, uint32_t, + sd_softdevice_enable(nrf_clock_lf_cfg_t const *p_clock_lf_cfg, nrf_fault_handler_t fault_handler)); + +/**@brief Disables the SoftDevice and by extension the protocol stack. + * + * Idempotent function to disable the SoftDevice. + * + * @post SoC library and protocol stack APIs are made unavailable. + * @post All interrupts that was protected by the SoftDevice will be disabled and initialized to priority 0 (highest). + * @post All peripherals used by the SoftDevice will be reset to default values. + * @post All of RAM become available. + * @post All interrupts are forwarded to the application. + * @post LFCLK source chosen in ::sd_softdevice_enable will be left running. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_DISABLE, uint32_t, sd_softdevice_disable(void)); + +/**@brief Check if the SoftDevice is enabled. + * + * @param[out] p_softdevice_enabled If the SoftDevice is enabled: 1 else 0. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_IS_ENABLED, uint32_t, sd_softdevice_is_enabled(uint8_t *p_softdevice_enabled)); + +/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the SoftDevice + * + * This function is only intended to be called when a bootloader is enabled. + * + * @param[in] address The base address of the interrupt vector table for forwarded interrupts. + + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table_base_set(uint32_t address)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_SDM_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_soc.h b/variants/wio-tracker-wm1110/softdevice/nrf_soc.h new file mode 100644 index 0000000000..c649ca836d --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_soc.h @@ -0,0 +1,1046 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup nrf_soc_api SoC Library API + * @{ + * + * @brief APIs for the SoC library. + * + */ + +#ifndef NRF_SOC_H__ +#define NRF_SOC_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup NRF_SOC_DEFINES Defines + * @{ */ + +/**@brief The number of the lowest SVC number reserved for the SoC library. */ +#define SOC_SVC_BASE (0x20) /**< Base value for SVCs that are available when the SoftDevice is disabled. */ +#define SOC_SVC_BASE_NOT_AVAILABLE (0x2C) /**< Base value for SVCs that are not available when the SoftDevice is disabled. */ + +/**@brief Guaranteed time for application to process radio inactive notification. */ +#define NRF_RADIO_NOTIFICATION_INACTIVE_GUARANTEED_TIME_US (62) + +/**@brief The minimum allowed timeslot extension time. */ +#define NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US (200) + +/**@brief The maximum processing time to handle a timeslot extension. */ +#define NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US (20) + +/**@brief The latest time before the end of a timeslot the timeslot can be extended. */ +#define NRF_RADIO_MIN_EXTENSION_MARGIN_US (82) + +#define SOC_ECB_KEY_LENGTH (16) /**< ECB key length. */ +#define SOC_ECB_CLEARTEXT_LENGTH (16) /**< ECB cleartext length. */ +#define SOC_ECB_CIPHERTEXT_LENGTH (SOC_ECB_CLEARTEXT_LENGTH) /**< ECB ciphertext length. */ + +#define SD_EVT_IRQn (SWI2_IRQn) /**< SoftDevice Event IRQ number. Used for both protocol events and SoC events. */ +#define SD_EVT_IRQHandler \ + (SWI2_IRQHandler) /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. \ + The default interrupt priority for this handler is set to 6 */ +#define RADIO_NOTIFICATION_IRQn (SWI1_IRQn) /**< The radio notification IRQ number. */ +#define RADIO_NOTIFICATION_IRQHandler \ + (SWI1_IRQHandler) /**< The radio notification IRQ handler. \ + The default interrupt priority for this handler is set to 6 */ +#define NRF_RADIO_LENGTH_MIN_US (100) /**< The shortest allowed radio timeslot, in microseconds. */ +#define NRF_RADIO_LENGTH_MAX_US (100000) /**< The longest allowed radio timeslot, in microseconds. */ + +#define NRF_RADIO_DISTANCE_MAX_US \ + (128000000UL - 1UL) /**< The longest timeslot distance, in microseconds, allowed for the distance parameter (see @ref \ + nrf_radio_request_normal_t) in the request. */ + +#define NRF_RADIO_EARLIEST_TIMEOUT_MAX_US \ + (128000000UL - 1UL) /**< The longest timeout, in microseconds, allowed when requesting the earliest possible timeslot. */ + +#define NRF_RADIO_START_JITTER_US \ + (2) /**< The maximum jitter in @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START relative to the requested start time. */ + +/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is disabled. */ +#define NRF_SOC_SD_PPI_CHANNELS_SD_DISABLED_MSK ((uint32_t)(0)) + +/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is enabled. */ +#define NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK \ + ((uint32_t)((1U << 17) | (1U << 18) | (1U << 19) | (1U << 20) | (1U << 21) | (1U << 22) | (1U << 23) | (1U << 24) | \ + (1U << 25) | (1U << 26) | (1U << 27) | (1U << 28) | (1U << 29) | (1U << 30) | (1U << 31))) + +/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is disabled. */ +#define NRF_SOC_SD_PPI_GROUPS_SD_DISABLED_MSK ((uint32_t)(0)) + +/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is enabled. */ +#define NRF_SOC_SD_PPI_GROUPS_SD_ENABLED_MSK ((uint32_t)((1U << 4) | (1U << 5))) + +/**@} */ + +/**@addtogroup NRF_SOC_ENUMS Enumerations + * @{ */ + +/**@brief The SVC numbers used by the SVC functions in the SoC library. */ +enum NRF_SOC_SVCS { + SD_PPI_CHANNEL_ENABLE_GET = SOC_SVC_BASE, + SD_PPI_CHANNEL_ENABLE_SET = SOC_SVC_BASE + 1, + SD_PPI_CHANNEL_ENABLE_CLR = SOC_SVC_BASE + 2, + SD_PPI_CHANNEL_ASSIGN = SOC_SVC_BASE + 3, + SD_PPI_GROUP_TASK_ENABLE = SOC_SVC_BASE + 4, + SD_PPI_GROUP_TASK_DISABLE = SOC_SVC_BASE + 5, + SD_PPI_GROUP_ASSIGN = SOC_SVC_BASE + 6, + SD_PPI_GROUP_GET = SOC_SVC_BASE + 7, + SD_FLASH_PAGE_ERASE = SOC_SVC_BASE + 8, + SD_FLASH_WRITE = SOC_SVC_BASE + 9, + SD_PROTECTED_REGISTER_WRITE = SOC_SVC_BASE + 11, + SD_MUTEX_NEW = SOC_SVC_BASE_NOT_AVAILABLE, + SD_MUTEX_ACQUIRE = SOC_SVC_BASE_NOT_AVAILABLE + 1, + SD_MUTEX_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 2, + SD_RAND_APPLICATION_POOL_CAPACITY_GET = SOC_SVC_BASE_NOT_AVAILABLE + 3, + SD_RAND_APPLICATION_BYTES_AVAILABLE_GET = SOC_SVC_BASE_NOT_AVAILABLE + 4, + SD_RAND_APPLICATION_VECTOR_GET = SOC_SVC_BASE_NOT_AVAILABLE + 5, + SD_POWER_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 6, + SD_POWER_SYSTEM_OFF = SOC_SVC_BASE_NOT_AVAILABLE + 7, + SD_POWER_RESET_REASON_GET = SOC_SVC_BASE_NOT_AVAILABLE + 8, + SD_POWER_RESET_REASON_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 9, + SD_POWER_POF_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 10, + SD_POWER_POF_THRESHOLD_SET = SOC_SVC_BASE_NOT_AVAILABLE + 11, + SD_POWER_POF_THRESHOLDVDDH_SET = SOC_SVC_BASE_NOT_AVAILABLE + 12, + SD_POWER_RAM_POWER_SET = SOC_SVC_BASE_NOT_AVAILABLE + 13, + SD_POWER_RAM_POWER_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 14, + SD_POWER_RAM_POWER_GET = SOC_SVC_BASE_NOT_AVAILABLE + 15, + SD_POWER_GPREGRET_SET = SOC_SVC_BASE_NOT_AVAILABLE + 16, + SD_POWER_GPREGRET_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 17, + SD_POWER_GPREGRET_GET = SOC_SVC_BASE_NOT_AVAILABLE + 18, + SD_POWER_DCDC_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 19, + SD_POWER_DCDC0_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 20, + SD_APP_EVT_WAIT = SOC_SVC_BASE_NOT_AVAILABLE + 21, + SD_CLOCK_HFCLK_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 22, + SD_CLOCK_HFCLK_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 23, + SD_CLOCK_HFCLK_IS_RUNNING = SOC_SVC_BASE_NOT_AVAILABLE + 24, + SD_RADIO_NOTIFICATION_CFG_SET = SOC_SVC_BASE_NOT_AVAILABLE + 25, + SD_ECB_BLOCK_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 26, + SD_ECB_BLOCKS_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 27, + SD_RADIO_SESSION_OPEN = SOC_SVC_BASE_NOT_AVAILABLE + 28, + SD_RADIO_SESSION_CLOSE = SOC_SVC_BASE_NOT_AVAILABLE + 29, + SD_RADIO_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 30, + SD_EVT_GET = SOC_SVC_BASE_NOT_AVAILABLE + 31, + SD_TEMP_GET = SOC_SVC_BASE_NOT_AVAILABLE + 32, + SD_POWER_USBPWRRDY_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 33, + SD_POWER_USBDETECTED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 34, + SD_POWER_USBREMOVED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 35, + SD_POWER_USBREGSTATUS_GET = SOC_SVC_BASE_NOT_AVAILABLE + 36, + SVC_SOC_LAST = SOC_SVC_BASE_NOT_AVAILABLE + 37 +}; + +/**@brief Possible values of a ::nrf_mutex_t. */ +enum NRF_MUTEX_VALUES { NRF_MUTEX_FREE, NRF_MUTEX_TAKEN }; + +/**@brief Power modes. */ +enum NRF_POWER_MODES { + NRF_POWER_MODE_CONSTLAT, /**< Constant latency mode. See power management in the reference manual. */ + NRF_POWER_MODE_LOWPWR /**< Low power mode. See power management in the reference manual. */ +}; + +/**@brief Power failure thresholds */ +enum NRF_POWER_THRESHOLDS { + NRF_POWER_THRESHOLD_V17 = 4UL, /**< 1.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V18, /**< 1.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V19, /**< 1.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V20, /**< 2.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V21, /**< 2.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V22, /**< 2.2 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V23, /**< 2.3 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V24, /**< 2.4 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V25, /**< 2.5 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V26, /**< 2.6 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V27, /**< 2.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V28 /**< 2.8 Volts power failure threshold. */ +}; + +/**@brief Power failure thresholds for high voltage */ +enum NRF_POWER_THRESHOLDVDDHS { + NRF_POWER_THRESHOLDVDDH_V27, /**< 2.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V28, /**< 2.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V29, /**< 2.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V30, /**< 3.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V31, /**< 3.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V32, /**< 3.2 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V33, /**< 3.3 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V34, /**< 3.4 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V35, /**< 3.5 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V36, /**< 3.6 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V37, /**< 3.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V38, /**< 3.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V39, /**< 3.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V40, /**< 4.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V41, /**< 4.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V42 /**< 4.2 Volts power failure threshold. */ +}; + +/**@brief DC/DC converter modes. */ +enum NRF_POWER_DCDC_MODES { + NRF_POWER_DCDC_DISABLE, /**< The DCDC is disabled. */ + NRF_POWER_DCDC_ENABLE /**< The DCDC is enabled. */ +}; + +/**@brief Radio notification distances. */ +enum NRF_RADIO_NOTIFICATION_DISTANCES { + NRF_RADIO_NOTIFICATION_DISTANCE_NONE = 0, /**< The event does not have a notification. */ + NRF_RADIO_NOTIFICATION_DISTANCE_800US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_1740US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_2680US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_3620US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_4560US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_5500US /**< The distance from the active notification to start of radio activity. */ +}; + +/**@brief Radio notification types. */ +enum NRF_RADIO_NOTIFICATION_TYPES { + NRF_RADIO_NOTIFICATION_TYPE_NONE = 0, /**< The event does not have a radio notification signal. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, /**< Using interrupt for notification when the radio will be enabled. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, /**< Using interrupt for notification when the radio has been disabled. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, /**< Using interrupt for notification both when the radio will be enabled and + disabled. */ +}; + +/**@brief The Radio signal callback types. */ +enum NRF_RADIO_CALLBACK_SIGNAL_TYPE { + NRF_RADIO_CALLBACK_SIGNAL_TYPE_START, /**< This signal indicates the start of the radio timeslot. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0, /**< This signal indicates the NRF_TIMER0 interrupt. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO, /**< This signal indicates the NRF_RADIO interrupt. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED, /**< This signal indicates extend action failed. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED /**< This signal indicates extend action succeeded. */ +}; + +/**@brief The actions requested by the signal callback. + * + * This code gives the SOC instructions about what action to take when the signal callback has + * returned. + */ +enum NRF_RADIO_SIGNAL_CALLBACK_ACTION { + NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE, /**< Return without action. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND, /**< Request an extension of the current + timeslot. Maximum execution time for this action: + @ref NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US. + This action must be started at least + @ref NRF_RADIO_MIN_EXTENSION_MARGIN_US before + the end of the timeslot. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_END, /**< End the current radio timeslot. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END /**< Request a new radio timeslot and end the current timeslot. */ +}; + +/**@brief Radio timeslot high frequency clock source configuration. */ +enum NRF_RADIO_HFCLK_CFG { + NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED, /**< The SoftDevice will guarantee that the high frequency clock source is the + external crystal for the whole duration of the timeslot. This should be the + preferred option for events that use the radio or require high timing accuracy. + @note The SoftDevice will automatically turn on and off the external crystal, + at the beginning and end of the timeslot, respectively. The crystal may also + intentionally be left running after the timeslot, in cases where it is needed + by the SoftDevice shortly after the end of the timeslot. */ + NRF_RADIO_HFCLK_CFG_NO_GUARANTEE /**< This configuration allows for earlier and tighter scheduling of timeslots. + The RC oscillator may be the clock source in part or for the whole duration of the + timeslot. The RC oscillator's accuracy must therefore be taken into consideration. + @note If the application will use the radio peripheral in timeslots with this + configuration, it must make sure that the crystal is running and stable before + starting the radio. */ +}; + +/**@brief Radio timeslot priorities. */ +enum NRF_RADIO_PRIORITY { + NRF_RADIO_PRIORITY_HIGH, /**< High (equal priority as the normal connection priority of the SoftDevice stack(s)). */ + NRF_RADIO_PRIORITY_NORMAL, /**< Normal (equal priority as the priority of secondary activities of the SoftDevice stack(s)). */ +}; + +/**@brief Radio timeslot request type. */ +enum NRF_RADIO_REQUEST_TYPE { + NRF_RADIO_REQ_TYPE_EARLIEST, /**< Request radio timeslot as early as possible. This should always be used for the first + request in a session. */ + NRF_RADIO_REQ_TYPE_NORMAL /**< Normal radio timeslot request. */ +}; + +/**@brief SoC Events. */ +enum NRF_SOC_EVTS { + NRF_EVT_HFCLKSTARTED, /**< Event indicating that the HFCLK has started. */ + NRF_EVT_POWER_FAILURE_WARNING, /**< Event indicating that a power failure warning has occurred. */ + NRF_EVT_FLASH_OPERATION_SUCCESS, /**< Event indicating that the ongoing flash operation has completed successfully. */ + NRF_EVT_FLASH_OPERATION_ERROR, /**< Event indicating that the ongoing flash operation has timed out with an error. */ + NRF_EVT_RADIO_BLOCKED, /**< Event indicating that a radio timeslot was blocked. */ + NRF_EVT_RADIO_CANCELED, /**< Event indicating that a radio timeslot was canceled by SoftDevice. */ + NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN, /**< Event indicating that a radio timeslot signal callback handler return was + invalid. */ + NRF_EVT_RADIO_SESSION_IDLE, /**< Event indicating that a radio timeslot session is idle. */ + NRF_EVT_RADIO_SESSION_CLOSED, /**< Event indicating that a radio timeslot session is closed. */ + NRF_EVT_POWER_USB_POWER_READY, /**< Event indicating that a USB 3.3 V supply is ready. */ + NRF_EVT_POWER_USB_DETECTED, /**< Event indicating that voltage supply is detected on VBUS. */ + NRF_EVT_POWER_USB_REMOVED, /**< Event indicating that voltage supply is removed from VBUS. */ + NRF_EVT_NUMBER_OF_EVTS +}; + +/**@} */ + +/**@addtogroup NRF_SOC_STRUCTURES Structures + * @{ */ + +/**@brief Represents a mutex for use with the nrf_mutex functions. + * @note Accessing the value directly is not safe, use the mutex functions! + */ +typedef volatile uint8_t nrf_mutex_t; + +/**@brief Parameters for a request for a timeslot as early as possible. */ +typedef struct { + uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ + uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ + uint32_t length_us; /**< The radio timeslot length (in the range 100 to 100,000] microseconds). */ + uint32_t timeout_us; /**< Longest acceptable delay until the start of the requested timeslot (up to @ref + NRF_RADIO_EARLIEST_TIMEOUT_MAX_US microseconds). */ +} nrf_radio_request_earliest_t; + +/**@brief Parameters for a normal radio timeslot request. */ +typedef struct { + uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ + uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ + uint32_t distance_us; /**< Distance from the start of the previous radio timeslot (up to @ref NRF_RADIO_DISTANCE_MAX_US + microseconds). */ + uint32_t length_us; /**< The radio timeslot length (in the range [100..100,000] microseconds). */ +} nrf_radio_request_normal_t; + +/**@brief Radio timeslot request parameters. */ +typedef struct { + uint8_t request_type; /**< Type of request, see @ref NRF_RADIO_REQUEST_TYPE. */ + union { + nrf_radio_request_earliest_t earliest; /**< Parameters for requesting a radio timeslot as early as possible. */ + nrf_radio_request_normal_t normal; /**< Parameters for requesting a normal radio timeslot. */ + } params; /**< Parameter union. */ +} nrf_radio_request_t; + +/**@brief Return parameters of the radio timeslot signal callback. */ +typedef struct { + uint8_t callback_action; /**< The action requested by the application when returning from the signal callback, see @ref + NRF_RADIO_SIGNAL_CALLBACK_ACTION. */ + union { + struct { + nrf_radio_request_t *p_next; /**< The request parameters for the next radio timeslot. */ + } request; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END. */ + struct { + uint32_t length_us; /**< Requested extension of the radio timeslot duration (microseconds) (for minimum time see @ref + NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US). */ + } extend; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND. */ + } params; /**< Parameter union. */ +} nrf_radio_signal_callback_return_param_t; + +/**@brief The radio timeslot signal callback type. + * + * @note In case of invalid return parameters, the radio timeslot will automatically end + * immediately after returning from the signal callback and the + * @ref NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN event will be sent. + * @note The returned struct pointer must remain valid after the signal callback + * function returns. For instance, this means that it must not point to a stack variable. + * + * @param[in] signal_type Type of signal, see @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE. + * + * @return Pointer to structure containing action requested by the application. + */ +typedef nrf_radio_signal_callback_return_param_t *(*nrf_radio_signal_callback_t)(uint8_t signal_type); + +/**@brief AES ECB parameter typedefs */ +typedef uint8_t soc_ecb_key_t[SOC_ECB_KEY_LENGTH]; /**< Encryption key type. */ +typedef uint8_t soc_ecb_cleartext_t[SOC_ECB_CLEARTEXT_LENGTH]; /**< Cleartext data type. */ +typedef uint8_t soc_ecb_ciphertext_t[SOC_ECB_CIPHERTEXT_LENGTH]; /**< Ciphertext data type. */ + +/**@brief AES ECB data structure */ +typedef struct { + soc_ecb_key_t key; /**< Encryption key. */ + soc_ecb_cleartext_t cleartext; /**< Cleartext data. */ + soc_ecb_ciphertext_t ciphertext; /**< Ciphertext data. */ +} nrf_ecb_hal_data_t; + +/**@brief AES ECB block. Used to provide multiple blocks in a single call + to @ref sd_ecb_blocks_encrypt.*/ +typedef struct { + soc_ecb_key_t const *p_key; /**< Pointer to the Encryption key. */ + soc_ecb_cleartext_t const *p_cleartext; /**< Pointer to the Cleartext data. */ + soc_ecb_ciphertext_t *p_ciphertext; /**< Pointer to the Ciphertext data. */ +} nrf_ecb_hal_data_block_t; + +/**@} */ + +/**@addtogroup NRF_SOC_FUNCTIONS Functions + * @{ */ + +/**@brief Initialize a mutex. + * + * @param[in] p_mutex Pointer to the mutex to initialize. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_MUTEX_NEW, uint32_t, sd_mutex_new(nrf_mutex_t *p_mutex)); + +/**@brief Attempt to acquire a mutex. + * + * @param[in] p_mutex Pointer to the mutex to acquire. + * + * @retval ::NRF_SUCCESS The mutex was successfully acquired. + * @retval ::NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN The mutex could not be acquired. + */ +SVCALL(SD_MUTEX_ACQUIRE, uint32_t, sd_mutex_acquire(nrf_mutex_t *p_mutex)); + +/**@brief Release a mutex. + * + * @param[in] p_mutex Pointer to the mutex to release. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_MUTEX_RELEASE, uint32_t, sd_mutex_release(nrf_mutex_t *p_mutex)); + +/**@brief Query the capacity of the application random pool. + * + * @param[out] p_pool_capacity The capacity of the pool. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RAND_APPLICATION_POOL_CAPACITY_GET, uint32_t, sd_rand_application_pool_capacity_get(uint8_t *p_pool_capacity)); + +/**@brief Get number of random bytes available to the application. + * + * @param[out] p_bytes_available The number of bytes currently available in the pool. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RAND_APPLICATION_BYTES_AVAILABLE_GET, uint32_t, sd_rand_application_bytes_available_get(uint8_t *p_bytes_available)); + +/**@brief Get random bytes from the application pool. + * + * @param[out] p_buff Pointer to unit8_t buffer for storing the bytes. + * @param[in] length Number of bytes to take from pool and place in p_buff. + * + * @retval ::NRF_SUCCESS The requested bytes were written to p_buff. + * @retval ::NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES No bytes were written to the buffer, because there were not enough bytes + * available. + */ +SVCALL(SD_RAND_APPLICATION_VECTOR_GET, uint32_t, sd_rand_application_vector_get(uint8_t *p_buff, uint8_t length)); + +/**@brief Gets the reset reason register. + * + * @param[out] p_reset_reason Contents of the NRF_POWER->RESETREAS register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RESET_REASON_GET, uint32_t, sd_power_reset_reason_get(uint32_t *p_reset_reason)); + +/**@brief Clears the bits of the reset reason register. + * + * @param[in] reset_reason_clr_msk Contains the bits to clear from the reset reason register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RESET_REASON_CLR, uint32_t, sd_power_reset_reason_clr(uint32_t reset_reason_clr_msk)); + +/**@brief Sets the power mode when in CPU sleep. + * + * @param[in] power_mode The power mode to use when in CPU sleep, see @ref NRF_POWER_MODES. @sa sd_app_evt_wait + * + * @retval ::NRF_SUCCESS The power mode was set. + * @retval ::NRF_ERROR_SOC_POWER_MODE_UNKNOWN The power mode was unknown. + */ +SVCALL(SD_POWER_MODE_SET, uint32_t, sd_power_mode_set(uint8_t power_mode)); + +/**@brief Puts the chip in System OFF mode. + * + * @retval ::NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN + */ +SVCALL(SD_POWER_SYSTEM_OFF, uint32_t, sd_power_system_off(void)); + +/**@brief Enables or disables the power-fail comparator. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_FAILURE_WARNING) when the power failure warning occurs. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] pof_enable True if the power-fail comparator should be enabled, false if it should be disabled. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_POF_ENABLE, uint32_t, sd_power_pof_enable(uint8_t pof_enable)); + +/**@brief Enables or disables the USB power ready event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_POWER_READY) when a USB 3.3 V supply is ready. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbpwrrdy_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBPWRRDY_ENABLE, uint32_t, sd_power_usbpwrrdy_enable(uint8_t usbpwrrdy_enable)); + +/**@brief Enables or disables the power USB-detected event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_DETECTED) when a voltage supply is detected on VBUS. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbdetected_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBDETECTED_ENABLE, uint32_t, sd_power_usbdetected_enable(uint8_t usbdetected_enable)); + +/**@brief Enables or disables the power USB-removed event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_REMOVED) when a voltage supply is removed from VBUS. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbremoved_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBREMOVED_ENABLE, uint32_t, sd_power_usbremoved_enable(uint8_t usbremoved_enable)); + +/**@brief Get USB supply status register content. + * + * @param[out] usbregstatus The content of USBREGSTATUS register. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBREGSTATUS_GET, uint32_t, sd_power_usbregstatus_get(uint32_t *usbregstatus)); + +/**@brief Sets the power failure comparator threshold value. + * + * @note: Power failure comparator threshold setting. This setting applies both for normal voltage + * mode (supply connected to both VDD and VDDH) and high voltage mode (supply connected to + * VDDH only). + * + * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDS. + * + * @retval ::NRF_SUCCESS The power failure threshold was set. + * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. + */ +SVCALL(SD_POWER_POF_THRESHOLD_SET, uint32_t, sd_power_pof_threshold_set(uint8_t threshold)); + +/**@brief Sets the power failure comparator threshold value for high voltage. + * + * @note: Power failure comparator threshold setting for high voltage mode (supply connected to + * VDDH only). This setting does not apply for normal voltage mode (supply connected to both + * VDD and VDDH). + * + * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDVDDHS. + * + * @retval ::NRF_SUCCESS The power failure threshold was set. + * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. + */ +SVCALL(SD_POWER_POF_THRESHOLDVDDH_SET, uint32_t, sd_power_pof_thresholdvddh_set(uint8_t threshold)); + +/**@brief Writes the NRF_POWER->RAM[index].POWERSET register. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERSET register to write to. + * @param[in] ram_powerset Contains the word to write to the NRF_POWER->RAM[index].POWERSET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_SET, uint32_t, sd_power_ram_power_set(uint8_t index, uint32_t ram_powerset)); + +/**@brief Writes the NRF_POWER->RAM[index].POWERCLR register. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERCLR register to write to. + * @param[in] ram_powerclr Contains the word to write to the NRF_POWER->RAM[index].POWERCLR register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_CLR, uint32_t, sd_power_ram_power_clr(uint8_t index, uint32_t ram_powerclr)); + +/**@brief Get contents of NRF_POWER->RAM[index].POWER register, indicates power status of RAM[index] blocks. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWER register to read from. + * @param[out] p_ram_power Content of NRF_POWER->RAM[index].POWER register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_GET, uint32_t, sd_power_ram_power_get(uint8_t index, uint32_t *p_ram_power)); + +/**@brief Set bits in the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[in] gpregret_msk Bits to be set in the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_SET, uint32_t, sd_power_gpregret_set(uint32_t gpregret_id, uint32_t gpregret_msk)); + +/**@brief Clear bits in the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[in] gpregret_msk Bits to be clear in the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_CLR, uint32_t, sd_power_gpregret_clr(uint32_t gpregret_id, uint32_t gpregret_msk)); + +/**@brief Get contents of the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[out] p_gpregret Contents of the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_GET, uint32_t, sd_power_gpregret_get(uint32_t gpregret_id, uint32_t *p_gpregret)); + +/**@brief Enable or disable the DC/DC regulator for the regulator stage 1 (REG1). + * + * @param[in] dcdc_mode The mode of the DCDC, see @ref NRF_POWER_DCDC_MODES. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_PARAM The DCDC mode is invalid. + */ +SVCALL(SD_POWER_DCDC_MODE_SET, uint32_t, sd_power_dcdc_mode_set(uint8_t dcdc_mode)); + +/**@brief Enable or disable the DC/DC regulator for the regulator stage 0 (REG0). + * + * For more details on the REG0 stage, please see product specification. + * + * @param[in] dcdc_mode The mode of the DCDC0, see @ref NRF_POWER_DCDC_MODES. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_PARAM The dcdc_mode is invalid. + */ +SVCALL(SD_POWER_DCDC0_MODE_SET, uint32_t, sd_power_dcdc0_mode_set(uint8_t dcdc_mode)); + +/**@brief Request the high frequency crystal oscillator. + * + * Will start the high frequency crystal oscillator, the startup time of the crystal varies + * and the ::sd_clock_hfclk_is_running function can be polled to check if it has started. + * + * @see sd_clock_hfclk_is_running + * @see sd_clock_hfclk_release + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_REQUEST, uint32_t, sd_clock_hfclk_request(void)); + +/**@brief Releases the high frequency crystal oscillator. + * + * Will stop the high frequency crystal oscillator, this happens immediately. + * + * @see sd_clock_hfclk_is_running + * @see sd_clock_hfclk_request + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_RELEASE, uint32_t, sd_clock_hfclk_release(void)); + +/**@brief Checks if the high frequency crystal oscillator is running. + * + * @see sd_clock_hfclk_request + * @see sd_clock_hfclk_release + * + * @param[out] p_is_running 1 if the external crystal oscillator is running, 0 if not. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_IS_RUNNING, uint32_t, sd_clock_hfclk_is_running(uint32_t *p_is_running)); + +/**@brief Waits for an application event. + * + * An application event is either an application interrupt or a pended interrupt when the interrupt + * is disabled. + * + * When the application waits for an application event by calling this function, an interrupt that + * is enabled will be taken immediately on pending since this function will wait in thread mode, + * then the execution will return in the application's main thread. + * + * In order to wake up from disabled interrupts, the SEVONPEND flag has to be set in the Cortex-M + * MCU's System Control Register (SCR), CMSIS_SCB. In that case, when a disabled interrupt gets + * pended, this function will return to the application's main thread. + * + * @note The application must ensure that the pended flag is cleared using ::sd_nvic_ClearPendingIRQ + * in order to sleep using this function. This is only necessary for disabled interrupts, as + * the interrupt handler will clear the pending flag automatically for enabled interrupts. + * + * @note If an application interrupt has happened since the last time sd_app_evt_wait was + * called this function will return immediately and not go to sleep. This is to avoid race + * conditions that can occur when a flag is updated in the interrupt handler and processed + * in the main loop. + * + * @post An application interrupt has happened or a interrupt pending flag is set. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_APP_EVT_WAIT, uint32_t, sd_app_evt_wait(void)); + +/**@brief Get PPI channel enable register contents. + * + * @param[out] p_channel_enable The contents of the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_GET, uint32_t, sd_ppi_channel_enable_get(uint32_t *p_channel_enable)); + +/**@brief Set PPI channel enable register. + * + * @param[in] channel_enable_set_msk Mask containing the bits to set in the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_SET, uint32_t, sd_ppi_channel_enable_set(uint32_t channel_enable_set_msk)); + +/**@brief Clear PPI channel enable register. + * + * @param[in] channel_enable_clr_msk Mask containing the bits to clear in the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_CLR, uint32_t, sd_ppi_channel_enable_clr(uint32_t channel_enable_clr_msk)); + +/**@brief Assign endpoints to a PPI channel. + * + * @param[in] channel_num Number of the PPI channel to assign. + * @param[in] evt_endpoint Event endpoint of the PPI channel. + * @param[in] task_endpoint Task endpoint of the PPI channel. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_CHANNEL The channel number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ASSIGN, uint32_t, + sd_ppi_channel_assign(uint8_t channel_num, const volatile void *evt_endpoint, const volatile void *task_endpoint)); + +/**@brief Task to enable a channel group. + * + * @param[in] group_num Number of the channel group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_TASK_ENABLE, uint32_t, sd_ppi_group_task_enable(uint8_t group_num)); + +/**@brief Task to disable a channel group. + * + * @param[in] group_num Number of the PPI group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_TASK_DISABLE, uint32_t, sd_ppi_group_task_disable(uint8_t group_num)); + +/**@brief Assign PPI channels to a channel group. + * + * @param[in] group_num Number of the channel group. + * @param[in] channel_msk Mask of the channels to assign to the group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_ASSIGN, uint32_t, sd_ppi_group_assign(uint8_t group_num, uint32_t channel_msk)); + +/**@brief Gets the PPI channels of a channel group. + * + * @param[in] group_num Number of the channel group. + * @param[out] p_channel_msk Mask of the channels assigned to the group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_GET, uint32_t, sd_ppi_group_get(uint8_t group_num, uint32_t *p_channel_msk)); + +/**@brief Configures the Radio Notification signal. + * + * @note + * - The notification signal latency depends on the interrupt priority settings of SWI used + * for notification signal. + * - To ensure that the radio notification signal behaves in a consistent way, the radio + * notifications must be configured when there is no protocol stack or other SoftDevice + * activity in progress. It is recommended that the radio notification signal is + * configured directly after the SoftDevice has been enabled. + * - In the period between the ACTIVE signal and the start of the Radio Event, the SoftDevice + * will interrupt the application to do Radio Event preparation. + * - Using the Radio Notification feature may limit the bandwidth, as the SoftDevice may have + * to shorten the connection events to have time for the Radio Notification signals. + * + * @param[in] type Type of notification signal, see @ref NRF_RADIO_NOTIFICATION_TYPES. + * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE shall be used to turn off radio + * notification. Using @ref NRF_RADIO_NOTIFICATION_DISTANCE_NONE is + * recommended (but not required) to be used with + * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE. + * + * @param[in] distance Distance between the notification signal and start of radio activity, see @ref + * NRF_RADIO_NOTIFICATION_DISTANCES. This parameter is ignored when @ref NRF_RADIO_NOTIFICATION_TYPE_NONE or + * @ref NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE is used. + * + * @retval ::NRF_ERROR_INVALID_PARAM The group number is invalid. + * @retval ::NRF_ERROR_INVALID_STATE A protocol stack or other SoftDevice is running. Stop all + * running activities and retry. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RADIO_NOTIFICATION_CFG_SET, uint32_t, sd_radio_notification_cfg_set(uint8_t type, uint8_t distance)); + +/**@brief Encrypts a block according to the specified parameters. + * + * 128-bit AES encryption. + * + * @note: + * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while + * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application + * main or low interrupt level. + * + * @param[in, out] p_ecb_data Pointer to the ECB parameters' struct (two input + * parameters and one output parameter). + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_ECB_BLOCK_ENCRYPT, uint32_t, sd_ecb_block_encrypt(nrf_ecb_hal_data_t *p_ecb_data)); + +/**@brief Encrypts multiple data blocks provided as an array of data block structures. + * + * @details: Performs 128-bit AES encryption on multiple data blocks + * + * @note: + * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while + * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application + * main or low interrupt level. + * + * @param[in] block_count Count of blocks in the p_data_blocks array. + * @param[in,out] p_data_blocks Pointer to the first entry in a contiguous array of + * @ref nrf_ecb_hal_data_block_t structures. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_ECB_BLOCKS_ENCRYPT, uint32_t, sd_ecb_blocks_encrypt(uint8_t block_count, nrf_ecb_hal_data_block_t *p_data_blocks)); + +/**@brief Gets any pending events generated by the SoC API. + * + * The application should keep calling this function to get events, until ::NRF_ERROR_NOT_FOUND is returned. + * + * @param[out] p_evt_id Set to one of the values in @ref NRF_SOC_EVTS, if any events are pending. + * + * @retval ::NRF_SUCCESS An event was pending. The event id is written in the p_evt_id parameter. + * @retval ::NRF_ERROR_NOT_FOUND No pending events. + */ +SVCALL(SD_EVT_GET, uint32_t, sd_evt_get(uint32_t *p_evt_id)); + +/**@brief Get the temperature measured on the chip + * + * This function will block until the temperature measurement is done. + * It takes around 50 us from call to return. + * + * @param[out] p_temp Result of temperature measurement. Die temperature in 0.25 degrees Celsius. + * + * @retval ::NRF_SUCCESS A temperature measurement was done, and the temperature was written to temp + */ +SVCALL(SD_TEMP_GET, uint32_t, sd_temp_get(int32_t *p_temp)); + +/**@brief Flash Write + * + * Commands to write a buffer to flash + * + * If the SoftDevice is enabled: + * This call initiates the flash access command, and its completion will be communicated to the + * application with exactly one of the following events: + * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. + * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. + * + * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the + * write has been completed + * + * @note + * - This call takes control over the radio and the CPU during flash erase and write to make sure that + * they will not interfere with the flash access. This means that all interrupts will be blocked + * for a predictable time (depending on the NVMC specification in the device's Product Specification + * and the command parameters). + * - The data in the p_src buffer should not be modified before the @ref NRF_EVT_FLASH_OPERATION_SUCCESS + * or the @ref NRF_EVT_FLASH_OPERATION_ERROR have been received if the SoftDevice is enabled. + * - This call will make the SoftDevice trigger a hardfault when the page is written, if it is + * protected. + * + * + * @param[in] p_dst Pointer to start of flash location to be written. + * @param[in] p_src Pointer to buffer with data to be written. + * @param[in] size Number of 32-bit words to write. Maximum size is the number of words in one + * flash page. See the device's Product Specification for details. + * + * @retval ::NRF_ERROR_INVALID_ADDR Tried to write to a non existing flash address, or p_dst or p_src was unaligned. + * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. + * @retval ::NRF_ERROR_INVALID_LENGTH Size was 0, or higher than the maximum allowed size. + * @retval ::NRF_ERROR_FORBIDDEN Tried to write to an address outside the application flash area. + * @retval ::NRF_SUCCESS The command was accepted. + */ +SVCALL(SD_FLASH_WRITE, uint32_t, sd_flash_write(uint32_t *p_dst, uint32_t const *p_src, uint32_t size)); + +/**@brief Flash Erase page + * + * Commands to erase a flash page + * If the SoftDevice is enabled: + * This call initiates the flash access command, and its completion will be communicated to the + * application with exactly one of the following events: + * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. + * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. + * + * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the + * erase has been completed + * + * @note + * - This call takes control over the radio and the CPU during flash erase and write to make sure that + * they will not interfere with the flash access. This means that all interrupts will be blocked + * for a predictable time (depending on the NVMC specification in the device's Product Specification + * and the command parameters). + * - This call will make the SoftDevice trigger a hardfault when the page is erased, if it is + * protected. + * + * + * @param[in] page_number Page number of the page to erase + * + * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. + * @retval ::NRF_ERROR_INVALID_ADDR Tried to erase to a non existing flash page. + * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. + * @retval ::NRF_ERROR_FORBIDDEN Tried to erase a page outside the application flash area. + * @retval ::NRF_SUCCESS The command was accepted. + */ +SVCALL(SD_FLASH_PAGE_ERASE, uint32_t, sd_flash_page_erase(uint32_t page_number)); + +/**@brief Opens a session for radio timeslot requests. + * + * @note Only one session can be open at a time. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) will be called when the radio timeslot + * starts. From this point the NRF_RADIO and NRF_TIMER0 peripherals can be freely accessed + * by the application. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0) is called whenever the NRF_TIMER0 + * interrupt occurs. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO) is called whenever the NRF_RADIO + * interrupt occurs. + * @note p_radio_signal_callback() will be called at ARM interrupt priority level 0. This + * implies that none of the sd_* API calls can be used from p_radio_signal_callback(). + * + * @param[in] p_radio_signal_callback The signal callback. + * + * @retval ::NRF_ERROR_INVALID_ADDR p_radio_signal_callback is an invalid function pointer. + * @retval ::NRF_ERROR_BUSY If session cannot be opened. + * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_SESSION_OPEN, uint32_t, sd_radio_session_open(nrf_radio_signal_callback_t p_radio_signal_callback)); + +/**@brief Closes a session for radio timeslot requests. + * + * @note Any current radio timeslot will be finished before the session is closed. + * @note If a radio timeslot is scheduled when the session is closed, it will be canceled. + * @note The application cannot consider the session closed until the @ref NRF_EVT_RADIO_SESSION_CLOSED + * event is received. + * + * @retval ::NRF_ERROR_FORBIDDEN If session not opened. + * @retval ::NRF_ERROR_BUSY If session is currently being closed. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_SESSION_CLOSE, uint32_t, sd_radio_session_close(void)); + +/**@brief Requests a radio timeslot. + * + * @note The request type is determined by p_request->request_type, and can be one of @ref NRF_RADIO_REQ_TYPE_EARLIEST + * and @ref NRF_RADIO_REQ_TYPE_NORMAL. The first request in a session must always be of type @ref + * NRF_RADIO_REQ_TYPE_EARLIEST. + * @note For a normal request (@ref NRF_RADIO_REQ_TYPE_NORMAL), the start time of a radio timeslot is specified by + * p_request->distance_us and is given relative to the start of the previous timeslot. + * @note A too small p_request->distance_us will lead to a @ref NRF_EVT_RADIO_BLOCKED event. + * @note Timeslots scheduled too close will lead to a @ref NRF_EVT_RADIO_BLOCKED event. + * @note See the SoftDevice Specification for more on radio timeslot scheduling, distances and lengths. + * @note If an opportunity for the first radio timeslot is not found before 100 ms after the call to this + * function, it is not scheduled, and instead a @ref NRF_EVT_RADIO_BLOCKED event is sent. + * The application may then try to schedule the first radio timeslot again. + * @note Successful requests will result in nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START). + * Unsuccessful requests will result in a @ref NRF_EVT_RADIO_BLOCKED event, see @ref NRF_SOC_EVTS. + * @note The jitter in the start time of the radio timeslots is +/- @ref NRF_RADIO_START_JITTER_US us. + * @note The nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) call has a latency relative to the + * specified radio timeslot start, but this does not affect the actual start time of the timeslot. + * @note NRF_TIMER0 is reset at the start of the radio timeslot, and is clocked at 1MHz from the high frequency + * (16 MHz) clock source. If p_request->hfclk_force_xtal is true, the high frequency clock is + * guaranteed to be clocked from the external crystal. + * @note The SoftDevice will neither access the NRF_RADIO peripheral nor the NRF_TIMER0 peripheral + * during the radio timeslot. + * + * @param[in] p_request Pointer to the request parameters. + * + * @retval ::NRF_ERROR_FORBIDDEN Either: + * - The session is not open. + * - The session is not IDLE. + * - This is the first request and its type is not @ref NRF_RADIO_REQ_TYPE_EARLIEST. + * - The request type was set to @ref NRF_RADIO_REQ_TYPE_NORMAL after a + * @ref NRF_RADIO_REQ_TYPE_EARLIEST request was blocked. + * @retval ::NRF_ERROR_INVALID_ADDR If the p_request pointer is invalid. + * @retval ::NRF_ERROR_INVALID_PARAM If the parameters of p_request are not valid. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_REQUEST, uint32_t, sd_radio_request(nrf_radio_request_t const *p_request)); + +/**@brief Write register protected by the SoftDevice + * + * This function writes to a register that is write-protected by the SoftDevice. Please refer to your + * SoftDevice Specification for more details about which registers that are protected by SoftDevice. + * This function can write to the following protected peripheral: + * - ACL + * + * @note Protected registers may be read directly. + * @note Register that are write-once will return @ref NRF_SUCCESS on second set, even the value in + * the register has not changed. See the Product Specification for more details about register + * properties. + * + * @param[in] p_register Pointer to register to be written. + * @param[in] value Value to be written to the register. + * + * @retval ::NRF_ERROR_INVALID_ADDR This function can not write to the reguested register. + * @retval ::NRF_SUCCESS Value successfully written to register. + * + */ +SVCALL(SD_PROTECTED_REGISTER_WRITE, uint32_t, sd_protected_register_write(volatile uint32_t *p_register, uint32_t value)); + +/**@} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_SOC_H__ + +/**@} */ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_svc.h b/variants/wio-tracker-wm1110/softdevice/nrf_svc.h new file mode 100644 index 0000000000..1de44656f3 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_svc.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NRF_SVC__ +#define NRF_SVC__ + +#include "stdint.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Supervisor call declaration. + * + * A call to a function marked with @ref SVCALL, will trigger a Supervisor Call (SVC) Exception. + * The SVCs with SVC numbers 0x00-0x0F are forwared to the application. All other SVCs are handled by the SoftDevice. + * + * @param[in] number The SVC number to be used. + * @param[in] return_type The return type of the SVC function. + * @param[in] signature Function signature. The function can have at most four arguments. + */ + +#ifdef SVCALL_AS_NORMAL_FUNCTION +#define SVCALL(number, return_type, signature) return_type signature +#else + +#ifndef SVCALL +#if defined(__CC_ARM) +#define SVCALL(number, return_type, signature) return_type __svc(number) signature +#elif defined(__GNUC__) +#ifdef __cplusplus +#define GCC_CAST_CPP (uint16_t) +#else +#define GCC_CAST_CPP +#endif +#define SVCALL(number, return_type, signature) \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") __attribute__((naked)) \ + __attribute__((unused)) static return_type signature \ + { \ + __asm("svc %0\n" \ + "bx r14" \ + : \ + : "I"(GCC_CAST_CPP number) \ + : "r0"); \ + } \ + _Pragma("GCC diagnostic pop") + +#elif defined(__ICCARM__) +#define PRAGMA(x) _Pragma(#x) +#define SVCALL(number, return_type, signature) \ + PRAGMA(swi_number = (number)) \ + __swi return_type signature; +#else +#define SVCALL(number, return_type, signature) return_type signature +#endif +#endif // SVCALL + +#endif // SVCALL_AS_NORMAL_FUNCTION + +#ifdef __cplusplus +} +#endif +#endif // NRF_SVC__ From deb7c274c4864812f4ebc936fefb8f2f5ccffaea Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Mon, 8 Jul 2024 19:02:05 +0800 Subject: [PATCH 129/211] Cleanup NRF s140 Softdevice variants (#4252) Note: This idea is originally from @caveman99 and should be credited as such. Submitting as a separate PR so the work in meshtastic/firmware#4148 can be a bit cleaner and Seeed boards can build while that work is ongoing. The nrf52 boards that depend on the v7 softdevice all use the same code and linker files. Rather than duplicate the code, keep it all together with the platform. --- boards/wio-tracker-wm1110.json | 2 +- .../platform/nrf52}/nrf52840_s140_v7.ld | 0 .../platform/nrf52}/softdevice/ble.h | 0 .../platform/nrf52}/softdevice/ble_err.h | 0 .../platform/nrf52}/softdevice/ble_gap.h | 0 .../platform/nrf52}/softdevice/ble_gatt.h | 0 .../platform/nrf52}/softdevice/ble_gattc.h | 0 .../platform/nrf52}/softdevice/ble_gatts.h | 0 .../platform/nrf52}/softdevice/ble_hci.h | 0 .../platform/nrf52}/softdevice/ble_l2cap.h | 0 .../platform/nrf52}/softdevice/ble_ranges.h | 0 .../platform/nrf52}/softdevice/ble_types.h | 0 .../nrf52}/softdevice/nrf52/nrf_mbr.h | 0 .../platform/nrf52}/softdevice/nrf_error.h | 0 .../nrf52}/softdevice/nrf_error_sdm.h | 0 .../nrf52}/softdevice/nrf_error_soc.h | 0 .../platform/nrf52}/softdevice/nrf_nvic.h | 0 .../platform/nrf52}/softdevice/nrf_sdm.h | 2 +- .../platform/nrf52}/softdevice/nrf_soc.h | 0 .../platform/nrf52}/softdevice/nrf_svc.h | 0 variants/wio-sdk-wm1110/platformio.ini | 6 +-- .../wio-tracker-wm1110/nrf52840_s140_v7.ld | 38 ------------------- variants/wio-tracker-wm1110/platformio.ini | 6 +-- variants/xiao_ble/nrf52840_s140_v7.ld | 38 ------------------- variants/xiao_ble/platformio.ini | 4 +- 25 files changed, 10 insertions(+), 86 deletions(-) rename {variants/wio-sdk-wm1110 => src/platform/nrf52}/nrf52840_s140_v7.ld (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_err.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_gap.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_gatt.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_gattc.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_gatts.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_hci.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_l2cap.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_ranges.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/ble_types.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf52/nrf_mbr.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_error.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_error_sdm.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_error_soc.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_nvic.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_sdm.h (99%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_soc.h (100%) rename {variants/xiao_ble => src/platform/nrf52}/softdevice/nrf_svc.h (100%) delete mode 100644 variants/wio-tracker-wm1110/nrf52840_s140_v7.ld delete mode 100644 variants/xiao_ble/nrf52840_s140_v7.ld diff --git a/boards/wio-tracker-wm1110.json b/boards/wio-tracker-wm1110.json index 04db525188..37a9186abb 100644 --- a/boards/wio-tracker-wm1110.json +++ b/boards/wio-tracker-wm1110.json @@ -53,6 +53,6 @@ "require_upload_port": true, "wait_for_upload_port": true }, - "url": "https://www.seeedstudio.com/Wio-WM1110-Dev-Kit-p-5677.html", + "url": "https://www.seeedstudio.com/Wio-Tracker-1110-Dev-Board-p-5799.html", "vendor": "Seeed Studio" } diff --git a/variants/wio-sdk-wm1110/nrf52840_s140_v7.ld b/src/platform/nrf52/nrf52840_s140_v7.ld similarity index 100% rename from variants/wio-sdk-wm1110/nrf52840_s140_v7.ld rename to src/platform/nrf52/nrf52840_s140_v7.ld diff --git a/variants/xiao_ble/softdevice/ble.h b/src/platform/nrf52/softdevice/ble.h similarity index 100% rename from variants/xiao_ble/softdevice/ble.h rename to src/platform/nrf52/softdevice/ble.h diff --git a/variants/xiao_ble/softdevice/ble_err.h b/src/platform/nrf52/softdevice/ble_err.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_err.h rename to src/platform/nrf52/softdevice/ble_err.h diff --git a/variants/xiao_ble/softdevice/ble_gap.h b/src/platform/nrf52/softdevice/ble_gap.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_gap.h rename to src/platform/nrf52/softdevice/ble_gap.h diff --git a/variants/xiao_ble/softdevice/ble_gatt.h b/src/platform/nrf52/softdevice/ble_gatt.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_gatt.h rename to src/platform/nrf52/softdevice/ble_gatt.h diff --git a/variants/xiao_ble/softdevice/ble_gattc.h b/src/platform/nrf52/softdevice/ble_gattc.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_gattc.h rename to src/platform/nrf52/softdevice/ble_gattc.h diff --git a/variants/xiao_ble/softdevice/ble_gatts.h b/src/platform/nrf52/softdevice/ble_gatts.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_gatts.h rename to src/platform/nrf52/softdevice/ble_gatts.h diff --git a/variants/xiao_ble/softdevice/ble_hci.h b/src/platform/nrf52/softdevice/ble_hci.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_hci.h rename to src/platform/nrf52/softdevice/ble_hci.h diff --git a/variants/xiao_ble/softdevice/ble_l2cap.h b/src/platform/nrf52/softdevice/ble_l2cap.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_l2cap.h rename to src/platform/nrf52/softdevice/ble_l2cap.h diff --git a/variants/xiao_ble/softdevice/ble_ranges.h b/src/platform/nrf52/softdevice/ble_ranges.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_ranges.h rename to src/platform/nrf52/softdevice/ble_ranges.h diff --git a/variants/xiao_ble/softdevice/ble_types.h b/src/platform/nrf52/softdevice/ble_types.h similarity index 100% rename from variants/xiao_ble/softdevice/ble_types.h rename to src/platform/nrf52/softdevice/ble_types.h diff --git a/variants/xiao_ble/softdevice/nrf52/nrf_mbr.h b/src/platform/nrf52/softdevice/nrf52/nrf_mbr.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf52/nrf_mbr.h rename to src/platform/nrf52/softdevice/nrf52/nrf_mbr.h diff --git a/variants/xiao_ble/softdevice/nrf_error.h b/src/platform/nrf52/softdevice/nrf_error.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_error.h rename to src/platform/nrf52/softdevice/nrf_error.h diff --git a/variants/xiao_ble/softdevice/nrf_error_sdm.h b/src/platform/nrf52/softdevice/nrf_error_sdm.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_error_sdm.h rename to src/platform/nrf52/softdevice/nrf_error_sdm.h diff --git a/variants/xiao_ble/softdevice/nrf_error_soc.h b/src/platform/nrf52/softdevice/nrf_error_soc.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_error_soc.h rename to src/platform/nrf52/softdevice/nrf_error_soc.h diff --git a/variants/xiao_ble/softdevice/nrf_nvic.h b/src/platform/nrf52/softdevice/nrf_nvic.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_nvic.h rename to src/platform/nrf52/softdevice/nrf_nvic.h diff --git a/variants/xiao_ble/softdevice/nrf_sdm.h b/src/platform/nrf52/softdevice/nrf_sdm.h similarity index 99% rename from variants/xiao_ble/softdevice/nrf_sdm.h rename to src/platform/nrf52/softdevice/nrf_sdm.h index 2786a86a45..33b6cc3421 100644 --- a/variants/xiao_ble/softdevice/nrf_sdm.h +++ b/src/platform/nrf52/softdevice/nrf_sdm.h @@ -141,7 +141,7 @@ the start of the SoftDevice (without MBR)*/ * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed * just above the MBR (the usual case). */ -#define SD_FLASH_SIZE 0x26000 +#define SD_FLASH_SIZE 0x27000 /** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual diff --git a/variants/xiao_ble/softdevice/nrf_soc.h b/src/platform/nrf52/softdevice/nrf_soc.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_soc.h rename to src/platform/nrf52/softdevice/nrf_soc.h diff --git a/variants/xiao_ble/softdevice/nrf_svc.h b/src/platform/nrf52/softdevice/nrf_svc.h similarity index 100% rename from variants/xiao_ble/softdevice/nrf_svc.h rename to src/platform/nrf52/softdevice/nrf_svc.h diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini index 619f86e1e2..aa10f525d3 100644 --- a/variants/wio-sdk-wm1110/platformio.ini +++ b/variants/wio-sdk-wm1110/platformio.ini @@ -1,4 +1,4 @@ -; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmware for 5005/19003, with or without OLED RAK 1921 +; The black Wio-WM1110 Dev Kit with sensors and the WM1110 module [env:wio-sdk-wm1110] extends = nrf52840_base board = wio-sdk-wm1110 @@ -8,10 +8,10 @@ build_unflags = ${nrf52840_base:build_unflags} -DUSBCON -DUSE_TINYUSB board_level = extra ; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e -build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -DWIO_WM1110 +build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -board_build.ldscript = variants/wio-sdk-wm1110/nrf52840_s140_v7.ld +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-sdk-wm1110> lib_deps = ${nrf52840_base.lib_deps} diff --git a/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld b/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld deleted file mode 100644 index 6aaeb4034f..0000000000 --- a/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld +++ /dev/null @@ -1,38 +0,0 @@ -/* Linker script to configure memory regions. */ - -SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) - -MEMORY -{ - FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xED000 - 0x27000 - - /* SRAM required by Softdevice depend on - * - Attribute Table Size (Number of Services and Characteristics) - * - Vendor UUID count - * - Max ATT MTU - * - Concurrent connection peripheral + central + secure links - * - Event Len, HVN queue, Write CMD queue - */ - RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x20040000 - 0x20006000 -} - -SECTIONS -{ - . = ALIGN(4); - .svc_data : - { - PROVIDE(__start_svc_data = .); - KEEP(*(.svc_data)) - PROVIDE(__stop_svc_data = .); - } > RAM - - .fs_data : - { - PROVIDE(__start_fs_data = .); - KEEP(*(.fs_data)) - PROVIDE(__stop_fs_data = .); - } > RAM -} INSERT AFTER .data; - -INCLUDE "nrf52_common.ld" diff --git a/variants/wio-tracker-wm1110/platformio.ini b/variants/wio-tracker-wm1110/platformio.ini index e8c6811866..5ecc414adc 100644 --- a/variants/wio-tracker-wm1110/platformio.ini +++ b/variants/wio-tracker-wm1110/platformio.ini @@ -1,12 +1,12 @@ -; The very slick RAK wireless RAK 4631 / 4630 board - Unified firmware for 5005/19003, with or without OLED RAK 1921 +; The red tracker Dev Board with the WM1110 module [env:wio-tracker-wm1110] extends = nrf52840_base board = wio-tracker-wm1110 ; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e -build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-tracker-wm1110 -DWIO_WM1110 +build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-tracker-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -board_build.ldscript = variants/wio-tracker-wm1110/nrf52840_s140_v7.ld +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-tracker-wm1110> lib_deps = ${nrf52840_base.lib_deps} diff --git a/variants/xiao_ble/nrf52840_s140_v7.ld b/variants/xiao_ble/nrf52840_s140_v7.ld deleted file mode 100644 index 6aaeb4034f..0000000000 --- a/variants/xiao_ble/nrf52840_s140_v7.ld +++ /dev/null @@ -1,38 +0,0 @@ -/* Linker script to configure memory regions. */ - -SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) - -MEMORY -{ - FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xED000 - 0x27000 - - /* SRAM required by Softdevice depend on - * - Attribute Table Size (Number of Services and Characteristics) - * - Vendor UUID count - * - Max ATT MTU - * - Concurrent connection peripheral + central + secure links - * - Event Len, HVN queue, Write CMD queue - */ - RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x20040000 - 0x20006000 -} - -SECTIONS -{ - . = ALIGN(4); - .svc_data : - { - PROVIDE(__start_svc_data = .); - KEEP(*(.svc_data)) - PROVIDE(__stop_svc_data = .); - } > RAM - - .fs_data : - { - PROVIDE(__start_fs_data = .); - KEEP(*(.fs_data)) - PROVIDE(__stop_fs_data = .); - } > RAM -} INSERT AFTER .data; - -INCLUDE "nrf52_common.ld" diff --git a/variants/xiao_ble/platformio.ini b/variants/xiao_ble/platformio.ini index 76e91e8444..6c47780d5f 100644 --- a/variants/xiao_ble/platformio.ini +++ b/variants/xiao_ble/platformio.ini @@ -3,9 +3,9 @@ extends = nrf52840_base board = xiao_ble_sense board_level = extra -build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Ivariants/xiao_ble/softdevice -Ivariants/xiao_ble/softdevice/nrf52 -DEBYTE_E22 -DEBYTE_E22_900M30S -DPRIVATE_HW +build_flags = ${nrf52840_base.build_flags} -Ivariants/xiao_ble -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -D EBYTE_E22 -DEBYTE_E22_900M30S -DPRIVATE_HW -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -board_build.ldscript = variants/xiao_ble/nrf52840_s140_v7.ld +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/xiao_ble> lib_deps = ${nrf52840_base.lib_deps} From d97e6b86b8bc9be3b24589795c7abac07140fb48 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Mon, 8 Jul 2024 19:03:23 +0800 Subject: [PATCH 130/211] Sync Wio lr1110 refresh with master (#4251) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix protobuf structs handling (#4140) * Fix protobuf structs handling * Log instead of assert --------- Co-authored-by: Ben Meadors * BLE based logging (#4146) * WIP log characteristic * Bluetooth logging plumbing * Characteristic * Callback * Check for nullptr * Esp32 bluetooth impl * Formatting * Add thread name and log level * Add settings guard * Remove comments * Field name * Fixes esp32 * Open it up * Whoops * Move va_end past our logic * Use `upload_protocol = esptool` as with the other heltec devices instead of `esp-builtin` (#4151) * Standardize lat/lon position logs (#4156) * Standardize lat/lon position logs * Missed sone and condensed logs * [create-pull-request] automated change (#4157) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Pause BLE logging during want_config flow (#4162) * Update NimBLE to 1.4.2 (#4163) * Implement replies for all telemetry types based on variant tag (#4164) * Implement replies for all telemetry types based on variant tag * Remove check for `ignoreRequest`: modules can set this, don't need to check --------- Co-authored-by: Ben Meadors * Esptool is better * Explicitly set characteristic * fix INA3221 sensor (#4168) - pass wire to begin() - remove redundant setAddr() (already set in header) * Show compass on waypoint frame; clear when waypoint deleted (#4116) * Clear expired or deleted waypoint frame * Return 0 to CallbackObserver * Add a missing comment * Draw compass for waypoint frame * Display our own waypoints * [create-pull-request] automated change (#4171) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Add semihosting support for nrf52 devices (#4137) * Turn off vscode cmake prompt - we don't use cmake on meshtastic * Add rak4631_dap variant for debugging with NanoDAP debug probe device. * The rak device can also run freertos (which is underneath nrf52 arduino) * Add semihosting support for nrf52840 devices Initial platformio.ini file only supports rak4630 Default to non TCP for the semihosting log output for now... Fixes https://github.com/meshtastic/firmware/issues/4135 * fix my botched merge - keep board_level = extra flag for rak3631_dbg --------- Co-authored-by: Ben Meadors * [create-pull-request] automated change (#4174) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Display alerts (#4170) * Move static functions into Screen.h, show compass during calibration * Move to _fontHeight macro to avoid collision * Move some alert functions to new alert handler * Catch missed reboot code * ESP32 fixes * Bump esp8266-oled-ssd1306 * Fixes for when a device has no screen * Use new startAlert(char*) helper class * Add EINK bits back to alert handling * Add noop class for no-display devices --------- Co-authored-by: Ben Meadors * Send file system manifest up on want_config (#4176) * Send file system manifest up on want_config * Platform specific methods * Helps to actually make the change * Clear * tell vscode, if formatting, use whatever our trunk formatter wants (#4186) without this flag if the user has set some other formatter (clang) in their user level settings, it will be looking in the wrong directory for the clang options (we want the options in .trunk/clang) Note: formatOnSave is true in master, which means a bunch of our older files are non compliant and if you edit them it will generate lots of formatting related diffs. I guess I'll start letting that happen with my future commits ;-). * fix the build - would loop forever if there were no files to send (#4188) * Show owner.short_name on boot (and E-Ink sleep screen) (#4134) * Show owner.short_name on boot and sleep screen (on e-ink) * Update Screen.cpp - new line for short_name Boot screen short_name now below the region setting. Looks better on small screens. * Draw short_name on right --------- Co-authored-by: Thomas Göttgens Co-authored-by: todd-herbert Co-authored-by: Ben Meadors * nrf52 soft device will watchdog if you use ICE while BT on... (#4189) so have debugger disable bluetooth. * correct xiao_ble build preventing sx1262 init (#4191) * Force a compile time failur if FromRadio or ToRadio get larger than (#4190) a BLE packet size. We are actually very close to this threshold so important to make sure we don't accidentally pass it. * Clear vector after complete config state (#4194) * Clear after complete config * Don't collect . entries * Log file name and size * [create-pull-request] automated change (#4200) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Make the logs Colorful! (#4199) * Squash needlessly static functions (#4183) * Trim extra vprintf and filter for unprintable characters * Deprecate Router Client role (and make it Client) (#4201) * [create-pull-request] automated change (#4205) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Move waypoint (#4202) * Move waypoint screen draw into the waypoint module * Get the observer set up for the waypoint screen draw * Static squashing: screen dimensions Macros moved back to Screen.cpp, as a band-aid until we eventually move all those static functions into the Screen class. * Move getCompassDiam into Screen class (supress compiler warnings) At this stage, the method is still static, because it's used by drawNodeInfo, which has no tidy reference to our screen instance. This is probably just another band-aid until these static functions all move. * Use new getCompassDiam function in AccelerometerThread * Properly gate display code in WaypointModule --------- Co-authored-by: Todd Herbert * Fix flakey phone api transition from file manifest to complete (#4209) * Try fix flakey phone api transition from file manifest to complete * Skip * enable colors in platformio serial monitor (#4217) * When talking via serial, encapsulate log messages in protobufs if necessary (#4187) * clean up RedirectablePrint::log so it doesn't have three very different implementations inline. * remove NoopPrint - it is no longer needed * when talking to API clients via serial, don't turn off log msgs instead encapsuate them * fix the build - would loop forever if there were no files to send * don't use Segger code if not talking to a Segger debugger * when encapsulating logs, make sure the strings always has nul terminators * nrf52 soft device will watchdog if you use ICE while BT on... so have debugger disable bluetooth. * Important to not print debug messages while writing to the toPhone scratch buffer * don't include newlines if encapsulating log records as protobufs --------- Co-authored-by: Ben Meadors * [create-pull-request] automated change (#4218) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Fix SHT41 support (#4222) * Add SHT41 Serial to I2c Detection Code On the Seeed Wio-WM1110 Dev Kit board, the SHT41 chip was being incorrectly detected as SHT31. This patch adds the necessary serial number for the SHT41 chip to be correctly detected. fixes meshtastic/firmware#4221 * Add missing sensor read for SHT41 * Typo fix in logs - mhz - MHz (#4225) As reported by karamo, a few different places in our logs had incorrect capitalization of MHz. fixes meshtastic/firmware#4126 * New new BLE logging characteristic with LogRecord protos (#4220) * New UUID * New log radio characteristic with LogRecord protobuf * LogRecord * Merge derp * How did you get there * Trunk * Fix length * Remove assert * minor cleanup proposal (#4169) * MESHTASTIC_EXCLUDE_WIFI and HAS_WIFI cleanup... Our code was checking HAS_WIFI and the new MESHTASTIC_EXCLUDE_WIFI flags in various places (even though EXCLUDE_WIFI forces HAS_WIFI to 0). Instead just check HAS_WIFI, only use EXCLUDE_WIFI inside configuration.h * cleanup: use HAS_NETWORKING instead of HAS_WIFI || HAS_ETHERNET We already had HAS_NETWORKING as flag in MQTT to mean 'we have tcpip'. Generallize that and move it into configuration.h so that we can use it elsewhere. * Use #pragma once, because supported by gcc and all modern compilers instead of #ifdef DOTHFILE_H etc... --------- Co-authored-by: Jonathan Bennett * Add PowerMon support (#4155) * Turn off vscode cmake prompt - we don't use cmake on meshtastic * Add rak4631_dap variant for debugging with NanoDAP debug probe device. * The rak device can also run freertos (which is underneath nrf52 arduino) * Add semihosting support for nrf52840 devices Initial platformio.ini file only supports rak4630 Default to non TCP for the semihosting log output for now... Fixes https://github.com/meshtastic/firmware/issues/4135 * powermon WIP (for https://github.com/meshtastic/firmware/issues/4136 ) * oops - mean't to mark the _dbg variant as an 'extra' board. * powermon wip * Make serial port on wio-sdk-wm1110 board work By disabling the (inaccessible) adafruit USB * Instrument (radiolib only for now) lora for powermon per https://github.com/meshtastic/firmware/issues/4136 * powermon gps support https://github.com/meshtastic/firmware/issues/4136 * Add CPU deep and light sleep powermon states https://github.com/meshtastic/firmware/issues/4136 * Change the board/swversion bootstring so it is a new "structured" log msg. * powermon wip * add example script for getting esp S3 debugging working Not yet used but I didn't want these nasty tricks to get lost yet. * Add PowerMon reporting for screen and bluetooth pwr. * make power.powermon_enables config setting work. * update to latest protobufs * fix bogus shellcheck warning * make powermon optional (but default enabled because tiny and no runtime impact) * tell vscode, if formatting, use whatever our trunk formatter wants without this flag if the user has set some other formatter (clang) in their user level settings, it will be looking in the wrong directory for the clang options (we want the options in .trunk/clang) Note: formatOnSave is true in master, which means a bunch of our older files are non compliant and if you edit them it will generate lots of formatting related diffs. I guess I'll start letting that happen with my future commits ;-). * add PowerStress module * nrf52 arduino is built upon freertos, so let platformio debug it * don't accidentally try to Segger ICE if we are using another ICE * clean up RedirectablePrint::log so it doesn't have three very different implementations inline. * remove NoopPrint - it is no longer needed * when talking to API clients via serial, don't turn off log msgs instead encapsuate them * fix the build - would loop forever if there were no files to send * don't use Segger code if not talking to a Segger debugger * when encapsulating logs, make sure the strings always has nul terminators * nrf52 soft device will watchdog if you use ICE while BT on... so have debugger disable bluetooth. * Important to not print debug messages while writing to the toPhone scratch buffer * don't include newlines if encapsulating log records as protobufs * update to latest protobufs (needed for powermon goo) * PowerStress WIP * fix linter warning * Cleanup buffer * Merge hex for wm1110 target(s) * Only sdk * Sudo * Fix exclude macros (#4233) * fix MESHTASTIC_EXCLUDE_BLUETOOTH * fix HAS_SCREEN=0 * fix MESHTASTIC_EXCLUDE_GPS * fix typo in build-nrf52.sh (#4231) chmod is the command, '+x' is the argument. * Tidy Wireless Paper variant files (#4238) * Quick tidy of pins_arduino.h Matches requests made at https://github.com/meshtastic/firmware/pull/4226#discussion_r1664183480) * Tidy variant.h * Change deprecated ADC attenuation parameter From 11dB to 12dB. Resolves compiler warning. Allegly, no impact on function: `This is deprecated, it behaves the same as `ADC_ATTEN_DB_12` * Updated raspbian CI to update apt repository ahead of libbluetooth. (#4243) * Fix BLE logging on nrf52 (#4244) * allow ble logrecords to be fetched either by NOTIFY or INDICATE ble types This allows 'lossless' log reading. If client has requested INDICATE (rather than NOTIFY) each log record emitted via log() will have to fetched by the client device before the meshtastic node can continue. * Fix serious problem with nrf52 BLE logging. When doing notifies of LogRecords it is important to use the binary write routines - writing using the 'string' write won't work. Because protobufs can contain \0 nuls inside of them which if being parsed as a string will cause only a portion of the protobuf to be sent. I noticed this because some log messages were not getting through. --------- Co-authored-by: Ben Meadors * Fix build when HAS_NETWORKING is false on nrf52 (#4237) (tested on a rak4631 by setting HAS_ETHERNET false when shrinking image) * If `toPhoneQueue` is full, still increment `fromNum` to avoid client never getting packets (#4246) * Update to SoftDevice 7.3.0 for wio-sdk-wm1110 and wio-tracker-wm1110 (#4248) * Update variant.h * Update wio-tracker-wm1110.json * Update wio-sdk-wm1110.json * Update platformio.ini * Update platformio.ini * Add files via upload * Add files via upload * Update variant.h --------- Co-authored-by: Mike Co-authored-by: Ben Meadors Co-authored-by: Mike G Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> Co-authored-by: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Co-authored-by: Warren Guy <5602790+warrenguy@users.noreply.github.com> Co-authored-by: todd-herbert Co-authored-by: geeksville Co-authored-by: Jonathan Bennett Co-authored-by: Alexander <156134901+Dorn8010@users.noreply.github.com> Co-authored-by: Thomas Göttgens Co-authored-by: quimnut Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com> Co-authored-by: Agent Blu, 006 Co-authored-by: Mark Trevor Birss --- .github/workflows/build_raspbian.yml | 1 + .vscode/settings.json | 5 +- arch/esp32/esp32.ini | 2 +- bin/build-nrf52.sh | 15 +- bin/mergehex | Bin 0 -> 2102544 bytes bin/s140_nrf52_7.3.0_softdevice.hex | 9726 +++++++++++++++++ bin/setup-python-for-esp-debug.sh | 12 + boards/wio-sdk-wm1110.json | 2 +- boards/wio-tracker-wm1110.json | 2 +- boards/wiscore_rak4631.json | 2 +- platformio.ini | 6 +- protobufs | 2 +- pyocd.yaml | 7 + src/AccelerometerThread.h | 36 +- src/BluetoothCommon.cpp | 6 +- src/BluetoothCommon.h | 4 +- src/ButtonThread.cpp | 5 +- src/DebugConfiguration.cpp | 2 +- src/DebugConfiguration.h | 19 +- src/FSCommon.cpp | 52 + src/FSCommon.h | 2 + src/GPSStatus.h | 2 +- src/Power.cpp | 2 +- src/PowerFSM.cpp | 17 + src/PowerMon.cpp | 45 + src/PowerMon.h | 34 + src/RedirectablePrint.cpp | 280 +- src/RedirectablePrint.h | 23 +- src/SerialConsole.cpp | 36 +- src/SerialConsole.h | 10 +- src/commands.h | 6 +- src/configuration.h | 13 +- src/detect/ScanI2CTwoWire.cpp | 4 +- src/gps/GPS.cpp | 22 +- src/gps/GPS.h | 2 + src/graphics/Screen.cpp | 452 +- src/graphics/Screen.h | 113 +- src/graphics/ScreenFonts.h | 8 +- src/main.cpp | 20 +- src/main.h | 2 + src/mesh/FloodingRouter.cpp | 3 +- src/mesh/LR11x0Interface.cpp | 3 +- src/mesh/MeshService.cpp | 7 +- src/mesh/NodeDB.cpp | 15 +- src/mesh/NodeDB.h | 4 +- src/mesh/PhoneAPI.cpp | 51 +- src/mesh/PhoneAPI.h | 17 +- src/mesh/RF95Interface.cpp | 31 +- src/mesh/RadioInterface.cpp | 3 +- src/mesh/RadioLibInterface.cpp | 21 + src/mesh/RadioLibInterface.h | 13 +- src/mesh/Router.cpp | 6 +- src/mesh/SX126xInterface.cpp | 3 +- src/mesh/SX128xInterface.cpp | 3 +- src/mesh/StreamAPI.cpp | 23 +- src/mesh/StreamAPI.h | 5 +- src/mesh/eth/ethClient.cpp | 4 + src/mesh/generated/meshtastic/config.pb.h | 14 +- src/mesh/generated/meshtastic/deviceonly.pb.h | 3 +- src/mesh/generated/meshtastic/localonly.pb.h | 2 +- src/mesh/generated/meshtastic/mesh.pb.cpp | 5 +- src/mesh/generated/meshtastic/mesh.pb.h | 44 +- src/mesh/generated/meshtastic/portnums.pb.h | 2 + src/mesh/generated/meshtastic/powermon.pb.cpp | 17 + src/mesh/generated/meshtastic/powermon.pb.h | 138 + src/mesh/http/ContentHandler.cpp | 2 +- src/mesh/wifi/WiFiAPClient.cpp | 2 +- src/modules/AdminModule.cpp | 16 +- src/modules/AdminModule.h | 2 +- src/modules/CannedMessageModule.cpp | 4 +- src/modules/Modules.cpp | 6 + src/modules/PositionModule.cpp | 4 +- src/modules/PowerStressModule.cpp | 77 + src/modules/PowerStressModule.h | 38 + src/modules/Telemetry/AirQualityTelemetry.cpp | 107 +- src/modules/Telemetry/AirQualityTelemetry.h | 5 + src/modules/Telemetry/DeviceTelemetry.cpp | 29 +- .../Telemetry/EnvironmentTelemetry.cpp | 105 +- src/modules/Telemetry/EnvironmentTelemetry.h | 5 + src/modules/Telemetry/PowerTelemetry.cpp | 79 +- src/modules/Telemetry/PowerTelemetry.h | 5 + .../Telemetry/Sensor/INA3221Sensor.cpp | 3 +- src/modules/WaypointModule.cpp | 150 +- src/modules/WaypointModule.h | 14 +- src/modules/esp32/PaxcounterModule.cpp | 6 +- src/modules/esp32/StoreForwardModule.cpp | 4 +- src/mqtt/MQTT.cpp | 25 +- src/mqtt/MQTT.h | 6 +- src/nimble/NimbleBluetooth.cpp | 45 +- src/nimble/NimbleBluetooth.h | 1 + src/platform/esp32/main-esp32.cpp | 29 +- src/platform/nrf52/NRF52Bluetooth.cpp | 112 +- src/platform/nrf52/NRF52Bluetooth.h | 2 +- src/platform/nrf52/main-nrf52.cpp | 35 +- src/shutdown.h | 2 +- src/sleep.cpp | 14 +- variants/heltec_wireless_paper/pins_arduino.h | 8 +- variants/heltec_wireless_paper/variant.h | 28 +- .../heltec_wireless_paper_v1/pins_arduino.h | 8 +- variants/heltec_wireless_paper_v1/variant.h | 28 +- .../heltec_wireless_tracker/platformio.ini | 4 +- variants/rak4631/platformio.ini | 92 +- variants/tlora_t3s3_v1/platformio.ini | 2 +- variants/wio-sdk-wm1110/nrf52840_s140_v7.ld | 38 + variants/wio-sdk-wm1110/platformio.ini | 16 +- variants/wio-sdk-wm1110/softdevice/ble.h | 652 ++ variants/wio-sdk-wm1110/softdevice/ble_err.h | 92 + variants/wio-sdk-wm1110/softdevice/ble_gap.h | 2895 +++++ variants/wio-sdk-wm1110/softdevice/ble_gatt.h | 232 + .../wio-sdk-wm1110/softdevice/ble_gattc.h | 764 ++ .../wio-sdk-wm1110/softdevice/ble_gatts.h | 904 ++ variants/wio-sdk-wm1110/softdevice/ble_hci.h | 135 + .../wio-sdk-wm1110/softdevice/ble_l2cap.h | 495 + .../wio-sdk-wm1110/softdevice/ble_ranges.h | 149 + .../wio-sdk-wm1110/softdevice/ble_types.h | 217 + .../wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h | 259 + .../wio-sdk-wm1110/softdevice/nrf_error.h | 90 + .../wio-sdk-wm1110/softdevice/nrf_error_sdm.h | 73 + .../wio-sdk-wm1110/softdevice/nrf_error_soc.h | 85 + variants/wio-sdk-wm1110/softdevice/nrf_nvic.h | 449 + variants/wio-sdk-wm1110/softdevice/nrf_sdm.h | 380 + variants/wio-sdk-wm1110/softdevice/nrf_soc.h | 1046 ++ variants/wio-sdk-wm1110/softdevice/nrf_svc.h | 98 + .../wio-tracker-wm1110/nrf52840_s140_v7.ld | 38 + variants/wio-tracker-wm1110/platformio.ini | 4 +- variants/wio-tracker-wm1110/softdevice/ble.h | 652 ++ .../wio-tracker-wm1110/softdevice/ble_err.h | 92 + .../wio-tracker-wm1110/softdevice/ble_gap.h | 2895 +++++ .../wio-tracker-wm1110/softdevice/ble_gatt.h | 232 + .../wio-tracker-wm1110/softdevice/ble_gattc.h | 764 ++ .../wio-tracker-wm1110/softdevice/ble_gatts.h | 904 ++ .../wio-tracker-wm1110/softdevice/ble_hci.h | 135 + .../wio-tracker-wm1110/softdevice/ble_l2cap.h | 495 + .../softdevice/ble_ranges.h | 149 + .../wio-tracker-wm1110/softdevice/ble_types.h | 217 + .../softdevice/nrf52/nrf_mbr.h | 259 + .../wio-tracker-wm1110/softdevice/nrf_error.h | 90 + .../softdevice/nrf_error_sdm.h | 73 + .../softdevice/nrf_error_soc.h | 85 + .../wio-tracker-wm1110/softdevice/nrf_nvic.h | 449 + .../wio-tracker-wm1110/softdevice/nrf_sdm.h | 380 + .../wio-tracker-wm1110/softdevice/nrf_soc.h | 1046 ++ .../wio-tracker-wm1110/softdevice/nrf_svc.h | 98 + variants/xiao_ble/platformio.ini | 2 +- version.properties | 2 +- 145 files changed, 29832 insertions(+), 838 deletions(-) create mode 100644 bin/mergehex create mode 100644 bin/s140_nrf52_7.3.0_softdevice.hex create mode 100644 bin/setup-python-for-esp-debug.sh create mode 100644 pyocd.yaml create mode 100644 src/PowerMon.cpp create mode 100644 src/PowerMon.h create mode 100644 src/mesh/generated/meshtastic/powermon.pb.cpp create mode 100644 src/mesh/generated/meshtastic/powermon.pb.h create mode 100644 src/modules/PowerStressModule.cpp create mode 100644 src/modules/PowerStressModule.h create mode 100644 variants/wio-sdk-wm1110/nrf52840_s140_v7.ld create mode 100644 variants/wio-sdk-wm1110/softdevice/ble.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_err.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gap.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gatt.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gattc.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gatts.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_hci.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_l2cap.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_ranges.h create mode 100644 variants/wio-sdk-wm1110/softdevice/ble_types.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_nvic.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_sdm.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_soc.h create mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_svc.h create mode 100644 variants/wio-tracker-wm1110/nrf52840_s140_v7.ld create mode 100644 variants/wio-tracker-wm1110/softdevice/ble.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_err.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gap.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gatt.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gattc.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gatts.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_hci.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_l2cap.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_ranges.h create mode 100644 variants/wio-tracker-wm1110/softdevice/ble_types.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_nvic.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_sdm.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_soc.h create mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_svc.h diff --git a/.github/workflows/build_raspbian.yml b/.github/workflows/build_raspbian.yml index 697d08727f..d262d87395 100644 --- a/.github/workflows/build_raspbian.yml +++ b/.github/workflows/build_raspbian.yml @@ -13,6 +13,7 @@ jobs: - name: Install libbluetooth shell: bash run: | + apt-get update -y apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code diff --git a/.vscode/settings.json b/.vscode/settings.json index 07e198f0a7..bf9b82111d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,8 @@ "trunk.enableWindows": true, "files.insertFinalNewline": false, "files.trimFinalNewlines": false, - "cmake.configureOnOpen": false + "cmake.configureOnOpen": false, + "[cpp]": { + "editor.defaultFormatter": "trunk.io" + } } diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index f3eb0cbc03..58c1302da8 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -44,7 +44,7 @@ lib_deps = ${networking_base.lib_deps} ${environmental_base.lib_deps} https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2 - h2zero/NimBLE-Arduino@^1.4.1 + h2zero/NimBLE-Arduino@^1.4.2 https://github.com/dbSuS/libpax.git#7bcd3fcab75037505be9b122ab2b24cc5176b587 https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6 https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index a9980f486b..fa6eacd237 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -2,8 +2,8 @@ set -e -VERSION=`bin/buildinfo.py long` -SHORT_VERSION=`bin/buildinfo.py short` +VERSION=$(bin/buildinfo.py long) +SHORT_VERSION=$(bin/buildinfo.py short) OUTDIR=release/ @@ -11,7 +11,7 @@ rm -f $OUTDIR/firmware* rm -r $OUTDIR/* || true # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale -platformio pkg update +platformio pkg update echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS" rm -f .pio/build/$1/firmware.* @@ -29,6 +29,15 @@ cp $DFUPKG $OUTDIR/$basename-ota.zip echo "Generating NRF52 uf2 file" SRCHEX=.pio/build/$1/firmware.hex + +# if WM1110 target, merge hex with softdevice 7.3.0 +if (echo $1 | grep -q "wio-sdk-wm1110"); then + echo "Merging with softdevice" + sudo chmod +x ./bin/mergehex + bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/merged_fimware.hex + SRCHEX=.pio/build/$1/merged_fimware.hex +fi + bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 cp bin/device-install.* $OUTDIR diff --git a/bin/mergehex b/bin/mergehex new file mode 100644 index 0000000000000000000000000000000000000000..2a93c571003f60f7d94e7a588acbc00285af9354 GIT binary patch literal 2102544 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

$&*Qh7qS<%!@nUL*MI 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

jqWDRdU%3zsH=u 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�hF6bG}d+&NiOQLS&25sIl1%U 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

d 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

guyN)-&D4*RZyzGw7}F7F7xLMB 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

;hP?-a_*c@MfW;siN=Mr7&&B&U!y||w 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 literal 0 HcmV?d00001 diff --git a/bin/s140_nrf52_7.3.0_softdevice.hex b/bin/s140_nrf52_7.3.0_softdevice.hex new file mode 100644 index 0000000000..639927f503 --- /dev/null +++ b/bin/s140_nrf52_7.3.0_softdevice.hex @@ -0,0 +1,9726 @@ +:020000040000FA +:1000000000040020810A000015070000610A0000BA +:100010001F07000029070000330700000000000050 +:10002000000000000000000000000000A50A000021 +:100030003D070000000000004707000051070000D6 +:100040005B070000650700006F07000079070000EC +:10005000830700008D07000097070000A10700003C +:10006000AB070000B5070000BF070000C90700008C +:10007000D3070000DD070000E7070000F1070000DC +:10008000FB070000050800000F0800001908000029 +:10009000230800002D080000370800004108000078 +:1000A0004B080000550800005F08000069080000C8 +:1000B000730800007D080000870800009108000018 +:1000C0009B080000A5080000AF080000B908000068 +:1000D000C3080000CD080000D7080000E1080000B8 +:1000E000EB080000F5080000FF0800000909000007 +:1000F000130900001D090000270900003109000054 +:100100003B0900001FB500F003F88DE80F001FBD8C +:1001100000F0ACBC40F6FC7108684FF01022401CA7 +:1001200008D00868401C09D00868401C04D0086842 +:1001300000F037BA9069F5E79069F9E7704770B554 +:100140000B46010B184400F6FF70040B4FF0805073 +:100150000022090303692403406943431D1B104621 +:1001600000F048FA29462046BDE8704000F042BA47 +:10017000F0B54FF6FF734FF4B4751A466E1E11E0DA +:10018000A94201D3344600E00C46091B30F8027B3B +:10019000641E3B441A44F9D19CB204EB134394B25D +:1001A00004EB12420029EBD198B200EB134002EBB2 +:1001B000124140EA0140F0BDF34992B00446D1E952 +:1001C0000001CDE91001FF224021684600F0F4FB58 +:1001D00094E80F008DE80F00684610A902E004C8FB +:1001E00041F8042D8842FAD110216846FFF7C0FF7C +:1001F0001090AA208DF8440000F099F9FFF78AFFCB +:1002000040F6FC7420684FF01025401C0FD0206889 +:1002100010226946803000F078F92068401C08D030 +:100220002068082210A900F070F900F061F9A869AF +:10023000EEE7A869F5E74FF080500369406940F6A2 +:10024000FC71434308684FF01022401C06D0086838 +:1002500000F58050834203D2092070479069F7E788 +:100260000868401C04D00868401C03D00020704778 +:100270009069F9E70420704770B504460068C34DE3 +:10028000072876D2DFE800F033041929631E250021 +:10029000D4E9026564682946304600F062F92A46CE +:1002A0002146304600F031F9AA002146304600F0E0 +:1002B00057FB002800D0032070BD00F009FC4FF46C +:1002C000805007E0201D00F040F90028F4D100F034 +:1002D000FFFB60682860002070BD241D94E80700C3 +:1002E000920000F03DFB0028F6D00E2070BDFFF715 +:1002F000A2FF0028FAD1D4E901034FF0805100EBAE +:10030000830208694D69684382420ED840F6F8704E +:1003100005684FF010226D1C09D0056805EB8305B8 +:100320000B6949694B439D4203D9092070BD55694A +:10033000F4E70168491C03D00068401C02D003E0C8 +:100340005069FAE70F2070BD2046FFF735FFFFF731 +:1003500072FF0028F7D1201D00F0F7F80028F2D135 +:1003600060680028F0D100F0E2F8FFF7D3FE00F05B +:10037000BFF8072070BD10B50C46182802D0012028 +:10038000086010BD2068FFF777FF206010BD41684E +:10039000054609B1012700E0002740F6F8742068FF +:1003A0004FF01026401C2BD02068AA68920000F065 +:1003B000D7FA38B3A86881002068401C27D020688D +:1003C000FFF7BDFED7B12068401C22D026684FF051 +:1003D0008050AC686D68016942695143A9420DD9EA +:1003E000016940694143A14208D92146304600F0E5 +:1003F000B8F822462946304600F087F800F078F831 +:100400007069D2E700F093F8FFF784FEF6E77069B1 +:10041000D6E77669DBE740F6FC7420684FF01026DB +:10042000401C23D02068401C0CD02068401C1FD0EA +:100430002568206805F18005401C1BD027683879A5 +:10044000AA2819D040F6F8700168491C42D001680A +:10045000491C45D00168491C3ED001680968491C07 +:100460003ED00168491C39D000683EE0B069DAE747 +:10047000B569DEE7B769E2E710212846FFF778FEA5 +:100480003968814222D12068401C05D0D4F8001080 +:1004900001F18002C03107E0B169F9E730B108CA63 +:1004A00051F8040D984201D1012000E000208A4259 +:1004B000F4D158B1286810B1042803D0FEE72846CB +:1004C000FFF765FF3149686808600EE0FFF722FE1C +:1004D00000F00EF87169BBE77169BFE7706904E06D +:1004E0004FF480500168491C01D000F0CBFAFEE7C0 +:1004F000BFF34F8F26480168264A01F4E06111439B +:100500000160BFF34F8F00BFFDE72DE9F0411746B3 +:100510000D460646002406E03046296800F054F8EF +:10052000641C2D1D361DBC42F6D3BDE8F08140F69B +:10053000FC700168491C04D0D0F800004FF48051D1 +:10054000FDE54FF010208069F8E74FF080510A690F +:10055000496900684A43824201D810207047002050 +:10056000704770B50C4605464FF4806608E0284693 +:1005700000F017F8B44205D3A4F5806405F5805562 +:10058000002CF4D170BD0000F40A0000000000202F +:100590000CED00E00400FA05144801680029FCD0C5 +:1005A0007047134A0221116010490B68002BFCD0E0 +:1005B0000F4B1B1D186008680028FCD0002010603D +:1005C00008680028FCD07047094B10B501221A605A +:1005D000064A1468002CFCD0016010680028FCD08A +:1005E0000020186010680028FCD010BD00E4014015 +:1005F00004E5014070B50C46054600F073F810B9EB +:1006000000F07EF828B121462846BDE8704000F091 +:1006100007B821462846BDE8704000F037B8000012 +:100620007FB5002200920192029203920A0B000B06 +:100630006946012302440AE0440900F01F0651F80C +:10064000245003FA06F6354341F82450401C8242F8 +:10065000F2D80D490868009A10430860081D016827 +:10066000019A1143016000F03DF800280AD00649C4 +:1006700010310868029A10430860091D0868039A3F +:10068000104308607FBD00000006004030B50F4CED +:10069000002200BF04EB0213D3F800582DB9D3F8A1 +:1006A000045815B9D3F808581DB1521C082AF1D3C3 +:1006B00030BD082AFCD204EB0212C2F80008C3F8CD +:1006C00004180220C3F8080830BD000000E0014013 +:1006D0004FF08050D0F83001082801D0002070473A +:1006E000012070474FF08050D0F83011062905D016 +:1006F000D0F83001401C01D0002070470120704725 +:100700004FF08050D0F830010A2801D00020704707 +:100710000120704708208F490968095808471020B0 +:100720008C4909680958084714208A4909680958FA +:100730000847182087490968095808473020854923 +:100740000968095808473820824909680958084744 +:100750003C20804909680958084740207D490968BC +:100760000958084744207B49096809580847482028 +:1007700078490968095808474C207649096809589A +:10078000084750207349096809580847542071499F +:1007900009680958084758206E49096809580847E8 +:1007A0005C206C4909680958084760206949096854 +:1007B00009580847642067490968095808476820AC +:1007C00064490968095808476C2062490968095852 +:1007D000084770205F4909680958084774205D4937 +:1007E00009680958084778205A490968095808478C +:1007F0007C205849096809580847802055490968EC +:10080000095808478420534909680958084788202F +:1008100050490968095808478C204E490968095809 +:10082000084790204B4909680958084794204949CE +:10083000096809580847982046490968095808472F +:100840009C204449096809580847A0204149096883 +:1008500009580847A4203F49096809580847A820B3 +:100860003C49096809580847AC203A4909680958C1 +:100870000847B0203749096809580847B420354966 +:10088000096809580847B8203249096809580847D3 +:10089000BC203049096809580847C0202D4909681B +:1008A00009580847C4202B49096809580847C82037 +:1008B0002849096809580847CC2026490968095879 +:1008C0000847D0202349096809580847D4202149FE +:1008D000096809580847D8201E4909680958084777 +:1008E000DC201C49096809580847E02019490968B3 +:1008F00009580847E4201749096809580847E820BB +:100900001449096809580847EC2012490968095830 +:100910000847F0200F49096809580847F4200D4995 +:10092000096809580847F8200A490968095808471A +:10093000FC2008490968095808475FF48070054998 +:10094000096809580847000003480449024A034B54 +:100950007047000000000020000B0000000B0000AA +:1009600040EA010310B59B070FD1042A0DD310C82C +:1009700008C9121F9C42F8D020BA19BA884201D97E +:10098000012010BD4FF0FF3010BD1AB1D30703D0C6 +:10099000521C07E0002010BD10F8013B11F8014B7C +:1009A0001B1B07D110F8013B11F8014B1B1B01D198 +:1009B000921EF1D1184610BD02F0FF0343EA032254 +:1009C00042EA024200F005B87047704770474FF0A6 +:1009D00000020429C0F0128010F0030C00F01B800C +:1009E000CCF1040CBCF1020F18BF00F8012BA8BF1A +:1009F00020F8022BA1EB0C0100F00DB85FEAC17CDE +:100A000024BF00F8012B00F8012B48BF00F8012B90 +:100A100070474FF0000200B51346944696462039C1 +:100A200022BFA0E80C50A0E80C50B1F12001BFF4A7 +:100A3000F7AF090728BFA0E80C5048BF0CC05DF80D +:100A400004EB890028BF40F8042B08BF704748BF5B +:100A500020F8022B11F0804F18BF00F8012B7047CF +:100A6000014B1B68DB6818470000002009480A4951 +:100A70007047FFF7FBFFFFF745FB00BD20BFFDE719 +:100A8000064B1847064A1060016881F308884068E1 +:100A900000470000000B0000000B000017040000DE +:100AA000000000201EF0040F0CBFEFF30881EFF3ED +:100AB0000981886902380078182803D100E0000015 +:100AC000074A1047074A12682C3212681047000084 +:100AD00000B5054B1B68054A9B58984700BD0000B0 +:100AE0007703000000000020F00A0000040000006E +:100AF000001000000000000000FFFFFF0090D00386 +:10100000C8130020395E020085C100009F5D020008 +:1010100085C1000085C1000085C1000000000000FE +:10102000000000000000000000000000C55E02009B +:1010300085C100000000000085C1000085C10000DE +:101040002D5F0200335F020085C1000085C10000F2 +:1010500085C1000085C1000085C1000085C1000078 +:10106000395F020085C1000085C100003F5F0200BA +:1010700085C10000455F02004B5F0200515F020026 +:1010800085C1000085C1000085C1000085C1000048 +:1010900085C1000085C1000085C1000085C1000038 +:1010A00085C10000575F020085C1000085C10000B6 +:1010B00085C1000085C1000085C1000085C1000018 +:1010C0005D5F020085C1000085C1000085C1000090 +:1010D00085C1000085C1000085C1000085C10000F8 +:1010E00085C1000085C1000085C1000085C10000E8 +:1010F00085C1000085C1000085C1000085C10000D8 +:1011000085C1000085C1000000F002F824F083FED4 +:101110000AA090E8000C82448344AAF10107DA4552 +:1011200001D124F078FEAFF2090EBAE80F0013F0F7 +:10113000010F18BFFB1A43F00103184718530200B0 +:10114000385302000A444FF0000C10F8013B13F032 +:10115000070408BF10F8014B1D1108BF10F8015B10 +:10116000641E05D010F8016B641E01F8016BF9D103 +:1011700013F0080F1EBF10F8014BAD1C0C1B09D15A +:101180006D1E58BF01F801CBFAD505E014F8016BCC +:1011900001F8016B6D1EF9D59142D6D3704700005E +:1011A0000023002400250026103A28BF78C1FBD870 +:1011B000520728BF30C148BF0B6070471FB500F011 +:1011C00003F88DE80F001FBD24F022BE70B51A4C45 +:1011D00005460A202070A01C00F0D5F85920A080F8 +:1011E00029462046BDE8704008F082B908F08BB966 +:1011F00070B50C461149097829B1A0F160015E294A +:1012000008D3012013E0602804D0692802D043F2FB +:1012100001000CE020CC0A4E94E80E0006EB8000A2 +:10122000A0F58050241FD0F8806E2846B04720607B +:1012300070BD012070470000080000201C00002045 +:10124000A05F02003249884201D20120704700208D +:10125000704770B50446A0F500002E4EB0F1786FCF +:1012600002D23444A4F500042948844201D2012565 +:1012700000E0002500F043F848B125B9B44204D39A +:101280002548006808E0012070BD002070BD002DD9 +:10129000F9D1B442F9D321488442F6D2F3E710B52C +:1012A0000446A0F50000B0F1786F03D21948044459 +:1012B000A4F5000400F023F84FF0804130B1164847 +:1012C000006804E08C4204D2012003E01348844209 +:1012D000F8D2002080F0010010BD10B520B1FFF75A +:1012E000DEFF08B1012010BD002010BD10B520B1F7 +:1012F000FFF7AFFF08B1012010BD002010BD084866 +:1013000008490068884201D10120704700207047D9 +:1013100000700200000000202000002008000020D3 +:101320005C000020BEBAFECA10B5044600210120B0 +:1013300000F042F800210B2000F03EF800210820C8 +:1013400000F03AF80421192000F036F804210D20AD +:1013500000F032F804210E2000F02EF804210F20B6 +:1013600000F02AF80421C84300F026F806211620D0 +:1013700000F022F80621152000F01EF82046FFF7A5 +:1013800025FF002010BD40F2231101807047FFF7B8 +:101390002DBF1148704710487047104A10B51468A7 +:1013A0000E4B0F4A08331A60FFF722FF0B48001D4F +:1013B000046010BD704770474907090E002804DB20 +:1013C00000F1E02080F80014704700F00F0000F1F9 +:1013D000E02080F8141D704703F900421005024018 +:1013E00001000001FD48002101604160018170475A +:1013F0002DE9FF4F93B09B46209F160004460DD069 +:101400001046FFF726FF18B1102017B0BDE8F08F87 +:101410003146012001F0D3FE0028F6D101258DF8D8 +:1014200042504FF4C050ADF84000002210A92846A9 +:1014300006F0C5FC0028E8D18DF84250A8464FF4CC +:1014400028500025ADF840001C2229466846079523 +:101450000DF01DF89DF81C000DF11C0A20F00F0086 +:10146000401C20F0F00010308DF81C0020788DF822 +:101470001D0061789DF81E000DF1400961F34200E6 +:1014800040F001008DF81E009DF8000008AA40F011 +:1014900002008DF800002089ADF83000ADF8325020 +:1014A0006089ADF83400CDF82CA060680E900AA9D0 +:1014B000CDF82890684606F090FA0028A5D160681B +:1014C000FFF70BFF40B16068FFF710FF20B96078AD +:1014D00000F00300022801D0012000E00020BF4CF2 +:1014E00008AA0AA92072BDF8200020808DF8428049 +:1014F00042F60120ADF840009DF81E0020F00600E5 +:10150000801C20F001008DF81E000220ADF8300094 +:10151000ADF8340014A80E90684606F05EFA002874 +:1015200089D1BDF82000608036B1211D304600F021 +:101530005FF90028C2D109E0BBF1000F05D00CF023 +:1015400021FDE8BB0CF01EFDD0BBA58017B1012F1B +:1015500043D04AE08DF8428042F6A620ADF8400024 +:1015600046461C220021684607950CF090FF9DF826 +:101570001C00ADF8346020F00F00401C20F0F0009B +:1015800010308DF81C009DF81D0020F0FF008DF834 +:101590001D009DF81E0020F0060040F00100801C98 +:1015A0008DF81E009DF800008DF8446040F00200A8 +:1015B0008DF80000CDE90A9AADF8306011A800E07E +:1015C00011E00E9008AA0AA9684606F006FA00285B +:1015D000A6D1BDF82000E08008E00CF0D3FC10B9E3 +:1015E0000CF0D0FC08B103200FE7E58000200CE7E9 +:1015F0003EB50446794D0820ADF80000A88828B112 +:101600002046FFF726FE18B110203EBD06203EBD45 +:101610002146012001F0D3FD0028F8D12088ADF843 +:1016200004006088ADF80600A088ADF80800E088E6 +:10163000ADF80A00A88801AB6A46002106F0AAFDB1 +:10164000BDF800100829E2D003203EBD7FB5634DF0 +:101650000446A88868B1002002900820ADF8080070 +:10166000CDF80CD02046FFF7F4FD20B1102004B0D7 +:1016700070BD0620FBE7A98802AA4FF6FF7006F0AE +:10168000CCFF0028F3D1BDF80810082901D00320B1 +:10169000EDE7BDF800102180BDF802106180BDF8B3 +:1016A0000410A180BDF80610E180E0E701B582B02A +:1016B0000220ADF80000494802AB6A46408800218C +:1016C00006F068FDBDF80010022900D003200EBD11 +:1016D0001CB5002100910221ADF800100190FFF728 +:1016E000DEFD08B110201CBD3C486A4641884FF61B +:1016F000FF7006F092FFBDF800100229F3D003201E +:101700001CBDFEB5354C06461546207A0F46C0076F +:1017100005D00846FFF79DFD18B11020FEBD0F2033 +:10172000FEBDF82D01D90C20FEBD3046FFF791FD1E +:1017300018BB208801A905F03AFE0028F4D13078C2 +:101740008DF80500208801A906F003FD0028EBD1E3 +:1017500000909DF800009DF8051040F002008DF803 +:101760000000090703D040F008008DF80000208831 +:10177000694606F08BFC0028D6D1ADF808502088C9 +:101780003B4602AA002106F005FDBDF80810A9425B +:10179000CAD00320FEBD7CB5054600200090019014 +:1017A0000888ADF800000C4628460195FFF795FD26 +:1017B00018B92046FFF773FD08B110207CBD15B1A4 +:1017C000BDF8000060B105486A4601884FF6FF7019 +:1017D00006F023FFBDF8001021807CBD240200200C +:1017E0000C20FAE72F48C088002800D0012070475D +:1017F00030B5044693B000200D46014600901422F7 +:1018000001A80CF044FE1C22002108A80CF03FFEA9 +:101810009DF80000CDF808D020F00F00401C20F00B +:10182000F00010308DF800009DF8010006AA20F0AD +:10183000FF008DF801009DF8200001A940F0020092 +:101840008DF8200001208DF8460042F60420ADF806 +:10185000440011A801902088ADF83C006088ADF8E4 +:101860003E00A088ADF84000E088ADF842009DF849 +:10187000020020F00600801C20F001008DF802001C +:101880000820ADF80C00ADF810000FA8059008A8CE +:1018900006F0A3F8002803D1BDF818002880002026 +:1018A00013B030BD24020020F0B5007B059F1E461A +:1018B00014460D46012800D0FFDF0C2030803A206E +:1018C0003880002C08D0287A032806D0287B0128ED +:1018D00000D0FFDF17206081F0BDA889FBE72DE96C +:1018E000F0470D4686B095F80C900E991446B9F164 +:1018F000010F0BD01022007B2E8A9046052807D0BE +:10190000062839D0FFDF06B0BDE8F0870222F2E7F3 +:10191000E8890C2200EB400002EB400018803320E5 +:101920000880002CEFD0E8896081002720E0009635 +:10193000688808F1020301AA696900F097FF06EBC5 +:101940000800801C07EB470186B204EB4102BDF89A +:1019500004009081F848007808B1012300E00023DA +:101960000DF1060140460E3214F029F87F1CBFB27B +:101970006089B842DBD8C6E734200880E889B9F12D +:10198000010F11D0122148430E301880002CBAD01C +:10199000E88960814846B9F1010F00D00220207328 +:1019A00000270DF1040A1FE00621ECE70096688885 +:1019B00008F1020301AA696900F058FF06EB08006C +:1019C000801C86B2B9F1010F12D007EBC70004EBFF +:1019D0004000BDF80410C18110220AF1020110304C +:1019E0000CF02BFD7F1CBFB26089B842DED88AE7BD +:1019F00007EB470104EB4102BDF80400D0810AF176 +:101A000002014046103213F0FCFFEBE72DE9F047EE +:101A10000E4688B090F80CC096F80C80378AF5898D +:101A20000C20DFF81493109902F10C04BCF1030FA1 +:101A300008D0BCF1040F3DD0BCF1070F75D0FFDF1B +:101A400008B061E705EB850C00EB4C0018803120F5 +:101A50000880002AF4D0A8F1060000F0FF0A5581A2 +:101A600024E01622002101A80CF011FD00977088D7 +:101A7000434601AA716900F0F9FEBDF80400208018 +:101A8000BDF80600E080BDF80800208199F800004C +:101A900008B1012300E00023A21C0DF10A01504609 +:101AA00013F08DFF07EB080087B20A346D1EADB24C +:101AB000D7D2C5E705EB850C00EB4C00188032202F +:101AC0000880002ABCD0A8F1050000F0FF0A55816B +:101AD00037E000977088434601AA716900F0C6FE9E +:101AE0009DF80600BDF80410E1802179420860F3FA +:101AF000000162F34101820862F38201C20862F3CD +:101B0000C301020962F30411420962F3451182091B +:101B100062F386112171C0096071BDF80700208150 +:101B200099F8000010B1012301E00EE000232246E5 +:101B30000DF10901504613F042FF07EB080087B290 +:101B40000A346D1EADB2C4D27AE7A8F1020084B2A5 +:101B500005FB08FC0CF10E00188035200880002AD7 +:101B6000A7D05581948100971FFA8CF370880E32AC +:101B7000716900F07BFE63E72DE9F84F1E460A9D70 +:101B80000C4681462AB1607A00F58070D080E089E9 +:101B9000108199F80C000C274FF000084FF00E0A46 +:101BA0000D2872D2DFE800F09D070E1B272F374566 +:101BB000546972727200214648460095FFF774FE20 +:101BC000BDE8F88F207B9146082802D0032800D07A +:101BD000FFDF3780302009E0A9F80A80F0E7207B9A +:101BE0009146042800D0FFDF378031202880B9F1EA +:101BF000000FF1D1E4E7207B9146042800D0FFDFFD +:101C000037803220F2E7207B9146022800D0FFDFA8 +:101C100037803320EAE7207B1746022800D0FFDF19 +:101C20003420A6F800A02880002FC9D0A7F80A8089 +:101C3000C6E7207B1746042800D0FFDF3520A6F832 +:101C400000A02880002FBBD04046A7F80A8012E0F1 +:101C5000207B1746052802D0062800D0FFDF102081 +:101C6000308036202880002FAAD0E0897881A7F81C +:101C70000E80B9F80E00B881A2E7207B91460728B4 +:101C800000D0FFDF37803720B0E72AE04FF01200A6 +:101C900018804FF038001700288091D0E0897881B3 +:101CA000A7F80E80A7F8108099F80C000A2805D034 +:101CB0000B2809D00C280DD0FFDF81E7207B0A28F4 +:101CC00000D0FFDF01200AE0207B0B2800D0FFDFDF +:101CD000042004E0207B0C2800D0FFDF05203873AF +:101CE0006EE7FFDF6CE770B50C46054601F0AAFB16 +:101CF00020B10078222804D2082070BD43F20200EF +:101D000070BD0521284612F0D1F8206008B10020EE +:101D100070BD032070BD30B44880087820F00F00FB +:101D2000C01C20F0F000903001F8080B1DCA81E8BB +:101D30001D0030BC07F05DBC100000202DE9FF47FE +:101D400084B0002782460297079890468946123051 +:101D50000AF069FA401D20F00306079828B907A980 +:101D60005046FFF7C0FF002854D1B9F1000F05D04D +:101D70000798017B19BB052504681BE098F8000053 +:101D8000092803D00D2812D0FFDF46E0079903256C +:101D90004868B0B3497B42887143914239D98AB2CD +:101DA000B3B2011D11F0F5FE0446078002E0079C66 +:101DB000042508340CB1208810B1032D29D02CE063 +:101DC0000798012112300AF060FAADF80C000246C3 +:101DD00002AB2946504608F0B8FA070001D1A01C12 +:101DE000029007983A461230C8F80400A8F802A0FA +:101DF00003A94046029B0AF055FAD8B10A2817D227 +:101E000000E006E0DFE800F007091414100B0D14E1 +:101E10001412132014E6002012E6112010E6082008 +:101E20000EE643F203000BE6072009E60D2007E665 +:101E3000032005E6BDF80C002346CDE900702A46D4 +:101E40005046079900F022FD57B9032D08D1079895 +:101E5000B3B2417B406871438AB2011D11F0ADFEFF +:101E6000B9F1000FD7D0079981F80C90D3E72DE98D +:101E7000FE4F91461A881C468A468046FAB102AB4C +:101E8000494608F062FA050019D04046A61C27888A +:101E900012F04FF93246072629463B46009611F0CC +:101EA0005EFD20882346CDE900504A465146404613 +:101EB00000F0ECFC002020800120BDE8FE8F002017 +:101EC000FBE710B586B01C46AAB104238DF800309C +:101ED0001388ADF808305288ADF80A208A788DF85A +:101EE0000E200988ADF80C1000236A462146FFF742 +:101EF00025FF06B010BD1020FBE770B50D4605218B +:101F000011F0D4FF040000D1FFDF294604F11200D4 +:101F1000BDE870400AF0A2B92DE9F8430D468046AD +:101F2000002607F063FB04462878102878D2DFE803 +:101F300000F0773B345331311231313108313131D6 +:101F400031312879001FC0B2022801D0102810D1E9 +:101F500014BBFFDF35E004B9FFDF0521404611F077 +:101F6000A5FF007B032806D004280BD0072828D023 +:101F7000FFDF072655E02879801FC0B2022820D055 +:101F800050B1F6E72879401FC0B2022819D01028B6 +:101F900017D0EEE704B9FFDF13E004B9FFDF2879BB +:101FA00001280ED1172137E00521404611F07EFFB0 +:101FB000070000D1FFDF07F1120140460AF02BF9BC +:101FC0002CB12A4621464046FFF7A5FE29E0132101 +:101FD000404602F01FFD24E004B9FFDF0521404622 +:101FE00011F064FF060000D1FFDF694606F1120020 +:101FF0000AF01BF9060000D0FFDFA988172901D2DB +:10200000172200E00A46BDF80000824202D90146CC +:1020100002E005E01729C5D3404600F047FCD0E7B1 +:10202000FFDF3046BDE8F883401D20F0030219B100 +:1020300002FB01F0001D00E000201044704713B5C2 +:10204000009858B10024684611F04DFD002C04D1D1 +:10205000F749009A4A6000220A701CBD0124002042 +:10206000F2E72DE9F0470C461546242200212046D0 +:102070000CF00DFA05B9FFDFA87860732888DFF847 +:10208000B0A3401D20F00301AF788946DAF80400C0 +:1020900011F047FD060000D1FFDF4FF00008266079 +:1020A000A6F8008077B109FB07F1091D0AD0DAF81C +:1020B000040011F036FD060000D1FFDF6660C6F8AF +:1020C000008001E0C4F80480298804F11200BDE812 +:1020D000F0470AF091B82DE9F047804601F112006F +:1020E0000D4681460AF09FF8401DD14F20F00302B3 +:1020F0006E7B14462968786811F03EFD3EB104FB02 +:1021000006F2121D03D06968786811F035FD0520CC +:1021100011F074FE0446052011F078FE201A012803 +:1021200002D1786811F0F2FC49464046BDE8F0471C +:102130000AF078B870B50546052111F0B7FE040025 +:1021400000D1FFDF04F112012846BDE870400AF01B +:1021500062B82DE9F04F91B04FF0000BADF828B008 +:10216000ADF804B047880C4605469246052138462E +:1021700011F09CFE060000D1FFDF24B1A780A4F877 +:1021800006B0A4F808B0297809220B20B2EB111F81 +:1021900073D12A7A04F1100138274FF00C084FF060 +:1021A00012090291102A69D2DFE802F068F2F1F018 +:1021B0008008D3898EA03DDCF3EEB7B7307B0228D0 +:1021C00000D0FFDFA88908EBC001ADF80410302172 +:1021D000ADF82810002C25D06081B5F80E800027BE +:1021E0001DE004EBC709317C89F80E10F189A9F8CC +:1021F0000C10CDF800806888042305AA296900F036 +:1022000035FBBDF81410A9F8101008F10400BDF852 +:1022100016107F1C1FFA80F8A9F81210BFB260894F +:10222000B842DED80CE1307B022800D0FFDFE9891C +:1022300008EBC100ADF804003020ADF8280095F897 +:102240000C90002CA9F10400C0B20F90EAD061817B +:10225000B5F81080002725E0CDF8008068884B464F +:1022600003AA696900F002FB08EB09001FFA80F875 +:102270006F48007818B1012302E0DDE0DAE00023C6 +:1022800004EBC702009204A90C320F9813F097FBDD +:10229000009ABDF80C007F1C1082009ABDF80E0059 +:1022A000BFB250826089B842D6D8C9E00AA800906F +:1022B00001AB224629463046FFF711FBC0E0307BD8 +:1022C000082805D0FFDF03E0307B082800D0FFDFBF +:1022D000E8891030ADF804003620ADF82800002C55 +:1022E0003FD0A9896181F189A18127E0307B09284C +:1022F00000D0FFDFA88901460C30ADF8040037207C +:10230000ADF82800002C2CD06181E8890090AB89C1 +:10231000688804F10C02296955E0E88939211030F8 +:1023200080B2ADF80400ADF82810002C72D0A98955 +:102330006181287A0E280AD002212173E989E1817E +:10234000288A0090EB8968886969029A3BE001213C +:10235000F3E70AA8009001AB224629463046FFF772 +:1023600055FB6DE0307B0A2800D0FFDFADF804900C +:10237000ADF828704CB3A9896181A4F810B0A4F815 +:102380000EB0012020735BE020E002E030E038E096 +:1023900041E0307B0B2800D0FFDF288AADF82870A1 +:1023A0001230ADF8040084B104212173A989618140 +:1023B000E989E181298A2182688A00902B8A6888CC +:1023C00004F11202696900F051FA39E0307B0C28FF +:1023D00000D0FFDFADF80490ADF828703CB30521C4 +:1023E0002173A4F80AB0A4F80EB0A4F810B027E046 +:1023F0000AA8009001AB224629463046FFF754FA5E +:102400001EE00AA8009001AB224629463046FFF79D +:10241000B3FB15E034E03B21ADF80400ADF8281023 +:1024200074B30120E080A4F808B084F80AB007E093 +:1024300010000020FFDF03E0297A012917D0FFDF19 +:10244000BDF80400AAF800006CB1BDF82800208097 +:10245000BDF804006080BDF82800392803D03C286E +:1024600001D086F80CB011B00020BDE8F08F3C21FF +:10247000ADF80400ADF8281014B1697AA172DFE755 +:10248000AAF80000EFE72DE9F84356880F4680468A +:1024900015460521304611F009FD040000D1FFDF8B +:1024A000123400943B46414630466A680AF02EF8E2 +:1024B000B8E570B50D46052111F0F8FC040000D117 +:1024C000FFDF294604F11200BDE8704009F0B8BEF4 +:1024D00070B50D46052111F0E9FC040000D1FFDFC5 +:1024E000294604F11200BDE8704009F0D6BE70B56F +:1024F0000546052111F0DAFC040000D1FFDF04F1EC +:10250000080321462846BDE870400422AFE470B5B8 +:102510000546052111F0CAFC040000D1FFDF214669 +:1025200028462368BDE870400522A0E470B5064641 +:10253000052111F0BBFC040000D1FFDF04F1120003 +:1025400009F071FE401D20F0030511E0011D008817 +:102550000322431821463046FFF789FC00280BD0A0 +:10256000607BABB2684382B26068011D11F05BFB17 +:10257000606841880029E9D170BD70B50E460546F6 +:1025800007F034F8040000D1FFDF012020726672EA +:102590006580207820F00F00C01C20F0F000303063 +:1025A0002070BDE8704007F024B8602801D00720F3 +:1025B00070470878C54900F0010008700020704796 +:1025C0002DE9F0438BB00D461446814606A9FFF76E +:1025D0008AFB002814D14FF6FF7601274FF42058CC +:1025E0008CB103208DF800001020ADF8100007A872 +:1025F000059007AA204604A913F005FA78B1072030 +:102600000BB0BDE8F0830820ADF808508DF80E70CF +:102610008DF80000ADF80A60ADF80C800CE006986B +:10262000A17801742188C1818DF80E70ADF8085031 +:10263000ADF80C80ADF80A606A4602214846069B58 +:10264000FFF77CFBDCE708B501228DF8022042F69B +:102650000202ADF800200A4603236946FFF731FC69 +:1026600008BD08B501228DF8022042F60302ADF83C +:1026700000200A4604236946FFF723FC08BD00B585 +:1026800087B079B102228DF800200A88ADF80820C1 +:102690004988ADF80A1000236A460521FFF74EFB72 +:1026A00007B000BD1020FBE709B1072309E40720AC +:1026B000704770B588B00D461446064606A9FFF768 +:1026C00012FB00280ED17CB10620ADF808508DF821 +:1026D0000000ADF80A40069B6A460821DC813046BE +:1026E000FFF72CFB08B070BD05208DF80000ADF899 +:1026F0000850F0E700B587B059B107238DF80030D6 +:10270000ADF80820039100236A460921FFF716FB64 +:10271000C6E71020C4E770B588B00C460646002511 +:1027200006A9FFF7E0FA0028DCD106980121123053 +:1027300009F0ABFD9CB12178062921D2DFE801F038 +:10274000200505160318801E80B2C01EE28880B2E4 +:102750000AB1A3681BB1824203D90C20C2E7102042 +:10276000C0E7042904D0A08850B901E00620B9E7E9 +:10277000012913D0022905D004291CD005292AD00B +:102780000720AFE709208DF800006088ADF8080049 +:10279000E088ADF80A00A068039023E00A208DF8D5 +:1027A00000006088ADF80800E088ADF80A00A06875 +:1027B0000A25039016E00B208DF800006088ADF824 +:1027C0000800A088ADF80A00E088ADF80C00A06809 +:1027D0000B25049006E00C208DF8000060788DF841 +:1027E00008000C256A4629463046069BFFF7A6FAE4 +:1027F00078E700B587B00D228DF80020ADF80810FD +:1028000000236A461946FFF799FA49E700B587B0F1 +:1028100071B102228DF800200A88ADF8082049889D +:10282000ADF80A1000236A460621FFF787FA37E75A +:10283000102035E770B586B0064601200D46ADF88C +:1028400008108DF80000014600236A463046FFF765 +:1028500075FA040008D12946304605F0B5FC002180 +:10286000304605F0CFFC204606B070BDF8B51C46DA +:1028700015460E46069F11F04AFC2346FF1DBCB2CA +:1028800031462A46009411F036F8F8BD30B41146AE +:10289000DDE902423CB1032903D0002330BC08F03B +:1028A00032BE0123FAE71A8030BC704770B50C467F +:1028B0000546FFF722FB2146284605F094FC2846F2 +:1028C000BDE87040012105F09DBC00001000002013 +:1028D0004FF0E0224FF400400021C2F88001BFF326 +:1028E0004F8FBFF36F8F1748016001601649900248 +:1028F00008607047134900B500220A600A60124B55 +:102900004FF060721A60002808BF00BD0F4A104BDC +:10291000DFF840C001280CD002281CBFFFDF00BD3B +:10292000032008601A604FF4000000BFCCF80000DC +:1029300000BD022008601A604FF04070F6E700B555 +:10294000FFDF00BD00F5004008F50140A4020020B3 +:1029500014F5004004F5014070B50B2000F0BDF9FE +:10296000082000F0BAF900210B2000F0D4F9002172 +:10297000082000F0D0F9F44C01256560A560002026 +:10298000C4F84001C4F84401C4F848010B2000F029 +:10299000B5F9082000F0B2F90B2000F091F925609C +:1029A00070BD10B50B2000F098F9082000F095F9E3 +:1029B000E548012141608160E4490A68002AFCD1B0 +:1029C0000021C0F84011C0F84411C0F848110B2094 +:1029D00000F094F9BDE81040082000F08FB910B560 +:1029E0000B2000F08BF9BDE81040082000F086B9FC +:1029F00000B530B1012806D0022806D0FFDF002044 +:102A000000BDD34800BDD34800BDD248001D00BD65 +:102A100070B5D1494FF000400860D04DC00BC5F8EB +:102A20000803CF4800240460C5F840410820C4359D +:102A300000F053F9C5F83C41CA48047070BD08B5B0 +:102A4000C14A002128B1012811D002281CD0FFDF83 +:102A500008BD4FF48030C2F80803C2F84803BB48F1 +:102A60003C300160C2F84011BDE80840D0E74FF4A7 +:102A70000030C2F80803C2F84803B448403001608F +:102A8000C2F84411B3480CE04FF48020C2F80803A8 +:102A9000C2F84803AD4844300160C2F84811AD485F +:102AA000001D0068009008BD70B516460D4604462E +:102AB000022800D9FFDF0022A348012304F11001FE +:102AC0008B4000EB8401C1F8405526B1C1F840218C +:102AD000C0F8043303E0C0F80833C1F84021C0F85F +:102AE000443370BD2DE9F0411D46144630B1012834 +:102AF00033D0022838D0FFDFBDE8F081891E0022E4 +:102B000021F07F411046FFF7CFFF012D23D0002099 +:102B1000944D924F012668703E61914900203C39E6 +:102B200008600220091D08608D49042030390860C2 +:102B30008B483D34046008206C6000F0DFF83004FE +:102B4000C7F80403082000F0BBF88349F007091F09 +:102B500008602E70D0E70120DAE7012B02D00022B6 +:102B6000012005E00122FBE7012B04D00022022016 +:102B7000BDE8F04198E70122F9E774480068704722 +:102B800070B500F0D8F8704C0546D4F84001002626 +:102B9000012809D1D4F80803C00305D54FF48030CB +:102BA000C4F80803C4F84061D4F8440101280CD1EA +:102BB000D4F80803800308D54FF40030C4F80803A4 +:102BC000C4F84461012013F0EEFED4F84801012856 +:102BD0000CD1D4F80803400308D54FF48020C4F882 +:102BE0000803C4F84861022013F0DDFE5E4805606A +:102BF00070BD70B500F09FF85A4D0446287850B16A +:102C0000FFF706FF687818B10020687013F0CBFE5C +:102C10005548046070BD0320F8E74FF0E0214FF401 +:102C20000010C1F800027047152000F067B84B494A +:102C300001200861082000F061B848494FF47C1079 +:102C4000C1F808030020024601EB8003C3F84025C9 +:102C5000C3F84021401CC0B20628F5D37047410A92 +:102C600043F609525143C0F3080010FB02F000F58F +:102C7000807001EB5020704710B5430B48F2376469 +:102C800063431B0C5C020C60384C03FB0400384BA4 +:102C90004CF2F72443435B0D13FB04F404EB402098 +:102CA00000F580704012107008681844086010BD6C +:102CB0002C484068704729490120C1F8000270473C +:102CC000002809DB00F01F0201219140400980002B +:102CD00000F1E020C0F80011704700280DDB00F083 +:102CE0001F02012191404009800000F1E020C0F85E +:102CF0008011BFF34F8FBFF36F8F7047002809DB40 +:102D000000F01F02012191404009800000F1E02005 +:102D1000C0F8801270474907090E002804DB00F153 +:102D2000E02080F80014704700F00F0000F1E02070 +:102D300080F8141D70470C48001F00680A4A0D49AE +:102D4000121D11607047000000B0004004B5004043 +:102D50004081004044B1004008F50140008000403F +:102D6000408500403C00002014050240F7C2FFFFF0 +:102D70006F0C0100010000010A4810B50468094900 +:102D800009480831086013F0A2FE0648001D0460DF +:102D900010BD0649002008604FF0E0210220C1F874 +:102DA000800270471005024001000001FC1F004036 +:102DB000374901200860704770B50D2000F049F8D0 +:102DC000344C0020C4F800010125C4F804530D2040 +:102DD00000F050F825604FF0E0216014C1F80001C8 +:102DE00070BD10B50D2000F034F82A480121416073 +:102DF0000021C0F80011BDE810400D2000F03AB8E5 +:102E0000254810B504682449244808310860214940 +:102E1000D1F80001012804D0FFDF1F48001D046025 +:102E200010BD1B48001D00680022C0B2C1F800217F +:102E300014F07FFBF1E710B5164800BFD0F8001181 +:102E40000029FBD0FFF7DCFFBDE810400D2000F0AB +:102E500011B800280DDB00F01F020121914040094C +:102E6000800000F1E020C0F88011BFF34F8FBFF366 +:102E70006F8F7047002809DB00F01F02012191408D +:102E80004009800000F1E020C0F880127047000087 +:102E900004D5004000D000401005024001000001B0 +:102EA0004FF0E0214FF00070C1F8800101F5C071D2 +:102EB000BFF34F8FBFF36F8FC1F80001394B8022F2 +:102EC00083F8002441F8800C704700B502460420C6 +:102ED000354903E001EBC0031B792BB1401EC0B2A2 +:102EE000F8D2FFDFFF2000BD41F8302001EBC00128 +:102EF00000224A718A7101220A7100BD2A4A00210A +:102F000002EBC0000171704710B50446042800D3DD +:102F1000FFDF254800EBC4042079012800D0FFDF43 +:102F20006079A179401CC0B2814200D060714FF03D +:102F3000E0214FF00070C1F8000210BD70B504250B +:102F4000194E1A4C16E0217806EBC1000279012ACD +:102F500008D1427983799A4204D04279827156F835 +:102F6000310080472078401CC0B22070042801D373 +:102F7000002020706D1EEDB2E5D270BD0C4810B57A +:102F800004680B490B4808310860064890F80004B3 +:102F90004009042800D0FFDFFFF7D0FF0448001DE0 +:102FA000046010BD19E000E0E0050020580000209A +:102FB00010050240010000010548064A01689142DF +:102FC00001D1002101600449012008607047000020 +:102FD0005C000020BEBAFECA40E5014070B50C4658 +:102FE000054609F02FFC21462846BDE870400AF04E +:102FF00010BD7047704770470021016081807047A5 +:103000002CFFFFFFDBE5B151007002002301FFFF41 +:103010008C00000078DB6A007A2E9AC67DB66CFAC6 +:10302000F35721CCC310D5E51471FB3C30B5FC4DF2 +:103030000446062CA9780ED2DFE804F0030E0E0E2B +:103040000509FFDF08E0022906D0FFDF04E00329BD +:1030500002D0FFDF00E0FFDFAC7030BD30B50446CA +:103060001038EF4D07280CD2DFE800F0040C060CF6 +:103070000C0C0C00FFDF05E0287E112802D0FFDFDA +:1030800000E0FFDF2C7630BD2DE9F04112F026FE86 +:10309000044614F063F8201AC5B2062010F0AEFE04 +:1030A0000446062010F0B2FE211ADD4C207E1228C4 +:1030B00018D000200F18072010F0A0FE06460720A9 +:1030C00010F0A4FE301A3918207E13280CD00020EE +:1030D0000144A078042809D000200844281AC0B26E +:1030E000BDE8F0810120E5E70120F1E70120F4E7E8 +:1030F000CB4810B590F825004108C94800F12600DA +:1031000005D00EF0F5FEBDE8104006F08CB80EF0CC +:10311000D0FEF8E730B50446A1F120000D460A289C +:103120004AD2DFE800F005070C1C2328353A3F445B +:10313000FFDF42E0207820283FD1FFDF3DE0B848A4 +:103140008178052939D0007E122836D020782428AD +:1031500033D0252831D023282FD0FFDF2DE0207851 +:1031600022282AD0232828D8FFDF26E0207822280A +:1031700023D0FFDF21E0207822281ED024281CD075 +:1031800026281AD0272818D0292816D0FFDF14E0C7 +:103190002078252811D0FFDF0FE0207825280CD0DB +:1031A000FFDF0AE02078252807D0FFDF05E0207840 +:1031B000282802D0FFDF00E0FFDF257030BD1FB5FB +:1031C00004466A46002001F0A5FEB4B1BDF8022015 +:1031D0004FF6FF700621824201D1ADF80210BDF812 +:1031E0000420824201D1ADF80410BDF808108142DC +:1031F00003D14FF44860ADF8080068460FF0E2FADA +:1032000006F011F804B010BD70B516460C46054620 +:10321000FEF71FF848B90CB1B44208D90C2070BDB4 +:1032200055F82400FEF715F808B1102070BD2046AF +:10323000641EE4B2F4D270BD2DE9F04105461F468C +:1032400090460E4600240068FEF750F830B9A98871 +:1032500028680844401EFEF749F808B110203FE7EF +:1032600028680028A88802D0B84202D850E0002878 +:10327000F5D0092034E72968085DB8B1671CCA5D3C +:10328000152A2ED03CDC152A3AD2DFE802F039129A +:10329000222228282A2A313139393939393939391C +:1032A00039392200085D30BB641CA4B2A242F9D8AF +:1032B00033E00228DDD1A01C085C88F80000072854 +:1032C00001D2400701D40A200AE7307840F001001B +:1032D00015E0C143C90707E0012807D010E0062028 +:1032E000FEE60107A1F180510029F5D01846F7E666 +:1032F0003078810701D50B20F2E640F002003070F3 +:103300002868005D384484B2A888A04202D2B0E7A1 +:103310004FF4485382B2A242ADD80020E0E610B587 +:10332000027843F2022354080122022C12D003DC5B +:103330003CB1012C16D106E0032C10D07F2C11D10A +:1033400012E0002011E080790324B4EB901F09D132 +:103350000A700BE08079B2EB901F03D1F8E7807917 +:103360008009F5D0184610BDFF200870002010BD60 +:1033700008B500208DF80000294890F82E1051B1B2 +:1033800090F82F0002280FD003280FD0FFDF00BFD6 +:103390009DF8000008BD22486946253001F009FE6D +:1033A0000028F5D0FFDFF3E7032000E001208DF8CF +:1033B0000000EDE738B50C460546694601F0F9FD19 +:1033C00000280DD19DF80010207861F3470020708F +:1033D00055F8010FC4F80100A888A4F805000020E2 +:1033E00038BD38B5137888B102280FD0FF281BD01C +:1033F0000CA46D46246800944C7905EB9414247851 +:1034000064F347031370032805D010E023F0FE0394 +:1034100013700228F7D1D8B240F001000AE0000092 +:10342000F00100200302FF0143F0FE00107010784D +:1034300020F0010010700868C2F801008888A2F826 +:10344000050038BD022110F031BD38B50C460978B1 +:10345000222901D2082038BDADF800008DF80220E5 +:1034600068460EF087FD05F0DEFE050003D1212140 +:103470002046FFF74FFE284638BD1CB500208DF8CA +:103480000000CDF80100ADF80500FB4890F82E00D3 +:10349000022801D0012000E000208DF807006846D6 +:1034A0000EF0F0FD002800D0FFDF1CBD00220A80D6 +:1034B000437892B263F3451222F040020A8000780A +:1034C0000C282BD2DFE800F02A06090E1116191C71 +:1034D0001F220C2742F0110009E042F01D00088075 +:1034E0000020704742F0110012E042F0100040F05E +:1034F0000200F4E742F01000F1E742F00100EEE7CD +:1035000042F0010004E042F00200E8E742F002006D +:1035100040F00400E3E742F00400E0E707207047D2 +:103520002DE9FF478AB00025BDF82C6082461C4675 +:1035300091468DF81C50700703D56068FDF789FE31 +:1035400068B9CD4F4FF0010897F82E0058B197F8A1 +:103550002F00022807D16068FDF7C8FE18B11020BF +:103560000EB0BDE8F087300702D5A08980283DD88D +:10357000700705D4B9F1000F02D097F8240098B372 +:10358000E07DC0F300108DF81B00627D0720032151 +:103590005AB3012A2CD0022AE2D0042AE0D18DF8B5 +:1035A0001710F00627D4A27D072022B3012A22D0CB +:1035B000022A23D0042AD3D18DF819108DF8159042 +:1035C000606810B307A9FFF7AAFE0028C8D19DF8CC +:1035D0001C00FF2816D0606850F8011FCDF80F10AE +:1035E0008088ADF8130014E000E001E00720B7E7A1 +:1035F0008DF81780D5E78DF81980DFE702208DF868 +:103600001900DBE743F20220AAE7CDF80F50ADF82E +:103610001350E07B40B9207C30B9607C20B9A07C9D +:1036200010B9E07CC00601D0062099E78DF800A013 +:10363000BDF82C00ADF80200A0680190A0680290CF +:1036400004F10F0001F0A9FC8DF80C00FFF790FECB +:103650008DF80D009DF81C008DF80E008DF81650A9 +:103660008DF81850E07D08A900F00F008DF81A00C1 +:1036700068460FF0E3F905F0D6FD71E7F0B58FB0BD +:1036800000258DF830508DF814508DF834500646D2 +:103690008DF82850019502950395049519B10FC92D +:1036A00001AC84E80F00744CA078052801D00428F0 +:1036B0000CD101986168884200D120B90398E16873 +:1036C000884203D110B108200FB0F0BD207DC006A4 +:1036D00001D51F2700E0FF273B460DAA05A903A837 +:1036E000FFF7AAFD0028EFD1A08AC10702D0C006CB +:1036F00000D4EE273B460AAA0CA901A8FFF79CFDBF +:103700000028E1D19DF81400C00701D00A20DBE7B2 +:10371000A08A410708D4A17D31B19DF828108907FE +:1037200002D043F20120CFE79DF82810C90709D045 +:10373000400707D4208818B144F25061884201D96B +:103740000720C1E78DF818508DF81960BDF8080002 +:10375000ADF81A000198079006A80FF07BF905F064 +:1037600062FD0028B0D18DF820508DF82160BDF8A1 +:103770001000ADF822000398099008A80FF08CF90A +:1037800005F051FD00289FD101AD241D95E80F00E3 +:1037900084E80F00002097E770B586B00D4604005E +:1037A00005D0FDF7A3FD20B1102006B070BD0820A4 +:1037B000FBE72078C107A98802D0FF2902D303E0E4 +:1037C0001F2901D20920F0E7800763D4FFF75CFCD2 +:1037D00038B12178C1F3C100012804D0032802D0F8 +:1037E00005E01320E1E7244890F82400C8B1C80799 +:1037F0004FF001064FF0000502D08DF80F6001E098 +:103800008DF80F50FFF7B4FD8DF800002078694661 +:10381000C0F3C1008DF8010060788DF80250C20835 +:1038200001D00720C1E730B3C20701D08DF8026094 +:10383000820705D59DF8022042F002028DF8022091 +:10384000400705D59DF8020040F004008DF8020005 +:10385000002022780B18C2F38002DA7001EB4002DC +:103860006388D380401CA388C0B253810228F0D360 +:10387000207A78B905E001E0F00100208DF80260BF +:10388000E6E7607A30B9A07A20B9E07A10B9207BF7 +:10389000C00601D0062088E704F1080001F07DFB96 +:1038A0008DF80E0068460EF0F6FC05F0BCFC002812 +:1038B00089D18DF810608DF81150E088ADF81200B4 +:1038C000ADF8145004A80EF039FD05F0ACFC00284A +:1038D00088D12078C00701D0152000E01320FFF721 +:1038E000BDFB002061E72DE9FF470220FD4E8DF86A +:1038F00004000027708EADF80600B84643F20209B6 +:103900004CE001A810F039FA050006D0708EA8B37B +:10391000A6F83280ADF806803EE0039CA07F010748 +:103920002DD504F124000090A28EBDF80800214698 +:1039300004F1360301F0BCFC050005D04D452AD04A +:10394000112D3CD0FFDF3AE0A07F20F00801E07F9E +:10395000420862F3C711A177810861F30000E077A4 +:1039600094F8210000F01F0084F820002078282817 +:1039700026D129212046FFF7CDFB21E014E04007A6 +:103980000AD5BDF8080004F10E0101F01CFB05008A +:103990000DD04D4510D100257F1CFFB2022010F044 +:1039A0002DFA401CB842ACD8052D11D008E0A07FFC +:1039B00020F00400A07703E0112D00D0FFDF0025E8 +:1039C000BDF806007086052D04D0284604B0C8E571 +:1039D000A6F832800020F9E770B50646FFF732FD01 +:1039E000054605F003FE040000D1FFDF6680207865 +:1039F00020F00F00801C20F0F00020302070032009 +:103A0000207295F83E006072BDE8704005F0F1BD8F +:103A10002DE9F04786B0040000D1FFDF2078B14DDA +:103A200020F00F00801C20F0F000703020706068E3 +:103A30000178491F1B2933D2DFE801F0FE32323210 +:103A400055FD320EFDFD42FC32323278FCFCFBFAB1 +:103A500032FCFCF9F8FCFC00C6883046FFF7F2FCAB +:103A60000546304607F045FCE0B16068007A85F80D +:103A70003E0021212846FFF74DFB3046FEF75AFB5A +:103A8000304603F0D7FE3146012014F017F8A87F26 +:103A900020F01000A877FFF726FF002800D0FFDFF6 +:103AA00006B05EE5207820F0F00020302070032082 +:103AB000207266806068007A607205F09AFDD8E72F +:103AC000C5882846FFF7BEFC00B9FFDF60680079B3 +:103AD000012800D0FFDF6068017A06B02846BDE803 +:103AE000F04707F0EBBDC6883046FFF7ABFC05009A +:103AF00000D1FFDF05F07DFD606831460089288137 +:103B000060684089688160688089A881012013F01D +:103B1000D5FF0020A875A87F00F003000228BFD1C0 +:103B2000FFF7E1FE0028BBD0FFDFB9E7007928B13D +:103B30000228B5D03C28B3D0FFDFB1E705F059FD2E +:103B40006668B6F806A0307A361D012806D0687E71 +:103B5000814605F0D4FA070003D101E0E878F7E7E1 +:103B6000FFDF00220221504610F097F9040000D137 +:103B7000FFDF22212046FFF7CDFA3079012800D05F +:103B80000220A17F804668F30101A177308B20815C +:103B9000708B6081B08BA08184F822908DF80880B2 +:103BA000B8680090F86801906A460321504610F00A +:103BB00074F900B9FFDFB888ADF81000B8788DF857 +:103BC000120004AA0521504610F067F900B9FFDF82 +:103BD000B888ADF80C00F8788DF80E0003AA04211F +:103BE000504610F05AF900B9FFDF062106F1120025 +:103BF0000DF00EF940B37079800700D5FFDF7179C1 +:103C0000E07D61F34700E075D6F80600A061708999 +:103C1000A083062106F10C000DF0FAF8F0B195F83A +:103C200025004108607861F3470006E041E039E093 +:103C300071E059E04EE02FE043E06070D5F82600D7 +:103C4000C4F80200688D12E0E07D20F0FE00801CC8 +:103C5000E075D6F81200A061F08AD9E7607820F00C +:103C6000FE00801C6070F068C4F80200308AE080BA +:103C7000B8F1010F04D0B8F1020F05D0FFDF0FE754 +:103C80000320FFF7D3F90BE7287E122800D0FFDFCF +:103C90001120FFF7E3F903E706B02046BDE8F0473F +:103CA00001F092BD05F0A5FC15F8300F40F00200C0 +:103CB00005E005F09EFC15F8300F40F00400287078 +:103CC000EEE6287E13280AD01528D8D15FF016001A +:103CD000FFF7C4F906B0BDE8F04705F08ABC142030 +:103CE000F6E70000F0010020A978052909D0042991 +:103CF000C5D105F07EFC022006B0BDE8F047FFF715 +:103D000095B900790028BAD0E87801F02DF905F0CE +:103D100070FC0320F0E7287E122802D1687E01F0B3 +:103D200023F91120D4E72DE9F05F054600784FF024 +:103D300000080009DFF8B8A891460C46464601285D +:103D40006ED002286DD007280BD00A286AD0FFDF7A +:103D5000A9F8006014B1A4F8008066800020BDE8D6 +:103D6000F09F6968012704F108000B784FF0020BFF +:103D70005B1F4FF6FF721B2B7ED2DFE803F0647DE2 +:103D80007D7D0E7D7D7D7D7D7D217D7D7D2BFDFC81 +:103D9000FBFA7D14D2F9E7F8F700C8884FF0120853 +:103DA000102621469AE14FF01C080A26BCB38888E9 +:103DB000A0806868807920726868C0796072C7E7FF +:103DC0004FF01B08142654B30320207268688088C3 +:103DD000A080BDE70A793C2ABAD00D1D4FF010082B +:103DE0002C26E4B16988A180298B6182298B2182EC +:103DF000698BA182A98BE1826B790246A91D1846C5 +:103E0000FFF7EFFA2979002001290CD084F80FB0D0 +:103E1000FF212176E06120626062A06298E70FE0F6 +:103E20003BE15EE199E1E77320760AF1040090E856 +:103E30000E00DAF81000C4E90930C4E9071287E778 +:103E4000A9F800608AE72C264FF01D08002CF7D057 +:103E5000A28005460F1D897B008861F30000288041 +:103E6000B97A490861F341002880B97A890861F379 +:103E700082002880B97A00E00CE1C90861F3C30030 +:103E80002880B97AAA1C0911491C61F3041000F0BA +:103E90007F0028807878B91CFFF7A3FA387D05F1F8 +:103EA000090207F11501FFF79CFA387B01F0A9F828 +:103EB0002874787B01F0A5F86874F87EA874787A85 +:103EC000E874387F2875B87B6875388AE882DAF834 +:103ED0001C10A961B97A504697F808A0C1F34111A6 +:103EE000012904D0008C504503D2824609E0FFDF4F +:103EF00010E0022903D0288820F0600009E0504536 +:103F000004D1288820F06000403002E0288840F08A +:103F100060002880A4F824A0524607F11D01A8697A +:103F20009BE011264FF02008002C89D0A280686801 +:103F300004F10A02007920726868007B6072696887 +:103F40008B1D48791946FFF74CFA01E70A264FF016 +:103F50002108002CE9D08888A080686880792072C8 +:103F60006868C07960729AF8301006E078E06BE01B +:103F700052E07FE019E003E03AE021F00401A6E01E +:103F80000B264FF02208002CCFD0C888A08068688C +:103F9000007920726868007A01F033F8607268680E +:103FA000407A01F02EF8A072D2E61C264FF02608C7 +:103FB000002CBAD0A2806868407960726868007A84 +:103FC000A0720AF1040090E80E00DAF81000C4E9CB +:103FD0000530C4E90312686800793C2803D04328FF +:103FE00003D0FFDFB4E62772B2E684F808B0AFE68C +:103FF00010264FF02408002C97D08888A08068688D +:10400000807920816868807A608168680089A081F1 +:1040100068688089E0819BE610264FF02308002C19 +:1040200098D08888A0806868C088208168680089E6 +:10403000608168684089A08168688089E0819AF819 +:10404000301021F0020142E030264FF02508002C0C +:104050009AD0A2806968282249680AF0EEF977E6CA +:104060002A264FF02F08002C8ED0A28069682222C9 +:10407000091DF2E714264FF01B08002C84D0A28003 +:10408000686800790128B0D02772DAE90710C4E91E +:1040900003105DE64A46214660E0287A012803D0F5 +:1040A000022817D0FFDF53E610264FF01F08002C20 +:1040B000A2D06888A080A8892081E8896081288AA8 +:1040C000A081688AE0819AF8301021F001018AF815 +:1040D00030103DE64FF012081026688800F07EFF91 +:1040E00036E6287AC8B3012838D0022836D003280B +:1040F00001D0FFDF2CE609264FF01108002C8FD0ED +:104100006F883846FFF79EF990F822A0A780687A5A +:104110002072042138460FF0DBFE052138460FF0EF +:10412000D7FE002138460FF0D3FE012138460FF0AC +:10413000CFFE032138460FF0CBFE022138460FF0A8 +:10414000C7FE062138460FF0C3FE072138460FF0A0 +:10415000BFFE504600F008FFFAE5FFE72846BDE83D +:10416000F05F01F0BBBC70B5012803D0052800D07A +:10417000FFDF70BD8DB22846FFF764F9040000D15F +:10418000FFDF20782128F4D005F030FA80B10178E3 +:1041900021F00F01891C21F0F00110310170022182 +:1041A000017245800020A075BDE8704005F021BA7D +:1041B00021462846BDE870401322FFF746B92DE995 +:1041C000F04116460C00804600D1FFDF307820F029 +:1041D0000F00801C20F0F000103030702078012893 +:1041E00004D0022818D0FFDFBDE8F0814046FFF779 +:1041F00029F9050000D1FFDF0320A87505F0F9F9C2 +:1042000094E80F00083686E80F00F94810F8301FD0 +:1042100041F001010170E7E74046FFF713F905009F +:1042200000D1FFDFA1884FF6FF700027814202D145 +:10423000E288824203D0814201D1E08840B105F09A +:10424000D8F994E80F00083686E80F00AF75CBE781 +:10425000A87D0128C8D178230022414613F084FBB1 +:104260000220A875C0E738B50C4624285CD008DCCD +:1042700020280FD0212825D022284BD0232806D152 +:104280004CE0252841D0262832D03F2851D00725A0 +:10429000284638BD0021052013F0E6FB08B11120A7 +:1042A00038BDA01C0EF0E1FA04F0BDFF0500EFD10F +:1042B000002208231146052013F056FB0528E7D0FD +:1042C000FFDFE5E76068FDF708F808B1102038BDAA +:1042D000618820886A460EF071FD04F0A4FF050095 +:1042E000D6D160680028D3D0BDF800100180CFE798 +:1042F000206820B1FCF7FAFF08B11025C8E7204676 +:104300000EF03BFE1DE00546C2E7A17820880EF0C6 +:1043100086FD16E0086801F08DFEF4E7087800F0ED +:1043200001000DF0B9FD0CE0618820880EF0C1FCA1 +:1043300007E0087800F001008DF8000068460EF0F4 +:10434000DFF804F070FFDEE770B505460C4608465E +:10435000FCF7A5FF08B1102070BD202D07D0212D3E +:104360000DD0222D0BD0252D09D0072070BD20881F +:10437000A11C0DF065FEBDE8704004F054BF06209E +:1043800070BD9B482530704708B5342200219848FD +:104390000AF07DF80120FEF749FE1120FEF75EFECF +:1043A00093496846263105F0B7F891489DF80020FA +:1043B00010F8251F62F3470121F00101017000216F +:1043C00041724FF46171A0F8071002218172FEF76B +:1043D0008FFE00B1FFDFFDF705F801F0BEF908BD63 +:1043E00010B50C464022002120460AF050F8A07F6C +:1043F00020F00300A077202020700020A07584F812 +:10440000230010BD70472DE9FC410746FCF721FF52 +:1044100010B11020BDE8FC81754E06F12501D6F8DB +:1044200025000090B6F82950ADF8045096F82B40BE +:104430008DF806403846FEF7BDFF0028EAD1FEF7AA +:1044400057FE0028E6D0009946F8251FB580B471C4 +:10445000E0E710B50446FCF722FF08B1102010BDBC +:1044600063486349224690F8250026314008FEF74C +:10447000B8FF002010BD3EB504460D460846FCF7C7 +:104480000EFF08B110203EBD14B143F204003EBD42 +:1044900057488078052803D0042801D008203EBD65 +:1044A000694602A80AF012FC2A4669469DF80800EF +:1044B000FEF797FF00203EBDFEB50D4604004FF00D +:1044C000000712D00822FEF79FFE002812D1002616 +:1044D00009E000BF54F826006946FEF720FF0028D7 +:1044E00008D1761CF6B2AE42F4D30DF01CFC10B12C +:1044F00043F20320FEBD3E4E86F824700CB3002725 +:104500001BE000BF54F8270002A9FEF708FF00B126 +:10451000FFDF9DF808008DF8000054F8270050F8E0 +:10452000011FCDF801108088ADF8050068460DF038 +:104530001FFC00B1FFDF7F1CFFB2AF42E2D386F861 +:1045400024500020FEBD2DE9F0418AB01546884672 +:1045500004001ED00F4608222946FEF755FE00280B +:1045600011D1002613E000BF54F826006946103030 +:1045700000F01FFD002806D13FB157F82600FCF7D8 +:1045800068FE10B110200AB02EE6761CF6B2AE42DC +:10459000EAD3681EC6B217E0701CC7B212E000BFB3 +:1045A00054F82600017C4A0854F827100B7CB2EB23 +:1045B000530F05D106221130113109F011FF50B10E +:1045C0007F1CFFB2AF42EBD3761EF6B2E4D2464672 +:1045D00024B1012003E043F20520D4E700200DF0D0 +:1045E000ECFB10B90DF0F5FB20B143F20420CAE753 +:1045F000F001002064B300270DF1170826E000BF8A +:1046000054F827006946103000F0D3FC00B1FFDFFA +:1046100054F82700102250F8111FCDF8011080889F +:10462000ADF8050054F827100DF1070009F005FF5B +:1046300096B156F827101022404609F0FEFE684653 +:104640000DF07BFB00B1FFDF7F1CFFB2AF42D7D381 +:10465000FEF713FF002096E7404601F0DFFCEEE78F +:1046600030B585B00446FDF7BDF830B906200FF02F +:10467000C5FB10B1062005B030BD2046FCF7E9FDB2 +:1046800018B96068FCF732FE08B11020F3E76088C3 +:104690004AF2B811884206D82078F94D28B101288D +:1046A00006D0022804D00720E5E7FEF721FD18E038 +:1046B0006078022804D0032802D043F20220DAE70F +:1046C00085F82F00C1B200200090ADF80400022947 +:1046D0002CD0032927D0FFDF68460DF009FC04F039 +:1046E000A2FD0028C7D1606801F08BFC207858B18A +:1046F00001208DF800000DF1010001F08FFC6846EB +:104700000EF0FDFB00B1FFDF207885F82E00FEF7EC +:10471000B4FE608860B1A88580B20DF046FB00B1A0 +:10472000FFDF0020A7E78DF80500D5E74020FAE776 +:104730004FF46170EFE710B50446FCF7B0FD20B907 +:10474000606838B1FCF7C9FD08B1102010BD606881 +:1047500001F064FCCA4830F82C1F6180C178617098 +:1047600080782070002010BD2DE9F843144689465A +:104770000646FCF794FDA0B94846FCF7B7FD80B9A2 +:104780002046FCF7B3FD60B9BD4DA878012800D1E3 +:104790003CB13178FF2906D049B143F20400BDE8AD +:1047A000F8831020FBE7012801D00420F7E7CCB301 +:1047B000052811D004280FD069462046FEF776FE62 +:1047C0000028ECD1217D49B1012909D0022909D065 +:1047D000032909D00720E2E70820E0E7024604E0C9 +:1047E000012202E0022200E003228046234617460F +:1047F00000200099FEF794FE0028D0D1A0892880DF +:10480000A07BE875BDF80000A882AF75BDF8001068 +:10481000090701D5A18931B1A1892980C00704D038 +:10482000032003E006E08021F7E70220FEF7FEFB0D +:1048300086F800804946BDE8F8430020FEF71EBF19 +:104840007CB58F4C05460E46A078022803D003287D +:1048500001D008207CBD15B143F204007CBD0720C7 +:104860000FF0D4FA10B9A078032806D0FEF70CFC9C +:1048700028B1A078032804D009E012207CBD1320C1 +:104880007CBD304600F053FB0028F9D1E670FEF7FE +:104890006FFD0AF058F901208DF800008DF8010035 +:1048A0008DF802502088ADF80400E07D8DF80600F8 +:1048B00068460EF0C1F904F0B6FC0028E0D1A078FB +:1048C000032805D05FF00400FEF7B0FB00207CBD9C +:1048D000E07800F03CFB0520F6E71CB510B143F290 +:1048E00004001CBD664CA078042803D0052801D024 +:1048F00008201CBD00208DF8000001218DF801105A +:104900008DF8020068460EF097F904F08CFC002840 +:10491000EFD1A078052805D05FF00200FEF786FBF6 +:1049200000201CBDE07800F01FFB0320F6E72DE916 +:10493000FC4180460E4603250846FCF7D7FC0028BC +:1049400066D14046FEF77EFD040004D02078222880 +:1049500004D208205EE543F202005BE5A07F00F090 +:1049600003073EB1012F0CD000203146FEF727FC93 +:104970000500EFD1012F06D0022F1AD0FFDF284605 +:1049800048E50120F1E7A07D3146022801D011B1B0 +:1049900007E011203EE56846FCF758FE0028D9D113 +:1049A0006946404606F04DFE0500E8D10120A0759D +:1049B000E5E7A07D032804D1314890F83000C00716 +:1049C00001D02EB30EE026B1A07F40071ED40021F7 +:1049D00000E00121404606F054FE0500CFD1A0754D +:1049E000002ECCD03146404600F0EDFA05461128A5 +:1049F000C5D1A07F4107C2D4316844F80E1F716849 +:104A0000616040F0040020740025B8E71125B6E786 +:104A10001020FFE470B50C460546FEF713FD0100BB +:104A200005D022462846BDE87040FEF70EBD43F291 +:104A3000020070BD10B5012807D1114B9B78012BE6 +:104A400000D011B143F2040010BD0DF0E0F9BDE853 +:104A5000104004F0E8BB012300F090BA00231A468E +:104A6000194600F08BBA70B506460C460846FCF7AE +:104A7000F0FB18B92068FCF712FC18B1102070BDCB +:104A8000F0010020F84D2A7E112A04D0132A00D309 +:104A90003EB10820F3E721463046FEF77DFE60B1C7 +:104AA000EDE70920132A0DD0142A0BD0A188FF2985 +:104AB000E5D31520FEF7D2FA0020D4E90012C5E9AB +:104AC0000712DCE7A1881F29D9D31320F2E71CB510 +:104AD000E548007E132801D208201CBD00208DF877 +:104AE000000068460DF02AFC04F09DFB0028F4D17C +:104AF0001120FEF7B3FA00201CBD2DE9F04FDFF8BE +:104B000068A3814691B09AF818009B4615460C465A +:104B1000132803D3FFF7DBFF00281FD12046FCF743 +:104B200098FBE8BB2846FCF794FBC8BB20784FF005 +:104B30000107C0074FF0000102D08DF83A7001E084 +:104B40008DF83A1020788846C0F3C1008DF8000037 +:104B500060788DF80910C10803D0072011B0BDE8B6 +:104B6000F08FB0B3C10701D08DF80970810705D56A +:104B70009DF8091041F002018DF80910400705D594 +:104B80009DF8090040F004008DF809009DF8090027 +:104B9000810703D540F001008DF80900002000E0F6 +:104BA00015E06E4606EB400162884A81401CA288EF +:104BB000C0B20A820328F5D32078C0F3C1000128CF +:104BC00025D0032823D04846FCF743FB28B110200A +:104BD000C4E7FFE78DF80970D8E799F800004008AE +:104BE00008D0012809D0022807D0032805D043F2B5 +:104BF0000220B3E78DF8028001E08DF8027048468C +:104C000050F8011FCDF803108088ADF80700FEF7BB +:104C1000AFFB8DF801000021424606EB41002B88D6 +:104C2000C3826B888383AB884384EB880385491CEC +:104C3000C285C9B282860329EFD3E088ADF83C0073 +:104C400068460DF053FC002887D19AF818005546A5 +:104C5000112801D0082081E706200FF0D7F838B1DD +:104C60002078C0F3C100012804D0032802D006E058 +:104C7000122073E795F8240000283FF46EAFFEF78A +:104C800003FA022801D2132068E7584600F04FF9D2 +:104C900000289DD185F819B068460DF06DFD04F02F +:104CA000C2FA040094D1687E00F051F91220FEF798 +:104CB000D5F9204652E770B56B4D287E122801D0F9 +:104CC0000820DCE60DF05BFD04F0ADFA040005D130 +:104CD000687E00F049F91120FEF7C0F92046CEE6C3 +:104CE00070B5064615460C460846FCF7D8FA18B9C2 +:104CF0002846FCF7D4FA08B11020C0E62A4621461F +:104D000030460EF03BF804F08EFA0028F5D12178F9 +:104D10007F29F2D10520B2E67CB505460C4608464F +:104D2000FCF797FA08B110207CBD2846FEF78AFBF5 +:104D300020B10078222804D208207CBD43F2020072 +:104D40007CBD494890F83000400701D511207CBD5A +:104D50002078C00802D16078C00801D007207CBD4F +:104D6000ADF8005020788DF8020060788DF80300CF +:104D70000220ADF8040068460CF03BFE04F053FA44 +:104D80007CBD70B586B014460D460646FEF75AFB4C +:104D900028B10078222805D2082006B06FE643F239 +:104DA0000200FAE72846FCF7A1FA20B944B12046F0 +:104DB000FCF793FA08B11020EFE700202060A080F4 +:104DC000294890F83000800701D51120E5E703A9B4 +:104DD00030460CF05EFE10B104F025FADDE7ADF8C8 +:104DE0000060BDF81400ADF80200BDF81600ADF883 +:104DF0000400BDF81000BDF81210ADF80600ADF8C3 +:104E000008107DB1298809B1ADF80610698809B18B +:104E1000ADF80210A98809B1ADF80810E98809B108 +:104E2000ADF80410DCB1BDF80610814201D9081AB2 +:104E30002080BDF80210BDF81400814201D9081A83 +:104E40006080BDF80800BDF80410BDF816200144CC +:104E5000BDF812001044814201D9081AA0806846AA +:104E60000CF0D5FEB8E70000F00100201CB56C493D +:104E70000968CDE9001068460DF03AFB04F0D3F95B +:104E80001CBD1CB500200090019068460DF030FB61 +:104E900004F0C9F91CBD70B505460C460846FCF780 +:104EA000FEF908B11020EAE5214628460DF012F976 +:104EB000BDE8704004F0B7B93EB505460C4608465B +:104EC000FCF7EDF908B110203EBD002000900190E4 +:104ED0000290ADF800502089ADF8080020788DF8D8 +:104EE0000200606801902089ADF808006089ADF883 +:104EF0000A0068460DF000F904F095F93EBD0EB5C4 +:104F0000ADF800000020019068460DF0F5F804F0BF +:104F10008AF90EBD10800888508048889080C88823 +:104F200010818888D080002050819081704710B512 +:104F3000044604F0E4F830B1407830B1204604F083 +:104F4000FCFB002010BD052010BD122010BD10B5C7 +:104F500004F0D5F8040000D1FFDF607800B9FFDF6E +:104F60006078401E607010BD10B504F0C8F80400F1 +:104F700000D1FFDF6078401C607010BD1CB5ADF83B +:104F800000008DF802308DF803108DF8042068467B +:104F90000DF0B7FE04F047F91CBD0CB521A2D2E913 +:104FA0000012CDE900120079694601EB501000783B +:104FB0000CBD0278520804D0012A02D043F202202C +:104FC0007047FEF7ACB91FB56A46FFF7A3FF684606 +:104FD0000DF008FC04F027F904B010BD70B50C000A +:104FE00006460DD0FEF72EFA050000D1FFDFA680A1 +:104FF00028892081288960816889A081A889E08129 +:105000003DE500B540B1012805D0022803D00328B2 +:1050100004D0FFDF002000BDFF2000BD042000BD44 +:1050200014610200070605040302010010B50446DE +:10503000FCF70FF908B1102010BD2078C0F3021062 +:10504000042807D86078072804D3A178102901D84C +:10505000814201D2072010BDE078410706D42179B2 +:105060004A0703D4000701D4080701D5062010BD64 +:10507000002010BD10B513785C08837F64F3C7135C +:10508000837713789C08C37F64F30003C377107899 +:10509000C309487863F34100487013781C090B7802 +:1050A00064F347130B701378DB0863F30000487058 +:1050B0005078487110BD10B5C4780B7864F30003C4 +:1050C0000B70C478640864F341030B70C478A408BF +:1050D00064F382030B70C478E40864F3C3030B70B9 +:1050E0000379117863F30001117003795B0863F3AE +:1050F0004101117003799B0863F3820111700079FB +:10510000C00860F3C301117010BD70B514460D46A0 +:10511000064604F06BFA80B10178182221F00F01E5 +:10512000891C21F0F001A03100F8081B214609F08C +:1051300084F9BDE8704004F05CBA29463046BDE809 +:1051400070401322FEF781B92DE9F047064608A802 +:10515000904690E8300489461F46142200212846D4 +:1051600009F095F90021CAF80010B8F1000F03D03A +:10517000B9F1000F03D114E03878C00711D02068CE +:10518000FCF78DF8C0BBB8F1000F07D120681230D2 +:1051900028602068143068602068A8602168CAF818 +:1051A00000103878800724D56068FCF796F818BBA3 +:1051B000B9F1000F21D0FFF7E4F80168C6F86811D3 +:1051C0008188A6F86C11807986F86E0101F013FDD4 +:1051D000F94FEF60626862B196F8680106F26911F2 +:1051E00040081032FEF7FDF810223946606809F0D9 +:1051F00024F90020BDE8F08706E0606820B1E8608F +:105200006068C6F86401F4E71020F3E730B505469E +:1052100008780C4620F00F00401C20F0F0011031FF +:1052200021700020607095F8230030B104280FD061 +:10523000052811D0062814D0FFDF20780121B1EB1A +:10524000101F04D295F8200000F01F00607030BDE0 +:1052500021F0F000203002E021F0F000303020702A +:10526000EBE721F0F0004030F9E7F0B591B002270C +:1052700015460C4606463A46ADF80870092103ABC0 +:1052800005F063F80490002810D004208DF8040085 +:105290008DF80170E034099605948DF818500AA92C +:1052A000684610F0FCFA00B1FFDF012011B0F0BD3C +:1052B00010B588B00C460A99ADF80000CBB118685B +:1052C000CDF80200D3F80400CDF80600ADF80A20AE +:1052D000102203A809F0B1F868460DF0F3FA03F0C4 +:1052E000A2FF002803D1A17F41F01001A17708B0EF +:1052F00010BD0020CDF80200E6E72DE9F84F064684 +:10530000808A0D4680B28246FEF79CF804463078CB +:10531000DFF8A48200274FF00209A8F120080F2827 +:1053200070D2DFE800F06FF23708387D8CC8F1F0FA +:10533000EFF35FF3F300A07F00F00300022809D031 +:105340005FF0000080F0010150460EF0AFFD050057 +:1053500003D101E00120F5E7FFDF98F85C10C907F1 +:1053600002D0D8F860000BE0032105F11D0012F017 +:10537000BEF8D5F81D009149B0FBF1F201FB120017 +:10538000C5F81D0070686867B068A8672078252890 +:1053900000D0FFDFCAE0A07F00F00300022809D0A0 +:1053A0005FF0000080F0010150460EF07FFD060026 +:1053B00003D101E00120F5E7FFDF3078810702D556 +:1053C0002178252904D040F001003070BDE8F88F25 +:1053D00085F80090307F287106F11D002D36C5E953 +:1053E0000206F3E7A07F00F00300022808D00020A7 +:1053F00080F0010150460EF059FD040004D102E096 +:105400000120F5E7A7E1FFDF2078C10604D50720DA +:1054100028703D346C60D9E740F008002070D5E773 +:10542000E07F000700D5FFDF307CB28800F0010389 +:1054300001B05046BDE8F04F092106F064B804B948 +:10544000FFDF716821B1102204F1240008F0F5FF9C +:1054500028212046FDF75EFEA07F00F00300022811 +:105460000ED104F12400002300901A462146504634 +:10547000FFF71EFF112807D029212046FDF74AFE1D +:10548000307A84F82000A1E7A07F000700D5FFDF75 +:1054900014F81E0F40F008002070E782A761E76152 +:1054A000C109607861F34100014660F382016170D7 +:1054B000307AE0708AE7A07F00F00300022809D06C +:1054C0005FF0000080F0010150460EF0EFFC040098 +:1054D00003D101E00120F5E7FFDF022104F185009F +:1054E00012F005F80420287004F5B4706860B4F870 +:1054F00085002882304810387C346C61C5E9028010 +:1055000064E703E024E15BE02DE015E0A07F00F01C +:105510000300022807D0002080F0010150460EF061 +:10552000C5FC18B901E00120F6E7FFDF324621464D +:105530005046BDE8F84FE8E504B9FFDF20782128A0 +:10554000A1D93079012803D1E07F40F00800E0774D +:10555000324621465046FFF7D8FD2046BDE8F84FB9 +:105560002321FDF7D7BD3279AA8005F1080309216F +:10557000504604F0EAFEE86010B10520287025E7E7 +:10558000A07F00F00300022808D0002080F0010175 +:1055900050460EF08BFC040003D101E00120F5E73A +:1055A000FFDF04F1620102231022081F0EF005FB49 +:1055B00007703179417009E75002002040420F0026 +:1055C000A07F00F00300022808D0002080F0010135 +:1055D00050460EF06BFC050003D101E00120F5E719 +:1055E000FFDF95F8840000F0030001287AD1A07F46 +:1055F00000F00307E07F10F0010602D0022F04D173 +:1056000033E095F8A000C0072BD0D5F8601121B386 +:1056100095F88320087C62F387000874A17FCA098B +:10562000D5F8601162F341000874D5F8601166F393 +:1056300000000874AEB1D5F86001102204F1240115 +:10564000883508F0FAFE287E40F001002876287898 +:1056500020F0010005F8880900E016B1022F04D0FF +:105660002DE095F88800C00727D0D5F85C1121B34C +:1056700095F88320087C62F387000874A17FCA092B +:10568000D5F85C1162F341000874D5F85C1166F33B +:10569000000008748EB1D5F85C01102204F12401D9 +:1056A000883508F0CAFE287840F0010005F8180B8C +:1056B000287820F0010005F8A009022F44D000202E +:1056C00000EB400005EBC00090F88800800709D58A +:1056D00095F87C00D5F86421400805F17D01103271 +:1056E000FDF77FFE8DF8009095F884006A4600F083 +:1056F00003008DF8010095F888108DF8021095F8D8 +:10570000A0008DF803002146504601F05DFA207894 +:10571000252805D0212807D0FFDF2078222803D9AB +:1057200022212046FDF7F6FCA07F00F003000228AE +:105730000CD0002080F0010150460EF0C9FB00287B +:105740003FF44FAEFFDF41E60120B9E70120F1E76A +:10575000706847703AE6FFDF38E670B5FE4C00250A +:1057600084F85C50256610F066F804F110012046BC +:1057700003F0F8FE84F8305070BD70B50D46FDF7AB +:1057800061FE040000D1FFDF4FF4B872002128460B +:1057900008F07DFE04F124002861A07F00F00300E2 +:1057A000022809D05FF0010105F1E00010F044F893 +:1057B000002800D0FFDF70BD0221F5E70A46014650 +:1057C00002F1E00010F059B870B50546406886B0A7 +:1057D00001780A2906D00D2933D00E292FD0FFDFFA +:1057E00006B070BD86883046FDF72CFE040000D15F +:1057F000FFDF20782128F3D028281BD168680221F8 +:105800000E3001F0D6F9A8B168680821801D01F0BA +:10581000D0F978B104F1240130460DF00FFA03F00D +:1058200002FD00B1FFDF06B02046BDE8704029212F +:10583000FDF770BC06B0BDE8704003F0DABE012190 +:1058400001726868C6883046FDF7FCFD040000D18F +:10585000FFDFA07F00F00301022902D120F0100039 +:10586000A077207821280AD06868017A09B10079E8 +:1058700080B1A07F00F00300022862D0FFDFA07F8C +:1058800000F003000228ABD1FEF72DF80028A7D0C6 +:10589000FFDFA5E703F0ADFEA17F08062BD5E07F73 +:1058A000C00705D094F8200000F01F00102820D079 +:1058B0005FF0050084F82300207829281DD02428D3 +:1058C000DDD13146042012F0F9F822212046FDF7FF +:1058D00021FCA07F00F00300022830D05FF0000020 +:1058E00080F0010130460EF0F3FA0028C7D0FFDF48 +:1058F000C5E70620DEE70420DCE701F0030002280C +:1059000008D0002080F0010130460EF0CFFA0500EB +:1059100003D101E00120F5E7FFDF25212046FDF757 +:10592000F9FB03208DF80000694605F1E0000FF057 +:105930009BFF0228A3D00028A1D0FFDF9FE7012012 +:10594000CEE703F056FE9AE72DE9F04387B099467B +:10595000164688460746FDF775FD04004BD02078B3 +:10596000222848D3232846D0E07F000743D4A07FD5 +:1059700000F00300022809D05FF0000080F0010170 +:1059800038460EF093FA050002D00CE00120F5E74E +:10599000A07F00F00300022805D001210022384634 +:1059A0000EF07BFA05466946284601F034F9009866 +:1059B00000B9FFDF45B10098E03505612078222865 +:1059C00006D0242804D007E000990020086103E0F5 +:1059D00025212046FDF79EFB00980121417047627A +:1059E000868001A9C0E902890FF059FF022802D080 +:1059F000002800D0FFDF07B0BDE8F08370B586B0A7 +:105A00000546FDF71FFD017822291ED9807F00F091 +:105A10000300022808D0002080F0010128460EF083 +:105A200045FA04002FD101E00120F5E7FFDF2AE06D +:105A3000B4F85E0004F1620630440178427829B17E +:105A400021462846FFF711FCB0B9C9E6ADF804209D +:105A50000921284602AB04F078FC03900028F4D01A +:105A600005208DF80000694604F1E0000FF0FCFE0F +:105A7000022801D000B1FFDF02231022314604F1D9 +:105A80005E000EF0D0F8B4F860000028D0D1A7E690 +:105A900010B586B00446FDF7D5FC017822291BD944 +:105AA000807F00F00300022808D0002080F0010170 +:105AB00020460EF0FBF9040003D101E00120F5E7D8 +:105AC000FFDF06208DF80000694604F1E0000FF0CA +:105AD000CBFE002800D0FFDF06B010BD2DE9F05F3F +:105AE00005460C4600270078904601093E4604F121 +:105AF000080BBA4602297DD0072902D00A2909D10C +:105B000046E0686801780A2905D00D2930D00E29B1 +:105B10002ED0FFDFBBE114271C26002C6BD0808821 +:105B2000A080FDF78FFC5FEA000900D1FFDF99F844 +:105B300017005A46400809F11801FDF752FC686841 +:105B4000C0892082696851F8060FC4F812004868BD +:105B5000C4F81600A07E01E03002002020F006000C +:105B600040F00100A07699F81E0040F020014DE0C1 +:105B70001A270A26002CD1D0C088A080FDF762FC2D +:105B8000050000D1FFDF59462846FFF73FFB7EE1C5 +:105B90000CB1A88BA080287A0B287DD006DC0128C8 +:105BA0007BD0022808D0032804D135E00D2875D019 +:105BB0000E2874D0FFDF6AE11E270926002CADD025 +:105BC000A088FDF73FFC5FEA000900D1FFDF287BDA +:105BD00000F003000128207A1BD020F00100207281 +:105BE000297B890861F341002072297BC90861F390 +:105BF000820001E041E1F2E02072297B090961F3B2 +:105C0000C300207299F81E0040F0400189F81E1070 +:105C10003DE140F00100E2E713270D26002CAAD059 +:105C2000A088FDF70FFC8146807F00F0030002286A +:105C300008D0002080F00101A0880EF037F905009F +:105C400003D101E00120F5E7FFDF99F81E0000F025 +:105C50000302022A50D0686F817801F00301012904 +:105C6000217A4BD021F00101217283789B0863F3E4 +:105C7000410121728378DB0863F38201217283780A +:105C80001B0963F3C3012172037863F306112172C8 +:105C9000437863F3C71103E061E0A9E090E0A1E07D +:105CA000217284F809A0C178A172022A29D0027950 +:105CB000E17A62F30001E1720279520862F3410174 +:105CC000E1720279920862F38201E1720279D208EC +:105CD00062F3C301E1724279217B62F30001217317 +:105CE0004279520862F3410121734279920862F3CA +:105CF00082012173407928E0A86FADE741F00101EE +:105D0000B2E74279E17A62F30001E1724279520826 +:105D100062F34101E1724279920862F38201E17219 +:105D20004279D20862F3C301E1720279217B62F306 +:105D3000000121730279520862F341012173027953 +:105D4000920862F3820121730079C00860F3C301F5 +:105D5000217399F80000232831D9262140E0182723 +:105D60001026E4B3A088FDF76DFB8346807F00F02A +:105D70000300022809D0002080F00101A0880EF065 +:105D800095F85FEA000903D101E00120F4E7FFDFA5 +:105D9000E868A06099F8000040F0040189F800105C +:105DA00099F80100800708D5012020739BF80000B6 +:105DB00023286CD92721584651E084F80CA066E0CE +:105DC00015270F265CB1A088FDF73CFB8146062213 +:105DD0005946E86808F0C7FB0120A073A0E041E045 +:105DE00048463CE016270926E4B3287B20724EE0A3 +:105DF000287B19270E26ACB3C4F808A0A4F80CA081 +:105E0000012807D0022805D0032805D0042803D094 +:105E1000FFDF0DE0207207E0697B042801F00F012D +:105E200041F0800121721ED0607A20F00300607280 +:105E3000A088FDF707FB05460078212827D02328F6 +:105E400000D0FFDFA87F00F00300022813D000205D +:105E500080F00101A0880EF03BF822212846FDF7D2 +:105E600059F914E004E0607A20F00300401CDEE7FA +:105E7000A8F8006010E00120EAE70CB16888A08073 +:105E8000287A68B301280AD002284FD0FFDFA8F88B +:105E900000600CB1278066800020BDE8F09F1527C8 +:105EA0000F26002CE4D0A088FDF7CCFA807F00F00C +:105EB0000300022808D0002080F00101A0880DF026 +:105EC000F5FF050003D101E00120F5E7FFDFD5F87C +:105ED0001D000622594608F046FB84F80EA0D6E7BE +:105EE00017270926002CC3D0A088FDF7ABFA8146FE +:105EF000807F00F00300022808D0002080F001011C +:105F0000A0880DF0D3FF050003D101E00120F5E7E3 +:105F1000FFDF6878800701D5022000E001202072B1 +:105F200099F800002328B2D9272159E719270E260E +:105F3000002C9DD0A088FDF785FA5FEA000900D10A +:105F4000FFDFC4F808A0A4F80CA084F808A0A07A89 +:105F500040F00300A07299F81E10C90961F3820095 +:105F6000A07299F81F2099F81E1012EAD11F05D0CF +:105F700099F8201001F01F0110292BD020F0080003 +:105F8000A07299F81F10607A61F3C3006072697A99 +:105F900001F003010129A2D140F00400607299F8D8 +:105FA0001E0000F003000228E87A16D0217B60F37F +:105FB00000012173AA7A607B62F300006073EA7AC1 +:105FC000520862F341012173A97A490861F3410043 +:105FD00060735CE740F00800D2E7617B60F300018A +:105FE0006173AA7A207B62F300002073EA7A520878 +:105FF00062F341016173A97A490861F3410020739A +:1060000045E710B5FE4C30B10146102204F12000E6 +:1060100008F013FA012084F8300010BD10B50446D2 +:1060200000F0E9FDF64920461022BDE8104020317D +:1060300008F003BA70B5F24D06004FF0000413D01B +:10604000FBF707F908B110240CE00621304608F0F0 +:1060500071FA411C05D028665FF0010085F85C00EC +:1060600000E00724204670BD0020F7E7007810F01C +:106070000F0204D0012A05D0022A0CD110E0000939 +:1060800009D10AE00009012807D0022805D0032819 +:1060900003D0042801D00720704708700020704703 +:1060A0000620704705282AD2DFE800F003070F1703 +:1060B0001F00087820F0FF001EE0087820F00F0095 +:1060C000401C20F0F000103016E0087820F00F009F +:1060D000401C20F0F00020300EE0087820F00F0087 +:1060E000401C20F0F000303006E0087820F00F006F +:1060F000401C20F0F000403008700020704707205E +:1061000070472DE9F041804688B00D4600270846CB +:10611000FBF7ECF8A8B94046FDF794F9040003D06A +:106120002078222815D104E043F2020008B0BDE82F +:10613000F08145B9A07F410603D500F00300022895 +:1061400001D01020F2E7A07FC10601D4010702D5DB +:106150000DB10820EAE7E17F090701D50D20E5E749 +:1061600000F0030002280DD165B12846FEF75EFF5E +:106170000700DBD1FBF736FB20B9E878800701D5B3 +:106180000620D3E7A07F00F00300022808D00020FB +:1061900080F0010140460DF089FE060002D00FE0BC +:1061A0000120F5E7A07F00F0030002280ED00020B8 +:1061B00080F00101002240460DF06FFE060007D07E +:1061C000A07F00F00300022804D009E00120EFE7DF +:1061D0000420ABE725B12A4631462046FEF74AFFA8 +:1061E0006946304600F017FD009800B9FFDF0099BE +:1061F000022006F1E0024870C1F824804A610022C2 +:106200000A81A27F02F00302022A1CD00120087139 +:10621000287800F00102087E62F3010008762A78EF +:10622000520862F3820008762A78920862F3C3006B +:1062300008762A78D20862F30410087624212046D2 +:10624000FCF768FF33E035B30871301D88613078A2 +:10625000400908777078C0F340004877287800F04C +:106260000102887F62F301008877A27FD20962F37E +:1062700082008877E27F62F3C3008877727862F3E6 +:1062800004108877A878C87701F1210228462031C8 +:10629000FEF711FF03E00320087105200876252191 +:1062A0002046FCF737FFA07F20F04000A07701A92F +:1062B00000980FF0F4FA022801D000B1FFDF384651 +:1062C00034E72DE9FF4F8DB09A4693460D460027DF +:1062D0000D98FDF7B7F8060006D03078262806D0CE +:1062E000082011B0BDE8F08F43F20200F9E7B07F5B +:1062F00000F00309B9F1020F11D04DB95846FEF76D +:1063000095FE0028EDD1B07F00F00300022806D0F2 +:10631000BBF1000F11D0FBF765FA20B10DE0BBF126 +:10632000000F50D109E006200DF068FD28B19BF860 +:106330000300800701D50620D3E7B07F00F00300FB +:10634000022809D05FF0000080F001010D980DF0E7 +:10635000ADFD040003D101E00120F5E7FFDF852D4D +:1063600027D007DCEDB1812D1DD0822D1DD0832DCE +:1063700008D11CE0862D1ED0882D1ED0892D1ED060 +:106380008A2D1ED00F2020710F281CD003F02EF96B +:10639000D8B101208DF81400201D06902079B0B1ED +:1063A00056E10020EFE70120EDE70220EBE70320B4 +:1063B000E9E70520E7E70620E5E70820E3E709200D +:1063C000E1E70A20DFE707208BE7112089E7B9F131 +:1063D000020F03D0A56F03D1A06F02E0656FFAE74B +:1063E000606F804631D04FF0010001904FF0020005 +:1063F00000905A4621463046FEF73CFE02E000007F +:10640000300200209BF8000000F00101A87861F341 +:106410000100A870B17FC90961F38200A870F17F03 +:1064200061F3C300A870617861F30410A87020784C +:10643000400928706078C0F3400068709BF8020043 +:10644000E87000206871287103E0022001900120AB +:106450000090A87898F80210C0F3C000C1F3C00102 +:10646000084003902CD05046FAF7F3FEC0BBDAF890 +:106470000C00FAF7EEFE98BBDAF81C00FAF7E9FE1A +:1064800070BBDAF80C00A060DAF81C00E0606078FD +:1064900098F8012042EA500161F34100607098F8D9 +:1064A0000210C0B200EA111161F300006070002018 +:1064B0002077009906F11700022907D0012106E094 +:1064C000607898F8012002EA5001E5E7002104EB2A +:1064D000810148610199701C022902D0012101E06B +:1064E00028E0002104EB81014861A87800F0030056 +:1064F000012857D198F8020000F00300012851D17B +:10650000B9F1020F04D02A1D691D5846FEF7D3FDCC +:10651000287998F8041008408DF82C00697998F8CB +:10652000052011408DF8301008433BD05046FAF753 +:1065300090FE08B11020D4E60AF110018B46B9F1A3 +:10654000020F17D00846002104F18C03CDE90003A7 +:1065500004F5AE7202920BAB2046039AFEF7F4FDEF +:106560000028E8D1B9F1020F08D0504608D14FF009 +:10657000010107E050464FF00101E5E75846F5E715 +:106580004FF0000104F1A403CDE9000304F5B0725B +:10659000029281F001010CAB2046039AFEF7D4FD74 +:1065A0000028C8D16078800733D4A87898F8021002 +:1065B000C0F38000C1F3800108432AD0297898F8FD +:1065C0000000F94AB9F1020F06D032F81120430059 +:1065D000DA4002F003070AE032F810204B00DA40FC +:1065E00012F0030705D0012F0AD0022F0AD0032F83 +:1065F00006D0039A6AB1012906D0042904D008E024 +:106600000227F6E70127F4E7012801D0042800D18A +:106610000427B07F40F08000B077F17F039860F3EB +:106620000001F1776078800705D50320A0710398F9 +:1066300070B9002029E00220022F18D0012F18D0B5 +:10664000042F2AD00020A071B07F20F08000B07706 +:1066500025213046FCF75EFD05A904F1E0000FF0AE +:1066600003F910B1022800D0FFDF002039E6A07145 +:10667000DFE7A0710D22002104F1200007F007FFE1 +:10668000207840F00200207001208DF8100004AA4C +:1066900031460D9800F098FADAE70120A071D7E7AB +:1066A0002DE9F04387B09046894604460025FCF763 +:1066B000C9FE060006D03078272806D0082007B08B +:1066C000BDE8F08343F20200F9E7B07F00F0030079 +:1066D000022809D05FF0000080F0010120460DF093 +:1066E000E5FB040003D101E00120F5E7FFDFA77916 +:1066F0005FEA090005D0012821D0B9F1020F26D1A7 +:1067000010E0B8F1000F22D1012F05D0022F05D0E3 +:10671000032F05D0FFDF2EE00C252CE001252AE019 +:10672000022528E04046FAF794FDB0B9032F0ED1B8 +:106730001022414604F11D0007F07FFE1BE0012FEF +:1067400002D0022F03D104E0B8F1000F13D00720CC +:10675000B5E74046FAF77DFD08B11020AFE71022FB +:10676000002104F11D0007F092FE0621404607F0CB +:10677000E1FEC4F81D002078252140F002002070C1 +:106780003046FCF7C7FC2078C10713D020F0010089 +:10679000207002208DF8000004F11D0002908DF899 +:1067A00004506946C3300FF05FF8022803D010B1DF +:1067B000FFDF00E02577002081E730B587B00D4688 +:1067C0000446FCF73FFE98B1807F00F003000228EA +:1067D00011D0002080F0010120460DF067FB04007D +:1067E0000ED02846FAF735FD38B1102007B030BD7D +:1067F00043F20200FAE70120ECE72078400701D4D9 +:106800000820F3E7294604F13D002022054607F061 +:1068100014FE207840F01000207001070FD520F002 +:106820000800207007208DF80000694604F1E000A0 +:1068300001950FF019F8022801D000B1FFDF002008 +:10684000D4E770B50D460646FCF7FCFD18B101789B +:10685000272921D102E043F2020070BD807F00F0C1 +:106860000300022808D0002080F0010130460DF01E +:106870001DFB040003D101E00120F5E7FFDFA07953 +:10688000022809D16078C00706D02A462146304642 +:10689000FEF7EBFC10B10FE0082070BDB4F860000B +:1068A0000E280BD204F1620102231022081F0DF002 +:1068B00084F9012101704570002070BD112070BD68 +:1068C00070B5064614460D460846FAF7C2FC18B9DC +:1068D0002046FAF7E4FC08B1102070BDA6F57F4011 +:1068E000FF380ED03046FCF7ADFD38B14178224676 +:1068F0004B08811C1846FCF774FD07E043F20200C8 +:1069000070BD2046FDF7A5FD0028F9D11021E01D3E +:1069100010F0EDFDE21D294604F1170000F08BF99F +:10692000002070BD2DE9F04104468AB01546884626 +:1069300000270846FAF7DAFC18B92846FAF7D6FC19 +:1069400018B110200AB0BDE8F0812046FCF77AFDAE +:10695000060003D0307827281BD102E043F2020062 +:10696000F0E7B07F00F00300022809D05FF00000DC +:1069700080F0010120460DF099FA040003D101E0F6 +:106980000120F5E7FFDF2078400702D56078800717 +:1069900001D40820D6E7B07F00F00300022805D01C +:1069A000A06F05D1A16F04E01C610200606FF8E7E1 +:1069B000616F407800B19DB1487810B1B8F1000F17 +:1069C0000ED0ADB1EA1D06A8E16800F034F910223E +:1069D00006A905F1170007F003FD18B1042707E029 +:1069E0000720AFE71022E91D04F12D0007F025FD77 +:1069F000B8F1000F06D0102208F1070104F11D00C4 +:106A000007F01BFD2078252140F002002070304661 +:106A1000FCF780FB2078C10715D020F00100207022 +:106A200002208DF8000004F11D0002901030039048 +:106A30008DF804706946B3300EF016FF022803D0BB +:106A400010B1FFDF00E0277700207BE7F8B515469F +:106A50000E460746FCF7F6FC040004D020782228F6 +:106A600004D00820F8BD43F20200F8BDA07F00F07A +:106A70000300022802D043F20500F8BD3046FAF7C1 +:106A8000E8FB18B92846FAF7E4FB08B11020F8BD76 +:106A900000953288B31C21463846FEF709FC1128C0 +:106AA00015D00028F3D1297C4A08A17F62F3C711D1 +:106AB000A177297CE27F61F30002E277297C8908D3 +:106AC00084F82010A17F21F04001A177F8BDA17FBB +:106AD0000907FBD4D6F80200C4F83600D6F8060041 +:106AE000C4F83A003088A0861022294604F1240018 +:106AF00007F0A3FC287C4108E07F61F34100E077C8 +:106B0000297C61F38200E077287C800884F82100EA +:106B1000A07F40F00800A0770020D3E770B50D46B5 +:106B200006460BB1072070BDFCF78CFC040007D0B3 +:106B30002078222802D3A07F800604D4082070BDCC +:106B400043F2020070BDADB1294630460CF076F834 +:106B500002F069FB297C4A08A17F62F3C711A17783 +:106B6000297CE27F61F30002E277297C890884F8BE +:106B7000201004E030460CF084F802F054FBA17FB2 +:106B800021F02001A17770BD70B50D46FCF75AFCCD +:106B9000040005D02846FAF782FB20B1102070BD12 +:106BA00043F2020070BD29462046FEF72FFB00206D +:106BB00070BD04E010F8012B0AB100207047491E97 +:106BC00089B2F7D20120704770B51546064602F02B +:106BD0000DFD040000D1FFDF207820F00F00801CA5 +:106BE00020F0F0002030207066802868A060BDE8AA +:106BF000704002F0FEBC10B5134C94F83000002831 +:106C000008D104F12001A1F110000EF06FFE012067 +:106C100084F8300010BD10B190F8B9202AB10A48AC +:106C200090F8350018B1002003E0B83001E00648C4 +:106C300034300860704708B50023009313460A46B5 +:106C40000DF031FB08BD00003002002018B1817842 +:106C5000012938D101E010207047018842F6011265 +:106C6000881A914231D018DC42F60102A1EB0200F1 +:106C700091422AD00CDC41B3B1F5C05F25D06FF44E +:106C8000C050081821D0A0F57060FF381BD11CE05F +:106C900001281AD002280AD117E0B0F5807F14D05D +:106CA00008DC012811D002280FD003280DD0FF28BE +:106CB00009D10AE0B0F5817F07D0A0F580700338D4 +:106CC00003D0012801D0002070470F2070470A2808 +:106CD0001FD008DC0A2818D2DFE800F0191B1F1F9C +:106CE000171F231D1F21102815D008DC0B2812D0D8 +:106CF0000C2810D00D2816D00F2806D10DE0112831 +:106D00000BD084280BD087280FD003207047002099 +:106D1000704705207047072070470F2070470420F8 +:106D20007047062070470C20704743F202007047FE +:106D300038B50C46050041D06946FFF797F90028A1 +:106D400019D19DF80010607861F302006070694607 +:106D5000681CFFF78BF900280DD19DF800106078B2 +:106D600061F3C5006070A978C1F34101012903D026 +:106D7000022905D0072038BD217821F0200102E04A +:106D8000217841F020012170410704D0A978C90879 +:106D900061F386106070607810F0380F07D0A97822 +:106DA000090961F3C710607010F0380F02D16078E4 +:106DB000400603D5207840F040002070002038BD08 +:106DC00070B504460020088015466068FFF7B0FFE4 +:106DD000002816D12089A189884211D8606880785E +:106DE000C0070AD0B1F5007F0AD840F20120B1FBFC +:106DF000F0F200FB1210288007E0B1F5FF7F01D907 +:106E00000C2070BD01F201212980002070BD10B559 +:106E10000478137864F3000313700478640864F34F +:106E2000410313700478A40864F382031370047898 +:106E3000E40864F3C30313700478240964F30413AF +:106E400013700478640964F34513137000788009A3 +:106E500060F38613137031B10878C10701D1800740 +:106E600001D5012000E0002060F3C713137010BDAE +:106E70004278530702D002F0070306E012F0380F01 +:106E800002D0C2F3C20300E001234A7863F3020296 +:106E90004A70407810F0380F02D0C0F3C20005E00D +:106EA000430702D000F0070000E0012060F3C502B4 +:106EB0004A7070472DE9F04F95B00D00824613D00F +:106EC00012220021284607F0E2FA4FF6FF7B05AABE +:106ED0000121584607F0A3F80024264637464FF410 +:106EE00020586FF4205972E0102015B0BDE8F08FE3 +:106EF0009DF81E0001280AD1BDF81C1041450BD099 +:106F000011EB09000AD001280CD002280CD0042C67 +:106F10000ED0052C0FD10DE0012400E00224BDF8B5 +:106F20001A6008E0032406E00424BDF81A7002E0A9 +:106F3000052400E00624BDF81A10514547D12C74F1 +:106F4000BEB34FF0000810AA4FF0070ACDE9028245 +:106F5000CDE900A80DF13C091023CDF81090424670 +:106F60003146584607F02BF908BBBDF83C002A46CD +:106F7000C0B210A90EF045FDC8B9AE81CFB1CDE9C0 +:106F800000A80DF1080C0AAE40468CE8410213231C +:106F900000223946584607F012F940B9BDF83C00C6 +:106FA000F11CC01EC0B22A1D0EF02BFD10B1032033 +:106FB0009BE70AE0BDF82900E881062C05D19DF881 +:106FC0001E00A872BDF81C00288100208DE705A8CE +:106FD00007F031F800288BD0FFF779FE85E72DE91F +:106FE000F0471C46DDE90978DDF8209015460E00D3 +:106FF000824600D1FFDF0CB1208818B1D5B1112035 +:10700000BDE8F087022D01D0012100E0002106F14A +:10701000140005F0CDFEA8F8000002463B462946C4 +:10702000504603F092F9C9F8000008B9A41C3C606E +:107030000020E5E71320E3E7F0B41446DDE904524D +:107040008DB1002314B1022C09D101E0012306E027 +:107050000D7CEE0703D025F0010501230D742146B8 +:10706000F0BC04F050BA1A80F0BC70472DE9FE4F16 +:1070700091461A881C468A468046FAB102AB4946B8 +:1070800003F063F9050019D04046A61C27880DF0CF +:1070900050F83246072629463B4600960CF05FFC26 +:1070A00020882346CDE900504A4651464046FFF726 +:1070B000C3FF002020800120BDE8FE8F0020FBE7F9 +:1070C0002DE9F04786B082460EA8904690E8B000C1 +:1070D000894604AA05A903A88DE807001E462A468A +:1070E00021465046FFF77BFF039901B1012139701A +:1070F000002818D1FA4904F1140204AB086003987F +:1071000005998DE8070042464946504606F003FAC5 +:10711000A8B1092811D2DFE800F005080510100A0F +:107120000C0C0E00002006B06AE71120FBE70720D8 +:10713000F9E70820F7E70D20F5E70320F3E7BDF8AE +:1071400010100398CDE9000133462A4621465046E7 +:10715000FFF772FFE6E72DE9F04389B01646DDE957 +:1071600010870D4681461C461422002103A807F013 +:107170008EF9012002218DF810108DF80C008DF889 +:107180001170ADF8146064B1A278D20709D08DF8FF +:107190001600E088ADF81A00A088ADF81800A068C5 +:1071A000079008A80095CDE90110424603A948467A +:1071B0006B68FFF785FF09B0BDE8F083F0B58BB0D1 +:1071C00000240646069407940727089405A8099406 +:1071D000019400970294CDE903400D461023224606 +:1071E000304606F0ECFF78B90AA806A9019400978A +:1071F0000294CDE90310BDF8143000222946304630 +:1072000006F07BFD002801D0FFF761FD0BB0F0BD5B +:1072100006F00CBC2DE9FC410C468046002602F02D +:10722000E5F9054620780D287ED2DFE800F0BC079E +:1072300013B325BD49496383AF959B00A8480068F7 +:1072400020B1417841F010014170ADE0404602F0BC +:10725000FDF9A9E0042140460CF028FE070000D10A +:10726000FFDF07F11401404605F037FDA5BB1321F0 +:107270004046FDF7CFFB97E0042140460CF016FE98 +:10728000070000D1FFDFE088ADF800000020B881E2 +:107290009DF80000010704D5C00602D5A088B8817A +:1072A00005E09DF8010040067ED5A088F88105B96B +:1072B000FFDF22462946404601F0ACFC022673E07F +:1072C000E188ADF800109DF8011009060FD50728D8 +:1072D00003D006280AD00AE024E0042140460CF03E +:1072E000E5FD060000D1FFDFA088F0810226CDB9C0 +:1072F000FFDF17E0042140460CF0D8FD070000D165 +:10730000FFDF07F1140006F0C8FB90F0010F02D177 +:10731000E079000648D5387C022640F00200387437 +:1073200005B9FFDF224600E03DE02946404601F076 +:1073300071FC39E0042140460CF0B8FD017C002DC1 +:1073400001F00206C1F340016171017C21F00201EC +:107350000174E7D1FFDFE5E702260121404602F094 +:10736000A7F921E0042140460CF0A0FD0546606825 +:1073700000902089ADF8040001226946404602F0E1 +:10738000B8F9287C20F0020028740DE0002DC9D146 +:10739000FFDFC7E7022600214046FBF799F8002DE2 +:1073A000C0D1FFDFBEE7FFDF3046BDE8FC813EB560 +:1073B0000C0009D001466B4601AA002006F084FFAC +:1073C00020B1FFF784FC3EBD10203EBD0020208090 +:1073D000A0709DF8050002A900F00700FEF762FE0C +:1073E00050B99DF8080020709DF8050002A9C0F36F +:1073F000C200FEF757FE08B103203EBD9DF808000D +:1074000060709DF80500C109A07861F30410A070B8 +:107410009DF80510890961F3C300A0709DF8041060 +:10742000890601D5022100E0012161F342009DF8A7 +:10743000001061F30000A07000203EBD70B514463E +:1074400006460D4651EA040005D075B10846F9F725 +:1074500044FF78B901E0072070BD2946304606F0A8 +:107460009AFF10B1BDE8704031E454B12046F9F7FD +:1074700034FF08B1102070BD21463046BDE8704091 +:1074800095E7002070BD2DE9FC5F0C46904605464F +:10749000002701780822007A3E46B2EB111F7DD109 +:1074A00004F10A0100910A31821E4FF0020A04F130 +:1074B000080B0191092A72D2DFE802F0EDE005F530 +:1074C00028287BAACE00688804210CF0EFFC060077 +:1074D00000D1FFDFB08928B152270726C3E00000A2 +:1074E0009402002051271026002C7DD06888A080AF +:1074F0000120A071A88900220099FFF79FFF0028B2 +:1075000073D1A8892081288AE081D1E0B5F8129052 +:10751000072824D1E87B000621D5512709F1140062 +:1075200086B2002CE1D0A88900220099FFF786FFDF +:1075300000285AD16888A08084F806A0A8892081F4 +:107540000120A073288A2082A4F81290A88A0090B3 +:1075500068884B46A969019A01F038FBA8E05027DA +:1075600009F1120086B2002C3ED0A88900225946AB +:10757000FFF764FF002838D16888A080A889E080E0 +:10758000287A072813D002202073288AE081E87B1C +:10759000C0096073A4F81090A88A01E085E082E039 +:1075A000009068884B4604F11202A969D4E70120D3 +:1075B000EAE7B5F81290512709F1140086B2002CC1 +:1075C00066D0688804210CF071FC83466888A0802E +:1075D000A88900220099FFF731FF00286ED184F8B6 +:1075E00006A0A889208101E052E067E00420A07392 +:1075F000288A2082A4F81290A88A009068884B46B6 +:10760000A969019A01F0E2FAA989ABF80E104FE0DE +:107610006888FBF717FF0746688804210CF046FCD2 +:10762000064607B9FFDF06B9FFDF687BC00702D057 +:107630005127142601E0502712264CB36888A080F9 +:10764000502F06D084F806A0287B594601F0CEFAC8 +:107650002EE0287BA11DF9E7FE49A88949898142CE +:1076600005D1542706269CB16888A08020E05327C6 +:107670000BE06888A080A889E08019E06888042170 +:107680000CF014FC00B9FFDF55270826002CF0D1C0 +:10769000A8F8006011E056270726002CF8D068886B +:1076A000A080002013E0FFDF02E0012808D0FFDF08 +:1076B000A8F800600CB1278066800020BDE8FC9F20 +:1076C00057270726002CE3D06888A080687AA0712D +:1076D000EEE7401D20F0030009B14143091D01EB15 +:1076E0004000704713B5DB4A00201071009848B184 +:1076F000002468460CF0F7F9002C02D1D64A009914 +:1077000011601CBD01240020F4E770B50D4614463D +:10771000064686B05C220021284606F0B8FE04B971 +:10772000FFDFA0786874A2782188284601F089FAE2 +:107730000020A881E881228805F11401304605F077 +:10774000B0FA6A460121304606F069FC1AE000BF33 +:107750009DF80300000715D5BDF806103046FFF769 +:107760002DFD9DF80300BDF8061040F010008DF8C7 +:107770000300BDF80300ADF81400FF233046059A5E +:1077800006F0D1FD684606F056FC0028E0D006B0B1 +:1077900070BD10B50C4601F1140005F0BAFA0146AF +:1077A000627C2046BDE8104001F080BA30B5044646 +:1077B000A84891B04FF6FF75C18905AA284606F082 +:1077C0002EFC30E09DF81E00A0422AD001282AD1CC +:1077D000BDF81C00B0F5205F03D042F601018842DD +:1077E00021D1002002AB0AAA0CA9019083E807006E +:1077F00007200090BDF81A1010230022284606F03A +:10780000DEFC38B9BDF828000BAAC0B20CA90EF0F6 +:10781000F8F810B1032011B030BD9DF82E00A04241 +:1078200001D10020F7E705A806F005FC0028C9D023 +:107830000520F0E770B5054604210CF037FB040085 +:1078400000D1FFDF04F114010C46284605F045FA8B +:1078500021462846BDE8704005F046BA70B58AB0AA +:107860000C460646FBF7EEFD050014D028782228CA +:1078700027D30CB1A08890B101208DF80C00032013 +:107880008DF8100000208DF8110054B1A088ADF8DB +:107890001800206807E043F202000AB070BD09201A +:1078A000FBE7ADF818000590042130460CF0FEFA15 +:1078B000040000D1FFDF04F1140005F040FA0007D6 +:1078C00001D40820E9E701F091FE60B108A8022187 +:1078D0000094CDE9011095F8232003A93046636890 +:1078E000FFF7EEFBD9E71120D7E72DE9F04FB2F80B +:1078F00002A0834689B0154689465046FBF7A2FD93 +:107900000746042150460CF0D1FA0026044605969D +:107910004FF002080696ADF81C6007B9FFDF04B906 +:10792000FFDF4146504603F055FF50B907AA06A9AC +:1079300005A88DE807004246214650466368FFF7D8 +:107940004EFB444807AB0660DDE9051204F1140064 +:10795000CDF80090CDE90320CDE9013197F823203F +:10796000594650466B6805F033FA06000AD0022EDD +:1079700004D0032E14D0042E00D0FFDF09B030460F +:10798000BDE8F08FBDF81C000028F7D00599CDE9BF +:1079900000104246214650466368FFF74DFBEDE775 +:1079A000687840F008006870E8E710B50C46FFF70B +:1079B000BFF900280BD1607800F00701012905D13B +:1079C00010F0380F02D02078810601D5072010BDB5 +:1079D00040F0C8002070002010BD2DE9F04F99B094 +:1079E00004464FF000081B48ADF81C80ADF820801D +:1079F000ADF82480A0F80880ADF81480ADF81880A8 +:107A0000ADF82880ADF82C80007916460D46474623 +:107A1000012808D0022806D0032804D0042802D068 +:107A2000082019B0ACE72046F9F713FCF0BB284654 +:107A3000F9F70FFCD0BB6068F9F758FCB0BB606881 +:107A400068B160892189884202D8B1F5007F05D9E3 +:107A50000C20E6E7940200201800002080460EAAC1 +:107A600006A92846FFF7ACF90028DAD168688078C3 +:107A7000C0F34100022808D19DF8190010F0380F1A +:107A800003D02869F9F729FC80B905A92069FFF717 +:107A90004FF90028C5D1206950B1607880079DF862 +:107AA000150000F0380002D5F0B301E011E0D8BBBA +:107AB0009DF8140080060ED59DF8150010F0380FC3 +:107AC00003D06068F9F709FC18B96068F9F70EFC93 +:107AD00008B11020A5E70BA906A8FFF7C9F99DF882 +:107AE0002D000BA920F00700401C8DF82D006069C7 +:107AF000FFF75BFF002894D10AA9A069FFF718F9E6 +:107B000000288ED19DF8280080062BD4A06940B1B2 +:107B10009DF8290000F00701012923D110F0380F4A +:107B200020D0E06828B100E01CE00078D0B11C282B +:107B300018D20FAA611C2046FFF769F901213846C7 +:107B400061F30F2082468DF85210B94642F60300C9 +:107B50000F46ADF850000DF13F0218A928680DF04E +:107B600052FF08B107205CE79DF8600015A9CDF829 +:107B70000090C01CCDE9019100F0FF0B00230BF237 +:107B80000122514614A806F075F9E8BBBDF854006F +:107B90000C90FB482A8929690092CDE901106B8974 +:107BA000BDF838202868069906F064F9010077D1FD +:107BB00020784FF0020AC10601D4800616D58DF850 +:107BC000527042F60210ADF85000CDF80C9008A9A2 +:107BD00003AACDF800A0CDE90121002340F2032241 +:107BE00014A80B9906F046F9010059D1E4484D4616 +:107BF00008380089ADF83D000FA8CDE90290CDF816 +:107C00000490CDF8109000E00CE04FF007095B46BF +:107C10000022CDF80090BDF854104FF6FF7006F02A +:107C20006CF810B1FFF753F8FBE69DF83C00000636 +:107C300024D52946012060F30F218DF852704FF4AE +:107C400024500395ADF8500062789DF80C00002395 +:107C500062F300008DF80C006278CDF800A05208A5 +:107C600062F341008DF80C0003AACDE9012540F232 +:107C7000032214A806F0FEF8010011D1606880B359 +:107C80002069A0B905A906A8FFF7F2F86078800777 +:107C900007D49DF8150020F038008DF8150006E097 +:107CA00077E09DF8140040F040008DF814008DF846 +:107CB000527042F60110ADF85000208940F20121C7 +:107CC000B0FBF1F201FB1202606809ABCDF8008055 +:107CD000CDE90103002314A8059906F0CBF80100B3 +:107CE00057D12078C00728D00395A06950B90AA9B8 +:107CF00006A8FFF7BDF89DF8290020F00700401CFA +:107D00008DF829009DF8280007A940F040008DF863 +:107D100028008DF8527042F60310ADF8500003AA07 +:107D2000CDF800A0CDE90121002340F2032214A8E0 +:107D30000A9906F09FF801002BD1E06868B3294644 +:107D4000012060F30F218DF8527042F60410ADF857 +:107D50005000E068002302788DF8582040788DF8B4 +:107D60005900E06816AA4088ADF85A00E06800792A +:107D70008DF85C00E068C088ADF85D00CDF800903B +:107D8000CDE901254FF4027214A806F073F8010042 +:107D900003D00C9800F0B6FF43E679480321083879 +:107DA000017156B100893080BDF824007080BDF8A3 +:107DB0002000B080BDF81C00F080002031E670B5D6 +:107DC00001258AB016460B46012802D0022816D19A +:107DD00004E08DF80E504FF4205003E08DF80E5063 +:107DE00042F60100ADF80C005BB10024601C60F3AA +:107DF0000F2404AA08A918460DF005FE18B10720A3 +:107E00004BE5102049E504A99DF820205C48CDE908 +:107E10000021801E02900023214603A802F20122C5 +:107E200006F028F810B1FEF752FF36E5544808383E +:107E30000EB1C1883180057100202EE5F0B593B0F8 +:107E4000044601268DF83E6041F601000F46ADF86C +:107E50003C0011AA0FA93046FFF7B1FF002837D127 +:107E60002000474C4FF00005A4F1080432D01C223A +:107E7000002102A806F00BFB9DF808008DF83E607B +:107E800040F020008DF8080042F60520ADF83C00D7 +:107E900004200797ADF82C00ADF8300039480A905F +:107EA0000EA80D900E950FA80990ADF82E506A46B9 +:107EB00009A902A8FFF791FD002809D1BDF800002B +:107EC0006081BDF80400A081401CE0812571002084 +:107ED00013B0F0BD6581A581BDF84400F4E72DE93C +:107EE000F74F2749A0B00024083917940A79A14612 +:107EF000012A04D0022A02D0082023B040E5CA8813 +:107F0000824201D00620F8E721988A46824201D1B8 +:107F10000720F2E70120214660F30F21ADF8480069 +:107F20004FF6FF788DF86E000691ADF84A8042F664 +:107F3000020B8DF872401CA9ADF86CB0ADF8704022 +:107F40001391ADF8508012A806F0A4F800252E4633 +:107F50002F460DAB072212A9404606F09EF898B1B5 +:107F60000A2861D1B5B3AEB3ADF86450ADF8666020 +:107F70009DF85E008DF8144019AC012868D06FE0C0 +:107F80009C020020266102009DF83A001FB30128E0 +:107F900059D1BDF8381059451FD118A809A9019425 +:107FA0000294CDE9031007200090BDF8361010238D +:107FB0000022404606F003F9B0BBBDF8600004287B +:107FC00001D006284AD1BDF82410219881423AD127 +:107FD0000F2092E73AE0012835D1BDF83800B0F51E +:107FE000205F03D042F6010188422CD1BAF8060086 +:107FF000BDF83610884201D1012700E0002705B105 +:108000009EB1219881421ED118A809AA0194029418 +:10801000CDE90320072000900D46102300224046A2 +:1080200006F0CDF800B902E02DE04E460BE0BDF8B9 +:108030006000022801D0102810D1C0B217AA09A9E7 +:108040000DF0DFFC50B9BDF8369082E7052054E70B +:1080500005A917A8221D0DF0D6FC08B103204CE796 +:108060009DF814000023001DC2B28DF81420229840 +:108070000092CDE901401BA8069905F0FBFE10B95E +:1080800002228AF80420FEF722FE36E710B50B46DE +:10809000401E88B084B205AA00211846FEF7B7FE3C +:1080A00000200DF1080C06AA05A901908CE8070034 +:1080B000072000900123002221464FF6FF7005F0B3 +:1080C0001CFE0446BDF81800012800D0FFDF204642 +:1080D000FEF7FDFD08B010BDF0B5FF4F044687B0B8 +:1080E00038790E46032804D0042802D0082007B0AF +:1080F000F0BD04AA03A92046FEF762FE0500F6D1F2 +:1081000060688078C0F3410002280AD19DF80D0014 +:1081100010F0380F05D02069F9F7DFF808B110200A +:10812000E5E7208905AA21698DE807006389BDF884 +:1081300010202068039905F09DFE10B1FEF7C7FDE1 +:10814000D5E716B1BDF814003080042038712846F8 +:10815000CDE7F8B50C0006460BD001464FF6FF758B +:1081600000236A46284606F0AFF820B1FEF7AFFDBF +:10817000F8BD1020F8BD69462046FEF7D9FD00285D +:10818000F8D1A078314600F001032846009A06F0A5 +:10819000CAF8EBE730B587B0144600220DF1080CA1 +:1081A00005AD01928CE82C00072200920A46014698 +:1081B00023884FF6FF7005F0A0FDBDF81410218054 +:1081C000FEF785FD07B030BD70B50D4604210BF0FC +:1081D0006DFE040000D1FFDF294604F11400BDE864 +:1081E000704004F0A5BD70B50D4604210BF05EFE95 +:1081F000040000D1FFDF294604F11400BDE87040FF +:1082000004F0B9BD70B50D4604210BF04FFE04001B +:1082100000D1FFDF294604F11400BDE8704004F0EE +:10822000D1BD70B5054604210BF040FE040000D11D +:10823000FFDF214628462368BDE870400122FEF793 +:1082400015BF70B5064604210BF030FE040000D1C6 +:10825000FFDF04F1140004F05CFD401D20F0030575 +:1082600011E0011D00880022431821463046FEF728 +:10827000FDFE00280BD0607CABB2684382B2A068E0 +:10828000011D0BF0D0FCA06841880029E9D170BD28 +:1082900070B5054604210BF009FE040000D1FFDF94 +:1082A000214628466368BDE870400222FEF7DEBE24 +:1082B00070B50E46054601F099F9040000D1FFDFC4 +:1082C0000120207266726580207820F00F00001D6A +:1082D00020F0F00040302070BDE8704001F089B916 +:1082E00010B50446012900D0FFDF2046BDE810404C +:1082F0000121FAF7EDB82DE9F04F97B04FF0000AE1 +:108300000C008346ADF814A0D04619D0E06830B117 +:10831000A068A8B10188ADF81410A0F800A05846D4 +:10832000FBF790F8070043F2020961D03878222861 +:108330005CD3042158460BF0B9FD050005D103E0DC +:10834000102017B0BDE8F08FFFDF05F1140004F036 +:10835000E0FC401D20F00306A078012803D002288D +:1083600001D00720EDE7218807AA584605F057FEFF +:1083700030BB07A805F05FFE10BB07A805F05BFE49 +:1083800048B99DF82600012805D1BDF82400A0F5C4 +:108390002451023902D04FF45050D2E7E068B0B116 +:1083A000CDE902A00720009005AACDF804A0049210 +:1083B000A2882188BDF81430584605F09EFC10B103 +:1083C000FEF785FCBDE7A168BDF8140008809DF8A4 +:1083D0001F00C00602D543F20140B2E70B9838B146 +:1083E000A1780078012905D080071AD40820A8E7D1 +:1083F0004846A6E7C007F9D002208DF83C00A868DF +:108400004FF00009A0B1697C4288714391420FD9B5 +:108410008AB2B3B2011D0BF0BCFB8046A0F800A0ED +:1084200006E003208DF83C00D5F800804FF00109EC +:108430009DF8200010F0380F00D1FFDF9DF82000DC +:108440002649C0F3C200084497F8231010F8010C25 +:10845000884201D90F2074E72088ADF8400014A9A4 +:108460000095CDE90191434607220FA95846FEF732 +:1084700027FE002891D19DF8500050B9A07801281E +:1084800007D1687CB3B2704382B2A868011D0BF0BB +:1084900094FB002055E770B5064615460C46084685 +:1084A000FEF7D4FB002805D12A4621463046BDE818 +:1084B000704084E470BD12E570B51E4614460D0090 +:1084C0000ED06CB1616859B160B10349C98881426D +:1084D00008D0072070BD000094020020296102002E +:1084E0001020F7E72068FEF7B1FB0028F2D13246F2 +:1084F00021462846BDE87040FFF76FBA70B51546B3 +:108500000C0006D038B1FE490989814203D007200A +:10851000E0E71020DEE72068FEF798FB0028D9D1BD +:1085200029462046BDE87040D6E570B5064686B0BF +:108530000D4614461046F8F7B2FED0BB6068F8F757 +:10854000D5FEB0BBA6F57F40FF3803D03046FAF722 +:1085500079FF80B128466946FEF7ACFC00280CD1B3 +:108560009DF810100F2008293DD2DFE801F0080621 +:108570000606060A0A0843F2020006B0AAE703202C +:10858000FBE79DF80210012908D1BDF80010B1F5F4 +:10859000C05FF2D06FF4C052D142EED09DF8061009 +:1085A00001290DD1BDF80410A1F52851062907D2E3 +:1085B00000E029E0DFE801F0030304030303DCE744 +:1085C0009DF80A1001290FD1BDF80810B1F5245FFC +:1085D000D3D0A1F60211B1F50051CED00129CCD0F3 +:1085E000022901D1C9E7FFDF606878B9002305AA35 +:1085F0002946304605F068FE10B1FEF768FBBCE77F +:108600009DF81400800601D41020B6E76188224648 +:1086100028466368FFF7BEFDAFE72DE9F0438146CA +:1086200087B0884614461046F8F739FE18B1102076 +:1086300007B0BDE8F083002306AA4146484605F08E +:1086400043FE10B1FEF743FBF2E79DF81800C006A9 +:1086500002D543F20140EBE70025072705A8019565 +:1086600000970295CDE9035062884FF6FF734146AB +:10867000484605F0A4FD060013D16068F8F70FFE28 +:1086800060B960680195CDE9025000970495238890 +:1086900062884146484605F092FD0646BDF8140042 +:1086A00020803046CEE739B1954B0A889B899A42A3 +:1086B00002D843F2030070471DE610B586B0904C17 +:1086C0000423ADF81430638943B1A4898C4201D2EC +:1086D000914205D943F2030006B010BD0620FBE726 +:1086E000ADF81010002100910191ADF80030022189 +:1086F0008DF8021005A9029104A90391ADF812208A +:108700006946FFF7F8FDE7E72DE9FC4781460D468E +:108710000846F8F79EFD88BB4846FAF793FE5FEAE5 +:1087200000080AD098F80000222829D304214846DE +:108730000BF0BCFB070005D103E043F20200BDE8EB +:10874000FC87FFDF07F1140004F0F9FA06462878E9 +:10875000012803D0022804D00720F0E7B0070FD586 +:1087600002E016F01C0F0BD0A8792C1DC00709D011 +:10877000E08838B1A068F8F76CFD18B11020DEE78A +:108780000820DCE721882A780720B1F5847F35D0DE +:108790001EDC40F20315A1F20313A94226D00EDC21 +:1087A000B1F5807FCBD003DCF9B1012926D1C6E732 +:1087B000A1F58073013BC2D0012B1FD113E0012B27 +:1087C000BDD0022B1AD0032BB9D0042B16D112E046 +:1087D000A1F20912082A11D2DFE802F00B040410FA +:1087E00010101004ABE7022AA9D007E0012AA6D096 +:1087F00004E0320700E0F206002AA0DACDB200F071 +:10880000F5FE50B198F82300CDE90005FA8923461A +:1088100039464846FEF79FFC91E711208FE72DE986 +:10882000F04F8BB01F4615460C4683460026FAF7DC +:1088300009FE28B10078222805D208200BB081E576 +:1088400043F20200FAE7B80801D00720F6E7032F49 +:1088500000D100274FF6FF79CCB1022D71D320460D +:10886000F8F744FD30B904EB0508A8F10100F8F76A +:108870003DFD08B11020E1E7AD1E38F8028CAAB228 +:108880002146484605F081FE40455AD1ADB21C490B +:10889000B80702D58889401C00E001201FFA80F843 +:1088A000F80701D08F8900E04F4605AA4146584697 +:1088B00005F0B5FB4FF0070A4FF00009FCB1204668 +:1088C00008E0408810283CD8361D304486B2AE42BD +:1088D00037D2A01902884245F3D352E09DF8170021 +:1088E00002074ED57CB304EB0608361DB8F80230FB +:1088F000B6B2102B25D89A19AA4222D802E040E03D +:1089000094020020B8F8002091421AD1C0061BD56D +:10891000CDE900A90DF1080C0AAAA11948468CE876 +:108920000700B8F800100022584605F0E6F910B12B +:10893000FEF7CDF982E7B8F80200BDF828108842AA +:1089400002D00B207AE704E0B8F80200304486B287 +:1089500006E0C00604D55846FEF730FC00288AD150 +:108960009DF81700BDF81A1020F010008DF81700C0 +:10897000BDF81700ADF80000FF235846009A05F037 +:10898000D2FC05A805F057FB18B9BDF81A10B9427A +:10899000A4D9042158460BF089FA040000D1FFDF66 +:1089A000A2895AB1CDE900A94D4600232146584677 +:1089B000FEF7D1FB0028BDD1A5813FE700203DE7B0 +:1089C0002DE9FF4F8BB01E4617000D464FF00004F7 +:1089D00012D0B00802D007200FB0B3E4032E00D1AC +:1089E00000265DB10846F8F778FC28B93888691E7A +:1089F0000844F8F772FC08B11020EDE7C74AB00749 +:108A000001D5D18900E00121F0074FF6FF7802D0AF +:108A1000D089401E00E0404686B206AA0B9805F0B9 +:108A2000FEFA4FF000094FF0070B0DF1140A38E081 +:108A30009DF81B00000734D5CDF80490CDF800B0A8 +:108A4000CDF80890CDE9039A434600220B9805F033 +:108A5000B6FB60BB05B3BDF814103A882144281951 +:108A6000091D8A4230D3BDF81E2020F8022BBDF824 +:108A7000142020F8022BCDE900B9CDE90290CDF801 +:108A800010A0BDF81E10BDF8143000220B9805F0A0 +:108A900096FB08B103209FE7BDF814002044001D99 +:108AA00084B206A805F0C7FA20B10A2806D0FEF75E +:108AB0000EF991E7BDF81E10B142B9D934B17DB1BC +:108AC0003888A11C884203D20C2085E7052083E763 +:108AD00022462946404605F058FD014628190180E6 +:108AE000A41C3C80002077E710B50446F8F7D7FBBC +:108AF00008B1102010BD8948C0892080002010BD19 +:108B0000F0B58BB00D4606461422002103A805F0EF +:108B1000BEFC01208DF80C008DF8100000208DF8AF +:108B20001100ADF814503046FAF78CFC48B10078CB +:108B3000222812D3042130460BF0B8F9040005D1E5 +:108B400003E043F202000BB0F0BDFFDF04F11400BC +:108B5000074604F0F4F8800601D40820F3E7207CEF +:108B6000022140F00100207409A80094CDE9011011 +:108B7000072203A930466368FEF7A2FA20B1217CE0 +:108B800021F001012174DEE729463046F9F791FC16 +:108B900008A9384604F0C2F800B1FFDFBDF8204054 +:108BA000172C01D2172000E02046A84201D92C46FC +:108BB00002E0172C00D2172421463046FFF713FBA2 +:108BC00021463046F9F799F90020BCE7F8B51C4674 +:108BD00015460E46069F0BF09AFA2346FF1DBCB2BF +:108BE00031462A4600940AF086FEF8BD70B50C4660 +:108BF00005460E220021204605F049FC0020208079 +:108C00002DB1012D01D0FFDF64E4062000E0052036 +:108C1000A0715FE410B548800878134620F00F007B +:108C2000001D20F0F00080300C4608701422194618 +:108C300004F1080005F001FC00F0DBFC374804609B +:108C400010BD2DE9F047DFF8D890491D064621F008 +:108C5000030117460C46D9F800000AF062FF050030 +:108C600000D1FFDF4FF000083560A5F800802146F5 +:108C7000D9F800000AF055FF050000D1FFDF75604C +:108C8000A5F800807FB104FB07F1091D0BD0D9F8CE +:108C900000000AF046FF040000D1FFDFB460C4F812 +:108CA0000080BDE8F087C6F80880FAE72DE9F041BA +:108CB0001746491D21F00302194D06460168144666 +:108CC00028680AF059FF2246716828680AF054FFA4 +:108CD0003FB104FB07F2121D03D0B16828680AF007 +:108CE0004BFF04200BF08AF8044604200BF08EF8AA +:108CF000201A012804D12868BDE8F0410AF006BF17 +:108D0000BDE8F08110B50C4605F058F900B1FFDF61 +:108D10002046BDE81040FDF7DABF000094020020B5 +:108D20001800002038B50C468288817B19B1418932 +:108D3000914200D90A462280C188121D90B26A462B +:108D40000AF0B2F8BDF80000032800D30320C1B236 +:108D5000208801F020F838BD38B50C468288817B28 +:108D600019B10189914200D90A462280C188121D99 +:108D700090B26A460AF098F8BDF80000022800D3C5 +:108D80000220C1B2208801F006F8401CC0B238BDF4 +:108D90002DE9FF5F82468B46F74814460BF103022C +:108DA000D0E90110CDE9021022F0030201A84FF42E +:108DB000907101920AF097FEF04E002C02D1F0491A +:108DC000019A8A60019901440191B57F05F101057D +:108DD00004D1E8B20CF098FD00B1FFDF019800EB80 +:108DE0000510C01C20F0030101915CB9707AB27AC1 +:108DF0001044C2B200200870B08C80B204F03DFF75 +:108E000000B1FFDF0198716A08440190214601A872 +:108E100000F084FF80460198C01C20F00300019000 +:108E2000B37AF27A717A04B100200AF052FF019904 +:108E300008440190214601A800F0B8FFCF48002760 +:108E40003D4690F801900CE0284600F04AFF0646A7 +:108E500081788088F9F7E8F871786D1C00FB01775C +:108E6000EDB24D45F0D10198C01C20F003000190F7 +:108E700004B100203946F9F7E2F8019900270844C7 +:108E80000190BE483D4690F801900CE0284600F065 +:108E900028FF0646C1788088FEF71BFC71786D1CA0 +:108EA00000FB0177EDB24D45F0D10198C01C20F0D8 +:108EB0000300019004B100203946FEF713FC01992C +:108EC0004FF0000908440190AC484D4647780EE049 +:108ED000284600F006FF0646807B30B106F1080008 +:108EE00002F09CF9727800FB02996D1CEDB2BD4254 +:108EF000EED10198C01C20F00300019004B10020C5 +:108F00009F494A78494602F08DF901990844019039 +:108F1000214601A800F0B8FE0198C01D20F007000E +:108F20000190DAF80010814204D3A0EB0B01B1F5F7 +:108F3000803F04DB4FF00408CAF8000004E0CAF8E0 +:108F40000000B8F1000F03D0404604B0BDE8F09F28 +:108F500084BB8C490020019A0EF044FEFBF714FA02 +:108F6000864C207F0090607F012825D0002328B305 +:108F70000022824800211030F8F73AFA00B1FFDFF2 +:108F80007E49E07F2031FEF759FF00B1FFDF7B48CB +:108F90004FF4F6720021443005F079FA7748042145 +:108FA000443080F8E91180F8EA11062180F8EB11CD +:108FB000032101710020C8E70123D8E702AAD8E7FE +:108FC00070B56E4C06464434207804EB4015E078CA +:108FD000083598B9A01990F8E80100280FD0A078BA +:108FE0000F2800D3FFDF20220021284605F04FFA8A +:108FF000687866F3020068700120E070284670BD52 +:109000002DE9F04105460C460027007805219046E1 +:109010003E46B1EB101F00D0FFDF287A50B1012887 +:109020000ED0FFDFA8F800600CB12780668000201A +:10903000BDE8F0810127092674B16888A08008E0A6 +:109040000227142644B16888A0802869E060A88AB5 +:109050002082287B2072E5E7A8F80060E7E730B5BA +:10906000464C012000212070617020726072032242 +:10907000A272E07261772177217321740521218327 +:109080001F216183607440A161610A21A177E077AB +:1090900039483B4DB0F801102184C07884F8220093 +:1090A0004FF4B06060626868C11C21F00301814226 +:1090B00000D0FFDF6868606030BD30B5304C1568A7 +:1090C000636810339D4202D20420136030BD2B4BE5 +:1090D0005D785A6802EB0512107051700320D08041 +:1090E000172090800120D0709070002090735878E5 +:1090F000401C5870606810306060002030BD70B552 +:1091000006461E480024457807E0204600F0E9FDA9 +:109110000178B14204D0641CE4B2AC42F5D1002025 +:1091200070BDF7B5074608780C4610B3FFF7E7FFA8 +:109130000546A7F12006202F06D0052E19D2DFE81C +:1091400006F00F383815270000F0D6FD0DB169780C +:1091500000E00021401AA17880B20844FF2808D816 +:10916000A07830B1A088022831D202E060881728A8 +:109170002DD20720FEBD000030610200B0030020A8 +:109180001C000020000000206E52463578000000D0 +:10919000207AE0B161881729EBD3A1881729E8D399 +:1091A000A1790029E5D0E1790029E2D0402804D94D +:1091B000DFE7242F0BD1207A48B161884FF6FB708E +:1091C000814202D8A188814201D90420D2E765B941 +:1091D000207802AA0121FFF770FF0028CAD1207869 +:1091E000FFF78DFF050000D1FFDF052E18D2DFE865 +:1091F00006F0030B0E081100A0786870A088E880C4 +:109200000FE06088A8800CE0A078A87009E0A07842 +:10921000E87006E054F8020FA8606068E86000E0BB +:10922000FFDF0020A6E71A2835D00DDC132832D244 +:10923000DFE800F01B31203131272723252D313184 +:1092400029313131312F0F00302802D003DC1E28A4 +:1092500021D1072070473A3809281CD2DFE800F0F6 +:10926000151B0F1B1B1B1B1B07000020704743F225 +:109270000400704743F202007047042070470D203D +:1092800070470F2070470820704711207047132047 +:109290007047062070470320704710B5007800F033 +:1092A000010009F0F3FDBDE81040BCE710B50078FF +:1092B00000F0010009F0F3FDBDE81040B3E70EB582 +:1092C000017801F001018DF80010417801F00101F1 +:1092D0008DF801100178C1F340018DF8021041783A +:1092E000C1F340018DF80310017889088DF804104E +:1092F000417889088DF8051081788DF80610C178BD +:109300008DF8071000798DF80800684608F0FDFD1B +:10931000FFF789FF0EBD2DE9FC5FDFF8F883FE4CF7 +:1093200000264FF490771FE0012000F082FD01201D +:10933000FFF746FE05463946D8F808000AF0F1FB6B +:10934000686000B9FFDF686808F0AAFCB0B1284681 +:10935000FAF75EFB284600F072FD28B93A466968C4 +:10936000D8F808000AF008FC94F9E9010428DBDACF +:1093700002200AF043FD07460025AAE03A46696844 +:10938000D8F808000AF0F8FBF2E7B8F802104046F7 +:10939000491C89B2A8F80210B94201D300214180CA +:1093A0000221B8F802000AF081FD002866D0B8F862 +:1093B0000200694609F0CFFCFFF735FF00B1FFDF7F +:1093C0009DF80000019078B1B8F802000AF0B1FEF3 +:1093D0005FEA000900D1FFDF48460AF020F918B122 +:1093E000B8F8020002F0E4F9B8F802000AF08FFEC3 +:1093F0005FEA000900D1FFDF48460AF008F9E8BB40 +:109400000321B8F802000AF051FD5FEA000B4BD1CE +:10941000FFDF49E0DBF8100010B10078FF284DD0E5 +:10942000022000F006FD0220FFF7CAFD82464846F2 +:109430000AF0F9F9CAF8040000B9FFDFDAF804000D +:109440000AF0C1FA002100900170B8F802105046ED +:10945000AAF8021002F0B2F848460AF0B6FA00B9CB +:10946000FFDF019800B10126504600F0E8FC18B972 +:109470009AF80100000705D5009800E027E0CBF836 +:10948000100011E0DBF8101039B10878401C10F022 +:10949000FF00087008D1FFDF06E0002211464846B1 +:1094A00000F0F0FB00B9FFDF94F9EA01022805DBC8 +:1094B000B8F8020002F049F80028ABD194F9E901AC +:1094C000042804DB48460AF0E4FA00B101266D1CCA +:1094D000EDB2BD4204D294F9EA010228BFF655AFBD +:1094E000002E7FF41DAFBDE8FC5F032000F0A1BC9F +:1094F00010B5884CE06008682061AFF2E510F9F71C +:10950000E4FC607010BD844800214438017081483B +:10951000017082494160704770B505464FF0805038 +:109520000C46D0F8A410491C05D1D0F8A810C943A6 +:109530000904090C0BD050F8A01F01F0010129709B +:10954000416821608068A080287830B970BD06210C +:1095500020460DF0CCFF01202870607940F0C0005B +:10956000607170BD70B54FF080540D46D4F8801016 +:10957000491C0BD1D4F88410491C07D1D4F88810A9 +:10958000491C03D1D4F88C10491C0CD0D4F880109D +:109590000160D4F884104160D4F888108160D4F858 +:1095A0008C10C16002E010210DF0A1FFD4F89000F2 +:1095B000401C0BD1D4F89400401C07D1D4F898007B +:1095C000401C03D1D4F89C00401C09D054F8900FE3 +:1095D000286060686860A068A860E068E86070BDA6 +:1095E0002846BDE8704010210DF081BF4A4800793F +:1095F000E6E470B5484CE07830B3207804EB4010D6 +:10960000407A00F00700204490F9E801002800DCCF +:10961000FFDF2078002504EB4010407A00F00700BF +:10962000011991F8E801401E81F8E8012078401CFA +:10963000C0B220700F2800D12570A078401CA07007 +:109640000DF0D4FDE57070BDFFDF70BD3EB5054681 +:1096500003210AF02BFC044628460AF058FD054673 +:1096600004B9FFDF206918B10078FF2800D1FFDFBF +:1096700001AA6946284600F005FB60B9FFDF0AE051 +:10968000002202A9284600F0FDFA00B9FFDF9DF88C +:10969000080000B1FFDF9DF80000411E8DF80010AA +:1096A000EED220690199884201D1002020613EBD9F +:1096B00070B50546A0F57F400C46FF3800D1FFDFAE +:1096C000012C01D0FFDF70BDFFF790FF040000D137 +:1096D000FFDF207820F00F00401D20F0F000503018 +:1096E000207065800020207201202073BDE870404A +:1096F0007FE72DE9F04116460D460746FFF776FF56 +:10970000040000D1FFDF207820F00F00401D20F082 +:10971000F00005E01C000020F403002048140020A5 +:109720005030207067800120207228682061A8884E +:10973000A0822673BDE8F0415BE77FB5FFF7DFFC51 +:10974000040000D1FFDF02A92046FFF7EBFA05462F +:1097500003A92046FFF700FB8DF800508DF80100AB +:10976000BDF80800001DADF80200BDF80C00001D9A +:10977000ADF80400E088ADF80600684609F070FB1B +:10978000002800D0FFDF7FBD2DE9F05FFC4E814651 +:10979000307810B10820BDE8F09F4846F7F77FFD0C +:1097A00008B11020F7E7F74C207808B9FFF757FC0D +:1097B000A17A607A4D460844C4B200F09DFAA042F6 +:1097C00007D2201AC1B22A460020FFF776FC0028F3 +:1097D000E1D17168EB48C91C002721F003017160D9 +:1097E000B3463E463D46BA463C4690F801800AE004 +:1097F000204600F076FA4178807B0E4410FB01553C +:10980000641CE4B27F1C4445F2D10AEB870000EBF4 +:10981000C600DC4E00EB85005C46F17A012200EBCD +:109820008100DBF80410451829464846FFF7B0FAD6 +:10983000070012D00020FFF762FC05000BD005F1F5 +:109840001300616820F00300884200D0FFDF7078C9 +:10985000401E7070656038469DE7002229464846E4 +:10986000FFF796FA00B1FFDFD9F8000060604FF60D +:10987000FF7060800120207000208CE72DE9F0410E +:109880000446BF4817460D46007810B10820BDE8D1 +:10989000F0810846F7F7DDFC08B11020F7E7B94E74 +:1098A000307808B9FFF7DBFB601E1E2807D8012CB3 +:1098B00023D12878FE2820D8B0770020E7E7A4F14C +:1098C00020001F2805D8E0B23A462946BDE8F041FD +:1098D00027E4A4F140001F2805D829462046BDE80A +:1098E000F04100F0D4BAA4F1A0001F2805D8294601 +:1098F0002046BDE8F04100F006BB0720C7E72DE990 +:10990000F05F81460F460846F7F7C9FC48B948465C +:10991000F7F7E3FC28B909F1030020F003014945FA +:1099200001D0102037E797484FF0000B4430817882 +:1099300069B14178804600EB411408343E883A46CC +:109940000021204600F089FA050004D027E0A7F89E +:1099500000B005201FE7B9F1000F24D03888B042CD +:1099600001D90C251FE0607800F00700824600F066 +:1099700060FA08EB0A063A4696F8E8014946401CA8 +:1099800086F8E801204600F068FA054696F8E801F6 +:10999000401E86F8E801032000F04BFA2DB10C2D93 +:1099A00001D0A7F800B02846F5E6754F5046BAF149 +:1099B000010F25D002280DD0BAF1030F35D0FFDFFB +:1099C00098F801104046491CC9B288F801100F29C7 +:1099D00037D038E0606828B16078000702D460882A +:1099E000FFF734FE98F8EA014446012802D178785E +:1099F000F9F78AFA94F9EA010428E1DBFFDFDFE7EF +:109A0000616821B14FF49072B8680AF0B5F898F81F +:109A1000E9014446032802D17878F9F775FA94F9F8 +:109A2000E9010428CCDBFFDFCAE76078C00602D575 +:109A30006088FFF70BFE98F9EB010628C0DBFFDF1B +:109A4000BEE780F801B08178491E88F8021096F8C8 +:109A5000E801401C86F8E801A5E770B50C4605460C +:109A6000F7F7F7FB18B92046F7F719FC08B11020F3 +:109A700070BD28460BF07FFF207008B1002070BD3C +:109A8000042070BD70B505460BF08EFFC4B22846A9 +:109A9000F7F723FC08B1102070BD35B128782C7081 +:109AA00018B1A04201D0072070BD2046FDF77EFE10 +:109AB000052805D10BF07BFF012801D0002070BDE7 +:109AC0000F2070BD70B5044615460E460846F7F7E0 +:109AD000C0FB18B92846F7F7E2FB08B1102070BDAB +:109AE000022C03D0102C01D0092070BD2A4631462B +:109AF00020460BF086FF0028F7D0052070BD70B51A +:109B000014460D460646F7F7A4FB38B92846F7F782 +:109B1000C6FB18B92046F7F7E0FB08B1102070BD6E +:109B20002246294630460BF06EFF0028F7D007206A +:109B300070BD3EB50446F7F7B2FB08B110203EBD3C +:109B4000684608F053F9FFF76EFB0028F7D19DF83F +:109B500006002070BDF808006080BDF80A00A080F3 +:109B600000203EBD70B505460C460846F7F7B5FB2C +:109B700020B95CB12068F7F792FB28B1102070BDC6 +:109B80001C000020B0030020A08828B121462846F0 +:109B9000BDE87040FDF762BE0920F0E770B50546EC +:109BA0000C460846F7F755FBA0BB681E1E280ED8CA +:109BB000032D01D90720E2E705B9FFDFFE4800EBDE +:109BC000850050F8041C2046BDE870400847A5F108 +:109BD00020001F2805D821462846BDE87040FAF726 +:109BE00042BBA5F160001F2805D821462846BDE8E4 +:109BF0007040F8F7DABCF02D0DD0F12D15D0BF2D47 +:109C0000D8D1A078218800F0010001F08DFB98B137 +:109C10000020B4E703E0A068F7F71BFB08B11020B1 +:109C2000ADE7204609F081F902E0207809F0A0F9BB +:109C3000BDE87040FFF7F7BA0820A0E770B504460A +:109C40000D460846F7F72BFB30B9601E1E280FD8CB +:109C50002846F7F7FEFA08B1102090E7012C03D050 +:109C6000022C01D0032C01D1062088E7072086E7CB +:109C7000A4F120001F28F9D829462046BDE87040ED +:109C8000FAF762BB09F092BC38B50446CB48007BBA +:109C900000F00105F9B904F01DFC0DB1226800E0E7 +:109CA0000022C7484178C06807F06DFDC4481030F5 +:109CB000C0788DF8000010B1012802D004E0012026 +:109CC00000E000208DF80000684608F0FFF8BA4870 +:109CD000243808F0B5FE002D02D02068283020601E +:109CE00038BD30B5B54D04466878A04200D8FFDFD6 +:109CF000686800EB041030BD70B5B04800252C46F4 +:109D0000467807E02046FFF7ECFF4078641C2844C3 +:109D1000C5B2E4B2B442F5D1284630E72DE9F041AE +:109D20000C4607464FF0000800F01FF90646FF28D2 +:109D300001D94FF013083868C01C20F003023A60C4 +:109D400054EA080421D19D48F3B2072128300DF0D0 +:109D5000DBFD09E0072C10D2DFE804F00604080858 +:109D60000A040600974804E0974802E0974800E09C +:109D700097480DF0E9FD054600E0FFDFA54200D061 +:109D8000FFDF641CE4B2072CE4D3386800EB061054 +:109D9000386040467BE5021D5143452900D24521EC +:109DA0000844C01CB0FBF2F0C0B270472DE9FC5F64 +:109DB000064682484FF000088B464746444690F8D6 +:109DC000019022E02046FFF78CFF050000D1FFDF65 +:109DD000687869463844C7B22846FEF7A3FF824632 +:109DE00001A92846FEF7B8FF0346BDF80400524615 +:109DF000001D81B2BDF80000001D80B20AF0D4F849 +:109E00006A78641C00FB0288E4B24C45DAD1306801 +:109E1000C01C20F003003060BBF1000F00D0002018 +:109E2000424639460AF0CEF8316808443060BDE851 +:109E3000FC9F6249443108710020C87070475F4937 +:109E40004431CA782AB10A7801EB421108318142C3 +:109E500001D001207047002070472DE9F0410646EF +:109E60000078154600F00F0400201080601E0F4699 +:109E7000052800D3FFDF50482A46183800EB84003D +:109E8000394650F8043C3046BDE8F04118472DE90A +:109E9000F0414A4E0C46402806D0412823D04228A3 +:109EA0002BD0432806D123E0A07861780D18E17803 +:109EB000814201D90720EAE42078012801D9132042 +:109EC000E5E4FF2D08D80BF009FF07460DF046F931 +:109ED000381A801EA84201DA1220D8E42068B06047 +:109EE000207930730DE0BDE8F041084600F078B805 +:109EF00008780228DED8307703E008780228D9D81D +:109F000070770020C3E4F8B500242C4DA02805D0BC +:109F1000A12815D0A22806D00720F8BD087800F0A7 +:109F20000100E8771FE00E4669463046FDF73DFD2B +:109F30000028F2D130882884B07885F8220012E019 +:109F400008680921F82801D3820701D00846F8BD26 +:109F50006A7C02F00302012A04D16A8BD73293B2E1 +:109F60008342F3D868622046F8BD2DE9F047DFF858 +:109F70004C900026344699F8090099F80A2099F87F +:109F800001700244D5B299F80B20104400F0FF088C +:109F900008E02046FFF7A5FE817B407811FB0066B4 +:109FA000641CE4B2BC42F4D199F8091099F80A0093 +:109FB0002944294441440DE054610200B0030020CB +:109FC0001C0000206741000045B30000DD2F0000A9 +:109FD000FB56010000B1012008443044BDE8F08781 +:109FE00038B50446407800F00300012803D0022869 +:109FF0000BD0072038BD606858B1F7F777F9D0B9B2 +:10A000006068F7F76AF920B915E06068F7F721F999 +:10A0100088B969462046FCF729F80028EAD160781B +:10A0200000F00300022808D19DF8000028B1606804 +:10A03000F7F753F908B1102038BD6189F8290DD818 +:10A04000208988420AD8607800F003020A48012A71 +:10A0500006D1D731426A89B28A4201D2092038BD7D +:10A0600094E80E0000F1100585E80E000AB9002101 +:10A070000183002038BD0000B00300202DE9F0412D +:10A08000074614468846084601F08AFD064608EB56 +:10A0900088001C22796802EBC0000D18688C58B14A +:10A0A0004146384601F08BFD014678680078C200D1 +:10A0B000082305F120000CE0E88CA8B141463846A1 +:10A0C00001F084FD0146786808234078C20005F15C +:10A0D000240009F0A8FD38B1062121726681D0E97B +:10A0E0000010C4E9031009E0287809280BD00520E6 +:10A0F000207266816868E060002028702046BDE814 +:10A10000F04101F02EBD072020726681F4E72DE9B1 +:10A11000F04116460D460746406801EB85011C22BA +:10A1200002EBC1014418204601F072FD40B100214C +:10A13000708865F30F2160F31F4106200DF0BEFC0F +:10A1400009202070324629463846BDE8F04195E79F +:10A150002DE9F0410E46074600241C21F07816E058 +:10A1600004EB8403726801EBC303D25C6AB1FFF7AE +:10A170003DFA050000D1FFDF6F802A4621463046B8 +:10A18000FFF7C5FF0120BDE8F081641CE4B2A042E6 +:10A19000E6D80020F7E770B5064600241C21C078F9 +:10A1A0000AE000BF04EB8403726801EBC303D51817 +:10A1B0002A782AB1641CE4B2A042F3D8402070BDD2 +:10A1C00028220021284604F062F9706880892881DD +:10A1D000204670BD70B5034600201C25DC780CE0DD +:10A1E00000EB80065A6805EBC6063244167816B1B5 +:10A1F000128A8A4204D0401CC0B28442F0D8402067 +:10A2000070BDF0B5044600201C26E5780EE000BFC6 +:10A2100000EB8007636806EBC7073B441F788F425B +:10A2200002D15B78934204D0401CC0B28542EFD883 +:10A230004020F0BD0078032801D0002070470120A5 +:10A2400070470078022801D0002070470120704735 +:10A250000078072801D000207047012070472DE9C1 +:10A26000F041064688461078F1781546884200D3BA +:10A27000FFDF2C781C27641CF078E4B2A04201D8E0 +:10A28000201AC4B204EB8401706807EBC1010844D2 +:10A29000017821B14146884708B12C7073E72878CE +:10A2A000A042E8D1402028706DE770B514460B88B5 +:10A2B0000122A240134207D113430B8001230A223B +:10A2C000011D09F07AFC047070BD2DE9FF4F81B0CB +:10A2D0000878DDE90E7B9A4691460E4640072CD45D +:10A2E000019809F026FF040000D1FFDF07F1040800 +:10A2F00020461FFA88F109F065F8050000D1FFDF5C +:10A30000204629466A4609F0B0FA0098A0F8037082 +:10A31000A0F805A0284609F056FB017869F306016C +:10A320006BF3C711017020461FFA88F109F08DF810 +:10A3300000B9FFDF019807F094F906EB0900017FEF +:10A34000491C017705B0BDE8F08F2DE9F84F0E46A6 +:10A350009A4691460746032109F0A8FD0446008D60 +:10A36000DFF8B885002518B198F80000B0421ED17A +:10A37000384609F0DEFE070000D1FFDF09F10401D5 +:10A38000384689B209F01EF8050010D03846294633 +:10A390006A4609F06AFA009800210A460180817035 +:10A3A00007F01CFA0098C01DCAF8000021E098F8D8 +:10A3B0000000B04216D104F1260734F8341F012002 +:10A3C00000FA06F911EA090F00D0FFDF2088012307 +:10A3D00040EA090020800A22391D384609F008FCAD +:10A3E000067006E0324604F1340104F12600FFF75E +:10A3F0005CFF0A2188F800102846BDE8F88FFEB5FA +:10A4000015460C46064602AB0C220621FFF79DFFBF +:10A41000002827D00299607812220A70801C4870A8 +:10A4200008224A80A07002982988052381806988C3 +:10A43000C180A9880181E988418100250C20CDE9EE +:10A440000005062221463046FFF73FFF294600223D +:10A4500066F31F41F02310460DF086FA6078801CE9 +:10A4600060700120FEBDFEB514460D46062206466C +:10A4700002AB1146FFF769FF002812D0029B1320A0 +:10A4800000211870A8785870022058809C800620FF +:10A49000CDE900010246052329463046FFF715FFA6 +:10A4A0000120FEBD2DE9FE430C46804644E002AB90 +:10A4B0000E2207214046FFF748FF002841D0606880 +:10A4C0001C2267788678BF1C06EB860102EBC1016F +:10A4D000451802981421017047700A214180698A49 +:10A4E0000181E98A4181A9888180A98981813046D9 +:10A4F00001F056FB029905230722C8806F700420E3 +:10A50000287000250E20CDE9000521464046FFF7C2 +:10A51000DCFE294666F30F2168F31F41F023002279 +:10A5200006200DF021FA6078FD49801C6070626899 +:10A530002046921CFFF793FE606880784028B6D1D1 +:10A540000120BDE8FE83FEB50D46064638E002ABAD +:10A550000E2207213046FFF7F8FE002835D0686844 +:10A560001C23C17801EB810203EBC202841802981C +:10A5700015220270627842700A224280A2894281CA +:10A58000A2888281084601F00BFB01460298818077 +:10A59000618AC180E18A0181A088B8B10020207061 +:10A5A00000210E20CDE9000105230722294630466F +:10A5B000FFF78BFE6A68DB492846D21CFFF74FFE87 +:10A5C0006868C0784028C2D10120FEBD0620E6E7B9 +:10A5D0002DE9FE430C46814644E0204601F002FB93 +:10A5E000D0B302AB082207214846FFF7AEFE002891 +:10A5F000A7D060681C2265780679AD1C06EB860141 +:10A6000002EBC10147180298B7F8108006210170CB +:10A61000457004214180304601F0C2FA014602989B +:10A6200005230722C180A0F804807D7008203870BF +:10A630000025CDE9000521464846FFF746FE29469C +:10A6400066F30F2169F31F41F023002206200DF06D +:10A650008BF96078801C60706268B3492046121DD7 +:10A66000FFF7FDFD606801794029B6D1012068E758 +:10A670002DE9F34F83B00D4691E0284601F0B2FA80 +:10A6800000287DD068681C2290F806A00AEB8A0199 +:10A6900002EBC10144185146284601F097FAA1780F +:10A6A000CB0069684978CA00014604F1240009F02A +:10A6B000D6FA07468188E08B4FF00009091A8EB25E +:10A6C00008B1C84607E04FF00108504601F053FAC0 +:10A6D00008B9B61CB6B2208BB04200D80646B346C5 +:10A6E00002AB324607210398FFF72FFE060007D082 +:10A6F000B8F1000F0BD0504601F03DFA10B106E062 +:10A7000000201FE60299B8884FF0020908800196E0 +:10A71000E28B3968ABEB09001FFA80F80A44039812 +:10A720004E46009209F005FDDDE90021F61D434685 +:10A73000009609F014F9E08B404480B2E083B988B8 +:10A74000884201D1012600E00026CDE900B6238A27 +:10A75000072229460398FFF7B8FD504601F00BFA8F +:10A7600010B9E089401EE08156B1A078401CA0706D +:10A770006868E978427811FB02F1CAB2012300E06F +:10A7800007E081690E3009F018FA80F800A0002077 +:10A79000E0836A6865492846921DFFF760FD686896 +:10A7A000817940297FF469AF0120CBE570B5064679 +:10A7B00048680D4614468179402910D104EB840184 +:10A7C0001C2202EBC101084401F043FA002806D024 +:10A7D0006868294684713046BDE8704048E770BD1E +:10A7E000FEB50C460746002645E0204601F0FAF982 +:10A7F000D8B360681C22417901EB810102EBC101F1 +:10A800004518688900B9FFDF02AB082207213846E6 +:10A81000FFF79BFD002833D00299607816220A705A +:10A82000801C4870042048806068407901F0B8F9C5 +:10A83000014602980523072281806989C18008208A +:10A84000CDE9000621463846FFF73FFD6078801CC1 +:10A850006070A88969890844B0F5803F00D3FFDFA4 +:10A86000A88969890844A8816E81626830492046B8 +:10A87000521DFFF7F4FC606841794029B5D10120F1 +:10A88000FEBD30B5438C458BC3F3C704002345B1EF +:10A89000838B641EED1AC38A6D1E1D4495FBF3F372 +:10A8A000E4B22CB1008918B1A04200D8204603447C +:10A8B0004FF6FF70834200D3034613800C7030BD07 +:10A8C0002DE9FC41074616460D46486802EB860115 +:10A8D0001C2202EBC10144186A4601A92046FFF779 +:10A8E000D0FFA089618901448AB2BDF8001091426D +:10A8F00012D0081A00D5002060816868407940288D +:10A900000AD1204601F09BF9002805D06868294645 +:10A9100046713846FFF764FFBDE8FC813000002037 +:10A9200035A2000043A2000051A2000053BC000069 +:10A930003FBC00002DE9FE4F0F468146154650886A +:10A94000032109F0B3FA0190B9F8020001F01BF9F4 +:10A9500082460146019801F045F9002824D001986B +:10A960001C2241680AEB8A0002EBC0000C1820464A +:10A9700001F04EF9002817D1B9F80000E18A8842A9 +:10A980000ED8A18961B1B8420ED100265146019876 +:10A9900001F015F9218C01EB0008608B30B114E057 +:10A9A000504601F0E8F8A0B3BDE8FE8F504601F034 +:10A9B000E2F808B1678308E0022FF5D3B9F8040084 +:10A9C0006083618A884224D80226B81B87B2B8F80F +:10A9D0000400A28B801A002814DD874200DA384672 +:10A9E0001FFA80FB688869680291D8F800100A4451 +:10A9F000009209F08CFBF61D009A5B4602990096C6 +:10AA000008F079FFA08B384480B2A083618B884224 +:10AA100007D96888019903B05246BDE8F04F01F0AC +:10AA200035B91FD14FF009002872B9F802006881CA +:10AA3000D8E90010C5E90410608BA881284601F010 +:10AA400090F85146019801F0BAF8014601980823A0 +:10AA500040680078C20004F1200009F0E4F800200A +:10AA6000A0836083504601F086F810B9A089401E8B +:10AA7000A0816888019903B00AF0FF02BDE8F04F99 +:10AA80001EE72DE9F041064615460F461C461846BE +:10AA9000F6F7DFFB18B92068F6F701FC10B11020BB +:10AAA000BDE8F0817168688C0978B0EBC10F01D303 +:10AAB0001320F5E73946304601F081F80146706809 +:10AAC00008230078C20005F1200009F076F8D4E9E7 +:10AAD0000012C0E900120020E2E710B5044603218D +:10AAE00009F0E4F90146007800F00300022805D0DF +:10AAF0002046BDE8104001F1140280E48A8A204615 +:10AB0000BDE81040AFE470B50446032109F0CEF96A +:10AB1000054601462046FFF75BFD002816D0294672 +:10AB20002046FFF75DFE002810D029462046FFF79B +:10AB30000AFD00280AD029462046FFF7B3FC00286A +:10AB400004D029462046BDE8704091E570BD2DE94E +:10AB5000F0410C4680461EE0E178427811FB02F19C +:10AB6000CAB2816901230E3009F05DF80778606888 +:10AB70001C22C179491EC17107EB8701606802EB95 +:10AB8000C10146183946204601F02CF818B130466C +:10AB900001F037F820B16068C1790029DCD17FE786 +:10ABA000FEF724FD050000D1FFDF0A202872384699 +:10ABB00000F0F6FF68813946204601F007F80146AB +:10ABC000606808234078C20006F1240009F02BF8E1 +:10ABD000D0E90010C5E90310A5F80280284600F06E +:10ABE000C0FFB07800B9FFDFB078401EB07057E703 +:10ABF00070B50C460546032109F058F90146406836 +:10AC0000C2792244C2712846BDE870409FE72DE911 +:10AC1000FE4F8246507814460F464FF00008002839 +:10AC20004FD0012807D0022822D0FFDF2068B8606B +:10AC30006068F860B8E602AB0E2208215046FFF7C4 +:10AC400084FB0028F2D00298152105230170217899 +:10AC500041700A214180C0F80480C0F80880A0F843 +:10AC60000C80628882810E20CDE90008082221E054 +:10AC7000A678304600F094FF054606EB86012C22AC +:10AC8000786802EBC1010822465A02AB11465046D1 +:10AC9000FFF75BFB0028C9D00298072101702178DB +:10ACA00041700421418008218580C680CDE90018CB +:10ACB00005230A4639465046FFF707FB87F8088008 +:10ACC00072E6A678022516B1022E13D0FFDF2A1DE8 +:10ACD000914602AB08215046FFF737FB0028A5D06C +:10ACE00002980121022E01702178417045808680F2 +:10ACF00002D005E00625EAE7A188C180E18801814C +:10AD0000CDE900980523082239465046D4E710B50E +:10AD10000446032109F0CAF8014600F10802204662 +:10AD2000BDE8104073E72DE9F04F0F4605468DB0A2 +:10AD300014465088032109F0B9F84FF000088DF847 +:10AD400014800646ADF81680042F7BD36A78002A5B +:10AD500078D028784FF6FF794FF01C0A132834D0AA +:10AD600008DC012871D006284AD007286ED01228A6 +:10AD70000ED106E014286AD0152869D0162807D10C +:10AD8000AAE10C2F04D1307800F00301022907D08A +:10AD9000CDF80880CDF80C8068788DF808004CE07C +:10ADA00040F0080030706878B07001208DF8140011 +:10ADB000A888ADF81800E888ADF81A002889ADF821 +:10ADC0001C006889ADF81E0011E1B078904239D1BD +:10ADD0003078010736D5062F34D120F008003070C6 +:10ADE0006088414660F31F4100200CF067FE02209E +:10ADF0008DF81400ADF81890A888ADF81A00F6E0A8 +:10AE0000082F1FD1A888EF88814600F0BCFE80463D +:10AE10000146304600F0E6FE18B1404600F0ABFEB9 +:10AE2000B8B1FC48D0E90010CDE902106878ADF85F +:10AE30000C908DF80800ADF80E70608802AA3146BB +:10AE4000FFF7E5FE0DB0BDE8F08FB6E01EE041E093 +:10AE5000ECE0716808EB88002C2202EBC000085A75 +:10AE6000B842EFD1EB4802AAD0E90210CDE90210B6 +:10AE700068788DF8080008F0FF058DF80A506088A2 +:10AE80003146FFF7C4FE224629461FE0082FD9D1DC +:10AE9000B5F80480E88800F076FE074601463046A3 +:10AEA00000F0A0FE0028CDD007EB870271680AEB06 +:10AEB000C2000844028A4245C4D101780829C1D1A0 +:10AEC000407869788842BDD1F9B222463046FFF712 +:10AED0001EF9B7E70E2F7FF45BAFE9886F898B46C9 +:10AEE000B5F808903046FFF775F9ABF140014029FD +:10AEF00001D309204AE0B9F1170F01D3172F01D26E +:10AF00000B2043E040280ED000EB800271680AEB72 +:10AF1000C20008440178012903D140786978884249 +:10AF200090D00A2032E03046FFF735F9014640283C +:10AF30002BD001EB810372680AEBC30002EB00081F +:10AF4000012288F800206A7888F801207068AA88B1 +:10AF50004089B84200D93846AD8903232372A282C2 +:10AF6000E7812082A4F80C906582084600F018FE64 +:10AF70006081A8F81490A8F81870A8F80E50A8F8E6 +:10AF800010B0204600F0EDFD5CE7042005212172A1 +:10AF9000A4F80A80E081012121739E49D1E90421AE +:10AFA000CDE9022169788DF80810ADF80A006088B3 +:10AFB00002AA3146FFF72BFEE3E7062F89D3B078CC +:10AFC00090421AD13078010717D520F00800307070 +:10AFD0006088414660F31F4100200CF06FFD0220A5 +:10AFE0008DF81400A888ADF81800ADF81A906088A4 +:10AFF000224605A9F9F7E3F824E704213046FFF7D4 +:10B0000000F905464028BFD0022083030090224665 +:10B010002946304600F003FE4146608865F30F2163 +:10B0200060F31F4106200CF049FD0BE70E2FABD15A +:10B0300004213046FFF7E5F881464028A4D0414678 +:10B04000608869F30F2160F31F4106200CF036FD84 +:10B05000A8890B906889099070682F894089B84247 +:10B0600000D938468346B5F80680A8880A90484635 +:10B0700000F096FD60810B9818B1022000900B9BA8 +:10B0800024E0B8F1170F1ED3172F1CD30420207211 +:10B0900009986082E781A4F810B0A4F80C8009EB4D +:10B0A000890271680AEBC2000D18DDE90913A5F8E1 +:10B0B0001480A5F818B0E9812B82204600F051FDDC +:10B0C00006202870BEE601200B2300902246494648 +:10B0D000304600F0A4FDB5E6082F8DD1A988304692 +:10B0E000FFF778F80746402886D000F044FD002896 +:10B0F0009BD107EB870271680AEBC20008448046C7 +:10B1000000F086FD002890D1ED88B8F80E002844A4 +:10B11000B0F5803F05D360883A46314600F0B6FD71 +:10B1200090E6002DCED0A8F80E0060883A46314651 +:10B13000FFF73CFB08202072384600F031FD6081AB +:10B14000A5811EE72DE9F05F0C4601281FD09579F7 +:10B1500092F8048092F8056005EB85011F2202EB4E +:10B16000C10121F0030B08EB060111FB05F14FF6BD +:10B17000FF7202EAC10909F1030115FB0611264F0E +:10B1800021F0031ABB6840B101283ED125E0616877 +:10B19000E57891F800804E78DEE75946184608F0C9 +:10B1A000C0FC606000B9FFDF5A460021606803F010 +:10B1B0006EF9E5705146B86808F0B3FC6168486103 +:10B1C00000B9FFDF6068426902EB090181616068D4 +:10B1D00080F800806068467017E0606852464169F8 +:10B1E000184608F0C9FC5A466168B86808F0C4FC03 +:10B1F000032008F003FE0446032008F007FE201A8F +:10B20000012802D1B86808F081FC0BEB0A00BDE808 +:10B21000F09F000060610200300000200246002123 +:10B2200002208FE7F7B5FF4C0A20164620700098E1 +:10B2300060B100254FEA0D0008F055FC0021A17017 +:10B240006670002D01D10099A160FEBD012500208E +:10B25000F2E770B50C46154638220021204603F06F +:10B2600016F9012666700A22002104F11C0003F081 +:10B270000EF905B9FFDF297A207861F3010020700B +:10B28000A87900282DD02A4621460020FFF75AFF32 +:10B2900061684020E34A88706168C870616808711D +:10B2A000616848716168887161682888088161688F +:10B2B00068884881606886819078002811D061682C +:10B2C0000620087761682888C885616828884886CC +:10B2D00060680685606869889288018681864685EF +:10B2E000828570BDC878002802D00022012029E79D +:10B2F000704770B50546002165F31F4100200CF032 +:10B30000DDFB0321284608F0D1FD040000D1FFDF5A +:10B3100021462846FEF71CFF002804D0207840F084 +:10B3200010002070012070BD70B505460C4603204A +:10B3300008F056FD08B1002070BDBA4885708480C1 +:10B34000012070BD2DE9FF4180460E460F0CFEF72F +:10B350004DF9050007D06F800321384608F0A6FD9F +:10B36000040008D106E004B03846BDE8F0411321DE +:10B37000F9F750BBFFDF5FEA080005D0B8F1060F10 +:10B3800018D0FFDFBDE8FF8120782A4620F00800B2 +:10B3900020700020ADF8020002208DF800004FF66A +:10B3A000FF70ADF80400ADF8060069463846F8F7BE +:10B3B00006FFE7E7C6F3072101EB81021C23606863 +:10B3C00003EBC202805C042803D008280AD0FFDF08 +:10B3D000D8E7012000904FF440432A46204600F071 +:10B3E0001EFCCFE704B02A462046BDE8F041FEF738 +:10B3F0008EBE2DE9F05F05464089002790460C4639 +:10B400003E46824600F0BFFB8146287AC01E0828CF +:10B410006BD2DFE800F00D04192058363C47722744 +:10B420001026002C6CD0D5E90301C4E902015CE0D0 +:10B4300070271226002C63D00A2205F10C0104F1BA +:10B44000080002F0FAFF50E071270C26002C57D0BC +:10B45000E868A06049E0742710269CB3D5E9030191 +:10B46000C4E902016888032108F020FD8346FEF745 +:10B47000BDF802466888508049465846FEF7FEFDF2 +:10B4800033E075270A26ECB1A88920812DE07627C4 +:10B490001426BCB105F10C0004F1080307C883E8C9 +:10B4A000070022E07727102664B1D5E90301C4E93B +:10B4B00002016888032108F0F9FC01466888FFF75B +:10B4C00046FB12E01CE073270826CCB168880321F4 +:10B4D00008F0ECFC01460078C00606D56888FEF747 +:10B4E00037FE10B96888F8F777FAA8F800602CB131 +:10B4F0002780A4F806A066806888A080002086E6E1 +:10B50000A8F80060FAE72DE9FC410C461E461746F4 +:10B510008046032108F0CAFC05460A2C0AD2DFE85F +:10B5200004F005050505050509090907042303E0DD +:10B53000062301E0FFDF0023CDE9007622462946FD +:10B540004046FEF7C2FEBDE8FC81F8B50546A0F511 +:10B550007F40FF382BD0284608F0D9FD040000D1E9 +:10B56000FFDF204608F05FF9002821D001466A4637 +:10B57000204608F07AF900980321B0F805602846C3 +:10B5800008F094FC0446052E13D0304600F0FBFA78 +:10B5900005460146204600F025FB40B1606805EBFA +:10B5A00085013E2202EBC101405A002800D0012053 +:10B5B000F8BD007A0028FAD00020F8BDF8B504469E +:10B5C000408808F0A4FD050000D1FFDF6A46284648 +:10B5D000616800F0C4FA01460098091F8BB230F888 +:10B5E000032F0280428842800188994205D1042AB3 +:10B5F00008D0052A20D0062A16D022461946FFF781 +:10B6000099F9F8BD001D0E46054601462246304612 +:10B61000F6F739FF0828F4D1224629463046FCF7D0 +:10B6200064F9F8BD30000020636864880A46011D93 +:10B630002046FAF789F9F4E72246001DFFF773FB6D +:10B64000EFE770B50D460646032108F02FFC040015 +:10B6500004D02078000704D5112070BD43F2020009 +:10B6600070BD2A4621463046FEF7C9FE18B9286843 +:10B6700060616868A061207840F0080020700020B8 +:10B6800070BD70B50D460646032108F00FFC04009E +:10B6900004D02078000704D4082070BD43F20200D3 +:10B6A00070BD2A4621463046FEF7DDFE00B9A58270 +:10B6B000207820F008002070002070BD2DE9F04FA8 +:10B6C0000E4691B08046032108F0F0FB0446404648 +:10B6D00008F02FFD07460020079008900990ADF86C +:10B6E00030000A9002900390049004B9FFDF0DF13E +:10B6F0000809FFB9FFDF1DE038460BA9002207F05B +:10B7000055FF9DF82C0000F07F050A2D00D3FFDFC8 +:10B710006019017F491E01779DF82C00000609D5AC +:10B720002A460CA907A8FEF7C0FD19F80510491C08 +:10B7300009F80510761EF6B2DED204F13400F84D99 +:10B7400004F1260BDFF8DCA304F12A07069010E0D1 +:10B750005846069900F08CFA064628700A2800D34D +:10B76000FFDF5AF8261040468847E08CC05DB042A3 +:10B7700002D0208D0028EBD10A202870E94D4E46DA +:10B7800028350EE00CA907A800F072FA0446375DD0 +:10B7900055F8240000B9FFDF55F82420394640460B +:10B7A0009047BDF81E000028ECD111B0BDE8F08F25 +:10B7B00010B5032108F07AFB040000D1FFDF0A2254 +:10B7C000002104F11C0002F062FE207840F0040029 +:10B7D000207010BD10B50C46032108F067FB204413 +:10B7E000007F002800D0012010BD2DE9F84F8946C8 +:10B7F00015468246032108F059FB070004D028466D +:10B80000F5F727FD40B903E043F20200BDE8F88FE9 +:10B810004846F5F744FD08B11020F7E7786828B1ED +:10B8200069880089814201D90920EFE7B9F8000051 +:10B830001C2488B100F0A7F980460146384600F084 +:10B84000D1F988B108EB8800796804EBC000085C86 +:10B8500001280BD00820D9E73846FEF79CFC80462B +:10B86000402807D11320D1E70520CFE7FDF7BEFE22 +:10B8700006000BD008EB8800796804EBC0000C18B8 +:10B88000B9F8000020B1E88910B113E01120BDE73C +:10B890002888172802D36888172801D20720B5E71F +:10B8A000686838B12B1D224641463846FFF7E9F853 +:10B8B0000028ABD104F10C0269462046FEF7E1FFF7 +:10B8C000288860826888E082B9F8000030B10220E0 +:10B8D0002070E889A080E889A0B12BE003202070C7 +:10B8E000A889A08078688178402905D180F80280F5 +:10B8F00039465046FEF7D6FD404600F051F9A9F80A +:10B90000000021E07868218B4089884200D90846F0 +:10B910002083A6F802A004203072B9F800007081DC +:10B92000E0897082F181208B3082A08AB08130461C +:10B9300000F017F97868C178402905D180F80380B4 +:10B9400039465046FEF7FFFD00205FE770B50D4613 +:10B950000646032108F0AAFA04000ED0284600F09B +:10B9600012F905460146204600F03CF918B1284678 +:10B9700000F001F920B1052070BD43F2020070BD56 +:10B9800005EB85011C22606802EBC101084400F050 +:10B990003FF908B1082070BD2A462146304600F024 +:10B9A00075F9002070BD2DE9F0410C461746804620 +:10B9B000032108F07BFA0546204600F0E4F804462F +:10B9C00095B10146284600F00DF980B104EB8401E1 +:10B9D0001C22686802EBC1014618304600F018F9D5 +:10B9E00038B10820BDE8F08143F20200FAE70520F3 +:10B9F000F8E73B46324621462846FFF742F8002842 +:10BA0000F0D1E2B229464046FEF75AFF708C083862 +:10BA1000082803D242484078F7F776FA0020E1E799 +:10BA20002DE9F0410D4617468046032108F03EFA05 +:10BA30000446284600F0A7F8064624B13846F5F734 +:10BA400008FC38B902E043F20200CBE73868F5F7AA +:10BA500000FC08B11020C5E73146204600F0C2F8CE +:10BA600060B106EB86011C22606802EBC10145183B +:10BA7000284600F0CDF818B10820B3E70520B1E75B +:10BA8000B888A98A884201D90C20ABE76168E88CA4 +:10BA90004978B0EBC10F01D31320A3E7314620460C +:10BAA00000F094F80146606808234078C20005F170 +:10BAB000240008F082F8D7E90012C0E90012F2B2BF +:10BAC00021464046FEF772FE00208BE72DE9F04745 +:10BAD0000D461F4690468146032108F0E7F90446CB +:10BAE000284600F050F806463CB14DB13846F5F70F +:10BAF000F4FB50B11020BDE8F08743F20200FAE7F2 +:10BB0000606858B1A0F80C8027E03146204600F06C +:10BB100069F818B1304600F02EF828B10520EAE7A0 +:10BB2000300000207861020006EB86011C2260686C +:10BB300002EBC1014518284600F06AF808B1082058 +:10BB4000D9E7A5F80880F2B221464846FEF7B8FECC +:10BB50001FB1A8896989084438800020CBE707F025 +:10BB600084BE017821F00F01491C21F0F001103151 +:10BB70000170FDF73EBD20B94E48807808B1012024 +:10BB80007047002070474B498988884201D10020C6 +:10BB90007047402801D2402000E0403880B2704712 +:10BBA00010B50446402800D9FFDF2046FFF7E3FF29 +:10BBB00010B14048808810BD4034A0B210BD40682C +:10BBC00042690078484302EBC0007047C278406881 +:10BBD000037812FB03F24378406901FB032100EB79 +:10BBE000C1007047C2788A4209D9406801EB8101DF +:10BBF0001C2202EBC101405C08B10120704700200B +:10BC000070470078062801D901207047002070474E +:10BC10000078062801D00120704700207047F0B45A +:10BC200001EB81061C27446807EBC6063444049DDB +:10BC300005262670E3802571F0BCFEF71FBA10B50B +:10BC4000418911B1FFF7DDFF08B1002010BD0120CF +:10BC500010BD10B5C18C8278B1EBC20F04D9C18977 +:10BC600011B1FFF7CEFF08B1002010BD012010BDBB +:10BC700010B50C4601230A22011D07F0D4FF0078FD +:10BC80002188012282409143218010BDF0B402EB53 +:10BC900082051C264C6806EBC505072363554B68D7 +:10BCA0001C79402C03D11A71F0BCFEF791BCF0BC9A +:10BCB000704700003000002010B5EFF3108000F056 +:10BCC000010472B6FC484178491C41704078012853 +:10BCD00001D10BF0B3FA002C00D162B610BD70B5E3 +:10BCE000F54CA07848B90125A570FFF7E5FF0BF0EA +:10BCF000B6FA20B100200BF080FA002070BD4FF0A2 +:10BD00008040E570C0F80453F7E770B5EFF310809A +:10BD100000F0010572B6E84C607800B9FFDF60788A +:10BD2000401E6070607808B90BF08CFA002D00D1CD +:10BD300062B670BDE04810B5817821B10021C170B4 +:10BD40008170FFF7E2FF002010BD10B504460BF034 +:10BD500086FAD9498978084000D001202060002067 +:10BD600010BD10B5FFF7A8FF0BF079FA02220123EE +:10BD7000D149540728B1D1480260236103200872D9 +:10BD800002E00A72C4F804330020887110BD2DE966 +:10BD9000F84FDFF824934278817889F80420002650 +:10BDA00089F80510074689F806600078DFF810B3B7 +:10BDB000354620B1012811D0022811D0FFDF0BF049 +:10BDC00060FA4FF0804498B10BF062FAB0420FD1A4 +:10BDD00030460BF061FA0028FAD042E00126EEE787 +:10BDE000FFF76AFF58460168C907FCD00226E6E75C +:10BDF0000120E060C4F80451B2490E600107D1F897 +:10BE00004412B04AC1F3423124321160AD49343199 +:10BE100008604FF0020AC4F804A3A060AA480168B1 +:10BE2000C94341F3001101F10108016841F010011B +:10BE3000016001E019F0A8FFD4F804010028F9D04E +:10BE400030460BF029FA0028FAD0B8F1000F04D1DF +:10BE50009D48016821F010010160C4F808A3C4F8EE +:10BE6000045199F805004E4680B1387870B90BF04E +:10BE7000F6F980460BF006FC6FF00042B8F1000FB7 +:10BE800002D0C6E9032001E0C6E90302DBF80000A6 +:10BE9000C00701D00BF0DFF9387810B13572BDE87A +:10BEA000F88F4FF01808C4F808830127A7614FF4F2 +:10BEB0002070ADF8000000BFBDF80000411EADF8D5 +:10BEC0000010F9D2C4F80C51C4F810517A48C01DC2 +:10BED0000BF06CFA3570FFF744FF676179493079F0 +:10BEE00020310860C4F80483D9E770B5050000D19B +:10BEF000FFDF4FF080424FF0FF30C2F8080300210F +:10BF0000C2F80011C2F80411C2F80C11C2F81011E5 +:10BF1000694C61700BF0AFF910B10120A070607036 +:10BF200067480068C00701D00BF095F92846BDE8C6 +:10BF300070402CE76048007A002800D0012070474C +:10BF40002DE9F04F61484FF0000A85B0D0F800B0FD +:10BF5000D14657465D4A5E49083211608406D4F8DE +:10BF6000080110B14FF0010801E04FF000080BF09C +:10BF7000F0F978B1D4F8240100B101208246D4F858 +:10BF80001C0100B101208146D4F8200108B101272D +:10BF900000E00027D4F8000100B101200490D4F89B +:10BFA000040100B101200390D4F80C0100B101207C +:10BFB0000290D4F8100100B101203F4D0190287883 +:10BFC00000260090B8F1000F04D0C4F808610120E9 +:10BFD0000BF013F9BAF1000F04D0C4F82461092062 +:10BFE0000BF00BF9B9F1000F04D0C4F81C610A2062 +:10BFF0000BF003F927B1C4F820610B200BF0FDF81A +:10C000002D48C01D0BF0DAF900B1FFDFDFF8AC807E +:10C010000498012780B1C4F80873E87818B1EE706D +:10C0200000200BF0EAF8287A022805D103202872B4 +:10C030000221C8F800102761039808B1C4F8046110 +:10C04000029850B1C4F80C61287A032800D0FFDFB1 +:10C05000C8F800602F72FFF758FE019838B1C4F895 +:10C060001061287A012801D100F05CF8676100981E +:10C0700038B12E70287A012801D1FFF772FEFFF740 +:10C0800044FE0D48C01D0BF0AFF91049091DC1F861 +:10C0900000B005B0BDE8F08F074810B5C01D0BF02B +:10C0A0008DF90549B0B1012008704FF0E021C1F8C9 +:10C0B0000002BDE81040FFE544000020340C0040C1 +:10C0C0000C0400401805004010ED00E0100502408F +:10C0D00001000001087A012801D1FFF742FEBDE806 +:10C0E000104024480BF080B970B5224CE41FA078B2 +:10C0F00008B90BF0A7F801208507A861207A00266F +:10C10000032809D1D5F80C0120B900200BF0C4F8A0 +:10C110000028F7D1C5F80C6126724FF0FF30C5F842 +:10C12000080370BD70B5134CE41F6079F0B10128AD +:10C1300003D0A179401E814218DA0BF090F8054631 +:10C140000BF0A0FA6179012902D9A179491CA171EA +:10C150000DB1216900E0E168411A022902DA11F10A +:10C16000020F06DC0DB1206100E0E060BDE8704028 +:10C17000F7E570BD4B0000200F4A12680D498A4256 +:10C180000CD118470C4A12680A4B9A4206D101B5E5 +:10C190000BF04AFA0BF01DFDBDE8014007490968A4 +:10C1A0000958084706480749054A064B70470000EA +:10C1B00000000000BEBAFECA5C000020040000209F +:10C1C000C8130020C8130020F8B51D46DDE9064756 +:10C1D0000E000AD007F0ADFF2346FF1DBCB231466A +:10C1E0002A46009407F0BBFBF8BDD0192246194639 +:10C1F00002F023F92046F8BD70B50D460446102222 +:10C20000002102F044F9258117206081A07B40F0D5 +:10C210000A00A07370BD4FF6FF720A80014602202B +:10C220000BF04CBC704700897047827BD30701D16B +:10C23000920703D48089088000207047052070474A +:10C24000827B920700D581817047014600200988D2 +:10C2500041F6FE52114200D00120704700B503465E +:10C26000807BC00701D0052000BD59811846FFF72B +:10C27000ECFFC00703D0987B40F004009873987BD4 +:10C2800040F001009873002000BD827B520700D56A +:10C2900009B14089704717207047827B61F3C30260 +:10C2A000827370472DE9FC5F0E460446017896467E +:10C2B000012000FA01F14DF6FF5201EA020962681D +:10C2C0004FF6FF7B1188594502D10920BDE8FC9F3C +:10C2D000B9F1000F05D041F6FE55294201D00120E9 +:10C2E000F4E741EA090111801D0014D000232B70EE +:10C2F00094F800C0052103221F464FF0020ABCF14A +:10C300000E0F76D2DFE80CF0F909252F47646B7722 +:10C31000479193B4D1D80420D8E7616820898B7BFA +:10C320009B0767D517284AD30B89834247D389894E +:10C33000172901D3814242D185F800A0A5F8010058 +:10C340003280616888816068817B21F0020181739D +:10C35000C6E0042028702089A5F801006089A5F8AE +:10C3600003003180BCE0208A3188C01D1FFA80F8AC +:10C37000414524D3062028702089A5F80100608952 +:10C38000A5F80300A089A5F805000721208ACDE9BA +:10C390000001636941E00CF0FF00082810D008207C +:10C3A00028702089A5F801006089A5F80300318074 +:10C3B0006A1D694604F10C0009F025FB10B15EE02E +:10C3C0001020EDE730889DF800100844308087E0A9 +:10C3D0000A2028702089A5F80100328044E00C2052 +:10C3E00028702089A5F801006089A5F80300318034 +:10C3F0003AE082E064E02189338800EB41021FFAD1 +:10C4000082F843453BD3B8F1050F38D30E222A708A +:10C410000BEA4101CDE90010E36860882A467146C5 +:10C42000FFF7D2FEA6F800805AE04020287060890D +:10C430003188C01C1FFA80F8414520D32878714606 +:10C4400020F03F00123028702089A5F80100608993 +:10C45000CDE9000260882A46E368FFF7B5FEA6F83A +:10C460000080287840063BD461682089888037E0C6 +:10C47000A0893288401D1FFA80F8424501D2042766 +:10C480003DE0162028702089A5F801006089A5F8F4 +:10C490000300A089CDE9000160882A46714623691E +:10C4A000FFF792FEA6F80080DEE718202870207AB9 +:10C4B0006870A6F800A013E061680A88920401D4AD +:10C4C00005271CE0C9882289914201D0062716E081 +:10C4D0001E21297030806068018821F4005101809C +:10C4E000B9F1000F0BD061887823002202200BF0F5 +:10C4F0003BFA61682078887006E033800327606823 +:10C50000018821EA090101803846DFE62DE9FF4F65 +:10C5100085B01746129C0D001E461CD03078C1070E +:10C5200003D000F03F00192801D9012100E00021CB +:10C530002046FFF7AAFEA8420DD32088A0F57F4130 +:10C54000FF3908D03078410601D4000605D508200F +:10C5500009B0BDE8F08F0720FAE700208DF8000051 +:10C560008DF8010030786B1E00F03F0C0121A81EF1 +:10C570004FF0050A4FF002094FF0030B9AB2BCF1DD +:10C58000200F75D2DFE80CF08B10745E7468748C29 +:10C59000749C74B574BA74C874D474E1747474F10E +:10C5A00074EF74EE74ED748B052D78D18DF80090D6 +:10C5B000A0788DF804007088ADF8060030798DF809 +:10C5C0000100707800F03F000C2829D00ADCA0F1AF +:10C5D0000200092863D2DFE800F0126215621A62D5 +:10C5E0001D622000122824D004DC0E281BD0102845 +:10C5F000DBD11BE016281FD01828D6D11FE02078E9 +:10C60000800701E020784007002848DAEEE0207833 +:10C610000007F9E72078C006F6E720788006F3E700 +:10C6200020784006F0E720780006EDE72088C00576 +:10C63000EAE720884005E7E720880005E4E720884E +:10C64000C004E1E72078800729D5032D27D18DF894 +:10C6500000B0B6F8010081E0217849071FD5062D0A +:10C660001DD381B27078012803D0022817D102E0CF +:10C67000C9E0022000E0102004228DF8002072782A +:10C680008DF80420801CB1FBF0F2ADF8062092B2C8 +:10C6900042438A4203D10397ADF80890A6E079E0BF +:10C6A0002078000776D598B282088DF800A0ADF802 +:10C6B0000420B0EB820F6DD10297ADF8061095E023 +:10C6C0002178C90666D5022D64D381B206208DF883 +:10C6D0000000707802285DD3B1FBF0F28DF8040001 +:10C6E000ADF8062092B242438A4253D1ADF8089089 +:10C6F0007BE0207880064DD5072003E020784006B7 +:10C700007FD508208DF80000A088ADF80400ADF8B2 +:10C710000620ADF8081068E02078000671D50920E1 +:10C72000ADF804208DF80000ADF8061002975DE02A +:10C730002188C90565D5022D63D381B20A208DF801 +:10C740000000707804285CD3C6E72088400558D5DF +:10C75000012D56D10B208DF80000A088ADF8040003 +:10C7600044E021E026E016E0FFE72088000548D5F8 +:10C77000052D46D30C208DF80000A088ADF80400EC +:10C78000B6F803006D1FADF80850ADF80600ADF81F +:10C790000AA02AE035E02088C00432D5012D30D12E +:10C7A0000D208DF8000021E02088800429D4B6F8FF +:10C7B0000100E080A07B000723D5032D21D3307832 +:10C7C00000F03F001B2818D00F208DF800002088B3 +:10C7D00040F40050A4F80000B6F80100ADF80400E1 +:10C7E000ED1EADF80650ADF808B003976946059800 +:10C7F000F5F792FB050008D016E00E208DF800003A +:10C80000EAE7072510E008250EE0307800F03F0049 +:10C810001B2809D01D2807D0022005990BF04EF9DE +:10C82000208800F400502080A07B400708D52046D7 +:10C83000FFF70BFDC00703D1A07B20F00400A0731D +:10C84000284685E61FB5022806D101208DF8000094 +:10C8500088B26946F5F760FB1FBD0000F8B51D46BC +:10C86000DDE906470E000AD007F063FC2346FF1DF2 +:10C87000BCB231462A46009407F071F8F8BDD019D1 +:10C880002246194601F0D9FD2046F8BD2DE9FF4F9B +:10C890008DB09B46DDE91B57DDF87CA00C46082BCC +:10C8A00005D0E06901F0FEF850B11020D2E02888F0 +:10C8B000092140F0100028808AF80010022617E0B5 +:10C8C000E16901208871E2694FF420519180E169AA +:10C8D0008872E06942F601010181E06900218173FB +:10C8E0002888112140F0200028808AF800100426B2 +:10C8F00038780A900A2038704FF0020904F11800C5 +:10C900004D460C9001F0C6FBB04681E0BBF1100F24 +:10C910000ED1022D0CD0A9EB0800801C80B20221A0 +:10C92000CDE9001005AB52461E990D98FFF796FF12 +:10C93000BDF816101A98814203D9F74800790F9074 +:10C9400004E003D10A9808B138702FE04FF00201DB +:10C95000CDE900190DF1160352461E990D98FFF707 +:10C960007DFF1D980088401B801B83B2C6F1FF002D +:10C97000984200D203461E990BA8D9B15FF000027D +:10C98000DDF878C0CDE9032009EB060189B2CDE9D5 +:10C9900001C10F980090BDF8161000220D9801F00B +:10C9A0000EFC387070B1C0B2832807D0BDF81600F5 +:10C9B00020833AE00AEB09018A19E1E7022011B06D +:10C9C000BDE8F08FBDF82C00811901F0FF08022DA1 +:10C9D0000DD09AF80120424506D1BDF820108142C1 +:10C9E00007D0B8F1FF0F04D09AF801801FE08AF851 +:10C9F0000180C94800680178052902D1BDF81610E8 +:10CA0000818009EB08001FFA80F905EB080085B268 +:10CA1000DDE90C1005AB0F9A01F03FFB28B91D981A +:10CA20000088411B4145BFF671AF022D13D0BBF109 +:10CA3000100F0CD1A9EB0800801C81B20220CDE9B7 +:10CA4000000105AB52461E990D98FFF707FF1D9890 +:10CA50000580002038700020B1E72DE9F8439C469E +:10CA6000089E13460027B26B9AB3491F8CB2F18F10 +:10CA7000A1F57F45FF3D05D05518AD882944891D96 +:10CA80008DB200E000252919B6F83C8008314145F7 +:10CA900020D82A44BCF8011022F8021BBCF803106D +:10CAA00022F8021B984622F8024B914607F02FFB12 +:10CAB0004FF00C0C41464A462346CDF800C006F024 +:10CAC0001AFFF587B16B00202944A41D214408807A +:10CAD00003E001E0092700E083273846BDE8F8833A +:10CAE00010B50B88848F9C420CD9846BE0180488A5 +:10CAF00044B1848824F40044A41D23440B801060B6 +:10CB0000002010BD0A2010BD2DE9F0478AB0002595 +:10CB1000904689468246ADF8185007274BE00598A5 +:10CB200006888088000446D4A8F8006007A801950C +:10CB300000970295CDE903504FF40073002231466F +:10CB4000504601F03CFB04003CD1BDF81800ADF8A4 +:10CB50002000059804888188B44216D10A0414D4B0 +:10CB600001950295039521F400410097049541F445 +:10CB7000804342882146504601F0BFF804000BD1A3 +:10CB80000598818841F40041818005AA08A948469A +:10CB9000FFF7A6FF0400DCD00097059802950195E9 +:10CBA000039504950188BDF81C300022504601F021 +:10CBB000A4F80A2C06D105AA06A94846FFF790FF5B +:10CBC0000400ACD0ADF8185004E00598818821F439 +:10CBD0000041818005AA06A94846FFF781FF002889 +:10CBE000F3D00A2C03D020460AB0BDE8F08700201D +:10CBF000FAE710B50C46896B86B051B10C218DF85F +:10CC00000010A18FADF80810A16B01916946FAF7E9 +:10CC100001FB00204FF6FF71A063E187A08706B0FB +:10CC200010BD2DE9F0410D460746896B0020069E98 +:10CC30001446002911D0012B0FD13246294638461F +:10CC4000FFF762FF002808D1002C06D032462946A3 +:10CC50003846BDE8F04100F034BFBDE8F0812DE971 +:10CC6000FC411446DDE9087C0E46DDE90A15521D3B +:10CC7000BCF800E092B2964502D20720BDE8FC81E4 +:10CC8000ACF8002017222A70A5F80160A5F803303F +:10CC90000522CDE900423B462A46FFF7DFFD002092 +:10CCA000ECE770B50C46154648220021204601F0FD +:10CCB000EEFB04F1080044F81C0F00204FF6FF7152 +:10CCC000E06161842084A5841720E08494F82A0020 +:10CCD00040F00A0084F82A0070BD4FF6FF720A8007 +:10CCE000014603200AF0EABE30B585B00C46054681 +:10CCF000FFF77FFFA18E284629B101218DF8001092 +:10CD00006946FAF787FA0020E0622063606305B0A5 +:10CD100030BDB0F8400070476000002090F8462019 +:10CD2000920703D4408808800020F4E70620F2E749 +:10CD300090F846209207EED5A0F84410EBE70146A4 +:10CD4000002009880A0700D5012011F0F00F01D05A +:10CD500040F00200CA0501D540F004008A0501D563 +:10CD600040F008004A0501D540F010000905D2D571 +:10CD700040F02000CFE700B5034690F84600C0071A +:10CD800001D0062000BDA3F842101846FFF7D7FFD8 +:10CD900010F03E0F05D093F8460040F0040083F8F1 +:10CDA000460013F8460F40F001001870002000BD47 +:10CDB00090F84620520700D511B1B0F84200AAE71A +:10CDC0001720A8E710F8462F61F3C3020270A2E70C +:10CDD0002DE9FF4F9BB00E00DDE92B34DDE929780A +:10CDE000289D24D02878C10703D000F03F001928DF +:10CDF00001D9012100E000212046FFF7D9FFB04210 +:10CE000015D32878410600F03F010CD41E290CD020 +:10CE1000218811F47F6F0AD13A8842B1A1F57F428F +:10CE2000FF3A04D001E0122901D1000602D5042006 +:10CE30001FB0C5E5FA491D984FF0000A08718DF83A +:10CE400018A08DF83CA00FAA0A60ADF81CA0ADF8A0 +:10CE500050A02978994601F03F02701F5B1C04F135 +:10CE6000180C4FF0060E4FF0040BCDF858C01F2AD7 +:10CE70007ED2DFE802F07D7D107D267DAC7DF47DE5 +:10CE8000F37DF27DF17DF47DF07D7D7DEF7DEE7DA6 +:10CE90007D7D7D7DED0094F84610B5F80100890791 +:10CEA00001D5032E02D08DF818B01EE34FF40061B7 +:10CEB000ADF85010608003218DF83C10ADF84000B3 +:10CEC000D4E2052EEFD1B5F801002083ADF81C00A7 +:10CED000B5F80310618308B1884201D9012079E1D6 +:10CEE0000020A07220814FF6FF702084169801F078 +:10CEF000D1F8052089F800000220029083460AAB91 +:10CF00001D9A16991B9801F0C8F890BB9DF82E0049 +:10CF1000012804D0022089F80100102003E001203C +:10CF200089F8010002200590002203A90BA808F04F +:10CF30006AFDE8BB9DF80C00059981423DD1398816 +:10CF4000801CA1EB0B01814237DB02990220CDE965 +:10CF500000010DF12A034A4641461B98FFF77EFC6B +:10CF600002980BF1020B801C81B217AA029101E01A +:10CF70009CE228E003A90BA808F045FD02999DF862 +:10CF80000C00CDE9000117AB4A4641461B98FFF75C +:10CF900065FC9DF80C000AAB0BEB00011FFA81FB4E +:10CFA00002991D9A084480B2029016991B9800E0DD +:10CFB00003E001F072F80028B6D0BBF1020F02D0F6 +:10CFC000A7F800B04FE20A208DF818004BE20021CC +:10CFD0000391072EFFF467AFB5F801002083ADF889 +:10CFE0001C00B5F80320628300283FF477AF90421D +:10CFF0003FF674AF0120A072B5F805002081002033 +:10D00000A073E06900F04EFD78B9E16901208871F4 +:10D01000E2694FF420519180E1698872E16942F63A +:10D0200001000881E06900218173F01F20841E98AF +:10D03000606207206084169801F02CF8072089F8B8 +:10D0400000000120049002900020ADF82A0028E0A2 +:10D0500019E29FE135E1E5E012E2A8E080E043E07B +:10D060000298012814D0E0698079012803D1BDF825 +:10D070002800ADF80E00049803ABCDE900B04A4695 +:10D0800041461B98FFF7EAFB0498001D80B204900C +:10D09000BDF82A00ADF80C00ADF80E00059880B27E +:10D0A00002900AAB1D9A16991B9800F0F6FF28B95A +:10D0B00002983988001D05908142D1D2029801283A +:10D0C00081D0E0698079012803D1BDF82800ADF84E +:10D0D0000E00049803ABCDE900B04A4641461B98C8 +:10D0E000FFF7BCFB0298BDE1072E02D0152E7FF49E +:10D0F000DAAEB5F801102183ADF81C10B5F80320A5 +:10D10000628300293FF4EAAE91423FF6E7AE012187 +:10D11000A1724FF0000BA4F808B084F80EB0052EF1 +:10D1200007D0C0B2691DE26908F06BFC00287FF4EB +:10D130004AAF4FF6FF70208401A906AA14A8CDF8C3 +:10D1400000B081E885032878214600F03F031D9A4E +:10D150001B98FFF79BFB8246208BADF81C0082E1F9 +:10D160000120032EC3D14021ADF85010B5F80110B5 +:10D170002183ADF81C100AAAB8F1000F00D00023DB +:10D18000CDE9020304921D98CDF804800090388800 +:10D190000022401E83B21B9801F011F88DF8180090 +:10D1A00090BB0B2089F80000BDF8280035E04FF057 +:10D1B000010C052E9BD18020ADF85000B5F8011070 +:10D1C0002183B5F803002084ADF81C10B0F5007F72 +:10D1D00003D907208DF8180087E140F47C422284AF +:10D1E0000CA8B8F1000F00D00023CDE90330CDE941 +:10D1F000018C1D9800903888401E83B21B9800F067 +:10D20000DEFF8DF8180018B18328A8D10220BFE0F6 +:10D210000D2189F80010BDF83000401C22E100000B +:10D2200060000020032E04D248067FF53CAE0020AB +:10D2300018E1B5F80110ADF81C102878400602D5A9 +:10D240008DF83CE002E007208DF83C004FF000082C +:10D250000320CDE902081E9BCDF810801D98019394 +:10D26000A6F1030B00901FFA8BF342461B9800F0C7 +:10D2700044FD8DF818008DF83C80297849060DD5BD +:10D280002088C00506D5208BBDF81C10884201D12E +:10D29000C4F8248040468DF81880E3E0832801D14B +:10D2A0004FF0020A4FF48070ADF85000BDF81C003A +:10D2B0002083A4F820B01E986062032060841321AC +:10D2C000CDE0052EFFF4EFADB5F80110ADF81C1060 +:10D2D000A28F6AB3A2F57F43FE3B29D008228DF8C6 +:10D2E0003C2000BF4FF0000B0523CDE9023BDDF8E9 +:10D2F00078C0CDF810B01D9A80B2CDF804C040F4CB +:10D3000000430092B5F803201B9800F0F6FC8DF85E +:10D310003CB04FF400718DF81800ADF85010832820 +:10D3200010D0F8B1A18FA1F57F40FE3807D0DCE026 +:10D330000B228DF83C204FF6FE72A287D2E7A4F8AC +:10D340003CB0D2E000942B4631461E9A1B98FFF762 +:10D3500084FB8DF8180008B183284BD1BDF81C0060 +:10D36000208353E700942B4631461E9A1B98FFF703 +:10D3700074FB8DF81800E8BBE18FA06B0844831D97 +:10D380008DE888034388828801881B98FFF767FC33 +:10D39000824668E095F80180022E70D15FEA0800AD +:10D3A00002D0B8F1010F6AD109208DF83C0007A81E +:10D3B00000908DF840804346002221461B98FFF7DD +:10D3C00030FC8DF842004FF0000B8DF843B050B99F +:10D3D000B8F1010F12D0B8F1000F04D1A18FA1F55F +:10D3E0007F40FF380AD0A08F40B18DF83CB04FF499 +:10D3F000806000E037E0ADF850000DE00FA91B9809 +:10D40000F9F708FF82468DF83CB04FF48060ADF824 +:10D410005000BAF1020F06D0FC480068C07928B16C +:10D420008DF8180027E0A4F8188044E0BAF1000F46 +:10D4300003D081208DF818003DE007A800904346F6 +:10D44000012221461B98FFF7ECFB8DF818002146BE +:10D450001B98FFF7CEFB9DF8180020B9192189F819 +:10D460000010012038809DF83C0020B10FA91B98C6 +:10D47000F9F7D0FE8246BAF1000F33D01BE018E076 +:10D480008DF818E031E02078000712D5012E10D178 +:10D490000A208DF83C00E088ADF8400003201B997D +:10D4A0000AF00CFB0820ADF85000C0E648067FF5F6 +:10D4B000FAAC4FF0040A2088BDF8501008432080D1 +:10D4C000BDF8500080050BD5A18FA1F57F40FE3837 +:10D4D00006D11E98E06228982063A6864FF0030AC2 +:10D4E0005046A5E49DF8180078B1012089F80000A5 +:10D4F000297889F80110BDF81C10A9F802109DF8D0 +:10D50000181089F80410052038802088BDF85010C4 +:10D5100088432080E4E72DE9FF4F8846087895B0DE +:10D52000012181404FF20900249C0140ADF82010F8 +:10D530002088DDF88890A0F57F424FF0000AFF3A7E +:10D5400006D039B1000705D5012019B0BDE8F08F2C +:10D550000820FAE7239E4FF0000B0EA886F800B0D3 +:10D5600018995D460988ADF83410A8498DF81CB0AB +:10D57000179A0A718DF838B0086098F800000128F1 +:10D580003BD0022809D003286FD1307820F03F002B +:10D590001D303070B8F80400E08098F800100320C7 +:10D5A000022904D1317821F03F011B31317094F808 +:10D5B0004610090759D505ABB9F1000F13D000216A +:10D5C00002AA82E80B000720CDE90009BDF834006B +:10D5D000B8F80410C01E83B20022159800F0EFFDC9 +:10D5E0000028D1D101E0F11CEAE7B8F80400A6F860 +:10D5F0000100BDF81400C01C04E198F805108DF876 +:10D600001C1098F80400012806D04FF4007A022874 +:10D610002CD00328B8D16CE12188B8F8080011F4A7 +:10D620000061ADF8201020D017281CD3B4F84010AA +:10D63000814218D3B4F84410172901D3814212D182 +:10D64000317821F03F01C91C3170A6F80100032197 +:10D65000ADF83410A4F8440094F8460020F002001D +:10D6600084F8460065E105257EE177E1208808F130 +:10D67000080700F4FE60ADF8200010F0F00F1BD09A +:10D6800010F0C00F03D03888228B9042EBD199B9AB +:10D69000B878C00710D0B9680720CDE902B1CDF83D +:10D6A00004B00090CDF810B0FB88BA88398815987E +:10D6B00000F023FB0028D6D12398BDF82010401C91 +:10D6C00080294ED006DC10290DD020290BD040290E +:10D6D00087D124E0B1F5807F6ED051457ED0B1F581 +:10D6E000806F97D1DEE0C80601D5082000E0102049 +:10D6F00082460DA907AA0520CDE902218DF8380040 +:10D70000ADF83CB0CDE9049608A93888CDE9000110 +:10D710005346072221461598FFF7B8F8A8E09DF870 +:10D720001C2001214FF00A0A002A9BD105ABB9F158 +:10D73000000F00D00020CDE902100720CDE900093C +:10D74000BDF834000493401E83B2218B002215984B +:10D7500000F035FD8DF81C000B203070BDF8140072 +:10D7600020E09DF81C2001214FF00C0A002A22D154 +:10D7700013ABB9F1000F00D00020CDE90210072053 +:10D78000CDE900090493BDF83400228C401E83B219 +:10D79000218B159800F013FD8DF81C000D203070C2 +:10D7A000BDF84C00401CADF8340005208DF8380061 +:10D7B000208BADF83C00BCE03888218B88427FF498 +:10D7C00052AF9DF81C004FF0120A00281CD1606A6D +:10D7D000A8B1B878C0073FF446AF00E018E0BA68D7 +:10D7E0000720CDE902B2CDF804B00090CDF810B01A +:10D7F000FB88BA88159800F080FA8DF81C00132079 +:10D8000030700120ADF8340093E00000600000208B +:10D810003988208B8142D2D19DF81C004FF0160A26 +:10D820000028A06B08D0E0B34FF6FF7000215F46E0 +:10D83000ADF808B0019027E068B1B978C907BED14A +:10D84000E18F0DAB0844821D03968DE80C024388DE +:10D850008288018809E0B878C007BCD0BA680DABEF +:10D8600003968DE80C02BB88FA881598FFF7F7F944 +:10D8700005005ED0072D72D076E0019005AA02A9BE +:10D880002046FFF72DF90146E28FBDF808008242DD +:10D8900001D00029F1D0E08FA16B084407800198E6 +:10D8A000E08746E09DF81C004FF0180A40B1208B3D +:10D8B000C8B13888208321461598FFF79AF938E0D7 +:10D8C00004F118000090237E012221461598FFF7ED +:10D8D000A8F98DF81C000028EDD119203070012026 +:10D8E000ADF83400E7E7052521461598FFF781F9E3 +:10D8F0003AE0208800F40070ADF8200050452DD1AA +:10D90000A08FA0F57F41FE3901D006252CE0D8F884 +:10D9100008004FF0160A48B1A063B8F80C10A187B0 +:10D920004FF6FF71E187A0F800B002E04FF6FF70FC +:10D93000A087BDF8200030F47F611AD07823002240 +:10D94000032015990AF010F898F80000207120883B +:10D95000BDF82010084320800EE000E00725208855 +:10D96000BDF8201088432080208810F47F6F1CD0E1 +:10D970003AE02188814321809DF8380020B10EA92A +:10D980001598F9F747FC05469DF81C000028EBD0D8 +:10D9900086F801A001203070208B70809DF81C005B +:10D9A00030710520ADF83400DEE7A18EE1B11898A2 +:10D9B0000DAB0088ADF834002398CDE90304CDE920 +:10D9C0000139206B0090E36A179A1598FFF700FA67 +:10D9D000054601208DF838000EA91598F9F71AFCB4 +:10D9E00000B10546A4F834B094F8460040070AD5C3 +:10D9F0002046FFF7A4F910F03E0F04D114F8460FAB +:10DA000020F0040020701898BDF8341001802846DA +:10DA10009BE500B585B0032806D102208DF80000F3 +:10DA200088B26946F9F7F6FB05B000BD10B5384C71 +:10DA30000B782268012B02D0022B2AD111E0137837 +:10DA40000BB1052B01D10423137023688A889A80B7 +:10DA50002268CB88D38022680B8913814989518140 +:10DA60000DE08B8893802268CB88D38022680B8955 +:10DA700013814B8953818B899381096911612168D5 +:10DA8000F9F7C8FB226800210228117003D0002892 +:10DA900000D0812010BD832010BD806B002800D0F5 +:10DAA000012070478178012909D10088B0F5205FF5 +:10DAB00003D042F60101884201D1002070470720BF +:10DAC0007047F0B587B0002415460E460746ADF8FE +:10DAD000184011E005980088288005980194811D60 +:10DAE000CDE902410721049400918388428801888E +:10DAF000384600F002F930B905AA06A93046FEF70B +:10DB0000EFFF0028E6D00A2800D1002007B0F0BDC2 +:10DB10006000002010B58B7883B102789A4205D15D +:10DB20000B885BB102E08B79091D4BB18B789A426F +:10DB3000F9D1B0F801300C88A342F4D1002010BD17 +:10DB4000812010BD072826D012B1012A27D103E079 +:10DB5000497801F0070102E04978C1F3C2010529C3 +:10DB60001DD2DFE801F00318080C12000AB10320EF +:10DB700070470220704704280DD250B10DE00528EF +:10DB800009D2801E022808D303E0062803D0032808 +:10DB900003D005207047002070470F207047812078 +:10DBA0007047C0B282060BD4000607D5FA48807AC7 +:10DBB0004143C01D01EBD00080B27047084670475A +:10DBC0000020704770B513880B800B781C0625D594 +:10DBD000F14CA47A844204D843F01000087000206D +:10DBE00070BD956800F0070605EBD0052D78F5406F +:10DBF00065F304130B701378D17803F0030341EA43 +:10DC0000032140F20123B1FBF3F503FB15119268E8 +:10DC1000E41D00FB012000EBD40070BD906870BDD6 +:10DC200037B51446BDF804101180117841F0040195 +:10DC300011709DF804100A061ED5D74AA368C1F3D7 +:10DC40000011927A824208D8FE2811D1D21DD20842 +:10DC50004942184600F01BFC0AE003EBD00200F03A +:10DC60000703012510789D40A84399400843107090 +:10DC7000207820F0100020703EBD2DE9F0410746CD +:10DC8000C81C0E4620F00300B04202D08620BDE83A +:10DC9000F081C14D002034462E60AF802881AA72E9 +:10DCA000E8801AE0E988491CE980810614D4E1780B +:10DCB00000F0030041EA002040F20121B0FBF1F244 +:10DCC00001FB12012068FFF76CFF2989084480B22C +:10DCD0002881381A3044A0600C3420784107E1D400 +:10DCE0000020D4E7AC4801220189C08800EB400045 +:10DCF00002EB8000084480B270472DE9FF4F89B0E5 +:10DD00001646DDE9168A0F46994623F44045084633 +:10DD100000F054FB040002D02078400703D4012017 +:10DD20000DB0BDE8F08F099806F086F802902078D3 +:10DD3000000606D59848817A0298814201D887204A +:10DD4000EEE7224601A90298FFF73CFF8346002038 +:10DD50008DF80C004046B8F1070F1AD00122214679 +:10DD6000FFF7F0FE0028DBD12078400611D5022015 +:10DD70008DF80C00ADF81070BDF80400ADF812007D +:10DD8000ADF814601898ADF81650CDF81CA0ADF899 +:10DD900018005FEA094004D500252E46A846012751 +:10DDA0000CE02178E07801F0030140EA012040F224 +:10DDB0000121B0FBF1F2804601FB12875FEA494086 +:10DDC00009D5B84507D1A178207901F0030140EACF +:10DDD0000120B04201D3BE4201D90720A0E7A81913 +:10DDE0001FFA80F9B94501D90D2099E79DF80C007B +:10DDF00028B103A90998F9F70BFA002890D1B84582 +:10DE000007D1A0784FEA192161F30100A07084F8CE +:10DE100004901A9800B10580199850EA0A0027D09A +:10DE2000199830B10BEB06002A46199900F005FB52 +:10DE30000EE00BEB06085746189E099806F067F9A6 +:10DE40002B46F61DB5B239464246009505F053FD06 +:10DE5000224601A90298FFF7B5FE9DF8040022466C +:10DE600020F010008DF80400DDE90110FFF7D8FE66 +:10DE7000002055E72DE9FF4FDFF81C91824685B061 +:10DE8000B9F80610D9F8000001EB410100EB81045C +:10DE900040F20120B2FBF0F1174600FB1175DDE9FD +:10DEA000138B4E4629460698FFF77BFE0346FFF785 +:10DEB00019FF1844B1880C30884202D9842009B077 +:10DEC0002FE70698C6B2300603D5B00601D5062066 +:10DED000F5E7B9F80620521C92B2A9F80620BBF16A +:10DEE000000F01D0ABF80020B00602D5C4F80880BE +:10DEF0000AE0B9F808201A4492B2A9F80820D9F823 +:10DF00000000891A0844A0602246FE200699FFF707 +:10DF100087FEE77025712078390A61F301002A0A2B +:10DF2000A17840F0040062F30101A17020709AF81A +:10DF300002006071BAF80000E08000252573300609 +:10DF400002D599F80A7000E00127B00601D54FF01C +:10DF500000084E4600244FF007090FE0CDE90258B3 +:10DF60000195CDF800900495F1882046129B089AFF +:10DF7000FFF7C3FE0028A2D1641CE4B2BC42EDD37B +:10DF800000209CE700B5FFF7ADFE03490C308A88FE +:10DF9000904203D9842000BD00060020CA8808688A +:10DFA00002EB420300EB8300521C037823F00403CE +:10DFB0000370CA80002101730846ECE72DE9F047A1 +:10DFC000804600F0FBF9070005D000264446F74DD7 +:10DFD00040F2012916E00120BDE8F087204600F05C +:10DFE000EDF90278C17802F0030241EA0222B2FBA5 +:10DFF000F9F309FB13210068FFF7D3FD3044641CDB +:10E0000086B2A4B2E988601E8142E7DCA8F1010073 +:10E01000E8802889801B288100203870DCE710B553 +:10E02000144631B1491E218005F006FFA070002082 +:10E0300010BD012010BD70B50446DC48C1880368DE +:10E0400001E0401C20802088884207D200EB40027B +:10E0500013EB820202D015786D07F2D580B28842A8 +:10E0600016D2AAB15079A072D08820819178107907 +:10E0700001F0030140EA0120A081A078E11CFFF734 +:10E08000A1FD20612088401C2080E080002070BD20 +:10E090000A2070BD0121018270472DE9FF4F85B034 +:10E0A0004FF6FF798246A3F8009048681E460D4659 +:10E0B00080788DF8060048680088ADF804000020DC +:10E0C0008DF80A00088A0C88A04200D304462C82EE +:10E0D00051E03878400708D4641C288AA4B2401C58 +:10E0E000288208F10100C0B246E0288A401C28823C +:10E0F000781D6968FFF70EFDD8BB3188494501D10D +:10E10000601E30803188A1EB080030806888A04212 +:10E1100038D3B878397900F0030041EA002801A922 +:10E12000781DFFF7F7FC20BB298949452ED0002236 +:10E1300039460798FFF706FDD8B92989414518D116 +:10E14000E9680391B5F80AC0D7F808B05046CDF891 +:10E1500000C005F0DCFFDDF800C05A460CF1070CEA +:10E160001FFA8CFC43460399CDF800C005F08DFBE7 +:10E1700060B1641CA4B200208046204600F01EF965 +:10E180000700A6D1641E2C820A2098E67480787954 +:10E19000B071F888B0803978F87801F0030140EA6E +:10E1A00001207081A6F80C80504605F045FE3A46E5 +:10E1B00006F10801FFF706FD306100207FE62DE93A +:10E1C000FF4F87B081461C469246DDF860B0DDF80F +:10E1D0005480089800F0F2F8050002D02878400733 +:10E1E00002D401200BB09CE5484605F025FE2978B5 +:10E1F000090605D56D49897A814201D88720F1E762 +:10E20000CAF309062A4601A9FFF7DCFC0746149861 +:10E2100007281CD000222946FFF794FC0028E1D1F2 +:10E220002878400613D501208DF808000898ADF82D +:10E230000C00BDF80400ADF80E00ADF81060ADF8AC +:10E24000124002A94846F8F7E3FF0028CAD129780E +:10E25000E87801F0030140EA0121AA78287902F068 +:10E26000030240EA0220564507D0B1F5007F04D9E9 +:10E27000611E814201DD0B20B4E7864201D90720EF +:10E28000B0E7801B85B2A54200D92546BBF1000F3F +:10E2900001D0ABF80050179818B1B9192A4600F010 +:10E2A000CCF8B8F1000F0DD03E4448464446169FC6 +:10E2B00005F03FFF2146FF1DBCB232462B460094BD +:10E2C00005F04DFB00208DE72DE9F04107461D4686 +:10E2D0001646084600F072F8040002D02078400785 +:10E2E00001D40120D3E4384605F0A6FD21780906C3 +:10E2F00005D52E49897A814201D88720C7E4224674 +:10E300003146FFF75FFC65B12178E07801F0030149 +:10E3100040EA0120B0F5007F01D8012000E0002094 +:10E3200028700020B3E42DE9F04107461D4616464B +:10E33000084600F043F8040002D02078400701D4DA +:10E340000120A4E4384605F077FD2178090605D5BB +:10E350001649897A814201D8872098E422463146BD +:10E36000FFF75EFCFF2D14D02178E07801F0030266 +:10E3700040EA022040F20122B0FBF2F302FB13005C +:10E3800015B900F2012080B2E070000A60F30101CB +:10E39000217000207BE410B50C4600F00FF810B19E +:10E3A0000178490704D4012010BD000000060020B8 +:10E3B000C18821804079A0700020F5E70749CA880C +:10E3C000824209D340B1096800EB40006FF00B02B4 +:10E3D00002EB8000084470470020704700060020D0 +:10E3E00070B504460D4621462B460AB9002070BD83 +:10E3F00001E0491C5B1C501E021E03D008781E78E9 +:10E40000B042F6D008781E78801BF0E730B50C4695 +:10E4100001462346051B954206D202E0521E9D5C32 +:10E420008D54002AFAD107E004E01D780D70491CD4 +:10E430005B1C521E002AF8D130BDF0B50E460146D5 +:10E44000334680EA030404F00304B4B906E002B9D9 +:10E45000F0BD13F8017B01F8017B521E01F00307A8 +:10E46000002FF4D10C461D4602E080CD80C4121F5F +:10E47000042AFAD221462B4600BF04E013F8014BD0 +:10E4800001F8014B521E002AF8D100BFE0E7F0B5B9 +:10E490000C460146E6B204E002B9F0BD01F8016B9A +:10E4A000521E01F00307002FF6D10B46E5B245EAF4 +:10E4B000052545EA054501E020C3121F042AFBD2C9 +:10E4C000194602E001F8016B521E002AFAD100BF82 +:10E4D000E3E7000010B509F0A0FDF4F7F9F909F041 +:10E4E000E7FBBDE8104009F0AFBC302834BF012085 +:10E4F00000207047202834BF4FF0A0420C4A01236F +:10E5000000F01F0003FA00F0002914BFC2F80C0548 +:10E51000C2F808057047202834BF4FF0A0410449D5 +:10E5200000F01F00012202FA00F0C1F81805704740 +:10E530000003005070B50346002002466FF02F051F +:10E540000EE09C5CA4F130060A2E02D34FF0FF309F +:10E5500070BD00EB800005EB4000521C2044D2B29D +:10E560008A42EED370BD30B50A230BE0B0FBF3F462 +:10E5700003FB1404B0FBF3F08D183034521E05F881 +:10E58000014CD2B2002AF1D130BD30B500234FF694 +:10E59000FF7510E0040A44EA002084B2C85C6040C1 +:10E5A000C0F30314604005EA00344440E0B25B1C51 +:10E5B00084EA40109BB29342ECD330BD2DE9F04188 +:10E5C000FE4B0026012793F864501C7893F868C02E +:10E5D000B8B183F89140A3F8921083F8902083F8A3 +:10E5E0008E70BCF1000F0CBF83F8946083F89450D8 +:10E5F000F3488068008805F08AFDBDE8F04105F029 +:10E6000021BA4FF6FF7083F89140A3F8920083F887 +:10E61000902083F88E70BCF1000F14BF83F89450E3 +:10E6200083F89460BDE8F0812DE9F041E44D29685C +:10E6300091F89C200024012A23D091F89620012AE9 +:10E6400030D091F86C301422DC4E0127012B32D0EF +:10E6500091F88E30012B4FD091F8A620012A1CBFD3 +:10E660000020BDE8F08144701F2200F8042B222214 +:10E67000A731FFF7E2FE286880F8A6400120BDE838 +:10E68000F08144701B220270D1F89D204260D1F8C5 +:10E69000A120826091F8A520027381F89C4001209E +:10E6A000BDE8F081447007220270D1F898204260E2 +:10E6B00081F89640E2E78046447000F8042B20225F +:10E6C0006E31FFF7BAFE88F80870286880F86C4051 +:10E6D00090F86E000028D1D1B6F87000A6F8980026 +:10E6E000A868417B86F89A1086F89670008805F035 +:10E6F0000EFD05F0B6F9C1E791F86C30012B0BD097 +:10E70000447017220270D1F890204260B1F8942032 +:10E71000028181F88E40B1E78046447000F8042BF6 +:10E7200020226E31FFF789FE88F80870286880F88B +:10E730006C4090F86E000028A0D1CDE7A04800689A +:10E7400090F86C10002914BFB0F870004FF6FF70FD +:10E75000704770B59A4C06462068002808BFFFDF56 +:10E760000025206845706660002808BFFFDF20682C +:10E77000417800291CBFFFDF70BDCC220021FFF7CC +:10E7800086FE2068FF2101707F2180F83810132158 +:10E790004184282180F86910012180F85C1080F8FC +:10E7A00061500AF0C1F9BDE8704009F0AEBA844981 +:10E7B0000968097881420CBF012000207047804819 +:10E7C000006890F82200C0F3400070477C48006861 +:10E7D00090F8220000F0010070477948006890F836 +:10E7E0002200C0F3001070472DE9F0437448002464 +:10E7F000036893F82400B3F822C0C0F38001C0F38B +:10E800004002114400F001000844CCF3001121B390 +:10E81000BCF1100F02BF6B4931F81000BDE8F08366 +:10E82000BCF1120F18BFBCF1130F0ED0BCF1150FC5 +:10E830001EBFFFDF2046BDE8F0830021624A32F8A8 +:10E84000102010FB0120BDE8F083604A002132F85F +:10E85000102010FB0120BDE8F08393F85E2093F8B0 +:10E860005F102E264FF47A774FF014084FF04009CE +:10E87000022A04BF4AF2D745B5FBF7F510D0012AAA +:10E8800004BF4AF22F75B5FBF7F510D04AF62315F1 +:10E89000B5FBF7F5082A08BF4E4613D0042A18D056 +:10E8A0002646082A0ED0042A13D0022A49D004F1A1 +:10E8B0002806042A0FD0082A1CBF4FF01908082286 +:10E8C00004D00AE04FF0140806F5A8764FF0400295 +:10E8D00003E006F5A8764FF0100218FB026212FB67 +:10E8E0000052C0EB00103A4D00EB800005EB8000B9 +:10E8F00010441CF0010F4FF4C8724FF4BF7504BFF1 +:10E90000CCF34006002E65D0CCF3400600F5A57090 +:10E91000EEB1082904BF174640260CD0042904BFD5 +:10E920002F46102607D0022907BF04F11807042636 +:10E9300004F12807082606EB860808EB86163E44F5 +:10E940001BE004F118064FF019080422C5E7082956 +:10E9500004BF164640270CD0042904BF2E461027BA +:10E9600007D0022907BF04F11806042704F128067E +:10E97000082707EB871706EB8706304400F19C0653 +:10E9800093F8690001F00C07002F08BF0020304405 +:10E9900018BF00F5416027D1082904BF164640275B +:10E9A0001BD0042904BF2E46102716D0022906BF0B +:10E9B00004F11806042704F128060CE00C060020D8 +:10E9C00068000020DC610200E4610200D461020002 +:10E9D000D4FEFFFF64E018BF0827C7EBC70707EBAB +:10E9E000470706EB4706304498301CF0010F17D05C +:10E9F000082908BF40210CD0042904BF2A46102151 +:10EA000007D0022907BF04F11802042104F12802EB +:10EA1000082101EB410303EB0111114408443BE0E1 +:10EA2000082904BF944640260CD0042904BFAC46F4 +:10EA3000102607D0022907BF04F1180C042604F1A0 +:10EA4000280C082606EB8616B3F840300CEB860C33 +:10EA50006044EB2B20D944F2552C0B3303FB0CF311 +:10EA60009B0D082907D0042902D0022905D008E00F +:10EA70002A46102108E0402106E004F11802042192 +:10EA800002E004F12802082101EB811102EB81016F +:10EA900001F5A57103FB010000F5B470BDE8F0833A +:10EAA00000F5A570082904BF944640260CD004291F +:10EAB00004BFAC46102607D0022907BF04F1180C8A +:10EAC000042604F1280C082606EB8616B3F8483015 +:10EAD0000CEB860C6044EB2BDED944F2552C0B3347 +:10EAE00003FB0CF39B0D0829C5D00429C0D00229D3 +:10EAF000C7D1C2E7FE4840F271210068806A4843EE +:10EB00007047FB48006890F83700002818BF0120C4 +:10EB1000704710B5F74C207B022818BF032808D196 +:10EB2000207D04F115010EF0E6FE08281CBF01202F +:10EB300010BD207B002816BF022800200120BDE860 +:10EB400010400AF021BDEB4908737047E849096895 +:10EB500081F8300070472DE9F047E54C2168087BCB +:10EB6000002816BF022800200120487301F10E0181 +:10EB70000AF0F4FC2168087B022816BF0328012252 +:10EB8000002281F82F204FF0080081F82D00487BEB +:10EB900001F10E034FF001064FF00007012804BFFA +:10EBA0005B7913F0C00F0AD001F10E03012804D1E4 +:10EBB000587900F0C000402801D0002000E001207A +:10EBC00081F82E00002A04BF91F8220010F0040FF3 +:10EBD00007D0087D01F115010EF08DFE216881F846 +:10EBE0002D002068476007F0BFFA2168C14D4FF043 +:10EBF0000009886095F82D000EF089FE804695F892 +:10EC00002F00002818BFB8F1000F04D095F82D0090 +:10EC10000EF0B1FC68B195F8300000281CBF95F8E3 +:10EC20002E0000281DD0697B05F10E0001290ED0B1 +:10EC300012E06E734A4605F10E0140460AF0E4FC0C +:10EC400095F82D1005F10E000EF063FF09E04079F4 +:10EC500000F0C000402831D0394605F10E000AF01E +:10EC60000BFD2068C77690F8220010F0040F08BF53 +:10EC7000BDE8F087002795F82D000EF017FD050080 +:10EC800008BFBDE8F087102102F0C2F8002818BFC5 +:10EC9000BDE8F08720683A4600F11C01C676284698 +:10ECA0000AF0B2FC206800F11C0160680FF08EF8D9 +:10ECB0006068BDE8F04701210FF0A3B80EF066FFD1 +:10ECC0004A4605F10E010AF09FFCCAE7884A12681D +:10ECD000137B0370D2F80E000860508A888070475A +:10ECE00078B584490446824E407B087332682078A8 +:10ECF00010706088ADF8000080B200F00101C0F330 +:10ED0000400341EA4301C0F3800341EA8301C0F3B9 +:10ED1000C00341EAC301C0F3001341EA0311C0F389 +:10ED2000401341EA4311C0F3801041EA801050843F +:10ED3000E07D012808BF012507D0022808BF022571 +:10ED400003D0032814BFFFDF0825306880F85E5029 +:10ED5000607E012808BF012507D0022808BF0225D0 +:10ED600003D0032814BFFFDF0825316881F85F5006 +:10ED700091F83500012829D0207B81F82400488CA7 +:10ED80001D280CBF002060688862607D81F8370014 +:10ED9000A07B002816BF0228002001200875D4F8A7 +:10EDA0000F00C1F81500B4F81300A1F81900A07EF7 +:10EDB00091F86B2060F3071281F86B20E07E012848 +:10EDC00018BF002081F83400002078BD91F85E2043 +:10EDD0000420082A08BF81F85E00082D08BF81F8CA +:10EDE0005F00C9E742480068408CC0F3001131B1B0 +:10EDF000C0F38000002804BF1F20704702E0C0F36A +:10EE0000400109B10020704710F0010F14BFEE203F +:10EE1000FF20704736480068408CC0F3001119B1DC +:10EE2000C0F3800028B102E0C0F3400008B1002028 +:10EE30007047012070472E49002209684A664B8CB2 +:10EE40001D2B0CBF81F8682081F8680070470023F3 +:10EE5000274A126882F85D30D164A2F85000012080 +:10EE600082F85D007047224A0023126882F85C3005 +:10EE7000A2F858000120516582F85C0070471C49D7 +:10EE8000096881F8360070471949096881F86100FE +:10EE900070471748006890F961007047144800688F +:10EEA00090F82200C0F3401070471148006890F8B5 +:10EEB0002200C0F3C0007047012070470C48006872 +:10EEC00090F85F00704770B509F018FE09F0F7FD83 +:10EED00009F0C0FC09F06CFD054C2068416E491C2E +:10EEE000416690F83300002558B109F01DFE03E09B +:10EEF000680000200C06002008F007FF206880F85A +:10EF000033502068457090F8391021B1BDE8704049 +:10EF100004200AF0AEBF90F86810D9B1406E81426B +:10EF200018D804200AF0A5FF206890F8220010F0FD +:10EF3000010F07D0A06843220188BDE8704001207E +:10EF4000FFF73CBBBDE8704043224FF6FF71002045 +:10EF5000FFF734BBBDE8704000200AF08ABF2DE9FE +:10EF6000F04782B00F468146FE4E4FF000083068F1 +:10EF7000458C15F0030F10D015F0010F05F00200BD +:10EF800005D0002808BF4FF0010806D004E0002893 +:10EF900018BF4FF0020800D1FFDF4FF0000A5446BF +:10EFA00015F0010F05F002000DD080B915F0040F27 +:10EFB0000DD04AF00800002F1CBF40F0010040F0C7 +:10EFC00002044DD09EE010B115F0040F0DD015F0E5 +:10EFD000070F10D015F0010F05F0020043D00028F4 +:10EFE00008BF15F0040F34D04AE0002F18BF4AF0D4 +:10EFF000090444D141E037B14AF00800044615F055 +:10F00000200F1BD07EE0316805F02002B1F84800E7 +:10F01000104308BF4AF0010474D04AF018000446B7 +:10F0200015F0200F6ED191F85E1011F00C0118BF91 +:10F030000121C94361F30000044663E0316891F89F +:10F040005E1011F00C0118BF012161F300000446AD +:10F0500058E04AF00800002F18BF40F0010451D1D9 +:10F0600040F010044EE0002818BF15F0040F07D040 +:10F07000002F18BF4AF00B0444D14AF0180441E0B5 +:10F0800015F0030F3DD115F0040F3AD077B1306879 +:10F090004AF0080490F85E0010F00C0118BF01213E +:10F0A00061F3410415F0200F24D02BE0306805F007 +:10F0B0002002B0F84810114308BF4AF0030421D0E1 +:10F0C0004AF0180415F0200F0AD000BF90F85E0037 +:10F0D00010F00C0018BF0120C04360F3410411E0A0 +:10F0E00090F85E1011F00C0118BF0121C94361F3C3 +:10F0F0000004EBE710F00C0018BF012060F30004DF +:10F1000000E0FFDF15F0400F1CD0CFB93168B1F837 +:10F110004800002804BF488C10F0010F0BD110F0FC +:10F12000020F08BF10F0200F05D115F0010F08BF26 +:10F1300015F0020F04D091F85E0010F00C0F01D111 +:10F1400044F040047068A0F800A0017821F020018C +:10F1500001704FF007010EF005FE414670680EF099 +:10F16000F8FF214670680FF000F814F0010F0CD082 +:10F170004FF006034FF000027B4970680EF0CFFF9E +:10F180003068417B70680EF02FFE14F0020F18D02B +:10F19000D6E90010B9F1000F4FF006034FF001025D +:10F1A00007D01C310EF0BBFF012170680EF029FE64 +:10F1B00007E015310EF0B3FF3068017D70680EF086 +:10F1C00020FE14F0040F18BFFFDF14F0080F19D051 +:10F1D000CDF800A03068BDF800200223B0F86A1016 +:10F1E00061F30B02ADF8002090F86B0003220109D7 +:10F1F0009DF8010061F307108DF801006946706801 +:10F200000EF08DFF012F62D13068B0F84810E1B3E5 +:10F2100090F82200C0F34000B8BB70680EF095FF74 +:10F22000401CC7B23068C7F1FF05B0F84820B0F8FD +:10F230005A10511AA942B8BF0D46AA423BD990F8BC +:10F24000220010F0010F36D144F0100421467068FE +:10F250000EF08BFFF81CC0B2ED1E284482B230685D +:10F26000B0F86A10436EC1F30B0151FA83F190F8C4 +:10F2700060303E4F1944BC460023E1FB07C31B0925 +:10F280006FF0240C03FB0C1100E020E080F860100C +:10F2900090F85F00012101F01FF90090BDF8000017 +:10F2A0009DF80210032340EA01400190042201A9C5 +:10F2B00070680EF034FF3068AAB2416C70680EF0CE +:10F2C00082FF3068B0F85A102944A0F85A1014F0A0 +:10F2D000400F06D0D6E900100123062261310EF05E +:10F2E0001EFF14F0200F18BFFFDF0020002818BFFA +:10F2F000FFDF02B0BDE8F0872DE9F043194C89B07B +:10F300002068002808BFFFDF20684178002944D129 +:10F310000178FF2941D0002680F83160A0F85A60BA +:10F32000867080F83960304609F062FB104802AD03 +:10F3300000F1240191E80E1085E80E10D0E90D10BF +:10F34000CDE9061002A809F041FB08F0BCFF2068D7 +:10F3500090F9610009F090F8064809F093F8064822 +:10F360000CE00000680000201A06002053E4B36E91 +:10F37000C8610200D0610200CD61020009F012FBF9 +:10F38000606809F038FB206890F8240010F0010F45 +:10F3900007D0252009F07EF80AE009B00C20BDE86E +:10F3A000F08310F0020F18BF262069D009F072F820 +:10F3B000206890F85E10252008F043FF206880F850 +:10F3C0002C6009F00FFB206890F85E10002009F017 +:10F3D00028F90F21052008F0F8FF206890F82E107A +:10F3E000002901BF90F82F10002990F8220010F09A +:10F3F000040F74D006F0B8FE0546206829468068E0 +:10F4000007F0AAFBDFF82884074690FBF8F008FB1A +:10F4100010704142284606F08EFB2168886097FBF9 +:10F42000F8F04A68104448600EF062FA014620681D +:10F43000426891426ED8C0E90165FE4D4FF0010867 +:10F4400095F82D000EF063FA814695F82F000127FC +:10F45000002818BFB9F1000F04D095F82D000EF068 +:10F460008AF8A0B195F8300000281CBF95F82E004E +:10F47000002824D0687B05F10E01012815D019E081 +:10F4800010F0040F14BF2720FFDF8FD190E73A461A +:10F490006F7305F10E0148460AF0B6F895F82D1085 +:10F4A00005F10E000EF035FB09E0487900F0C000D0 +:10F4B000402815D0414605F10E000AF0DDF820681D +:10F4C00090F8220010F0040F24D095F82D000EF0D3 +:10F4D000EDF805001ED0102101F09AFC40B119E0B2 +:10F4E0000EF054FB3A4605F10E010AF08DF8E6E7FE +:10F4F00020683A4600F11C01C77628460AF084F8D5 +:10F50000206800F11C0160680EF060FC0121606859 +:10F510000EF077FC2068417B0E3008F038FF206841 +:10F5200090F85C1061B3B0F85810A0F84810416D25 +:10F53000416490F82210C1F30011F1B9B0F86A00EB +:10F540000221C0F30B05ADF80050684607F0B0FF8C +:10F5500028B1BDF80000C0F30B00A84204D1BDF8EB +:10F560000000401CADF800002168BDF80000B1F8B3 +:10F570006A2060F30B02A1F86A20206880F85C60C2 +:10F58000206890F85D1039B1B0F85010A0F8401024 +:10F59000C16CC16380F85D60B0F86A10426EC1F35F +:10F5A0000B0151FA82F190F86020DFF88CC211440F +:10F5B00063460022E1FB0C3212096FF0240302FBC8 +:10F5C000031180F860100EF00CFA032160680EF051 +:10F5D00090FA216881F8330009B00020BDE8F0837B +:10F5E0009649886070472DE9F043944C83B02268B7 +:10F5F00092F831303BB1508C1D2808BFFFDF03B0BB +:10F60000BDE8F0435FE401260027F1B1054692F81A +:10F61000600008F03FFF206890F85F10FF2008F0BE +:10F6200010FE20684FF4A57190F85F20002009F0CB +:10F63000D4F8206890F8221011F0030F00F02C810C +:10F64000002D00F0238100F027B992F822108046A7 +:10F65000D07EC1F30011002956D0054660680780AE +:10F66000017821F020010170518C132937D01FDC63 +:10F67000102908BF022144D0122908BF062140D01A +:10F68000FFDF6C4D606805F10E010EF091FB697BA8 +:10F6900060680EF0A9FB2068418C1D2918BF152950 +:10F6A00063D0B0F84820416C60680EF0B6FB5CE0B7 +:10F6B000152918BF1D29E3D14FF001010EF052FBAF +:10F6C0006068017841F020010170216885B11C312A +:10F6D0000EF07CFB012160680EF093FBD1E7002166 +:10F6E0000EF040FB6068017841F020010170C8E72E +:10F6F00015310EF06BFB2068017D60680EF081FB18 +:10F70000BFE70EF02FFBBCE70021FFF728FC606885 +:10F71000C17811F03F0F28D0017911F0100F24D0DB +:10F720000EF01EFB2368024693F82410C1F38000FC +:10F73000C1F3400C604401F00101084493F82C101F +:10F74000C1F3800CC1F34005AC4401F001016144F8 +:10F75000401AC1B293F85E0000F0BEFE0090032391 +:10F760000422694660680EF0DAFC2068002590F8F3 +:10F77000241090F82C0021EA000212F0010F18BFAB +:10F7800001250ED111F0020F04D010F0020F08BFB6 +:10F79000022506D011F0040F03D010F0040F08BFAB +:10F7A0000425B8F1000F2BD0012D1BD0022D08BF6E +:10F7B00026201BD0042D14BFFFDF272016D0206881 +:10F7C00090F85E10252008F03CFD206890F822108B +:10F7D000C1F3001169B101224FF49671002008F0C5 +:10F7E000FCFF0DE0252008F055FEE8E708F052FE8A +:10F7F000E5E790F85E204FF49671002008F0EDFFE9 +:10F80000206890F82C10294380F82C1090F82420C0 +:10F8100032EA01011CD04670418C13292BD026DC22 +:10F82000102904BF03B0BDE8F083122923D007E0FC +:10F8300040420F000C06002053E4B36E6800002025 +:10F84000C1F30010002818BFFFDF03B0BDE8F0834C +:10F85000418C1D2908BF80F82C70DCD0C1F3001149 +:10F86000002914BF80F8316080F83170D3E7152982 +:10F8700018BF1D29DBD190F85E2003B04FF00101C5 +:10F88000BDE8F043084609F094B900BF90F85F2046 +:10F890000121084609F08DF92168002DC87E7CD031 +:10F8A0004A8C3D46C2F34000002808BF47F00805D7 +:10F8B00012F0400F18BF45F04005002819BFD1F8DD +:10F8C0003C90B1F84080D1F84490B1F8488060682D +:10F8D000072107800EF046FA002160680EF039FC1F +:10F8E000294660680EF041FC15F0080F17D020681B +:10F8F000BDF800100223B0F86A2062F30B01ADF8E6 +:10F90000001090F86B00032201099DF8010061F3DB +:10F9100007108DF80100694660680EF000FC606811 +:10F920000EF0DCFA2168C0F1FE00B1F85A20A8EB15 +:10F9300002018142A8BF0146CFB2D019404544D24E +:10F9400045F0100160680EF010FC60680EF0C6FA19 +:10F950002168C0F1FE00B1F85A10A8EB0101814204 +:10F96000A8BF0146CFB260680EF0EFFB3844421CDE +:10F970002068B0F86A10436EC1F30B0151FA83F1AD +:10F9800090F86030FE4D1944AC460023E1FB05C3FE +:10F990004FEA131C6FF0240300E03CE00CFB031162 +:10F9A00080F8601090F85F00012100F095FD009054 +:10F9B000BDF800009DF80210032340EA01400190C9 +:10F9C000042201A960680EF0AAFB216891F82200C8 +:10F9D00010F0400F05D001230622613160680EF05F +:10F9E0009EFB20683A46B0F85A0000EB09016068B7 +:10F9F0000EF0E9FB2068B0F85A103944A0F85A100C +:10FA000009F0BFFC002818BFFFDF20684670867031 +:10FA100003B0BDE8F0830121FFF7A1FAF0E7D94870 +:10FA200010B50068417841B90078FF2805D0002161 +:10FA30000846FFF7D8FD002010BD09F05FF809F077 +:10FA40003EF808F007FF08F0B3FF0C2010BD2DE9C9 +:10FA5000F041CC4D0446174628680E4690F86C00DD +:10FA6000002818BFFFDF2868002F80F86E7018BFCD +:10FA7000BDE8F0812188A0F870106188A0F8861098 +:10FA8000A188A0F88810E188A0F88A1094F888115D +:10FA900080F88C1090F82F10002749B1427B00F1BC +:10FAA0000E01012A04D1497901F0C001402935D065 +:10FAB00090F8301041B1427B00F10E01012A04BFE1 +:10FAC000497911F0C00F29D000F17A00F3F794FAC8 +:10FAD0006868FF2E0178C1F380116176D0F80310B9 +:10FAE000C4F81A10B0F80700E08328681ED0C0F8E8 +:10FAF0008010E18BA0F8841000F17402511E304692 +:10FB00000DF014FF002808BFFFDF286890F873107D +:10FB100041F0020180F87310BDE8F081D0F80E10BA +:10FB2000C0F87A10418AA0F87E10D1E7C0F8807042 +:10FB3000A0F88470617E80F87310D4F81A104167C1 +:10FB4000E18BA0F87810BDE8F08170B58D4C0125EF +:10FB5000206890F82200C0F3C00038B13C22FF2199 +:10FB6000A068FFF774FF206880F86C50206890F858 +:10FB7000220010F0010F1CBFA06801884FF03C026A +:10FB800012BF01204FF6FF710020FEF717FD20681D +:10FB900080F8395070BD7B49096881F832007047A0 +:10FBA0002DE9F041774C0026206841780127354641 +:10FBB000012906D0022901D003297DD0FFDFBDE84D +:10FBC000F081817802250029418C46D0C1F34002A2 +:10FBD000002A08BF11F0010F6FD090F85F204FF09E +:10FBE00001014FF0000008F0E4FF216891F82200C5 +:10FBF000C0F34000002814BF0C20222091F85F10B1 +:10FC000008F01FFB2068457090F8330058B108F0E9 +:10FC100068F8206890F85F0010F00C0F0CBF4020CF +:10FC2000452008F077FF206890F83400002818BFBE +:10FC300008F08FFF216891F85F0091F8691010F0CB +:10FC40000C0F08BF0021962008F0F6FE09F090FB8B +:10FC5000002818BFFFDFBDE8F081C1F3001282B1B8 +:10FC600010293FD090F8330020B108F03AF8402036 +:10FC700008F050FF206890F8221011F0040F36D0E1 +:10FC800043E090F8242090F82C309A422AD1B0F822 +:10FC90004800002808BF11F0010F05D111F0020F34 +:10FCA00008BF11F0200F6FD04FF001014FF000009E +:10FCB000FFF799FC206801E041E035E0418C11F04C +:10FCC000010F04BFC1F34001002907D1B0F85A1059 +:10FCD000B0F84820914218BFBDE8F08180F831703B +:10FCE000BDE8F081BDE8F041002101207BE490F8FF +:10FCF0003710012914BF0329102646F00E0190F891 +:10FD00005E204FF0000008F054FF206890F83400A7 +:10FD1000002818BF08F01DFF0021962008F08CFE77 +:10FD200020684570BDE8F081B0F85A10B0F848007E +:10FD3000814242D0BDE8F0410121084653E4817878 +:10FD4000D9B1418C11F0010F22D080F86C7090F87D +:10FD50006E20B0F870100120FEF730FC206845706E +:10FD600008F0CCFE08F0ABFE08F074FD08F020FEB1 +:10FD7000BDE8F04103200AF07CB88178012004E05E +:10FD800053E4B36E6800002017E0BDE8F0412AE4B8 +:10FD900011F0020F04BFFFDFBDE8F081B0F85A1088 +:10FDA000B0F84000814208D001210846FFF71BFC53 +:10FDB000216803204870BDE8F081BDE8F041FFF7FD +:10FDC00082B8FFF780B810B5FE4C206890F8341068 +:10FDD00049B1383008F0CCFE18B921687F2081F88D +:10FDE000380008F0ACFE206890F8330018B108F035 +:10FDF0009BFE07F08AFF0AF02EFCA8B1206890F85D +:10FE00002210C1F3001179B14078022818BFFFDF3A +:10FE100000210120FFF7E7FB2068417800291EBF81 +:10FE200040780128FFDF10BDBDE81040FFF74BB858 +:10FE30002DE9F047E34C0F4680462168B8F1030FE7 +:10FE4000488C08BFC0F3400508D000F0010591F8C8 +:10FE50003200002818BF4FF0010901D14FF000090E +:10FE600008F00CFB0646B8F1030F0CBF4FF0020878 +:10FE70004FF0010835EA090008BFBDE8F0872068A7 +:10FE800090F8330068B10DF08FFD38700146FF28FF +:10FE900007D06068C01C0DF060FD38780DF091FD52 +:10FEA000064360680178C1F3801221680B7D9A4295 +:10FEB00008D10622C01C1531FEF792FA002808BFAF +:10FEC000012000D000203978FF2906D0C8B9206869 +:10FED00090F82D00884216D113E0A0B1616811F8A6 +:10FEE000030BC0F380100DF006FD05460DF061FE1A +:10FEF00038B128460DF0DAFB18B1102100F088FF68 +:10FF000008B1012000E00020216891F8221011F0D2 +:10FF1000040F01D0F0B11AE0CEB9AB4890F8370029 +:10FF2000002818BF404515D1616811F8030BC0F3D4 +:10FF300080100DF0E0FC04460DF03BFE38B1204689 +:10FF40000DF0B4FB18B1102100F062FF10B10120D8 +:10FF5000BDE8F0870020BDE8F0872DE9F04F994D0E +:10FF6000044683B0286800264078022818BFFFDFC7 +:10FF700028684FF07F0B90F8341049B1383008F002 +:10FF8000F7FD002804BF286880F838B008F0D7FDD6 +:10FF900068680DF009FF8046002C00F0458208F0EB +:10FFA00010FA002800F04082012400274FF0FF09DA +:10FFB000B8F1050F1ED1686890F8240000F01F000A +:10FFC000102817D9286890F8360098B18DF800905D +:10FFD00069460520FFF72CFF002800F025822868DD +:10FFE00080F8A64069682222A730C91CFEF725FACE +:10FFF00000F01ABA68680EF062F8002800F0148267 +:020000040001F9 +:100000004046DFF8C4814FF0030A062880F02182C1 +:10001000DFE800F0FCFCFC03FCFB8DF80090694677 +:100020000320FFF705FF002800F0F180296891F810 +:10003000340010B191F89C00D8B12868817801296A +:100040004DD06868042107800DF08CFE08F10E0188 +:1000500068680DF0ADFE98F80D1068680DF0C4FEEC +:100060002868B0F84020C16B68680DF0FAFE00F017 +:1000700063B99DF8000081F89C400A7881F89D20C2 +:10008000FF280FD001F19F029E310DF04FFC002898 +:1000900008BFFFDF286890F89E1041F0020180F849 +:1000A0009E100DE068680278C2F3801281F89E20ED +:1000B000D0F80320C1F89F20B0F80700A1F8A300F2 +:1000C000286800F1A50490F838007F2808BFFFDFFA +:1000D000286890F83810217080F838B0ADE790F8B3 +:1000E00022000721C0F3801938480479686869F351 +:1000F000861407800DF036FE002168680EF029F89E +:10010000214668680EF031F80623002208F10E013E +:1001100068680EF004F82868417B68680DF064FE9A +:1001200068680DF0DBFE2968B1F84020C0F1FE01DF +:100130008A42B8BF1146CFB2BA423CD9F81EC7B204 +:1001400044F0100B594668680EF00FF868680DF01F +:10015000FCFF384400F101082868B0F86A10426ECC +:10016000C1F30B0151FA82F190F86020184C0A4457 +:10017000A4460023E2FB04C319096FF0240301FB2A +:10018000032180F8601090F85F004246012100F0E2 +:10019000A3F90190BDF804009DF80610032340EA7E +:1001A00001400290042202A968680DF0B8FF594688 +:1001B00068680DF0DAFFB9F1000F0FD0D5E9001033 +:1001C000012307E0680000200C060020C86102003F +:1001D00053E4B36E062261310DF0A1FF28683A4660 +:1001E000C16B68680DF0EFFF2868A0F85A70B0F88E +:1001F00040108F420CBF0121002180F8311009F01E +:10020000C0F8002818BFFFDF96E007E021E128686A +:100210008078002840F00A8100F006B98DF800903F +:1002200068680178C1F38019D0F803100191B0F823 +:100230000700ADF8080069460520FFF7F9FD002822 +:1002400028687DD0817800297CD090F85FB0D5E90E +:100250000104D0F80F10C4F80E10B0F8131061822A +:10026000417D2175817D6175B0F81710E182B0F88C +:1002700019106180B0F81B10A180B0F81D10E1804A +:1002800000F11F0104F1080015F085FE686890F880 +:10029000241001F01F01217690F82400400984F811 +:1002A000880184F864B084F865B01BF00C0F0CBFB3 +:1002B0000021012104F130000EF0ABF92868002282 +:1002C00090F8691084F8661090F8610084F867006F +:1002D0009DF80010A868FFF7BAFB022009F0C9FDDD +:1002E000B2480DF1040B08210468686807800DF01E +:1002F00039FD002168680DF02CFF214668680DF07B +:1003000034FF0623002208F10E0168680DF007FF94 +:100310002868417B68680DF067FD494668680DF004 +:1003200070FD06230122594668680DF0F8FE09F0B9 +:1003300028F8002818BFFFDF286880F801A077E0C0 +:100340006DE0FFE76868D5F808804FF00109027892 +:1003500098F80D10C2F34012114088F80D10D0F833 +:100360000F10C8F80E10B0F81310A8F81210417D45 +:1003700088F81410817D88F81510B0F81710A8F8C7 +:100380001610B0F81910A8F80210B0F81B10A8F851 +:100390000410B0F81D10A8F8061000F11F0108F1B4 +:1003A000080015F0F8FD686890F8241001F01F01AE +:1003B00088F8181090F824000021400988F8880176 +:1003C00088F8649088F8659008F130000EF021F903 +:1003D0002868002290F8691088F8661090F861008B +:1003E00088F867009DF80010A868FFF730FB2868C0 +:1003F00080F86C4090F86E20B0F870100120FEF785 +:10040000DDF82868477008F079FB08F058FB08F021 +:1004100021FA08F0CDFA012009F02BFD08E090F850 +:100420002200C0F3001008B1012601E0FEF74BFDE9 +:10043000286890F8330018B108F076FB07F065FCE7 +:1004400096B10AF008F960B100210120FFF7CBF85E +:1004500013E0286890F82200C0F300100028E5D0CF +:10046000E2E7FEF730FD08E028688178012904D131 +:1004700090F85F10FF2007F0E4FE2868417800291B +:1004800019BF4178012903B0BDE8F08F40780328F7 +:1004900018BFFFDF03B0BDE8F08F70B5444C0646CF +:1004A0000D462068807858B107F0F2FD21680346B8 +:1004B000304691F85F202946BDE870400AF085BAC1 +:1004C00007F0E6FD21680346304691F85E20294694 +:1004D000BDE870400AF079BA78B50C460021009169 +:1004E000082804BF4FF4C87040210DD0042804BF71 +:1004F0004FF4BF70102107D0022807BF01F1180088 +:10050000042101F128000821521D02FB01062848A0 +:100510009DF80010006890F8602062F3050141F03A +:1005200040058DF8005090F85F00012829D002287E +:100530002ED004281CBF0828FFDF2FD025F0800014 +:100540008DF80000C4EB041000EB80004FF01E019A +:1005500001EB800006FB04041648844228BFFFDF3D +:100560001548A0FB0410BDF80110000960F30C0150 +:10057000ADF80110BDF800009DF8021040EA0140FE +:1005800078BD9DF8020020F0E0008DF80200D5E76C +:100590009DF8020020F0E000203004E09DF8020009 +:1005A00020F0E00040308DF80200C7E7C86102008B +:1005B00068000020C4BF0300898888880023C383A3 +:1005C000428401EBC202521EB2FBF1F1018470477A +:1005D0002DE9F04104460026D9B3552333224FF4C8 +:1005E000FA4501297DD0022900F01481032918BFA2 +:1005F000BDE8F08104F17001207B00F01F00207342 +:1006000084F889605FF0000004EB000C9CF808C0DF +:1006100003EA5C05ACEB050C0CF0FF0C0CF03305A9 +:1006200002EA9C0CAC440D180CEB1C1C0CF00F0CDB +:1006300085F814C04D7E401CAC44C0B281F819C08E +:100640000528E1D30CF0FF00252898BFBDE8F08114 +:10065000DCE0FFE704F17005802200212846FDF769 +:1006600016FFAE71EE712E736E73EE732E746E7193 +:10067000AE76EE76212085F84000492085F84100CD +:10068000FE2085F874002588702200212046FDF7A1 +:10069000FEFE2580012584F8645084F865502820EA +:1006A00084F86600002104F130000DF0B2FF1B2237 +:1006B000A4F84E20A4F85020A4F85220A4F8542006 +:1006C0004FF4A470A4F85600A4F8580065734FF4D2 +:1006D00048606080A4F8F060A4F8F260A4F8F460C8 +:1006E00000E023E0A4F8F660A4F8F86084F8FA606B +:1006F00084F8FD60A4F8066184F80461A4F8186128 +:10070000A4F81A6184F8B66184F8B76184F8C0610E +:1007100084F8C16184F88C6184F88F6184F8A861E1 +:10072000C4F8A061C4F8A461BDE8F081A4F8066132 +:1007300084F8FB606088FE490144B1FBF0F1A4F845 +:1007400090104BF68031A4F89210B4F806C0A4F8CB +:100750009860B4F89C704FEACC0C4743BCFBF0FCAB +:1007600097FBF0F70CF1010CA4F89C701FFA8CFCBD +:100770000CFB00F704F17001A4F89AC0B7F5C84F5C +:10078000C4BFACF1010CA1F82AC0B5FBF0FC0CF120 +:10079000010CA1F830C000F5802C0CF5EE3CACF15A +:1007A0000105B5FBF0FCA1F820C0CD8B05FB00FCDA +:1007B000BCFBF0F0C8830846217B01F01F012173C8 +:1007C0004676002104EB010C9CF808C003EA5C05A6 +:1007D000ACEB050C0CF0FF0C0CF0330502EA9C0CA2 +:1007E000AC4445180CEB1C1C0CF00F0C85F814C025 +:1007F000457E491CAC44C9B280F819C00529E1D333 +:100800000CF0FF00252898BFBDE8F081FFDFBDE8B0 +:10081000F08100BFB4F8B011B4F8B4316288A4F824 +:100820009860B4F89CC0DB000CFB02FCB3FBF1F356 +:100830009CFBF1FC5B1CA4F89CC09BB203FB01FC7D +:1008400004F17000A4F89A30BCF5C84FC4BF5B1E19 +:100850004385B5FBF1F35B1C0386438C01EBC303BB +:100860005B1EB3FBF1F30384C38B5A43B2FBF1F17C +:10087000C183BDE8F0812DE9F04104460025A1B314 +:1008800055234FF4FA464FF0330C01297DD002294D +:1008900000F0E080032918BFBDE8F08104F170008A +:1008A000217B01F01F01217384F889500021621817 +:1008B000127A03EA5205521BD2B202F033050CEA57 +:1008C00092022A44451802EB121202F00F022A7516 +:1008D000457E491C2A44C9B242760529E7D3D0B2E5 +:1008E000252898BFBDE8F081B1E0FFE704F170066C +:1008F000802200213046FDF7CAFDB571F5713573D0 +:100900007573F57335747571B576F576212086F8B3 +:100910004000492086F84100FE2086F874002688B1 +:10092000702200212046FDF7B2FD2680012684F8C2 +:10093000646084F86560282084F86600002104F172 +:1009400030000DF066FE1B22A4F84E20A4F85020C3 +:10095000A4F85220A4F854204FF4A470A4F8560030 +:10096000A4F858006673A4F8F850202084F8FA0020 +:1009700084F8F050C4F8F45084F8245184F82551D8 +:1009800084F82E5184F82F5100E005E084F81451CA +:1009900084F82051BDE8F081618865480844B0FBC7 +:1009A000F1F0A4F890004BF68030A4F89200E288B1 +:1009B000A4F89850B4F89C70D2004F43B2FBF1F207 +:1009C00097FBF1F7521CA4F89C7092B202FB01F75E +:1009D00004F17000A4F89A20B7F5C84FC4BF521EA6 +:1009E0004285B6FBF1F2521C028601F5802202F527 +:1009F000EE32561EB6FBF1F20284C68B06FB01F204 +:100A0000B2FBF1F1C1830146207B00F01F0020738F +:100A10004D7600202218127A03EA5205521BD2B2F8 +:100A200002F033050CEA92022A440D1802EB12126E +:100A300002F00F022A754D7E401C2A44C0B24A764D +:100A40000528E7D3D0B2252898BFBDE8F081FFDFA5 +:100A5000BDE8F081D0F81811628804F1700348896C +:100A6000C989A4F89850B4F89CC0C9000CFB02FCDA +:100A7000B1FBF0F19CFBF0FC491CA4F89CC089B2CE +:100A800001FB00FCA4F89A10BCF5C84FC4BF491E76 +:100A90005985B6FBF0F1491C1986598C00EBC10150 +:100AA000491EB1FBF0F11984D98B5143B1FBF0F031 +:100AB000D883BDE8F0812DE9F003447E0CB1252CEC +:100AC00003D9BDE8F00312207047002A02BF0020BE +:100AD000BDE8F003704791F80DC01F260123154DA6 +:100AE0004FF00008BCF1000F7AD0BCF1010F1EBF1F +:100AF0001F20BDE8F0037047B0F800C00A7C8F7B70 +:100B000091F80F907A404F7C87EA090742EA072262 +:100B100082EA0C0C5FF000070CF0FF0999FAA9F9C2 +:100B20004FEA1C2C4FEA19699CFAACFC04E0000067 +:100B3000FFDB050053E4B36E4FEA1C6C49EA0C2C52 +:100B40000CEB0C1C7F1C9444FFB21FFA8CFC032F8F +:100B5000E2D38CEA020CFB4F0022ECFB0572120977 +:100B60006FF0240502FB05C2D2B201EBD2078276F8 +:100B700002F007053F7A03FA05F52F4218BFC27647 +:100B80007ED104FB0CF2120C521CD2B25FF00004B6 +:100B900000EB040C9CF814C094453CBFA2EB0C0283 +:100BA000D2B212D30D194FF0000C2D7A03FA0CF7C4 +:100BB0003D421CBF521ED2B2002A69D00CF1010C7A +:100BC0000CF0FF0CBCF1080FF0D304F1010C0CF099 +:100BD000FF04052CDCD33046BDE8F0037047FFE787 +:100BE00090F81AC00C7E474604FB02C2D54C4FF069 +:100BF000000CE2FB054C4FEA1C1C6FF024040CFBBC +:100C00000422D2B201EBD204827602F0070C247ADD +:100C100003FA0CFC14EA0C0F1FBFC2764046BDE875 +:100C2000F003704790F819C0B2FBFCF40CFB1422DF +:100C3000521CD2B25FF0000400EB040C9CF814C00C +:100C400094453CBFA2EB0C02D2B212D30D194FF067 +:100C5000000C2D7A03FA0CF815EA080F1CBF521E7F +:100C6000D2B272B10CF1010C0CF0FF0CBCF1080F08 +:100C7000F0D304F1010C0CF0FF04052CDCD3AAE73F +:100C800009E00CEBC401C1763846BDE8F0037047BB +:100C90000CEBC401C1764046BDE8F0037047AA4A98 +:100CA000016812681140A94A126811430160704737 +:100CB00030B4A749A44B00244FF0010C0A78521C11 +:100CC000D2B20A70202A08BF0C700D781A680CFA8C +:100CD00005F52A42F2D0097802680CFA01F1514078 +:100CE000016030BC704770B46FF01F02010C02EA63 +:100CF00090251F23A1F5AA4054381CBFA1F5AA4096 +:100D0000B0F1550009D0A1F52850AA381EBFA1F5B1 +:100D10002A40B0F1AA00012000D100204FF0000CC1 +:100D2000624601248CEA0106F6431643B6F1FF3F02 +:100D300011D005F001064FEA5C0C4CEAC63C03F00A +:100D4000010652086D085B08641C42EAC632162C84 +:100D5000E8DD70BC704770BC0020704790F804C09C +:100D60003CF01F011CBF0020704730B401785522B1 +:100D700002EA5103C91AC9B201F03304332303EA6A +:100D800091012144447801EB111102EA5405641BDE +:100D9000E4B204F0330503EA94042C4404EB141485 +:100DA00001F00F0104F00F040C448178C07802EACE +:100DB0005105491BC9B201F0330503EA91012944E9 +:100DC00001EB111101F00F01214402EA5004001B54 +:100DD000C0B200F0330403EA9000204400EB10108E +:100DE00000F00F00014402EA5C00ACEB0000C0B26E +:100DF00000F0330203EA9000104400EB101000F002 +:100E00000F00084401288CBF0120002030BC70472F +:100E10000A000ED00123012A0BDB491EC9B210F8CB +:100E200001C0BCF1000F01D0002070475B1C934251 +:100E3000F3DD01207047002A08BF70471144401EAF +:100E400012F0010F03D011F8013D00F8013F5208E4 +:100E500008BF704711F8013C437011F8023D00F8DB +:100E6000023F521EF6D1704770B58CB000F11004ED +:100E70001D4616460DF1FF3C5FF0080014F8012CEA +:100E80008CF8012014F8022D0CF8022F401EF5D129 +:100E900001F1100C6C460DF10F0108201CF8012C1B +:100EA0004A701CF8022D01F8022F401EF6D1204690 +:100EB00013F01CFB7EB16A1E04F130005FF00801E4 +:100EC00010F8013C537010F8023D02F8023F491E31 +:100ED000F6D10CB070BD08982860099868600A982F +:100EE000A8600B98E8600CB070BD38B505460C469C +:100EF000684607F03DFE002808BF38BD9DF9002078 +:100F00002272E07E607294F90A100020511A48BFE4 +:100F1000494295F82D308B42C8BF38BDFF2B08BF22 +:100F200038BDE17A491CC9B2E17295F82E30994278 +:100F300003D8A17A7F2918BF38BDA2720020E072C1 +:100F4000012038BD53E4B36E04620200086202005F +:100F5000740000200C2818BF0B2810D00D2818BFD3 +:100F60001F280CD0202818BF212808D0222818BFFD +:100F7000232804D024281EBF2628002070474FF0C5 +:100F8000010070470C2963D2DFE801F006090E1357 +:100F9000161B323C415C484E002A5BD058E0072AC1 +:100FA00018BF082A56D053E00C2A18BF0B2A51D07C +:100FB0004EE00D2A4ED04BE0A2F10F000C2849D98B +:100FC00046E023B1A2F110000B2843D940E0122AD9 +:100FD00018BF112A3ED090F8380020B1122A37D31A +:100FE0001A2A37D934E0162A32D31A2A32D92FE0F6 +:100FF000A2F10F0103292DD990F8380008B31B2A5C +:1010000028D925E0002B08BF042A21D122E013B102 +:10101000062A1FD01CE0012A1AD11BE01C2A1CBF83 +:101020001D2A1E2A16D013E01F2A18BF202A11D00D +:10103000212A18BF222A0DD0232A1CBF242A262A9F +:1010400008D005E013B10E2A04D001E0052A01D032 +:1010500000207047012070472DE9F0410D460446FD +:10106000866805F02FFA58B905F07EF840F236711F +:1010700004F061FDA060204605F024FA0028F3D0BA +:1010800095B13046A16805F067FD00280CDD2844C5 +:10109000401EB0FBF5F707FB05F1304604F04BFDB1 +:1010A000A0603846BDE8F0810020BDE8F08170B551 +:1010B0000446904228BF70BD101B64280BD325182E +:1010C0008D4206D8042105F07AFD00281CBF284671 +:1010D00070BD204670BD6420F1E711F00C0F13D0F5 +:1010E00001F0040100290DBF4022102296214FF487 +:1010F000167101F5BC71A0EB010388428CBF93FB14 +:10110000F2F0002080B27047022919BF6FF00D0184 +:1011100001EBD0006FF00E0101EB9000F2E7084404 +:1011200018449830002A14BF042100210844704755 +:1011300010B4002A14BF4FF429624FF4A472002B9C +:1011400019BF4FF429634FF0080C4FF4A4734FF00C +:10115000010C00280CBF0124002491F866001CF04B +:101160000C0F08BF0020D11808449830002C14BF81 +:1011700004210021084410BC704700280CBF012343 +:10118000002391F86600002BA0F6482000F50050DF +:1011900018BF04231844496A81422CBF0120002053 +:1011A00012F00C0118BF012131EA000014BF002029 +:1011B0000120704710B413680B66137813F00C030A +:1011C00018BF0123527812F00C0218BF012253EA13 +:1011D000020C04BF10BC7047002B0CBF4FF4A4736B +:1011E0004FF42963002A19BF4FF429624FF0080C0D +:1011F0004FF4A4724FF0010C00280CBF012400240E +:1012000091F866001CF00C0F08BF00201A4410442F +:101210009830002C14BF0422002210444A6A8242F3 +:1012200024BF10BC704791F860004FF0030230F00B +:101230000C0381F8603091F8610020F00C0081F817 +:10124000610008BF81F86020002808BF81F8612094 +:1012500010BC704710F0010F1CBF0120704710F048 +:10126000020F1CBF0220704710F0040018BF0820B6 +:1012700070472DE9F0470446174689464FF00108AC +:1012800008460DF0FAF8054648460DF0FAF810F059 +:10129000010F18BF012624D015F0010F18BF01233C +:1012A0002AD000BF56EA030108BF4FF0000810F033 +:1012B000070F08BF002615F0070F08BF002394F89A +:1012C0006400B0420CBF00203046387094F86510BE +:1012D000994208BF00237B70002808BF002B25D14E +:1012E00015E010F0020F18BF0226D5D110F0040F40 +:1012F00014BF08260026CFE715F0020F18BF0223FF +:10130000D0D115F0040F14BF08230023CAE74846C4 +:101310000DF0BDF8B4F87010401A00B247F6FE7137 +:10132000884201DC002801DC4FF0000816B1082ECD +:101330000CD018E094F86400012818BF022812D0DD +:1013400004281EBF0828FFDF032D0CD194F8C0012C +:1013500048B1B4F8C401012894F8640006D0082804 +:1013600001D0082038704046BDE8F087042818BF37 +:101370000420F7D1F5E7012814BF0228704710F0C8 +:101380000C0018BF0420704738B4CBB2C1F3072C4F +:10139000C1B2C0F30724012B07D0022B09D0042BC4 +:1013A00008BFBCF1040F2DD006E0BCF1010F03D142 +:1013B00028E0BCF1020F25D0012906D0022907D070 +:1013C000042908BF042C1DD004E0012C02D119E02F +:1013D000022C17D001EA0C0161F3070204EA0301B1 +:1013E00061F30F22D1B211F0020F18BF022310D007 +:1013F000C2F307218DF8003011F0020F18BF02214F +:101400001BD111E0214003EA0C03194061F30702EC +:10141000E6E711F0010F18BF0123E9D111F0040F25 +:1014200014BF08230023E3E711F0010F18BF0121C7 +:1014300003D111F0040118BF08218DF80110082B09 +:1014400001BF000C012804208DF80000BDF8000049 +:1014500038BC70474FF0000C082902D0042909D08D +:1014600011E001280FD10420907082F803C013808E +:1014700001207047012806D00820907082F803C030 +:1014800013800120704700207047162A10D12A22AD +:101490000C2818BF0D280FD04FF0230C1F280DD09B +:1014A00031B10878012818BF002805D0162805D0CA +:1014B00000207047012070471A70FBE783F800C0D6 +:1014C000F8E7012908D002290BD0042912BF082906 +:1014D00040F6A660704707E0002804BF40F2E240F3 +:1014E000704740F6C410704700B5FFDF40F2E2409D +:1014F00000BD00000178406829B190F82C1190F8E7 +:101500008C0038B901E001F0BDBD19B1042901D04A +:10151000012070470020704770B50C460546062133 +:1015200002F0C4FC606008B1002006E007212846F4 +:1015300002F0BCFC606018B101202070002070BD7A +:10154000022070BD2DE9FC470C4606466946FFF7B0 +:10155000E3FF00287DD19DF8000050B1FDF7EEF8C3 +:10156000B0427CD0214630460AF008FC002873D1F6 +:101570002DE00DF097F9B04271D02146304612F0BF +:10158000B6FA002868D1019D95F8F00022E001200C +:1015900000E00020804695F839004FF0010A4FF036 +:1015A0000009F0B195F83A0080071AD584F8019047 +:1015B00084F800A084F80490E68095F83B1021722E +:1015C000A98F6181E98FA18185F8399044E0019D5F +:1015D00095F82C0170350028DBD1287F0028D8D061 +:1015E000D5E7304602F0A5FD070000D1FFDF384601 +:1015F00001F0B5FF40B184F801900F212170E68021 +:10160000208184F804A027E0304602F080FD070026 +:1016100000D1FFDFB8F1000F21D0384601F0F7FF0D +:10162000B8B19DF8000038B90198D0F81801418888 +:10163000B14201D180F80090304607F00DFF84F8E8 +:1016400001900C21217084F80490E680697F21725A +:1016500000E004E085F81C900120BDE8FC87002034 +:10166000FBE71CB56946FFF757FF00B1FFDF68468F +:1016700001F014FDFE4900208968A1F8F2001CBDAC +:101680002DE9FC4104460E46062002F0B7FB054654 +:10169000072002F0B3FB2844C7B20025A8463E4409 +:1016A00017E02088401C80B22080B04202D3404620 +:1016B000A4F8008080B2B84204D3B04202D2002025 +:1016C000BDE8FC816946FFF727FF0028F8D06D1CB4 +:1016D000EDB2AE42E5D84FF6FF7020801220EFE762 +:1016E00038B54FF6FF70ADF800000DE00621BDF8EB +:1016F000000002F0EDFB04460721BDF8000002F0F7 +:10170000E7FB0CB100B1FFDF00216846FFF7B8FF2F +:101710000028EBD038BD70B507F00CFF0BF034FF9C +:10172000D44C4FF6FF76002526836683D2A0257021 +:1017300001680079A4F14002657042F8421FA11CC3 +:101740001071601C12F0EFFA1B2020814FF4A4717D +:101750006181A081E18107212177617703212174D3 +:10176000042262746082A082A4F13E00E1820570CE +:101770004680BF480C300570A4F11000057046800B +:1017800084F8205070BD70B5B94C16460D466060A7 +:10179000217007F047FEFFF7A3FFFFF7BCFF20789B +:1017A0000FF0BDFFB6480DF0D0F92178606812F057 +:1017B0005FFA20780BF0DCF8284608F0AFFEB0485E +:1017C000FCF7C7FF217860680AF0B2FB3146207849 +:1017D00012F024FDBDE870400BF0D6BE10B5012418 +:1017E0000AB1002010BD21B1012903D000242046F8 +:1017F00010BD02210CF024FDF9E710B50378044672 +:10180000002B406813460A46014609D05FF00100EC +:10181000FFF78EFC6168496A884203D9012010BD38 +:101820000020F5E7002010BD2DE9F04117468A7829 +:101830001E46804642B11546C87838B1044669074D +:1018400006D52AB1012104E00725F5E70724F6E7CC +:101850000021620702D508B1012000E0002001420A +:1018600006D0012211464046FFF7C7FF98B93DE078 +:1018700051B1002201214046FFF7BFFF58B9600770 +:1018800034D50122114620E060B1012200214046FA +:10189000FFF7B3FF10B10920BDE8F081680725D537 +:1018A000012206E068074FEA44700AD5002814DBDD +:1018B000002201214046FFF7A0FFB8B125F0040542 +:1018C00014E0002812DA012200214046FFF795FFBC +:1018D00060B100BF24F0040408E001221146404634 +:1018E000FFF78BFF10B125F00405F3E73D7034706E +:1018F0000020D1E770B58AB0044600886946FFF73A +:101900000BFE002806D1A08830B1012804D002289F +:1019100002D012200AB070BD04AB03AA214668466B +:10192000FFF782FF0500F5D19DF800100120002689 +:101930000029019906D081F8C101019991F80C1292 +:10194000B1BB2DE081F82F01019991F8561139B9F9 +:10195000019991F82E1119B9019991F8971009B1CF +:101960003A2519E00199059681F82E01019A9DF812 +:101970000C0082F83001019B9DF8102083F8312182 +:10198000A388019CA4F832318DF814008DF815203D +:1019900005AA0020FFF70EFC019880F82F6126E0D1 +:1019A000019991F8C01119B9019991F8971009B1ED +:1019B0003A2519E00199059681F8C00101989DF832 +:1019C0000C2080F8C221019B9DF8100083F8C30110 +:1019D000A388019CA4F8C4318DF814208DF815005B +:1019E00005AA0120FFF7E6FB019880F8C1612846AF +:1019F00090E710B504460020A17801B90120E278F3 +:101A00000AB940F0020001F058FB002803D120463B +:101A1000BDE810406EE710BD70B5044691F8650052 +:101A200091F866300D4610F00C0F00D1002321898B +:101A3000A088FFF774FB696A814229D2401A401CD2 +:101A4000A1884008091A8AB2A2802189081A208137 +:101A5000668895F864101046FFF73FFB864200D277 +:101A600030466080E68895F8651020890AE000001D +:101A70007800002018080020FFFFFFFF1F00000073 +:101A8000D8060020FFF729FB864200D23046E080CE +:101A900070BDF0B585B00D46064603A9FFF73CFDC5 +:101AA00000282DD19DF80C0060B300220499FB2082 +:101AB000B1F84E30FB2B00D30346B1F85040FB2069 +:101AC000FB2C00D30446DFF85CC59CE88110009035 +:101AD0000197CDF808C0ADF80230ADF80640684671 +:101AE000FFF79AFF6E80BDF80400E880BDF808009B +:101AF0006881BDF80200A880BDF80600288100209A +:101B000005B0F0BD0122D1E72DE9F04186B00446D1 +:101B100000886946FFF700FD002876D12189E0881A +:101B200001F0E4FA002870D1A188608801F0DEFAA3 +:101B300000286AD12189E08801F0CFFA002864D119 +:101B4000A188608801F0C9FA07005ED1208802A947 +:101B5000FFF79FFF00B1FFDFBDF81010628809207A +:101B6000914252D3BDF80C10E28891424DD3BDF89A +:101B70001210BDF80E2023891144A2881A44914204 +:101B800043D39DF80010019D4FF00008012640F658 +:101B9000480041B185F8B761019991F8F81105F550 +:101BA000DB7541B91AE085F82561019991F84A1170 +:101BB00005F5927509B13A2724E0E18869806188CA +:101BC000E9802189814200D30146A980A188814210 +:101BD00000D208462881012201990FE0E18869803E +:101BE0006188E9802189814200D30146A980A188CA +:101BF000814200D208462881019900222846FFF739 +:101C00000BFF2E7085F80180384606B044E67BE76E +:101C100070B504460CF0FCFDB0B12078182811D145 +:101C2000207901280ED1E088062102F03FF9040056 +:101C300008D0208807F010FC2088062102F048F91F +:101C400000B1FFDF012070BDF74D28780028FAD0E1 +:101C5000002666701420207020223146201DFCF7DB +:101C600016FC022020712E70ECE710B50446FCF73C +:101C7000DBFC002813D0207817280FD1207968B119 +:101C8000E088072102F012F940B1008807F0E4FB78 +:101C9000E088072102F01CF900B1FFDF012010BD30 +:101CA0002DE9F0475FEA000800D1FFDFDE4802219E +:101CB0001A308146FFF7E4FC00B1FFDFDA4C062062 +:101CC000678B02F09BF80546072002F097F828443E +:101CD000C5B2681CC6B2608BB04203D14046FFF764 +:101CE000C4FF58B9608BA84203D14046FFF790FF6C +:101CF00020B9608B4146FFF725FC38B1404601F022 +:101D000003FA0028E7D10120BDE8F0870221484608 +:101D1000FFF7B6FC10B9608BB842DCD14046BDE895 +:101D2000F04712F0C1BA10B501F053F908B10C2018 +:101D300010BD0BF07DFC002010BD10B504460078EE +:101D400018B1012801D0122010BD01F053F920B1C3 +:101D50000BF0C0FD08B10C2010BD207801F013F984 +:101D6000E21D04F11703611CBDE810400BF0DABC62 +:101D700010B5044601F02DF908B10C2010BD2078F3 +:101D800028B1012803D0FF280BD0122010BD01F08C +:101D9000FAF8611C0BF00CFC08B1002010BD072004 +:101DA00010BD01200BF03EFCF7E710B50BF095FDE0 +:101DB00008B1002010BD302010BD10B5044601F060 +:101DC00019F908B10C2010BD20460BF080FD002051 +:101DD00010BD10B501F00EF920B10BF07BFD08B17C +:101DE0000C2010BD0BF0F6FC002010BDFF2181700F +:101DF0004FF6FF7181808D4949680A7882718A881F +:101E000002814988418101214170002070477CB5E1 +:101E10000025022A19D015DC12F10C0F15D009DCAF +:101E200012F1280F11D012F1140F0ED012F1100F71 +:101E300011D10AE012F1080F07D012F1040F04D0FB +:101E40004AB902E0D31E052B05D8012806D0022886 +:101E500008D003280AD0122528467CBD1046FDF77D +:101E600013F8F9E710460CF06BFEF5E70846144648 +:101E70006946FFF751FB08B10225EDE79DF8000028 +:101E80000198002580F86740E6E710B51346012267 +:101E9000FEF7EAFF002010BD10B5044610F02FFA3F +:101EA000052804D020460FF029FC002010BD0C208E +:101EB00010BD10B5044601F09DF808B10C2010BD0E +:101EC0002146002007F037FB002010BD10B5044666 +:101ED0000FF0A3FC50B108F0A6FD38B1207808F04F +:101EE00029FB20780DF04DF9002010BD0C2010BD0D +:101EF00010B5044601F07EF808B10C2010BD214653 +:101F0000012007F018FB002010BD38B504464FF63D +:101F1000FF70ADF80000A079E179884216D02079F1 +:101F2000FCF7E3FA90B16079FCF7DFFA70B10022B8 +:101F3000A079114612F0A0FD40B90022E0791146C7 +:101F400012F09AFD10B9207A072801D9122038BD65 +:101F500008F076FD60B910F0D2F948B90021684662 +:101F6000FFF78EFB20B1204606F044F9002038BD73 +:101F70000C2038BD2DE9FC41817805461A2925D071 +:101F80000EDC16292ED2DFE801F02D2D2D2D2D216E +:101F90002D2D2D2D2D2D2D2D2D2D2D2D2D21212195 +:101FA0002A291FD00BDCA1F11E010C291AD2DFE86F +:101FB00001F019191919191919191919190D3A399D +:101FC00004290FD2DFE801F00E020E022888B0F5D6 +:101FD000706F07D201276946FFF79EFA20B10220F1 +:101FE000BDE8FC811220FBE79DF8000000F0D2FF65 +:101FF000019C10B104F58A7401E004F5C6749DF8E3 +:10200000000000F0C7FF019E10B106F2151601E0B6 +:1020100006F28D166846FFF76DFA08B1207838B1E0 +:102020000C20DDE70C620200180800207800002078 +:102030002770A8783070684601F030F80020CFE7AC +:102040007CB50D466946FFF767FA002618B12E6089 +:102050002E7102207CBD9DF8000000F09BFF019CCA +:102060009DF80000703400F095FF019884F84260FC +:1020700081682960017B297194F842100029F5D10B +:1020800000207CBD10B5044600F0B4FF20B10BF079 +:1020900021FC08B10C2010BD207800F074FFE2791B +:1020A000611C0BF093FD08B1002010BD022010BD93 +:1020B00010B5886E60B1002241F8682F0120CA7106 +:1020C0008979884012F0CCFC002800D01F2010BD78 +:1020D0000C2010BD1CB50C466946FFF71DFA002800 +:1020E00009D19DF8000000280198B0F8700000D0D8 +:1020F000401C208000201CBD1CB504460088694699 +:10210000FFF70AFA08B102201CBD606828B1DDE9BA +:102110000001224601F04CF81CBDDDE90001FFF78B +:10212000C7FF1CBD70B51C460D4618B1012801D073 +:10213000122070BD1946104601F078F830B12146E2 +:10214000284601F07DF808B1002070BD302070BD38 +:1021500070B5044600780E46012804D018B1022854 +:1021600001D0032840D1607828B1012803D002288B +:1021700001D0032838D1E07B10B9A078012833D1F1 +:10218000A07830F005012FD110F0050F2CD0628916 +:10219000E188E0783346FFF7C5FF002825D1A07815 +:1021A00005281DD16589A289218920793346FFF749 +:1021B000B9FF002819D1012004EB40014A891544D8 +:1021C0002218D378927893420ED1CA8889888A429D +:1021D0000AD1401CC0B20228EED3E088A84203D343 +:1021E000A07B08B1072801D9122070BD002070BD66 +:1021F00010B586B0044600F0E1FE10B10C2006B028 +:1022000010BD022104F10A0001F02FF8A0788DF82A +:102210000800A0788DF8000060788DF80400207820 +:102220008DF80300A07B8DF80500E07B00B1012054 +:102230008DF80600A078C10717D0E07801F00CF8FF +:102240008DF80100E088ADF80A006089ADF80C0057 +:10225000A078400716D5207900F0FEFF8DF8020027 +:102260002089ADF80E00A0890AE040070AD5E07881 +:1022700000F0F2FF8DF80200E088ADF80E006089F2 +:10228000ADF8100002A80FF0D4FA0028B7D16846C4 +:102290000CF07CFFB3E710B504460121FFF758FFAF +:1022A000002803D12046BDE81040A1E710BD027808 +:1022B000012A01D0BAB118E042783AB1012A05D01A +:1022C000022A12D189B1818879B100E059B14188DF +:1022D00049B1808838B101EB8101490000EB8000F1 +:1022E000B1EB002F01D2002070471220704770B56B +:1022F000044600780D46012809D010F000F80528A2 +:1023000003D00FF0A6F9002800D00C2070BD0CF00F +:102310000AFE88B10CF01CFE0CF018FF0028F5D165 +:1023200025B160780CF0ACFE0028EFD1A188608860 +:10233000BDE870400FF0A3BA122070BD10B504467E +:102340000121FFF7B4FF002804D12046BDE810406A +:102350000121CCE710BDF0B5871FDDE9056540F62A +:102360007B44A74213D28F1FA74210D288420ED8B7 +:10237000B2F5FA7F0BD2A3F10A00241FA04206D2C5 +:10238000521C4A43B2EB830F01DAAE4201D900205E +:10239000F0BD0120F0BD2DE9FC47477A894604468F +:1023A00017F0050F7ED0F8087CD194F83A0008B9F0 +:1023B000012F77D10025A8462E46F90789F0010A9A +:1023C00019D0208A514600F031FFE8B360895146A8 +:1023D00000F036FFC0B3208A6189884262D8A18E9E +:1023E000E08DCDE90001238D628CA18BE08AFFF79F +:1023F000B2FF48B30125B8070ED504EB4500828E25 +:10240000C18DCDE90012038D428C818BC08AFFF70C +:10241000A2FFC8B1A8466D1C78071ED504EB45067F +:102420005146308A00F002FF70B17089514600F0C9 +:1024300007FF48B1308A7189884253D8B18EF08D38 +:10244000CDE90001338D00E00BE0728CB18BF08A96 +:10245000FFF781FF28B12E466D1CB9F1000F03D0A4 +:1024600030E03020BDE8FC87F80707D0780705D5B5 +:1024700004EB460160894989884233D1228A0121CF +:102480001BE0414503D004EB4100008A024404EB09 +:102490004100C38A868AB34224D1838B468BB342E0 +:1024A00020D100E01EE0438C068CB3421AD1038D8C +:1024B000C08C834216D1491CC9B2A942E1D36089BC +:1024C00090420FD3207810B101280BD102E0A07800 +:1024D0000028F9D1607838B1012805D0022803D04E +:1024E000032801D01220BDE70020BBE7002152E7FE +:1024F0000178C90702D0406811F0A9BE11F076BE7C +:1025000010B50078012800D00020FCF7B8FC0020AE +:1025100010BD2DE9F0478EB00D46AFF6A422D2E9EA +:102520000092014690462846FFF735FF06000CD181 +:1025300000F044FD40B9FE4F387828B90CF0B2F9EC +:10254000A0F57F41FF3903D00C200EB0BDE8F08725 +:10255000032105F1100000F088FEF54809AA3E3875 +:102560000990F4480A90F248062110380B900CA804 +:1025700001F06AFC040037D00021FEF77CF904F179 +:1025800030017B8ABA8ACB830A84797C0091BA466F +:102590003B7CBA8A798A208801F044FD00B1FFDFD4 +:1025A000208806F058FF218804F10E0000F02CFD71 +:1025B000E1A004F1120700680590032105A804F0CA +:1025C0006DFF002005A90A5C3A54401CC0B20328E4 +:1025D000F9D3A88B6080688CA080288DE080687A11 +:1025E000410703D508270AE00920AEE7C10701D05B +:1025F000012704E0800701D5022700E000273A46C2 +:10260000BAF8160011460FF0CFF90146A062204635 +:102610000FF0D8F93A4621460020FEF7AEFD00B98A +:102620000926C34A21461C320020FEF7C3FD0027BD +:1026300084F8767084F87770A87800F0A4FC60764F +:10264000D5F80300C4F81A00B5F80700E083C4F811 +:10265000089084F80C80012084F8200101468DF850 +:102660000070684604F01AFF9DF8000000F00701B2 +:10267000C0F3C1021144C0F3401008448DF80000BB +:10268000401D2076092801D20830207601212046FD +:10269000FEF7F1F868780CF051FCEEBBA9782878C9 +:1026A000EA1C0CF01EFC48B10CF052FCA97828780A +:1026B000EA1C0CF0BFFC060002D052E0122650E0EB +:1026C000687A00F005010020CA0700D001208A07BF +:1026D00001D540F00200490701D540F008000CF098 +:1026E000E9FB06003DD1214603200CF0CDFC06009D +:1026F00037D10CF0D2FC060033D1697A01F0050124 +:102700008DF80810697AC90708D06889ADF80A0001 +:10271000288AADF80C0000E023E00120697A8A07DE +:1027200000D5401C490707D505EB40004189ADF8AD +:102730000E10008AADF8100002A80FF07AF80646D5 +:1027400095F83A0000B101200CF0C6FB4EB90CF030 +:10275000FDFC060005D1A98F20460FF00BF80600FE +:1027600008D0208806F078FE2088062101F0B0FB12 +:1027700000B1FFDF3046E8E601460020C9E638B583 +:102780006B48007878B90FF0BAFD052805D00CF039 +:1027900089F8A0F57F41FF3905D068460FF0B3F8FE +:1027A000040002D00CE00C2038BD0098008806F030 +:1027B00053FE00980621008801F08AFB00B1FFDF7C +:1027C000204638BD1CB582894189CDE900120389B4 +:1027D000C28881884088FFF7BEFD08B100201CBD7B +:1027E00030201CBD70B50546FFF7ECFF00280ED168 +:1027F0002888062101F05AFB040007D000F042FCB3 +:1028000020B1D4F81801017831B901E0022070BD7F +:10281000D4F86411097809B13A2070BD052181719D +:10282000D4F8181100200881D4F81811A88848811C +:10283000D4F81811E8888881D4F818112889C8813B +:10284000D4F81801028941898A4204D88279082A79 +:1028500001D88A4201D3122070BD29884180D4F862 +:10286000181102200870002070BD3EB50446FEF726 +:1028700075FAB0B12E480125A0F1400245702368D9 +:1028800042F8423F237900211371417069460620C6 +:1028900001F095FA00B1FFDF684601F06EFA10B161 +:1028A0000EE012203EBDBDF80440029880F8205191 +:1028B000684601F062FA18B9BDF80400A042F4D1EC +:1028C00000203EBD70B505460088062101F0EEFAF5 +:1028D000040007D000F0D6FB20B1D4F81811087816 +:1028E00030B901E0022070BDD4F86401007808B16D +:1028F0003A2070BDB020005D10F0010F22D0D5F855 +:1029000002004860D5F806008860D4F8180169898B +:1029100010228181D4F8180105F10C010E3004F564 +:102920008C74FBF78AFD216803200870288805E075 +:1029300018080020840000201122330021684880FC +:10294000002070BD0C2070BD38B504460078EF281B +:102950004DD86088ADF80000009800F097FC88B36F +:102960006188080708D4D4E9012082423FD8202A90 +:102970003DD3B0F5804F3AD8207B18B3072836D81E +:10298000607B28B1012803D0022801D003282ED172 +:102990004A0703D4022801D0032805D1A07B08B13F +:1029A000012824D1480707D4607D28B1012803D02D +:1029B000022801D003281AD1C806E07D03D50128DA +:1029C00015D110E013E0012801D003280FD1C8066B +:1029D00009D4607E012803D0022801D0032806D143 +:1029E000A07E0F2803D8E07E18B1012801D0122064 +:1029F00038BD002038BDF8B514460D46064608F02F +:102A00001FF808B10C20F8BD3046FFF79DFF0028E5 +:102A1000F9D1FCF73EFA2870B07554B9FF208DF853 +:102A2000000069460020FCF71EFA69460020FCF70A +:102A30000EFA3046BDE8F840FCF752B90022DAE75A +:102A40000078C10801D012207047FA4981F82000AF +:102A50000020704710B504460078C00704D1608894 +:102A600010B1FCF7D7F980B12078618800F001023D +:102A7000607800F02FFC002806D1FCF7B3F901467E +:102A80006088884203D9072010BD122010BD6168FC +:102A9000FCF7E9F9002010BD10B504460078C00726 +:102AA00004D1608810B1FBF78AFE70B1207861888C +:102AB00000F00102607800F00DFC002804D160886D +:102AC0006168FCF7C4F9002010BD122010BD7CB570 +:102AD000044640784225012808D8A078FBF767FE15 +:102AE00020B120781225012802D090B128467CBD63 +:102AF000FCF7DBF920B1A0880028F7D08028F5D8B2 +:102B0000FCF7DAF960B160780028EFD0207801286E +:102B100008D006F0C3FD044607F05DFC00287FD016 +:102B20000C207CBDFBF7F5FF10B9FCF7B7F990B3AB +:102B300007F086FF0028F3D1FBF700FEA0F57F41E8 +:102B4000FF39EDD1FCF707F8A68842F21070464332 +:102B5000A079FCF770F9FBF739FEF8B100220721E4 +:102B600001A801F071F9040058D0B3480021846035 +:102B70002046FDF72DFD2046FCF732FDAD4D04F15A +:102B800030006A8AA98AC2830184FBF726FE60B1FD +:102B9000E88A01210DE0FFE712207CBD31460020CC +:102BA00007F0CBFC88B3FFDF44E0FCF787F9014670 +:102BB000E88A07F091FD0146A0620022204606F057 +:102BC00070FDFBF70AFE38B9FCF778F9024621469A +:102BD0000120FEF7D2FAD0B1964A21461C320120DC +:102BE000FEF7E8FA687C00902B7CAA8A698A208824 +:102BF00001F018FA00B1FFDF208806F02CFC314606 +:102C0000204607F09AFC00B1FFDF13E008E007213F +:102C1000BDF8040001F05CF900B1FFDF09207CBDC4 +:102C200044B1208806F018FC2088072101F050F9F3 +:102C300000B1FFDF00207CBD002148E770B50D46E4 +:102C4000072101F033F9040003D094F88F0110B18B +:102C50000AE0022070BD94F87D00142801D01528E8 +:102C600002D194F8DC0108B10C2070BD1022294675 +:102C700004F5C870FBF7E1FB012084F88F01002008 +:102C800070BD10B5072101F011F918B190F88F113E +:102C900011B107E0022010BD90F87D10142903D077 +:102CA000152901D00C2010BD022180F88F110020C1 +:102CB00010BD2DE9FC410C464BF6803212219442A6 +:102CC0001DD8E4B16946FEF727FC002815D19DF810 +:102CD000000000F05FF9019E9DF80000703600F0E2 +:102CE00059F9019DAD1C2F88224639463046FDF723 +:102CF00065FC2888B842F6D10020BDE8FC81084672 +:102D0000FBE77CB5044600886946FEF705FC002811 +:102D100010D19DF8000000F03DF9019D9DF80000E4 +:102D2000703500F037F90198A27890F82C10914294 +:102D300001D10C207CBD7F212972A9720021E9728A +:102D4000E17880F82D10217980F82E10A17880F894 +:102D50002C1000207CBD1CB50C466946FEF7DCFB40 +:102D600000280AD19DF8000000F014F9019890F8AD +:102D70008C0000B10120207000201CBD7CB50D46E8 +:102D800014466946FEF7C8FB002809D19DF80000EB +:102D900000F000F9019890F82C00012801D00C20D7 +:102DA0007CBD9DF8000000F0F5F8019890F87810CF +:102DB000297090F87900207000207CBD70B50D4618 +:102DC0001646072101F072F818B381880124C388E0 +:102DD000428804EB4104AC4217D842F210746343BA +:102DE000A4106243B3FBF2F2521E94B24FF4FA7293 +:102DF000944200D91446A54200D22C46491C641CBA +:102E0000B4FBF1F24A43521E91B290F8C8211AB9AC +:102E100001E0022070BD01843180002070BD10B53A +:102E20000C46072101F042F840B1022C08D91220CB +:102E300010BD000018080020780000200220F7E7ED +:102E400014F0010180F8FD10C4F3400280F8FC206A +:102E500004D090F8FA1009B107F054FC0020E7E71D +:102E6000017889B1417879B141881B290CD38188D7 +:102E70001B2909D3C188022906D3F64902680A65CD +:102E800040684865002070471220704710B504461E +:102E90000EF086FD204607F0D8FB0020C8E710B5ED +:102EA00007F0D6FB0020C3E72DE9F04115460F4699 +:102EB00006460122114638460EF076FD04460121F1 +:102EC000384607F009FC844200D20446012130460E +:102ED00000F065F806460121002000F060F8311886 +:102EE000012096318C4206D901F19600611AB1FB9E +:102EF000F0F0401C80B228800020BDE8F08110B5C1 +:102F0000044600F077F808B10C2091E7601C0AF045 +:102F100038FE207800F00100FBF718FE207800F062 +:102F200001000CF010F8002082E710B504460720DD +:102F300000F056FF08B10C207AE72078C00711D0C6 +:102F400000226078114611F097FD08B112206FE75A +:102F5000A06809F01DFB6078D4F8041009F021FB8B +:102F6000002065E7002009F013FB00210846F5E783 +:102F700010B505F036FE00205AE710B5006805F0E0 +:102F800084F8002054E718B1022801D001207047CE +:102F90000020704708B1002070470120704710B52D +:102FA000012904D0022905D0FFDF204640E7C000F8 +:102FB000503001E080002C3084B2F6E710B50FF0FD +:102FC0009EF9042803D0052801D0002030E7012015 +:102FD0002EE710B5FFF7F2FF10B10CF07BF828B91F +:102FE00007F02EFD20B1FBF78CFD08B101201FE793 +:102FF00000201DE710B5FFF7E1FF18B907F020FD2D +:10300000002800D0012013E72DE9FE4300250F46DC +:1030100080460A260421404604F069FA4046FDF73E +:103020003EFE062000F0EAFE044616E06946062051 +:1030300000F0C5FE0BE000BFBDF80400B84206D0AA +:103040000298042241460E30FBF7CAF950B1684697 +:1030500000F093FE0500EFD0641E002C06DD002D6D +:10306000E4D005E04046FDF723FEF5E705B9FFDFB4 +:10307000D8F80000FDF737FE761E01D00028C9D031 +:10308000BDE8FE8390F8F01090F88C0020B919B1DB +:10309000042901D0012070470020704701780029E1 +:1030A0000AD0416891F8FA20002A05D0002281F860 +:1030B000FA20406807F026BB704770B514460546F5 +:1030C000012200F01BF9002806D121462846BDE860 +:1030D0007040002200F012B970BDFB2802D8B1F593 +:1030E000296F01D911207047002070471B38E12853 +:1030F00006D2B1F5A47F03D344F29020814201D9D6 +:1031000012207047002070471FB55249403191F896 +:103110002010CA0702D102781D2A0AD08A0702D4D9 +:1031200002781C2A28D049073DD40178152937D0C8 +:1031300039E08088ADF8000002A9FEF7EDF900B192 +:10314000FFDF9DF80800FFF725FF039810F8601FC8 +:103150008DF8021040788DF803000020ADF80400CF +:1031600001B9FFDF9DF8030000B9FFDF6846FEF7F5 +:1031700040FCD8B1FFDF19E08088ADF800004FF4C3 +:103180002961FB20ADF80410ADF80200ADF806008F +:10319000ADF808106846FEF73AFD38B1FFDF05E0EC +:1031A000807BC00702D0002004B041E60120FBE78D +:1031B000F8B50746508915460C4640B1B0F5004FAA +:1031C00005D20022A878114611F056FC08B1122051 +:1031D000F8BDA06E04F1700630B1A97894F86E00C5 +:1031E000814201D00C20F8BD012184F86F10A9782C +:1031F00084F86E106968A1666989A4F86C10288942 +:10320000B084002184F86F1028886946FEF762FFB9 +:10321000B08CBDF80010081A00B2002804DD214669 +:103220003846FEF745FFDDE70020F8BD042803D34C +:1032300021B9B0F5804F01D90020704701207047B7 +:10324000042803D321B9B0F5804F01D9002070477D +:1032500001207047D8070020012802D018B10020B3 +:103260007047022070470120704710B500224FF4CC +:10327000C84408E030F81230A34200D9234620F8B1 +:103280001230521CD2B28A42F4D3D1E580B2C106C8 +:103290000BD401071CD481064FEAC07101D5B9B91E +:1032A00000E099B1800713D410E0410610D48106E4 +:1032B0000ED4C1074FEA807104D0002902DB400719 +:1032C00004D405E0010703D4400701D4012070476E +:1032D0000020704770B50C460546FF2904D8FBF75F +:1032E0007CFA18B11F2C01D9122070BD2846FBF7BB +:1032F0005EFA08B1002070BD422070BD0AB1012203 +:1033000000E00222024202D1C80802D109B1002025 +:10331000704711207047000030B5058825F400443F +:1033200021448CB24FF4004194420AD2121B92B253 +:103330001B339A4201D2A94307E005F4004121431F +:1033400003E0A21A92B2A9431143018030BD0844A0 +:10335000083050434A31084480B2704770B51D466A +:1033600016460B46044629463046049AFFF7EFFFFF +:103370000646B34200D2FFDF282200212046FBF799 +:1033800086F84FF6FF70A082283EB0B26577608065 +:10339000B0F5004F00D9FFDF618805F13C008142A4 +:1033A00000D2FFDF60880835401B343880B22080AF +:1033B0001B2800D21B2020800020A07770BD8161D7 +:1033C000886170472DE9F05F0D46C188044600F121 +:1033D0002809008921F4004620F4004800F063FB2E +:1033E00010B10020BDE8F09F4FF0000A4FF0010B34 +:1033F000B0450CD9617FA8EB0600401A0838854219 +:1034000019DC09EB06000021058041801AE0608884 +:10341000617F801B471A083F0DD41B2F00DAFFDFA6 +:10342000BD4201DC294600E0B9B2681A0204120C60 +:1034300004D0424502DD84F817A0D2E709EB06006C +:103440000180428084F817B0CCE770B5044600F1E3 +:103450002802C088E37D20F400402BB1104402888C +:10346000438813448B4201D2002070BD00258A425C +:1034700002D30180458008E0891A0904090C4180C3 +:1034800003D0A01D00F01FFB08E0637F0088083315 +:10349000184481B26288A01DFFF73EFFE575012048 +:1034A00070BD70B5034600F12804C588808820F4FB +:1034B00000462644A84202D10020188270BD988997 +:1034C0003588A84206D3401B75882D1A2044ADB21A +:1034D000C01E05E02C1AA5B25C7F20443044401D7C +:1034E0000C88AC4200D90D809C8924B10024147052 +:1034F0000988198270BD0124F9E770B5044600F10E +:103500002801808820F400404518208A002825D012 +:10351000A189084480B2A08129886A881144814227 +:1035200000D2FFDF2888698800260844A1898842E4 +:1035300012D1A069807F2871698819B1201D00F01F +:10354000C2FA08E0637F28880833184481B2628891 +:10355000201DFFF7E1FEA6812682012070BD2DE926 +:10356000F041418987880026044600F12805B942C8 +:1035700019D004F10A0800BF21F400402844418812 +:1035800019B1404600F09FFA08E0637F00880833D5 +:10359000184481B262884046FFF7BEFE761C6189FE +:1035A000B6B2B942E8D13046BDE8F0812DE9F0412C +:1035B00004460B4627892830A68827F40041B4F832 +:1035C0000A8001440D46B74201D10020ECE70AB160 +:1035D000481D106023B1627F691D1846FAF72DFF60 +:1035E0002E88698804F1080021B18A1996B200F08A +:1035F0006AFA06E0637F62880833991989B2FFF797 +:103600008BFE474501D1208960813046CCE7818817 +:10361000C088814201D10120704700207047018994 +:103620008088814201D1012070470020704770B529 +:103630008588C38800F1280425F4004223F4004162 +:1036400014449D421AD08389058A5E1925886388AF +:10365000EC18A64214D313B18B4211D30EE0437F72 +:1036600008325C192244408892B2801A80B2233317 +:10367000984201D211B103E08A4201D1002070BD0D +:10368000012070BD2DE9F0478846C18804460089B5 +:1036900021F4004604F1280720F4004507EB060951 +:1036A00000F001FA002178BBB54204D9627FA81B63 +:1036B000801A002503E06088627F801B801A08382A +:1036C00023D4E28962B1B9F80020B9F802303BB1E5 +:1036D000E81A2177404518DBE0893844801A09E070 +:1036E000801A217740450ADB607FE1890830304449 +:1036F00039440844C01EA4F81280BDE8F08745454F +:1037000003DB01202077E7E7FFE761820020F4E791 +:103710002DE9F74F044600F12805C088884620F4BB +:10372000004A608A05EB0A0608B1404502D2002033 +:10373000BDE8FE8FE08978B13788B6F8029007EBD4 +:103740000901884200D0FFDF207F4FF0000B50EAD4 +:10375000090106D088B33BE00027A07FB94630714D +:10376000F2E7E18959B1607F2944083050440844A8 +:10377000B4F81F1020F8031D94F821108170E2891D +:1037800007EB080002EB0801E1813080A6F802B0E7 +:1037900002985F4650B1637F30880833184481B285 +:1037A0006288A01DFFF7B8FDE78121E0607FE18915 +:1037B00008305044294408442DE0FFE7E089B4F87C +:1037C0001F102844C01B20F8031D94F8211081709D +:1037D00009EB0800E28981B202EB0800E081378042 +:1037E00071800298A0B1A01D00F06DF9A4F80EB090 +:1037F000A07F401CA077A07D08B1E088A08284F85B +:1038000016B000BFA4F812B084F817B001208FE7FB +:10381000E0892844C01B30F8031DA4F81F108078ED +:1038200084F82100EEE710B5818800F1280321F427 +:1038300000442344848AC288A14212D0914210D00D +:10384000818971B9826972B11046FFF7E8FE50B9FB +:103850001089283220F400401044197900798842F8 +:1038600001D1002010BD184610BD00F12803407F93 +:1038700008300844C01E1060088808B9DB1E1360B9 +:1038800008884988084480B270472DE9F04100F16A +:103890002806407F1C4608309046431808884D880B +:1038A000069ADB1EA0B1C01C80B2904214D9801AC7 +:1038B000A04200DB204687B298183A464146FAF704 +:1038C0008FFD002816D1E01B84B2B844002005E02B +:1038D000ED1CADB2F61EE8E7101A80B20119A9423C +:1038E00006D8304422464146BDE8F041FAF778BD9B +:1038F0004FF0FF3058E62DE9F04100F12804407FF9 +:103900001E46083090464318002508884F88069ABE +:10391000DB1E90B1C01C80B2904212D9801AB04216 +:1039200000DB304685B299182A464046FAF785FDF5 +:10393000701B86B2A844002005E0FF1CBFB2E41E45 +:10394000EAE7101A80B28119B94206D82118324626 +:103950004046FAF772FDA81985B2284624E62DE9FB +:10396000F04100F12804407F1E460830904643187D +:10397000002508884F88069ADB1E90B1C01C80B2D3 +:10398000904212D9801AB04200DB304685B29818B6 +:103990002A464146FAF751FD701B86B2A844002022 +:1039A00005E0FF1CBFB2E41EEAE7101A80B28119DD +:1039B000B94206D8204432464146FAF73EFDA819DE +:1039C00085B22846F0E5401D704710B5044600F169 +:1039D0002801C288808820F400431944904206D010 +:1039E000A28922B9228A12B9A28A904201D100206A +:1039F00010BD0888498831B1201D00F064F800200E +:103A00002082012010BD637F62880833184481B290 +:103A1000201DFFF781FCF2E70021C181017741827F +:103A2000C1758175704703881380C28942B1C2880D +:103A300022F4004300F128021A440A60C08970474A +:103A40000020704710B50446808AA0F57F41FF39F9 +:103A500000D0FFDFE088A082E08900B10120A075DE +:103A600010BD4FF6FF71818200218175704710B53E +:103A70000446808AA0F57F41FF3900D1FFDFA07D99 +:103A800028B9A088A18A884201D1002010BD012058 +:103A900010BD8188828A914201D1807D08B10020C9 +:103AA00070470120704720F4004221F400439A42FD +:103AB00007D100F4004001F40041884201D0012008 +:103AC00070470020704730B5044600880D4620F44A +:103AD0000040A84200D2FFDF21884FF40040884315 +:103AE0002843208030BD70B50C00054609D0082C55 +:103AF00000D2FFDF1DB1A1B2286800F044F8201DFC +:103B000070BD0DB100202860002070BD002102684A +:103B100003E093881268194489B2002AF9D100F0B1 +:103B200032B870B500260D460446082900D2FFDFE2 +:103B3000206808B91EE0044620688188A94202D0A6 +:103B400001680029F7D181880646A94201D10068A1 +:103B50000DE005F1080293B20022994209D32844EE +:103B6000491B026081802168096821600160206032 +:103B700000E00026304670BD00230B608A8002689A +:103B80000A600160704700234360021D01810260EA +:103B90007047F0B50F460188408815460C181E4640 +:103BA000AC4200D3641B3044A84200D9FFDFA01907 +:103BB000A84200D9FFDF3819F0BD2DE9F041884651 +:103BC00006460188408815460C181F46AC4200D3B3 +:103BD000641B3844A84200D9FFDFE019A84200D98D +:103BE000FFDF70883844708008EB0400BDE8F08186 +:103BF0002DE9F041054600881E461746841B88467D +:103C0000BC4200D33C442C8068883044B84200D980 +:103C1000FFDFA019B84200D9FFDF68883044688010 +:103C200008EB0400E2E72DE9F04106881D46044652 +:103C3000701980B2174688462080B84201D3C01B55 +:103C400020806088A84200D2FFDF7019B84200D9F6 +:103C5000FFDF6088401B608008EB0600C6E730B5D8 +:103C60000D460188CC18944200D3A41A408898428B +:103C700000D8FFDF281930BD2DE9F041C84D0446BA +:103C80009046A8780E46A04200D8FFDF05EB8607D5 +:103C9000B86A50F8240000B1FFDFB868002816D0D9 +:103CA000304600F044F90146B868FFF73AFF0500D6 +:103CB0000CD0B86A082E40F8245000D3FFDFB94872 +:103CC0004246294650F82630204698472846BDE807 +:103CD000F0812DE9F8431E468C1991460F460546A2 +:103CE000FF2C00D9FFDFB14500D9FFDFE4B200951A +:103CF0004DB300208046E81C20F00300A84200D00D +:103D0000FFDF4946DFF89892684689F8001089F885 +:103D1000017089F8024089F8034089F8044089F865 +:103D2000054089F8066089F80770414600F008F9F7 +:103D3000002142460F464B460098C01C20F003006D +:103D4000009012B10EE00120D4E703EB8106B062CF +:103D5000002005E0D6F828C04CF82070401CC0B206 +:103D6000A042F7D30098491C00EB8400C9B2009030 +:103D70000829E1D3401BBDE8F88310B50446EDF7F0 +:103D80008EFA08B1102010BD2078854A618802EBB8 +:103D9000800092780EE0836A53F8213043B14A1CC8 +:103DA0006280A180806A50F82100A060002010BDD0 +:103DB000491C89B28A42EED86180052010BD70B5D9 +:103DC00005460C460846EDF76AFA08B1102070BDAA +:103DD000082D01D3072070BD25700020608070BDC4 +:103DE0000EB56946FFF7EBFF00B1FFDF6846FFF74E +:103DF000C4FF08B100200EBD01200EBD10B5044661 +:103E0000082800D3FFDF6648005D10BD3EB50546BB +:103E100000246946FFF7D3FF18B1FFDF01E0641CFF +:103E2000E4B26846FFF7A9FF0028F8D02846FFF75C +:103E3000E5FF001BC0B23EBD59498978814201D9D6 +:103E4000C0B27047FF2070472DE9F041544B06295E +:103E500003D007291CD19D7900E0002500244FF6EE +:103E6000FF7603EB810713F801C00AE06319D7F866 +:103E700028E09BB25EF823E0BEF1000F04D0641C82 +:103E8000A4B2A445F2D8334603801846B34201D108 +:103E900000201CE7BDE8F041EEE6A0F57F43FF3BC4 +:103EA00001D0082901D300207047E5E6A0F57F4244 +:103EB000FF3A0BD0082909D2394A9378834205D9B1 +:103EC00002EB8101896A51F8200070470020704799 +:103ED0002DE9F04104460D46A4F57F4143F202006E +:103EE000FF3902D0082D01D30720F0E62C494FF00E +:103EF00000088A78A242F8D901EB8506B26A52F826 +:103F00002470002FF1D027483946203050F8252062 +:103F100020469047B16A284641F8248000F007F80F +:103F200002463946B068FFF727FE0020CFE61D495C +:103F3000403131F810004FF6FC71C01C084070474A +:103F40002DE9F843164E8846054600242868C01C13 +:103F500020F0030028602046FFF7E9FF315D484369 +:103F6000B8F1000F01D0002200E02A68014600925B +:103F700032B100274FEA0D00FFF7B5FD1FB106E093 +:103F800001270020F8E706EB8401009A8A6029687F +:103F9000641C0844E4B22860082CD7D3EBE6000088 +:103FA0003C0800201862020070B50E461D461146FE +:103FB00000F0D3F804462946304600F0D7F82044F4 +:103FC000001D70BD2DE9F04190460D4604004FF0F4 +:103FD000000610D00027E01C20F00300A04200D013 +:103FE000FFDFE5B141460020FFF77DFD0C3000EB1F +:103FF000850617B113E00127EDE7614F04F10C00CE +:10400000AA003C602572606000EB85002060002102 +:104010006068FAF73CFA41463868FFF764FD3046BD +:10402000BDE8F0812DE9FF4F554C804681B02068F6 +:104030009A46934600B9FFDF2068027A424503D9C9 +:10404000416851F8280020B143F2020005B0BDE8F4 +:10405000F08F5146029800F080F886B258460E99CB +:1040600000F084F885B27019001D87B22068A1465F +:1040700039460068FFF755FD04001FD06780258092 +:104080002946201D0E9D07465A4601230095FFF73D +:1040900065F92088314638440123029ACDF800A002 +:1040A000FFF75CF92088C1193846FFF788F9D9F87D +:1040B00000004168002041F82840C7E70420C5E718 +:1040C00070B52F4C0546206800B9FFDF2068017AE3 +:1040D000A9420DD9426852F8251049B1002342F88F +:1040E00025304A880068FFF747FD2168087A06E016 +:1040F00043F2020070BD4A6852F820202AB9401EDF +:10410000C0B2F8D20868FFF701FD002070BD70B59D +:104110001B4E05460024306800B9FFDF3068017A85 +:10412000A94204D9406850F8250000B1041D20467A +:1041300070BD70B5124E05460024306800B9FFDF2F +:104140003068017AA94206D9406850F8251011B1AB +:1041500031F8040B4418204670BD10B50A46012101 +:10416000FFF7F5F8C01C20F0030010BD10B50A469B +:104170000121FFF7ECF8C01C20F0030010BD000087 +:104180008C00002070B50446C2F110052819FAF71A +:1041900054F915F0FF0109D0491ECAB28020A0547D +:1041A0002046BDE870400021FAF771B970BD30B506 +:1041B00005E05B1EDBB2CC5CD55C6C40C454002BCC +:1041C000F7D130BD10B5002409E00B78521E44EA47 +:1041D000430300F8013B11F8013BD2B2DC09002A8D +:1041E000F3D110BD2DE9F04389B01E46DDE9107909 +:1041F00090460D00044622D002460846F949FDF7D4 +:1042000044FE102221463846FFF7DCFFE07B000623 +:1042100006D5F44A3946102310320846FFF7C7FF87 +:10422000102239464846FFF7CDFFF87B000606D539 +:10423000EC4A4946102310320846FFF7B8FF102217 +:1042400000212046FAF723F90DE0103EB6B208EB44 +:104250000601102322466846FFF7A9FF224628469A +:104260006946FDF712FE102EEFD818D0F2B2414683 +:104270006846FFF787FF10234A46694604A8FFF700 +:1042800096FF1023224604A96846FFF790FF2246B6 +:1042900028466946FDF7F9FD09B0BDE8F083102313 +:1042A0003A464146EAE770B59CB01E4605461346BD +:1042B00020980C468DF80800202219460DF10900BF +:1042C000FAF7BBF8202221460DF12900FAF7B5F8DC +:1042D00017A913A8CDE90001412302AA31462846B7 +:1042E000FFF780FF1CB070BD2DE9FF4F9FB014AEEB +:1042F000DDE92D5410AFBB49CDE9007620232031F4 +:104300001AA8FFF76FFF4FF000088DF808804FF0F4 +:1043100001098DF8099054F8010FCDF80A00A08822 +:10432000ADF80E0014F8010C1022C0F340008DF817 +:10433000100055F8010FCDF81100A888ADF8150050 +:1043400015F8010C2C99C0F340008DF8170006A851 +:104350008246FAF772F80AA8834610222299FAF7E1 +:104360006CF8A0483523083802AA40688DF83C80D4 +:10437000CDE900760E901AA91F98FFF733FF8DF84C +:1043800008808DF809902068CDF80A00A088ADF863 +:104390000E0014F8010C1022C0F340008DF810003C +:1043A0002868CDF81100A888ADF8150015F8010CA3 +:1043B0002C99C0F340008DF817005046FAF73DF8ED +:1043C000584610222299FAF738F8864835230838DB +:1043D00002AA40688DF83C90CDE900760E901AA9AB +:1043E0002098FFF7FFFE23B0BDE8F08FF0B59BB03B +:1043F0000C460546DDE922101E461746DDE920324F +:10440000D0F801C0CDF808C0B0F805C0ADF80CC0B8 +:104410000078C0F340008DF80E00D1F80100CDF80F +:104420000F00B1F80500ADF8130008781946C0F385 +:1044300040008DF815001088ADF8160090788DF8C2 +:1044400018000DF119001022F9F7F7FF0DF12900FE +:1044500010223146F9F7F1FF0DF1390010223946EB +:10446000F9F7EBFF17A913A8CDE90001412302AA30 +:1044700021462846FFF7B6FE1BB0F0BDF0B5A3B04D +:1044800017460D4604461E46102202A82899F9F741 +:10449000D4FF06A820223946F9F7CFFF0EA8202224 +:1044A0002946F9F7CAFF1EA91AA8CDE90001502331 +:1044B00002AA314616A8FFF795FE1698206023B091 +:1044C000F0BDF0B589B00446DDE90E070D46397838 +:1044D000109EC1F340018DF8001031789446C1F36D +:1044E00040018DF801101968CDF802109988ADF8D7 +:1044F000061099798DF808100168CDF809108188A7 +:10450000ADF80D1080798DF80F0010236A466146D2 +:1045100004A8FFF74CFE2246284604A9FDF7B5FC87 +:10452000D6F801000090B6F80500ADF80400D7F801 +:104530000100CDF80600B7F80500ADF80A0000202C +:10454000039010236A46214604A8FFF730FE224656 +:10455000284604A9FDF799FC09B0F0BD1FB51C68F9 +:1045600000945B68019313680293526803920246B9 +:1045700008466946FDF789FC1FBD10B588B00446A2 +:104580001068049050680590002006900790084637 +:104590006A4604A9FDF779FCBDF80000208008B048 +:1045A00010BD1FB51288ADF800201A88ADF80220A2 +:1045B0000022019202920392024608466946FDF7E4 +:1045C00064FC1FBD7FB5074B14460546083B9A1C8B +:1045D0006846FFF7E6FF224669462846FFF7CDFF0B +:1045E0007FBD00007062020070B5044600780E4680 +:1045F000012813D0052802D0092813D10EE0A068A5 +:1046000061690578042003F059FA052D0AD0782352 +:1046100000220420616903F0A7F903E00420616926 +:1046200003F04CFA31462046BDE8704001F08AB8EC +:1046300010B500F12D03C2799C78411D144064F33C +:104640000102C271D2070DD04A795C7922404A71C9 +:104650000A791B791A400A718278C9788A4200D98E +:10466000817010BD00224A71F5E74178012900D020 +:104670000C21017070472DE9F04F93B04FF0000B03 +:104680000C690D468DF820B0097801260C201746DC +:104690004FF00D084FF0110A4FF008091B2975D291 +:1046A000DFE811F01B00C40207031F035E03710360 +:1046B000A303B803F9031A0462049504A204EF04E7 +:1046C0002D05370555056005F305360639066806DC +:1046D0008406FE062207EB06F00614B120781D289A +:1046E0002AD0D5F808805FEA08004FD001208DF865 +:1046F0002000686A02220D908DF824200A208DF88F +:104700002500A8690A90A8880028EED098F8001023 +:1047100091B10F2910D27DD2DFE801F07C1349DE80 +:10472000FCFBFAF9F8F738089CF6F50002282DD1C1 +:1047300024B120780C2801D00026F0E38DF8202049 +:10474000CBE10420696A03F0B9F9A8880728EED103 +:10475000204600F0F2FF022809D0204600F0EDFFCD +:10476000032807D9204600F0E8FF072802D20120DD +:10477000207004E0002CB8D020780128D7D198F818 +:104780000400C11F0A2902D30A2061E0C4E1A0701D +:10479000D8F80010E162B8F80410218698F80600F5 +:1047A00084F83200012028700320207044E007289C +:1047B000BDD1002C99D020780D28B8D198F80310DD +:1047C00094F82F20C1F3C000C2F3C002104201D000 +:1047D000062000E00720890707D198F8051001425C +:1047E000D2D198F806100142CED194F8312098F831 +:1047F000051020EA02021142C6D194F8322098F83E +:10480000061090430142BFD198F80400C11F0A2945 +:10481000BAD200E008E2617D81427CD8D8F800106D +:104820006160B8F80410218198F80600A072012098 +:1048300028700E20207003208DF82000686A0D90EB +:1048400004F12D000990601D0A900F300B9022E1B9 +:104850002875FCE3412891D1204600F06EFF042822 +:1048600002D1E078C00704D1204600F066FF0F288F +:1048700084D1A88CD5F80C8080B24FF0400BE6694B +:10488000FFF745FC324641465B464E46CDF8009068 +:10489000FFF731F80B208DF82000686A0D90E06971 +:1048A0000990002108A8FFF79FFE2078042806D071 +:1048B000A07D58B1012809D003280AD04AE3052079 +:1048C0002070032028708DF82060CEE184F800A0CD +:1048D00032E712202070EAE11128BCD1204600F016 +:1048E0002CFF042802D1E078C00719D0204600F040 +:1048F00024FF062805D1E078C00711D1A07D022849 +:104900000ED0204608E0CCE084E072E151E124E1E1 +:1049100003E1E9E019E0B0E100F00FFF11289AD1BE +:10492000102208F1010104F13C00F9F786FD6078DE +:1049300001286ED012202070E078C00760D0A07DE2 +:104940000028C8D00128C6D05AE0112890D12046AE +:1049500000F0F3FE082804D0204600F0EEFE1328F5 +:1049600086D104F16C00102208F101010646F9F726 +:1049700064FD207808280DD014202070E178C80745 +:104980000DD0A07D02280AD06278022A04D0032824 +:10499000A1D035E00920F0E708B1012837D1C807D8 +:1049A00013D0A07D02281DD000200090D4E906215C +:1049B00033460EA8FFF777FC10220EA904F13C0045 +:1049C000F9F70EFDC8B1042042E7D4E90912201D11 +:1049D0008DE8070004F12C0332460EA8616BFFF747 +:1049E00070FDE9E7606BC1F34401491E0068C840EF +:1049F00000F0010040F08000D7E72078092806D1B8 +:104A000085F800908DF8209036E32870EFE30920B8 +:104A1000FBE79EE1112899D1204600F08EFE0A287E +:104A200002D1E078C00704D1204600F086FE1528A8 +:104A30008CD104F13C00102208F101010646F9F77F +:104A4000FCFC20780A2816D016202070D4E9093200 +:104A5000606B611D8DE80F0004F15C0304F16C02D2 +:104A600047310EA8FFF7C2FC10220EA93046F9F715 +:104A7000B7FC18B1F9E20B20207073E22046FFF773 +:104A8000D7FDA078216AC0F110020B18002118464A +:104A9000F9F7FDFC26E3394608A8FFF7A5FD064611 +:104AA0003CE20228B7D1204600F047FE042804D398 +:104AB000204600F042FE082809D3204600F03DFEC3 +:104AC0000E2829D3204600F038FE122824D2A07DDB +:104AD0000228A0D10E208DF82000686A0D9098F869 +:104AE00001008DF82400F5E3022894D1204600F05F +:104AF00024FE002810D0204600F01FFE0128F9D027 +:104B0000204600F01AFE0C28F4D004208DF8240072 +:104B100098F801008DF8250060E21128FCD1002CE6 +:104B2000FAD020781728F7D16178606A022912D06C +:104B30005FF0000101EB4101182606EBC1011022D4 +:104B4000405808F10101F9F778FC0420696A00F087 +:104B5000E7FD2670F0E50121ECE70B28DCD1002C05 +:104B6000DAD020781828D7D16078616A02281CD062 +:104B70005FF0000000EB4002102000EBC20009587B +:104B8000B8F8010008806078616A02280FD0002020 +:104B900000EB4002142000EBC2000958404650F8D8 +:104BA000032F0A604068486039E00120E2E70120F5 +:104BB000EEE71128B0D1002CAED020781928ABD167 +:104BC0006178606A022912D05FF0000101EB4101B7 +:104BD0001C2202EBC1011022405808F10101F9F733 +:104BE0002CFC0420696A00F09BFD1A20B6E001212C +:104BF000ECE7082890D1002C8ED020781A288BD191 +:104C0000606A98F80120017862F347010170616AD7 +:104C1000D8F8022041F8012FB8F806008880042057 +:104C2000696A00F07DFD90E2072011E638780128DE +:104C300094D1182204F114007968F9F7FEFBE079A9 +:104C4000C10894F82F0001EAD001E07861F3000078 +:104C5000E070217D002974D12178032909D0C00793 +:104C600025D0032028708DF82090686A0D9041208F +:104C700008E3607DA178884201D90620E8E5022694 +:104C80002671E179204621F0E001E171617A21F09D +:104C9000F0016172A17A21F0F001A172FFF7C8FC66 +:104CA0002E708DF82090686A0D900720EAE20420AB +:104CB000ABE6387805289DD18DF82000686A0D9004 +:104CC000B8680A900720ADF824000A988DF830B033 +:104CD0006168016021898180A17A8171042020703E +:104CE000F8E23978052985D18DF82010696A0D918F +:104CF000391D09AE0EC986E80E004121ADF8241019 +:104D00008DF830B01070A88CD7F80C8080B2402697 +:104D1000A769FFF70EFA41463A463346C846CDF832 +:104D20000090FEF71CFE002108A8FFF75DFCE0786C +:104D300020F03E00801CE0702078052802D00F2073 +:104D40000CE04AE1A07D20B1012802D0032802D066 +:104D500002E10720BEE584F80080EDE42070EBE47A +:104D6000102104F15C0002F0C2FB606BB0BBA07DBF +:104D700018B1012801D00520FDE006202870F84870 +:104D80006063A063C2E23878022894D1387908B110 +:104D90002875B7E3A07D022802D0032805D022E0C1 +:104DA000B8680028F5D060631CE06078012806D060 +:104DB000A07994F82E10012805D0E94806E0A179E1 +:104DC00094F82E00F7E7B8680028E2D06063E07836 +:104DD000C00701D0012902D0E14803E003E0F868F0 +:104DE0000028D6D0A06306200FE68DF82090696ACF +:104DF0000D91E1784846C90709D06178022903D1AD +:104E0000A17D29B1012903D0A17D032900D007206C +:104E1000287033E138780528BBD1207807281ED0C8 +:104E200084F800A005208DF82000686A0D90B8680D +:104E30000A90ADF824A08DF830B003210170E1781C +:104E4000CA070FD0A27D022A1AD000210091D4E90E +:104E5000061204F15C03401CFFF725FA6BE384F8AB +:104E60000090DFE7D4E90923211D8DE80E0004F14D +:104E70002C0304F15C02401C616BFFF722FB5AE338 +:104E8000626BC1F34401491E1268CA4002F001017D +:104E900041F08001DAE738780528BDD18DF820008F +:104EA000686A0D90B8680A90ADF824A08DF830B00B +:104EB000042100F8011B102204F15C01F9F7BDFA8E +:104EC000002108A8FFF790FB2078092801D01320C3 +:104ED00044E70A2020709AE5E078C10742D0A17D1E +:104EE000012902D0022927D038E0617808A80129D9 +:104EF00016D004F16C010091D4E9061204F15C03B0 +:104F0000001DFFF7BBFA0A20287003268DF82080C9 +:104F1000686A0D90002108A8FFF766FBE1E2C7E28E +:104F200004F15C010091D4E9062104F16C03001D39 +:104F3000FFF7A4FA0026E9E7C0F3440114290DD2D3 +:104F40004FF0006101EBB0104FEAB060E0706078A4 +:104F5000012801D01020BDE40620FFE6607801287A +:104F60003FF4B6AC0A2050E5E178C90708D0A17D2E +:104F7000012903D10B202870042030E028702EE096 +:104F80000E2028706078616B012818D004F15C0352 +:104F900004F16C020EA8FFF7E1FA2046FFF748FB88 +:104FA000A0780EAEC0F1100230440021F9F76FFA7C +:104FB00006208DF82000686A09960D909BE004F1A8 +:104FC0006C0304F15C020EA8FFF7C8FAE8E7397831 +:104FD000022903D139790029D0D0297592E28DF8C0 +:104FE0002000686A0D9056E538780728F6D1D4E994 +:104FF00009216078012808D004F16C00CDE9000295 +:10500000029105D104F16C0304E004F15C00F5E7C2 +:1050100004F15C0304F14C007A680646216AFFF74C +:1050200063F96078012822D1A078216AC0F11002CA +:105030000B1800211846F9F72AFAD4E90923606B06 +:1050400004F12D018DE80F0004F15C0300E05BE248 +:1050500004F16C0231460EA8FFF7C8F910220EA920 +:1050600004F13C00F9F7BCF908B10B20ACE485F879 +:10507000008000BF8DF82090686A0D908DF824A004 +:1050800009E538780528A9D18DF82000686A0D90C7 +:10509000B8680A90ADF824A08DF830B080F8008090 +:1050A000617801291AD0D4E9092104F12D03A66BF6 +:1050B00003910096CDE9013204F16C0304F15C0226 +:1050C00004F14C01401CFFF791F9002108A8FFF7FB +:1050D0008BFA6078012805D015203FE6D4E9091243 +:1050E000631DE4E70E20287006208DF82000686A12 +:1050F000CDF824B00D90A0788DF82800CBE4387856 +:105100000328C0D1E079C00770D00F202870072095 +:1051100065E7387804286BD11422391D04F1140096 +:10512000F9F78BF9616A208CA1F80900616AA0780F +:10513000C871E179626A01F003011172616A627AF1 +:105140000A73616AA07A81F8240016205DE485F86C +:1051500000A08DF82090696A50460D9192E0000001 +:10516000706202003878052842D1B868A861617879 +:10517000606A022901D0012100E0002101EB410118 +:10518000142606EBC1014058082102F0B0F96178FD +:10519000606A022901D0012100E0002101EB4101F8 +:1051A00006EBC101425802A8E169FFF70BFA6078EB +:1051B000626A022801D0012000E0002000EB4001DB +:1051C000102000EBC1000223105802A90932FEF79B +:1051D000EEFF626AFD4B0EA80932A169FFF7E1F903 +:1051E0006178606A022904D0012103E044E18DE086 +:1051F000BFE0002101EB4101182606EBC101A278B6 +:1052000040580EA9F9F719F96178606A022901D0AE +:10521000012100E0002101EB410106EBC1014158F1 +:10522000A0780B18C0F1100200211846F9F72FF9E9 +:1052300005208DF82000686A0D90A8690A90ADF8E5 +:1052400024A08DF830B0062101706278616A022ACC +:1052500001D0012200E0002202EB420206EBC20272 +:10526000401C89581022F9F7E8F8002108A8FFF738 +:10527000BBF91220C5F818B028708DF82090686A24 +:105280000D900B208DF8240005E43878052870D1A6 +:105290008DF82000686A0D90B8680A900B20ADF870 +:1052A00024000A98072101706178626A022901D0FE +:1052B000012100E0002101EB4103102101EBC301BA +:1052C00051580988A0F801106178626A022902D059 +:1052D000012101E02FE1002101EB4103142101EB49 +:1052E000C30151580A6840F8032F4968416059E0EA +:1052F0001920287001208DF8300074E616202870DF +:105300008DF830B0002108A8FFF76EF9032617E1E9 +:1053100014202870AEE6387805282AD18DF82000B0 +:10532000686A0D90B8680A90ADF824A08DF830B086 +:1053300080F800906278616A4E46022A01D001220C +:1053400000E0002202EB42021C2303EBC202401CDD +:1053500089581022F9F771F8002108A8FFF744F9DD +:10536000152028708DF82060686A0D908DF82460F3 +:1053700039E680E0387805287DD18DF82000686A0C +:105380000D90B8680A90ADF8249009210170616908 +:10539000097849084170616951F8012FC0F802206D +:1053A0008988C18020781C28A8D1A1E7E078C007AF +:1053B00002D04FF0060C01E04FF0070C6078022895 +:1053C0000AD000BF4FF0000000EB040101F1090119 +:1053D00005D04FF0010004E04FF00100F4E74FF07A +:1053E00000000B78204413EA0C030B7010F8092F0F +:1053F00002EA0C02027004D14FF01B0C84F800C0CA +:10540000D2B394F801C0BCF1010F00D09BB990F861 +:1054100000C0E0465FEACC7C04D028F001060670AC +:10542000102606E05FEA887C05D528F002060670A3 +:1054300013262E70032694F801C0BCF1020F00D091 +:1054400092B991F800C05FEACC7804D02CF0010644 +:105450000E70172106E05FEA8C7805D52CF0020665 +:105460000E701921217000260078D0BBCAB3C3BBCF +:105470001C20207035E012E002E03878062841D187 +:105480001A2015E4207801283CD00C283AD0204678 +:10549000FFF7EBF809208DF82000686A0D9031E0E5 +:1054A0003878052805D00620387003261820287083 +:1054B00046E005208DF82000696A0D91B9680A91CF +:1054C0000221ADF8241001218DF830100A990870DE +:1054D000287D4870394608A8FFF786F80646182048 +:1054E0002870012E0ED02BE001208DF82000686A74 +:1054F0000D9003208DF82400287D8DF8250085F877 +:1055000014B012E0287D80B11D2020701720287073 +:105510008DF82090686A0D9002208DF8240039469D +:1055200008A8FFF761F806460AE00CB1FE202070DB +:105530009DF8200020B1002108A8FFF755F80CE4E1 +:1055400013B03046BDE8F08F2DE9F04387B00C462C +:105550004E6900218DF804100120257803460227AA +:105560004FF007094FF0050C85B1012D53D0022DE6 +:1055700039D1FE2030708DF80030606A059003202C +:105580008DF80400207E8DF8050063E02179012963 +:1055900025D002292DD0032928D0042923D1B17D7B +:1055A000022920D131780D1F042D04D30A3D032D8B +:1055B00001D31D2917D12189022914D38DF8047034 +:1055C000237020899DF80410884201E0686202007F +:1055D00018D208208DF80000606A059057E07078B6 +:1055E0000128EBD0052007B0BDE8F0831D20307006 +:1055F000E4E771780229F5D131780C29F3D18DF8DF +:105600000490DDE7083402F804CB94E80B0082E84C +:105610000B000320E7E71578052DE4D18DF800C0D5 +:10562000656A0595956802958DF8101094F80480C8 +:10563000B8F1010F13D0B8F1020F2DD0B8F1030F5C +:105640001CD0B8F1040FCED1ADF804700E20287034 +:10565000207E687000216846FEF7C6FF0CE0ADF8BA +:1056600004700B202870207E002100F01F0068705D +:105670006846FEF7B9FF37700020B4E7ADF8047054 +:105680008DF8103085F800C0207E687027701146B4 +:105690006846FEF7A9FFA6E7ADF804902B70207FBF +:1056A0006870607F00F00100A870A07F00F01F000C +:1056B000E870E27F2A71C0071CD094F8200000F047 +:1056C0000700687194F8210000F00700A87100211C +:1056D0006846FEF789FF2868F062A8883086A879B6 +:1056E00086F83200A069407870752879B0700D2076 +:1056F0003070C1E7A9716971E9E700B587B0042886 +:105700000CD101208DF800008DF8040000200591D7 +:105710008DF8050001466846FEF766FF07B000BD3C +:1057200070B50C46054602F0C9F921462846BDE889 +:1057300070407823002202F017B908B10078704752 +:105740000C20704770B50C0005784FF000010CD0AC +:1057500021702146EFF7D1FD69482178405D8842EC +:1057600001D1032070BD022070BDEFF7C6FD0020FF +:1057700070BD0279012A05D000220A704B78012BF6 +:1057800002D003E0042070470A758A610279930011 +:10579000521C0271C15003207047F0B587B00F460C +:1057A00005460124287905EB800050F8046C7078D8 +:1057B000411E02290AD252493A46083901EB8000BB +:1057C000314650F8043C2846984704460CB1012C59 +:1057D00011D12879401E10F0FF00287101D0032458 +:1057E000E0E70A208DF80000706A0590002101961C +:1057F0006846FFF7A7FF032CD4D007B02046F0BDC2 +:1058000070B515460A46044629461046FFF7C5FFFF +:10581000064674B12078FE280BD1207C30B10020E0 +:105820002870294604F10C00FFF7B7FF2046FEF769 +:105830001CFF304670BD704770B50E4604467C2292 +:105840000021F8F724FE0225012E03D0022E04D0F9 +:10585000052070BD0120607000E065702046FEF7F5 +:1058600004FFA575002070BD28B1027C1AB10A465C +:1058700000F10C01C4E70120704710B5044686B062 +:10588000042002F01BF92078FE2806D000208DF8B5 +:10589000000069462046FFF7E7FF06B010BD7CB563 +:1058A0000E4600218DF804104178012903D0022909 +:1058B00003D0002405E0046900E044690CB1217CB8 +:1058C00089B16D4601462846FFF753FF032809D1E9 +:1058D000324629462046FFF793FF9DF80410002921 +:1058E00000D004207CBD04F10C05EBE730B40C467D +:1058F0000146034A204630BC024B0C3AFEF751BE2B +:10590000AC6202006862020070B50D46040011D05E +:1059100085B1220100212846F8F7B9FD102250492F +:105920002846F8F78AFD4F48012101704470456010 +:10593000002070BD012070BD70B505460024494EA1 +:1059400011E07068AA7B00EB0410817B914208D1C2 +:10595000C17BEA7B914204D10C222946F8F740FD35 +:1059600030B1641CE4B230788442EAD3002070BDC8 +:10597000641CE0B270BD70B50546FFF7DDFF00287E +:1059800005D1384C20786178884201D3002070BD61 +:105990006168102201EB00102946F8F74EFD2078CF +:1059A000401CC0B2207070BD2E48007870472D4951 +:1059B0000878012802D0401E08700020704770B59A +:1059C0000D460021917014461180022802D0102843 +:1059D00015D105E0288890B10121A17010800CE05C +:1059E000284613B1FFF7C7FF01E0FFF7A5FFA0703E +:1059F00010F0FF0F03D0A8892080002070BD012087 +:105A000070BD0023DBE770B5054614460E0009D0D3 +:105A100000203070A878012806D003D911490A78EF +:105A200090420AD9012070BD24B1287820702888BE +:105A3000000A5070022008700FE064B1496810221B +:105A400001EB001120461039F8F7F7FC2878207395 +:105A50002888000A607310203070002070BD00009C +:105A6000BB620200900000202DE9F04190460C46F8 +:105A700007460025FE48072F00EB881607D2DFE80F +:105A800007F00707070704040400012500E0FFDF13 +:105A900006F81470002D13D0F548803000EB880113 +:105AA00091F82700202803D006EB4000447001E065 +:105AB00081F8264006EB44022020507081F82740F0 +:105AC000BDE8F081F0B51F4614460E460546202A73 +:105AD00000D1FFDFE649E648803100EB871C0CEB84 +:105AE000440001EB8702202E07D00CEB46014078E2 +:105AF0004B784870184620210AE092F8253040780B +:105B000082F82500F6E701460CEB4100057040786D +:105B1000A142F8D192F82740202C03D00CEB44048A +:105B2000637001E082F826300CEB4104202363709F +:105B300082F82710F0BD30B50D46CE4B4419002237 +:105B4000181A72EB020100D2FFDFCB48854200DD5C +:105B5000FFDFC9484042854200DAFFDFC548401CEC +:105B6000844207DA002C01DB204630BDC148401CCE +:105B7000201830BDBF48C043FAE710B5044601689D +:105B8000407ABE4A52F82020114450B10220084405 +:105B900020F07F40EDF763F894F90810BDE810405D +:105BA000C9E70420F3E72DE9F047B14E803696F8B7 +:105BB0002D50DFF8BC9206EB850090F8264034E0CB +:105BC00009EB85174FF0070817F81400012806D0D5 +:105BD00004282ED005282ED0062800D0FFDF01F0A3 +:105BE00025F9014607EB4400427806EB850080F872 +:105BF000262090F82720A24202D1202280F82720D8 +:105C0000084601F01EF92A4621460120FFF72CFF25 +:105C10009B48414600EB041002682046904796F8E6 +:105C20002D5006EB850090F82640202CC8D1BDE809 +:105C3000F087022000E003208046D0E710B58C4CAE +:105C40002021803484F8251084F8261084F8271049 +:105C5000002084F8280084F82D0084F82E10411EBE +:105C6000A16044F8100B2074607420736073A073FB +:105C70008449E07720750870487000217C4A103C08 +:105C800002F81100491CC9B22029F9D30120ECF710 +:105C9000D6FE0020ECF7D3FE012084F82200EDF7B9 +:105CA000FFF87948EDF711F9764CA41E207077487B +:105CB000EDF70BF96070BDE81040ECF74DBE10B584 +:105CC000ECF76FFE6F4CA41E2078EDF717F96078A3 +:105CD000EDF714F9BDE8104001F0E0B8202070475E +:105CE0000020ECF785BE70B5054601240E46AC4099 +:105CF0005AB1FFF7F5FF0146654800EBC500C0F853 +:105D00001015C0F81465634801E06248001D046086 +:105D100070BD2DE9F34F564C0025803404EB810A09 +:105D200089B09AF82500202821D0691E0291544993 +:105D3000009501EB0017391D03AB07C983E8070085 +:105D4000A18BADF81C10A07F8DF81E009DF81500EA +:105D5000A046C8B10226494951F820400399A2192A +:105D6000114421F07F41019184B102210FE0012013 +:105D7000ECF765FE0020ECF762FEECF730FE01F078 +:105D80008DF884F82F50A9E00426E4E700218DF86F +:105D90001810022801D0012820D103980119099870 +:105DA000081A801C9DF81C1020F07F4001B10221D0 +:105DB000353181420BD203208DF815000398C4F1D0 +:105DC0003201401A20F07F40322403900CE098F812 +:105DD000240018B901F043FA002863D0322C03D212 +:105DE00014B101F04FF801E001F058F8254A10789D +:105DF00018B393465278039B121B00219DF818405C +:105E0000994601281AD0032818D000208DF81E00CA +:105E1000002A04DD981A039001208DF818009DF8DF +:105E20001C0000B1022103981B4A20F07F40039020 +:105E300003AB099801F03EF810B110E00120E5E74E +:105E40009DF81D0018B99BF80000032829D08DF893 +:105E50001C50CDF80C908DF818408DF81E509DF810 +:105E6000180010B30398012381190022184615E089 +:105E7000840A0020FF7F841E0020A107CC6202005C +:105E8000840800209A00002017780100A75B010019 +:105E900000F0014004F50140FFFF3F00ECF722FE57 +:105EA00006E000200BB0BDE8F08F0120ECF7C7FD45 +:105EB00097F90C20012300200199ECF713FEF87BE1 +:105EC000C00701D0ECF7F7FE012188F82F108AF8FF +:105ED000285020226946FE48F8F7AFFA0120E1E792 +:105EE0002DE9F05FDFF8E883064608EB860090F8BE +:105EF0002550202D1FD0A8F180002C4600EB8617DE +:105F0000A0F50079DFF8CCB305E0A24607EB4A0024 +:105F10004478202C0AD0ECF730FE09EB04135A46E3 +:105F200001211B1D00F0C6FF0028EED0AC4202D0BC +:105F3000334652461EE0E84808B1AFF30080ECF764 +:105F40001CFE98F82F206AB1D8F80C20411C891A41 +:105F50000902CA1701EB12610912002902DD0020B3 +:105F6000BDE8F09F3146FFF7D4FE08B10120F7E706 +:105F700033462A4620210420FFF7A4FDEFE72DE950 +:105F8000F041D34C2569ECF7F8FD401B0002C11726 +:105F900000EB1160001200D4FFDF94F8220000B182 +:105FA000FFDF012784F8227094F82E00202800D10A +:105FB000FFDF94F82E60202084F82E00002584F85E +:105FC0002F5084F8205084F82150C4482560007870 +:105FD000022833D0032831D000202077A068401C4D +:105FE00005D04FF0FF30A0600120ECF728FD002025 +:105FF000ECF725FDECF721FEECF719FEECF7EFFCD2 +:106000000EF0D6FDB648056005604FF0E0214FF474 +:106010000040B846C1F88002ECF7BBFE94F82D7042 +:106020003846FFF75DFF0028FAD0A948803800EB1A +:10603000871010F81600022802D006E00120CCE7F5 +:106040003A4631460620FFF70FFD84F8238004EB23 +:10605000870090F82600202804D0A048801E4078B1 +:10606000ECF752FF207F002803D0ECF7D6FD257710 +:10607000657725E5964910B591F82D2000248039E3 +:1060800001EB821111F814302BB1641CE4B2202C06 +:10609000F8D3202010BD934901EB041108600020C3 +:1060A000C87321460120FFF7DFFC204610BD10B564 +:1060B000012801D0032800D171B3854A92F82D3010 +:1060C000834C0022803C04EB831300BF13F8124082 +:1060D0000CB1082010BD521CD2B2202AF6D37F4A40 +:1060E00048B1022807D0072916D2DFE801F01506CB +:1060F000080A0C0E100000210AE01B2108E03A21DA +:1061000006E0582104E0772102E0962100E0B52165 +:1061100051701070002010BD072010BD6F4810B5E1 +:106120004078ECF79CFD80B210BD10B5202811D24C +:10613000674991F82D30A1F1800202EB831414F825 +:1061400010303BB191F82D3002EB831212F8102081 +:10615000012A01D0002010BD91F82D200146002019 +:10616000FFF782FC012010BD10B5ECF706FDBDE87D +:106170001040ECF774BD2DE9F0410E46544F017804 +:106180002025803F0C4607EB831303E0254603EBF5 +:1061900045046478944202D0202CF7D108E0202CEA +:1061A00006D0A14206D103EB41014978017007E016 +:1061B000002085E403EB440003EB45014078487080 +:1061C000494F7EB127B1002140F22D40AFF300804E +:1061D0003078A04206D127B100214FF48660AFF39A +:1061E0000080357027B1002140F23540AFF30080C8 +:1061F000012065E410B542680B689A1A1202D417A0 +:1062000002EB1462121216D4497A91B1427A82B921 +:10621000364A006852F82110126819441044001DD3 +:10622000891C081A0002C11700EB11600012322805 +:1062300001DB012010BD002010BD2DE9F047294EE3 +:10624000814606F500709846144600EB811712E06F +:1062500006EB0415291D4846FFF7CCFF68B988F8FE +:106260000040A97B99F80A00814201D80020DEE4B1 +:1062700007EB44004478202CEAD10120D7E42DE933 +:10628000F047824612480E4600EB8600DFF8548045 +:1062900090F825402020107008F5007099461546AA +:1062A00000EB86170BE000BF08EB04105146001D01 +:1062B000FFF7A0FF28B107EB44002C704478202C96 +:1062C000F2D1297889F800104B46224631460FE07A +:1062D000040B0020FFFF3F00000000009A00002098 +:1062E00000F500408408002000000000CC6202009D +:1062F0005046BDE8F047A0E72DE9FC410F460446B3 +:106300000025FE4E10E000BF9DF80000256806EB5A +:1063100000108168204600F0E1FD2068A84202D10B +:106320000020BDE8FC8101256B4601AA39462046C4 +:10633000FFF7A5FF0028E7D02846F2E770B504462E +:10634000EF480125A54300EB841100EB85104022A6 +:10635000F8F773F8EB4E26B1002140F29D40AFF301 +:106360000080E748803000EB850100EB8400D0F826 +:106370002500C1F8250026B1002140F2A140AFF36D +:106380000080284670BD8A4203D003460520FFF7EF +:1063900099BB202906D0DA4A02EB801000EB4100BD +:1063A00040787047D649803101EB800090F8250095 +:1063B0007047D24901EB0010001DFFF7DEBB7CB532 +:1063C0001D46134604460E4600F1080221461846B3 +:1063D000ECF752FC94F908000F2804DD1F382072F6 +:1063E0002068401C206096B10220C74951F8261051 +:1063F000461820686946801B20F07F40206094F991 +:1064000008002844C01C1F2803DA012009E00420EA +:10641000EBE701AAECF730FC9DF8040010B10098FE +:10642000401C00900099206831440844C01C20F0B2 +:106430007F4060607CBDFEB50C46064609786079F9 +:10644000907220791F461546507279B12179002249 +:106450002846A368FFF7B3FFA9492846803191F881 +:106460002E20202A0AD00969491D0DE0D4E9022313 +:10647000217903B02846BDE8F040A0E7A349497858 +:10648000052900D20521314421F07F4100F026FD8D +:1064900039462846FFF730FFD4E9023221796846B1 +:1064A000FFF78DFF2B4600213046019A00F002FDD8 +:1064B000002806D103B031462846BDE8F04000F080 +:1064C0000DBDFEBD2DE9F14F84B000F0C3FCF0B16D +:1064D00000270498007800284FF000006DD1884D07 +:1064E000884C82468346803524B1002140F2045016 +:1064F000AFF3008095F82D8085F823B0002624B1F5 +:10650000002140F20950AFF3008017B105E00127E8 +:10651000DFE74046FFF712FF804624B1002140F23A +:106520001150AFF30080ECF728FB814643466A46E2 +:106530000499FFF780FF24B1002140F21750AFF318 +:10654000008095F82E0020280CD029690098401A68 +:106550000002C21700EB1260001203D5684600F07B +:10656000BDFC01264CB1002140F22150AFF3008068 +:10657000002140F22650AFF300806B46644A0021B0 +:10658000484600F097FC98B127B941466846FFF7A6 +:10659000B3FE064326B16846FFF7EFFA0499886018 +:1065A0004FF0010A24B1002140F23A50AFF30080CD +:1065B00095F82300002897D1504605B073E42DE9E3 +:1065C000F04F89B08B46824600F044FC4C4C80343E +:1065D00030B39BF80000002710B1012800D0FFDF86 +:1065E000484D25B1002140F2F950AFF300804349F6 +:1065F000012001EB0A18A946CDF81C005FEA090644 +:1066000004D0002140F20160AFF30080079800F051 +:1066100018FC94F82D50002084F8230067B119E08D +:1066200094F82E000127202800D1FFDF9BF80000FE +:106630000028D5D0FFDFD3E72846FFF77FFE0546C9 +:1066400026B1002140F20B60AFF3008094F82300E4 +:106650000028D3D126B1002140F21560AFF30080AD +:10666000ECF78BFA2B4602AA59460790FFF7E3FE98 +:1066700098F80F005FEA060900F001008DF813009A +:1066800004D0002140F21F60AFF300803B462A4651 +:1066900002A9CDF800A0079800F02BFC064604EBF9 +:1066A000850090F828000090B9F1000F04D0002177 +:1066B00040F22660AFF3008000F0B8FB0790B9F11C +:1066C000000F04D0002140F22C60AFF3008094F85A +:1066D0002300002892D1B9F1000F04D0002140F22C +:1066E0003460AFF300800DF1080C9CE80E00C8E99F +:1066F0000112C8F80C30BEB30CE000008408002082 +:10670000840A002000000000CC6202009A000020F1 +:10671000FFFF3F005FEA090604D0002140F241601C +:10672000AFF300800098B84312D094F82E002028D0 +:106730000ED126B1002140F24660AFF3008028461A +:10674000FFF7CEFB20B99BF80000D8B3012849D051 +:10675000B9F1000F04D0002140F26360AFF3008074 +:10676000284600F05CFB01265FEA090504D0002101 +:1067700040F26C60AFF30080079800F062FB25B137 +:1067800000214FF4CE60AFF300808EB194F82D005D +:1067900004EB800090F82600202809D025B10021C4 +:1067A00040F27760AFF30080F7484078ECF7ACFB3D +:1067B00025B1002140F27C60AFF3008009B0304683 +:1067C000BDE8F08FFFE7B9F1000F04D0002140F2DF +:1067D0004E60AFF3008094F82D2051460420FFF75F +:1067E00043F9C0E7002E3FF409AF002140F25960A1 +:1067F000AFF3008002E72DE9F84FE44D814695F8AC +:106800002D004FF00008E24C4FF0010B474624B139 +:10681000002140F28A60AFF30080584600F011FB7F +:1068200085F8237024B1002140F28F60AFF300801F +:1068300095F82D00FFF782FD064695F8230028B154 +:10684000002CE4D0002140F295604BE024B10021FF +:1068500040F29960AFF30080CC48803800EB86119D +:1068600011F81900032856D1334605EB830A4A462E +:106870009AF82500904201D1012000E0002000900C +:106880000AF125000021FFF776FC0146009801423D +:1068900003D001228AF82820AF77E1B324B1002188 +:1068A00040F29E60AFF30080324649460120FFF778 +:1068B000DBF89AF828A024B1002140F2A960AFF3D8 +:1068C000008000F0B3FA834624B1002140F2AE60AC +:1068D000AFF3008095F8230038B1002C97D0002149 +:1068E00040F2B260AFF3008091E7BAF1000F07D039 +:1068F00095F82E00202803D13046FFF7F1FAE0B1D9 +:1069000024B1002140F2C660AFF30080304600F0B1 +:1069100086FA4FF0010824B1002140F2CF60AFF3B6 +:106920000080584600F08DFA24B1002140F2D36077 +:10693000AFF300804046BDE8F88F002CF1D0002175 +:1069400040F2C160AFF30080E6E70120ECF750B8F9 +:106950008D48007870472DE9F0418C4C94F82E005A +:1069600020281FD194F82D6004EB860797F8255056 +:10697000202D00D1FFDF8549803901EB861000EB27 +:106980004500407807F8250F0120F87084F82300AF +:10699000294684F82E50324602202234FFF764F84C +:1069A0000020207005E42DE9F0417A4E774C012556 +:1069B00038B1012821D0022879D003287DD0FFDF0B +:1069C00017E400F05FFAFFF7C6FF207E00B1FFDF9B +:1069D00084F821500020ECF732F8A168481C04D05C +:1069E000012300221846ECF77DF814F82E0F2178C9 +:1069F00006EB01110A68012154E0FFF7ACFF01200A +:106A0000ECF71DF894F8210050B1A068401C07D0A5 +:106A100014F82E0F217806EB01110A68062141E0D7 +:106A2000207EDFF86481002708F10208012803D0E6 +:106A300002281ED0FFDFB5E7A777ECF7EEF898F84D +:106A40000000032801D165772577607D524951F810 +:106A5000200094F8201051B948B161680123091A47 +:106A600000221846ECF73EF8022020769AE72776B7 +:106A700098E784F8205000F005FAA07F50B198F80C +:106A8000010061680123091A00221846ECF72AF870 +:106A9000257600E0277614F82E0F217806EB0111F9 +:106AA0000A680021BDE8F041104700E005E03648E3 +:106AB0000078BDE8F041ECF727BAFFF74CFF14F877 +:106AC0002E0F217806EB01110A680521EAE710B5BF +:106AD0002E4C94F82E00202800D1FFDF14F82E0F42 +:106AE00021782C4A02EB01110A68BDE8104004210C +:106AF00010477CB5254C054694F82E00202800D17F +:106B0000FFDFA068401C00D0FFDF94F82E00214971 +:106B100001AA01EB0010694690F90C002844ECF73B +:106B2000ABF89DF904000F2801DD012000E00020F2 +:106B3000009908446168084420F07F41A16094F8FE +:106B40002100002807D002B00123BDE870400022D8 +:106B50001846EBF7C7BF7CBD30B5104A0B1A541C62 +:106B6000B3EB940F1ED3451AB5EB940F1AD393428F +:106B700003D9101A43185B1C14E0954210D9511A1E +:106B80000844401C43420DE098000020040B002004 +:106B90000000000084080020CC620200FF7F841EF9 +:106BA000FFDF0023184630BD0123002201460220EA +:106BB000EBF798BF0220EBF742BFEBF7DEBF2DE902 +:106BC000FE4FEE4C05468A4694F82E00202800D150 +:106BD000FFDFEA4E94F82E10A0462046A6F520725C +:106BE00002EB011420218DF8001090F82D10376968 +:106BF00000EB8101D8F8000091F82590284402AA02 +:106C000001A90C36ECF738F89DF90800002802DDE0 +:106C10000198401C0190A0680199642D084452D34A +:106C2000D74B00225B1B72EB02014CD36168411A07 +:106C300021F07F41B1F5800F45D220F07F40706098 +:106C400086F80AA098F82D1044466B464A4630460E +:106C5000FFF7F3FAB0B3A068401C10D0EBF78DFF3C +:106C6000A168081A0002C11700EB11600012022887 +:106C70002BDD0120EBF7E3FE4FF0FF30A06094F82E +:106C80002D009DF8002020210F34FFF77CFBA17F11 +:106C9000BA4A803A02EB8111E27F01EB420148706F +:106CA00054F80F0C284444F80F0C012020759DF86F +:106CB0000000202803D0B3484078ECF725F90120E4 +:106CC000BDE8FE8F01E00020FAE77760FBE72DE9E1 +:106CD000F047AA4C074694F82D00A4F1800606EB75 +:106CE000801010F8170000B9FFDF94F82D50A0466F +:106CF000A54C24B1002140F6EA00AFF3008040F635 +:106D0000F60940F6FF0A06EB851600BF16F81700D5 +:106D1000012819D0042811D005280FD006280DD03D +:106D20001CB100214846AFF300800FF02DF8002C75 +:106D3000ECD000215046AFF30080E7E72A46394601 +:106D40000120FEF791FEF2E74FF0010A4FF0000933 +:106D5000454624B1002140F60610AFF300805046AE +:106D600000F06FF885F8239024B1002140F60B1055 +:106D7000AFF3008095F82D00FFF7E0FA064695F88E +:106D8000230028B1002CE4D0002140F611101FE0B0 +:106D900024B1002140F61510AFF3008005EB86000A +:106DA00000F1270133463A462630FFF7E4F924B1D3 +:106DB000002140F61910AFF3008000F037F882464A +:106DC00095F8230038B1002CC3D0002140F61F10E5 +:106DD000AFF30080BDE785F82D60012085F8230022 +:106DE000504600F02EF8002C04D0002140F62C1064 +:106DF000AFF30080BDE8F08730B504465F480D462C +:106E000090F82D005D49803901EB801010F81400D6 +:106E100000B9FFDF5D4800EB0410C57330BD574972 +:106E200081F82D00012081F82300704710B55848E3 +:106E300008B1AFF30080EFF3108000F0010072B6EC +:106E400010BD10B5002804D1524808B1AFF300803E +:106E500062B610BD50480068C005C00D10D0103893 +:106E600040B2002804DB00F1E02090F8000405E0C7 +:106E700000F00F0000F1E02090F8140D4009704779 +:106E80000820704710B53D4C94F82400002804D128 +:106E9000F4F712FF012084F8240010BD10B5374C20 +:106EA00094F82400002804D0F4F72FFF002084F881 +:106EB000240010BD10B51C685B68241A181A24F051 +:106EC0007F4420F07F40A14206D8B4F5800F03D262 +:106ED000904201D8012010BD002010BDD0E9003241 +:106EE000D21A21F07F43114421F07F41C0E90031E3 +:106EF00070472DE9FC418446204815468038089C9F +:106F000000EB85160F4616F81400012804D002285D +:106F100002D00020BDE8FC810B46204A01216046DA +:106F2000FFF7C8FFF0B101AB6A4629463846FFF7C4 +:106F3000A6F9B8B19DF804209DF800102846FFF787 +:106F400022FA06EB440148709DF8000020280DD07D +:106F500006EB400044702A4621460320FEF784FDDC +:106F60000120D7E72A4621460420F7E703480121FC +:106F700000EB850000F8254FC170ECE7040B002002 +:106F8000FF1FA107980000200000000084080020D7 +:106F9000000000000000000004ED00E0FFFF3F00E3 +:106FA0002DE9F041044680074FF000054FF001063F +:106FB0000CD56B480560066000F0E8F920B169481F +:106FC000016841F48061016024F00204E0044FF0A4 +:106FD000FF3705D564484660C0F8087324F4805430 +:106FE000600003D56148056024F08044E0050FD5BA +:106FF0005F48C0F80052C0F808735E490D60091D73 +:107000000D605C4A04210C321160066124F4807426 +:10701000A00409D558484660C0F80052C0F808736B +:107020005648056024F40054C4F38030C4F3C031E2 +:10703000884200D0FFDF14F4404F14D0504846601F +:10704000C0F808734F488660C0F80052C0F8087353 +:107050004D490D600A1D16608660C0F808730D600A +:10706000166024F4404420050AD5484846608660EE +:10707000C0F80873C0F848734548056024F40064FC +:107080000DF070FD4348044200D0FFDFBDE8F08101 +:10709000F0B50022202501234FEA020420FA02F174 +:1070A000C9072DD051B2002910DB00BF4FEA51179C +:1070B0004FEA870701F01F0607F1E02703FA06F6FB +:1070C000C7F88061BFF34F8FBFF36F8F0CDB00BF3A +:1070D0004FEA51174FEA870701F01F0607F1E02733 +:1070E00003FA06F6C7F8806204DB01F1E02181F8BB +:1070F000004405E001F00F0101F1E02181F8144D99 +:1071000002F10102AA42C9D3F0BD10B5224C2060A1 +:107110000846F4F7EAFE2068FFF742FF2068FFF711 +:10712000B7FF0DF045F900F092F90DF01BFD0DF0E1 +:1071300058FCEBF7B5FEBDE810400DF0EDB910B509 +:10714000154C2068FFF72CFF2068FFF7A1FF0DF01A +:1071500009FDF4F7C9FF0020206010BD0A20704728 +:10716000FC1F00403C17004000C0004004E5014007 +:10717000008000400485004000D0004004D500405D +:1071800000E0004000F0004000F5004000B000408A +:1071900008B50040FEFF0FFD9C00002070B5264999 +:1071A0000A680AB30022154601244B685B1C4B6039 +:1071B0000C2B00D34D600E7904FA06F30E681E42C4 +:1071C0000FD0EFF3108212F0010272B600D001224C +:1071D0000C689C430C6002B962B6496801600020EB +:1071E00070BD521C0C2AE0D3052070BD4FF0E02189 +:1071F0004FF48000C1F800027047EFF3108111F0E6 +:10720000010F72B64FF0010202FA00F20A48036859 +:1072100042EA0302026000D162B6E7E706480021B5 +:1072200001604160704701218140034800680840C7 +:1072300000D0012070470000A0000020012081073D +:10724000086070470121880741600021C0F80011E3 +:1072500018480170704717490120087070474FF0B7 +:107260008040D0F80001012803D01248007800289F +:1072700000D00120704710480068C00700D00120EE +:1072800070470D480C300068C00700D001207047DF +:107290000948143000687047074910310A68D20362 +:1072A00006D5096801F00301814201D10120704730 +:1072B00000207047A8000020080400404FF08050D4 +:1072C000D0F830010A2801D0002070470120704713 +:1072D00000B5FFF7F3FF20B14FF08050D0F8340134 +:1072E00008B1002000BD012000BD4FF08050D0F853 +:1072F00030010E2801D000207047012070474FF068 +:107300008050D0F83001062803D0401C01D0002066 +:107310007047012070474FF08050D0F830010D28A1 +:1073200001D000207047012070474FF08050D0F806 +:107330003001082801D000207047012070474FF02D +:107340008050D0F83001102801D000207047012073 +:10735000704700B5FFF7F3FF30B9FFF7DCFF18B94E +:10736000FFF7E3FF002800D0012000BD00B5FFF7C4 +:10737000C6FF38B14FF08050D0F83401062803D34F +:10738000401C01D0002000BD012000BD00B5FFF76A +:10739000B6FF48B14FF08050D0F83401062803D32F +:1073A000401C01D0012000BD002000BD0021017063 +:1073B000084670470146002008707047EFF31081BF +:1073C00001F0010172B60278012A01D0012200E029 +:1073D00000220123037001B962B60AB10020704790 +:1073E0004FF400507047E9E7EFF3108111F0010FFF +:1073F00072B64FF00002027000D162B600207047F2 +:10740000F2E700002DE9F04115460E46044600273C +:1074100000F0EBF8A84215D3002341200FE000BF95 +:1074200094F84220A25CF25494F84210491CB1FB3B +:10743000F0F200FB12115B1C84F84210DBB2AB428D +:10744000EED3012700F0DDF83846BDE8F08172493F +:1074500010B5802081F800047049002081F84200B6 +:1074600081F84100433181F8420081F84100433105 +:1074700081F8420081F841006948FFF797FF6848AA +:10748000401CFFF793FFEBF793FCBDE8104000F0C2 +:10749000B8B840207047614800F0A7B80A460146D6 +:1074A0005E48AFE7402070475C48433000F09DB82D +:1074B0000A46014659484330A4E7402101700020A4 +:1074C000704710B504465548863000F08EF820709D +:1074D000002010BD0A460146504810B58630FFF71F +:1074E00091FF08B1002010BD42F2070010BD70B539 +:1074F0000C460646412900D9FFDF4A48006810388B +:1075000040B200F054F8C5B20D2000F050F8C0B2FF +:10751000854201D3012504E0002502E00DB1EBF71F +:107520008AFC224631463D48FFF76CFF0028F5D023 +:1075300070BD2DE9F0413A4F0025064617F10407CA +:1075400057F82540204600F041F810B36D1CEDB20D +:10755000032DF5D33148433000F038F8002825D00A +:107560002E4800F033F8002820D02C48863000F058 +:107570002DF800281AD0EBF734FC2948FFF71EFF3E +:10758000B0F5005F00D0FFDFBDE8F0412448FFF711 +:107590002BBF94F841004121265414F8410F401CA0 +:1075A000B0FBF1F201FB12002070D3E74DE7002899 +:1075B00004DB00F1E02090F8000405E000F00F008B +:1075C00000F1E02090F8140D4009704710F8411FB9 +:1075D0004122491CB1FBF2F302FB131140788142B6 +:1075E00001D1012070470020704710F8411F4078FA +:1075F000814201D3081A02E0C0F141000844C0B240 +:10760000704710B50648FFF7D9FE002803D1BDE842 +:107610001040EBF7D1BB10BD0DE000E0340B0020B3 +:10762000AC00002004ED00E070B5154D2878401C3A +:10763000C4B26878844202D000F0DBFA2C7070BDCE +:107640002DE9F0410E4C4FF0E02600BF00F0C6FAE5 +:107650000EF09AFB40BF20BF677820786070D6F8A4 +:107660000052E9F798FE854305D1D6F8040210B917 +:107670002078B842EAD000F0ACFA0020BDE8F081F2 +:10768000BC0000202DE9F04101264FF0E02231033B +:107690004FF000084046C2F88011BFF34F8FBFF390 +:1076A0006F8F204CC4F800010C2000F02EF81E4D06 +:1076B0002868C04340F30017286840F01000286095 +:1076C000C4F8046326607F1C02E000BF0EF05CFB80 +:1076D000D4F800010028F9D01FB9286820F0100064 +:1076E0002860124805686660C4F80863C4F8008121 +:1076F0000C2000F00AF82846BDE8F08110B50446D9 +:10770000FFF7C0FF2060002010BD002809DB00F05B +:107710001F02012191404009800000F1E020C0F8E3 +:107720008012704700C0004010ED00E008C5004026 +:107730002DE9F047FF4C0646FF21A06800EB06123A +:1077400011702178FF2910D04FF0080909EB0111C1 +:1077500009EB06174158C05900F0F4F9002807DD7D +:10776000A168207801EB061108702670BDE8F0874B +:1077700094F8008045460DE0A06809EB05114158DA +:10778000C05900F0DFF9002806DCA068A84600EB2D +:1077900008100578FF2DEFD1A06800EB061100EB73 +:1077A00008100D700670E1E7F0B5E24B04460020CA +:1077B00001259A680C269B780CE000BF05EB0017AA +:1077C000D75DA74204D106EB0017D7598F4204D0EA +:1077D000401CC0B28342F1D8FF20F0BD70B5FFF766 +:1077E000ECF9D44C08252278A16805EB02128958DF +:1077F00000F0A8F9012808DD2178A06805EB011147 +:107800004058BDE87040FFF7CFB9FFF7A1F8BDE8D9 +:107810007040EBF779BB2DE9F041C64C2578FFF7B6 +:10782000CCF9FF2D6ED04FF00808A26808EB0516C2 +:10783000915900F087F90228A06801DD80595DE0C8 +:1078400000EB051109782170022101EB0511425C62 +:107850005AB1521E4254815901F5800121F07F41F5 +:1078600081512846FFF764FF34E00423012203EB33 +:10787000051302EB051250F803C0875CBCF1000F42 +:1078800010D0BCF5007F10D9CCF3080250F806C028 +:107890000CEB423C2CF07F4C40F806C0C3589A1ABF +:1078A000520A09E0FF2181540AE0825902EB4C326E +:1078B00022F07F428251002242542846FFF738FFCF +:1078C0000C21A06801EB05114158E06850F8272011 +:1078D000384690472078FF2814D0FFF76EF92278B9 +:1078E000A16808EB02124546895800F02BF90128DF +:1078F00093DD2178A06805EB01114058BDE8F04107 +:10790000FFF752B9BDE8F081F0B51D4614460E46AA +:107910000746FF2B00D3FFDFA00700D0FFDF85481D +:10792000FF210022C0E90247C57006710170427054 +:1079300082701046012204E002EB0013401CE15467 +:10794000C0B2A842F8D3F0BD70B57A4C064665784F +:107950002079854200D3FFDFE06840F82560607839 +:10796000401C6070284670BD2DE9FF5F1D468B46A8 +:107970000746FF24FFF721F9DFF8B891064699F88A +:107980000100B84200D8FFDF00214FF001084FF09E +:107990000C0A99F80220D9F808000EE008EB011350 +:1079A000C35CFF2B0ED0BB4205D10AEB011350F88C +:1079B00003C0DC450CD0491CC9B28A42EED8FF2C6A +:1079C00002D00DE00C46F6E799F803108A4203D185 +:1079D000FF2004B0BDE8F09F1446521C89F8022035 +:1079E00008EB04110AEB0412475440F802B00421DA +:1079F000029B0022012B01EB04110CD040F8012066 +:107A00004FF4007808234FF0020C454513D9E905DF +:107A1000C90D02D002E04550F2E7414606EB413283 +:107A200003EB041322F07F42C250691A0CEB0412DC +:107A3000490A81540BE005B9012506EB453103EBFA +:107A4000041321F07F41C1500CEB0411425499F80A +:107A500000502046FFF76CFE99F80000A84201D0C4 +:107A6000FFF7BCFE3846B4E770B50C460546FFF795 +:107A7000A4F8064621462846FFF796FE0446FF284E +:107A80001AD02C4D082101EB0411A868415830464A +:107A900000F058F800F58050C11700EBD1404013BA +:107AA0000221AA6801EB0411515C09B100EB4120ED +:107AB000002800DC012070BD002070BD2DE9F047DA +:107AC00088468146FFF770FE0746FF281BD0194DF8 +:107AD0002E78A8683146344605E0BC4206D02646DA +:107AE00000EB06121478FF2CF7D10CE0FF2C0AD023 +:107AF000A6420CD100EB011000782870FF2804D0BA +:107B0000FFF76CFE03E0002030E6FFF753F8414634 +:107B10004846FFF7A9FF0123A968024603EB0413B7 +:107B2000FF20C854A878401EB84200D1A87001EBCD +:107B3000041001E0000C002001EB06110078087031 +:107B4000104613E6081A0002C11700EB116000127C +:107B50007047000010B5202000F07FF8202000F0D2 +:107B60008DF84D49202081F80004E9F712FC4B49BB +:107B700008604B48D0F8041341F00101C0F8041329 +:107B8000D0F8041341F08071C0F804134249012079 +:107B90001C39C1F8000110BD10B5202000F05DF8BF +:107BA0003E480021C8380160001D01603D4A481E62 +:107BB00010603B4AC2F80803384B1960C2F8000154 +:107BC000C2F8600138490860BDE81040202000F08C +:107BD00055B834493548091F086070473149334862 +:107BE000086070472D48C8380160001D521E0260B1 +:107BF00070472C4901200860BFF34F8F70472DE973 +:107C0000F0412849D0F8188028480860244CD4F85E +:107C100000010025244E6F1E28B14046E9F712FBF3 +:107C200040B9002111E0D4F8600198B14046E9F76D +:107C300009FB48B1C4F80051C4F860513760BDE891 +:107C4000F041202000F01AB831684046BDE8F0410C +:107C50000EF0A4B8FFDFBDE8F08100280DDB00F0D6 +:107C60001F02012191404009800000F1E020C0F88E +:107C70008011BFF34F8FBFF36F8F7047002809DB70 +:107C800000F01F02012191404009800000F1E02036 +:107C9000C0F880127047000020E000E0C8060240F3 +:107CA00000000240180502400004024001000001EB +:107CB0005E4800210170417010218170704770B5DD +:107CC000054616460C460220EAF714FE57490120E5 +:107CD00008705749F01E086056480560001F046090 +:107CE00070BD10B50220EAF705FE5049012008706A +:107CF00051480021C0F80011C0F80411C0F8081163 +:107D00004E494FF40000086010BD48480178D9B1D1 +:107D10004B4A4FF4000111604749D1F8003100226D +:107D2000002B1CBFD1F80431002B02D0D1F8081170 +:107D300019B142704FF0100104E04FF001014170A1 +:107D400040490968817002704FF00000EAF7D2BD27 +:107D500010B50220EAF7CEFD34480122002102705E +:107D60003548C0F80011C0F80411C0F808110260CD +:107D700010BD2E480178002904BF407870472E4876 +:107D8000D0F80011002904BF02207047D0F800117C +:107D900000291CBFD0F80411002905D0D0F8080133 +:107DA000002804BF01207047002070471F4800B51D +:107DB0000278214B4078C821491EC9B282B1D3F85C +:107DC00000C1BCF1000F10D0D3F8000100281CBF87 +:107DD000D3F8040100280BD0D3F8080150B107E014 +:107DE000022802D0012805D002E00029E4D1FFDFFB +:107DF000002000BD012000BD0C480178002904BF0F +:107E0000807870470C48D0F8001100291CBFD0F8CA +:107E10000411002902D0D0F8080110B14FF0100071 +:107E2000704708480068C0B270470000BE000020DC +:107E300010F5004008F5004000F0004004F5014056 +:107E400008F5014000F400405748002101704170DE +:107E5000704770B5064614460D460120EAF74AFD04 +:107E600052480660001D0460001D05605049002056 +:107E7000C1F850014F490320086050494E4808603E +:107E8000091D4F48086070BD2DE9F0410546464880 +:107E90000C46012606704B4945EA024040F08070CE +:107EA0000860FFF72CFA002804BF47480460002749 +:107EB000464CC4F80471474945480860002D02BF8C +:107EC000C4F800622660BDE8F081012D18BFFFDF15 +:107ED000C4F80072266041493F480860BDE8F0815F +:107EE0003148017871B13B4A394911603749D1F8BD +:107EF00004210021002A08BF417002D0384A1268CC +:107F0000427001700020EAF7F5BC2748017800298B +:107F100004BF407870472D48D0F80401002808BFFE +:107F200070472F480068C0B27047002808BF7047EC +:107F30002DE9F0471C480078002808BFFFDF234CDC +:107F4000D4F80401002818BFBDE8F0874FF00209FB +:107F5000C4F80493234F3868C0F30018386840F021 +:107F600010003860D4F80401002804BF4FF4004525 +:107F70004FF0E02608D100BFC6F880520DF004FF94 +:107F8000D4F804010028F7D0B8F1000F03D1386805 +:107F900020F010003860C4F80893BDE8F0870B4962 +:107FA0000120886070470000C100002008F50040F3 +:107FB000001000401CF500405011004098F50140B1 +:107FC0000CF0004004F5004018F5004000F00040BF +:107FD0000000020308F501400000020204F5014020 +:107FE00000F4004010ED00E0012804BF41F6A47049 +:107FF0007047022804BF41F288307047042804BF4C +:1080000046F218007047082804BF47F2A0307047B6 +:1080100000B5FFDF41F6A47000BD10B5FE48002496 +:1080200001214470047044728472C17280F825404A +:10803000C462846380F83C4080F83D40FF2180F8B2 +:108040003E105F2180F83F1018300DF09FFFF3497C +:10805000601E0860091D0860091D0C60091D08608C +:10806000091D0C60091D0860091D0860091D0860D4 +:10807000091D0860091D0860091D0860091D0860C8 +:10808000091D0860091D086010BDE549486070477A +:10809000E448016801F00F01032904BF0120704783 +:1080A000016801F00F01042904BF02207047016834 +:1080B00001F00F01052904D0006800F00F00062828 +:1080C00007D1D948006810F0060F0CBF0820042023 +:1080D000704700B5FFDF012000BD012812BF022854 +:1080E00000207047042812BF08284FF4C87070475A +:1080F00000B5FFDF002000BD012804BF2820704725 +:10810000022804BF18207047042812BF08284FF423 +:10811000A870704700B5FFDF282000BD70B5C148CA +:10812000016801F00F01032908BF012414D0016880 +:1081300001F00F01042904BF022418210DD00168A9 +:1081400001F00F0105294BD0006800F00F00062850 +:108150001CBFFFDF012443D02821AF48C26A806AD8 +:10816000101A0E18082C04BF4EF6981547F2A030CE +:108170002DD02046042C08BF4EF628350BD0012800 +:1081800008BF41F6A47506D0022C1ABFFFDF41F6E6 +:10819000A47541F28835012C08BF41F6A47016D0B1 +:1081A000022C08BF002005D0042C1ABFFFDF0020DE +:1081B0004FF4C8702D1A022C08BF41F2883006D047 +:1081C000042C1ABFFFDF41F6A47046F21800281AEB +:1081D0004FF47A7100F2E730B0FBF1F0304470BD3B +:1081E0009148006810F0060F0CBF082404244FF4D7 +:1081F000A871B2E710B58D49026801F118040A634D +:1082000042684A63007A81F83800207E48B1207FB6 +:10821000F6F781F9A07E011C18BF0121207FF6F737 +:1082200069F9607E002808BF10BD607FF6F773F91A +:10823000E07E011C18BF0121607FBDE81040F6F709 +:1082400059B930B50024054601290AD0022908BFD2 +:108250004FF0807405D0042916BF08294FF0C74499 +:10826000FFDF44F4847040F480107149086045F4E5 +:10827000403001F1040140F00070086030BD30B5BD +:108280000024054601290AD0022908BF4FF0807456 +:1082900005D0042916BF08294FF0C744FFDF44F476 +:1082A000847040F480106249086045F4403001F168 +:1082B000040140F0007008605E48D0F8000100281A +:1082C00018BFFFDF30BD2DE9F04102274FF0E02855 +:1082D00001250024C8F88071BFF34F8FBFF36F8F63 +:1082E000554804600560FFF751F8544E18B13068E6 +:1082F00040F480603060FFF702F838B1306820F059 +:10830000690040F0960040F0004030604D494C4814 +:1083100008604FF01020806CB0F1FF3F04D04A4954 +:108320000A6860F317420A60484940F25B600860DF +:10833000091F40F203100860081F05603949032037 +:10834000086043480560444A42491160444A434931 +:108350001160121F43491160016821F440710160EE +:10836000016841F480710160C8F8807231491020C1 +:10837000C1F80403284880F83140C46228484068A6 +:10838000002808BFBDE8F081BDE8F0410047274A5A +:108390000368C2F81A308088D08302F11800017295 +:1083A00070471D4B10B51A7A8A4208D10146062241 +:1083B000981CF6F715F8002804BF012010BD002016 +:1083C00010BD154890F825007047134A5170107081 +:1083D0007047F0B50546800000F1804000F5805000 +:1083E0008B88C0F820360B78D1F8011043EA0121C0 +:1083F000C0F8001605F10800012707FA00F61A4C2C +:10840000002A04BF2068B04304D0012A18BFFFDF50 +:1084100020683043206029E0280C0020000E004036 +:10842000C40000201015004014140040100C00205F +:108430001415004000100040FC1F00403C17004095 +:108440002C000089781700408C150040381500403A +:108450005016004000000E0408F501404080004026 +:10846000A4F501401011004040160040206807FAB2 +:1084700005F108432060F0BD0CF0C4BCFE4890F844 +:1084800032007047FD4AC17811600068FC49000263 +:1084900008607047252808BF02210ED0262808BF93 +:1084A0001A210AD0272808BF502106D00A2894BFD5 +:1084B0000422062202EB4001C9B2F24A1160F249DD +:1084C000086070472DE9F047EB4CA17A012956D09E +:1084D000022918BFBDE8F087627E002A08BFBDE808 +:1084E000F087012950D0E17E667F0D1C18BF012561 +:1084F0005FF02401DFF894934FF00108C9F84C8035 +:10850000DFF88CA34718DAF80000B84228BFFFDF75 +:108510000020C9F84C01CAF80070300285F0010152 +:1085200040EA015040F0031194F82000820002F16B +:10853000804202F5C042C2F81015D64901EB800115 +:10854000A07FC20002F1804202F5F832C2F8141591 +:10855000D14BC2F81035E27FD30003F1804303F51D +:10856000F833C3F81415CD49C3F8101508FA00F014 +:1085700008FA02F10843CA490860BDE8F087227E84 +:10858000002AAED1BDE8F087A17E267F002914BF66 +:10859000012500251121ADE72DE9F041C14E8046AE +:1085A00003200D46C6F80002BD49BF4808602846B2 +:1085B0000CF02CFCB04F0124B8F1000F04BFBC72CA +:1085C000346026D0B8F1010F23D1B848006860B9F3 +:1085D00015F00C0F09D0C6F80443012000F0DAFEB4 +:1085E000F463346487F83C4002E0002000F0D2FEDF +:1085F00028460CF0F3FC0220B872FEF7B7FE38B93B +:10860000FEF7C4FE20B9AA48016841F4C021016008 +:1086100074609E48C4649E4800682946BDE8F041E5 +:1086200050E72DE9F0479F4E814603200D46C6F8DE +:108630000002DFF86C829C48C8F8000008460CF085 +:10864000E5FB28460CF0CAFC01248B4FB9F1000F62 +:1086500003D0B9F1010F0AD031E0BC72B86B40F41D +:108660008010B8634FF48010C8F8000027E00220A3 +:10867000B872B86B40F40010B8634FF40010C8F83B +:1086800000008A48006860B915F00C0F09D0C6F8E0 +:108690000443012000F07EFEF463346487F83C401C +:1086A00002E0002000F076FEFEF760FE38B9FEF72B +:1086B0006DFE20B97E48016841F4C0210160EAF7EF +:1086C000F7FA2946BDE8F047FCE62DE9F84F754C6E +:1086D0008246032088461746C4F80002DFF8C0919E +:1086E0007148C9F8000010460CF090FBDFF8C4B1E7 +:1086F000614E0125BAF1000F04BFCBF80040B572FE +:1087000004D0BAF1010F18BFFFDF2FD06A48C0F8BC +:1087100000806B4969480860B06B40F40020B0638A +:10872000D4F800321021C4F808130020C4F8000265 +:10873000DFF890C18A03CCF80020C4F80001C4F827 +:108740000C01C4F81001C4F80401C4F81401C4F801 +:1087500018015D4800680090C4F80032C9F8002094 +:10876000C4F80413BAF1010F14D026E038460CF017 +:1087700035FCFEF7FBFD38B9FEF708FE20B94C4882 +:10878000016841F4C02101605048CBF8000002208C +:10879000B072BBE74548006860B917F00C0F09D00C +:1087A000C4F80453012000F0F5FDE563256486F864 +:1087B0003C5002E0002000F0EDFD4FF40020C9F82D +:1087C00000003248C56432480068404528BFFFDFDA +:1087D00039464046BDE8F84F74E62DE9F041264C95 +:1087E0000646002594F8310017468846002808BF41 +:1087F000FFDF16B1012E16D021E094F831000128D8 +:1088000008D094F83020394640460CF014FBE16A59 +:10881000451814E094F830103A4640460CF049FBF5 +:10882000E16A45180BE094F8310094F83010012803 +:108830003A46404609D00CF064FBE16A45183A46D6 +:1088400029463046BDE8F0413FE70CF014FBE16AF1 +:108850004518F4E72DE9F84F124CD4F8000220F047 +:108860000309D4F804034FF0100AC0F30018C4F849 +:1088700008A300262CE00000280C0020241500404E +:108880001C150040081500405415004000800040B1 +:108890004C850040006000404C81004010110040B9 +:1088A00004F5014000100040000004048817004057 +:1088B00068150040ACF50140488500404881004003 +:1088C000A8F5014008F501401811004004100040CF +:1088D000C4F80062FC48FB490160FC4D0127A97AFD +:1088E000012902D0022903D015E0297E11B912E036 +:1088F000697E81B1A97FEA7F07FA01F107FA02F2E6 +:108900001143016095F82000800000F1804000F5DF +:10891000C040C0F81065FF208DF80000C4F8106159 +:10892000276104E09DF80000401E8DF800009DF8CE +:10893000000018B1D4F810010028F3D09DF8000011 +:10894000002808BFFFDFC4F81061002000F022FDFE +:108950006E72AE72EF72C4F80092B8F1000F18BFD9 +:10896000C4F804A3BDE8F88FFF2008B58DF8000017 +:10897000D7480021C0F810110121016105E000BFB6 +:108980009DF80010491E8DF800109DF8001019B1D7 +:10899000D0F810110029F3D09DF80000002808BF7E +:1089A000FFDF08BD0068CB4920F07F4008607047BA +:1089B0004FF0E0200221C0F8801100F5C070BFF335 +:1089C0004F8FBFF36F8FC0F80011704710B490E85D +:1089D0001C10C14981E81C10D0E90420C1E9042021 +:1089E00010BC70474FF0E0210220C1F80001704731 +:1089F000BA4908707047BA490860704770B50546B3 +:108A0000EAF756F9B14C2844E16A884298BFFFDF83 +:108A100001202074EAF74CF9B24A28440021606131 +:108A2000C2F84411B0490860A06BB04940F480001E +:108A3000A063D001086070BD70B5A44C0546AC4A77 +:108A40000220207410680E4600F00F00032808BFB3 +:108A5000012213D0106800F00F00042808BF022282 +:108A60000CD0106800F00F0005281BD0106800F033 +:108A70000F0006281CBFFFDF012213D094F831003D +:108A800094F83010012815D028460CF081FA954949 +:108A900060610020C1F844016169E06A08449249BC +:108AA000086070BD9348006810F0060F0CBF0822E4 +:108AB0000422E3E7334628460CF038FAE7E7824918 +:108AC0004FF4800008608148816B21F4800181634C +:108AD000002101747047C20002F1804202F5F832B1 +:108AE000854BC2F81035C2F81415012181407F482A +:108AF00001607648826B1143816370477948012198 +:108B00004160C1600021C0F84411774801606F489E +:108B1000C1627047794908606D48D0F8001241F091 +:108B20004001C0F8001270476948D0F8001221F0E7 +:108B30004001C0F800127149002008607047644885 +:108B4000D0F8001221F01001C0F80012012181615B +:108B500070475E49FF2081F83E005D480021C0F863 +:108B60001C11D0F8001241F01001C0F8001270473B +:108B7000574981B0D1F81C21012A0DD0534991F8F1 +:108B80003E10FF290DBF00204942017001B008BF0F +:108B90007047012001B07047594A126802F07F0205 +:108BA000524202700020C1F81C0156480068009033 +:108BB000EFE7F0B517460C00064608BFFFDF434D50 +:108BC00014F0010F2F731CBF012CFFDF002E0CBF10 +:108BD000012002206872EC7201281CBF0228FFDF0E +:108BE000F0BD3A4981F83F007047384A136C036082 +:108BF000506C086070472DE9F84F38480078042819 +:108C000028BFFFDF314CDFF8C080314D94F83C00C5 +:108C100000260127E0B1D5F8040110F1000918BFC2 +:108C20004FF00109D5F81001002818BF012050EAC3 +:108C300009014FF4002B17D08021C5F80813C8F89C +:108C400000B084F83C6090F0010F18BFBDE8F88FC9 +:108C5000DFF89090D9F84C01002871D0A07A012853 +:108C60006FD002286ED0D1E0D5F80001DFF890A0D7 +:108C700030B3C5F800616F61FF20009002E0401E34 +:108C8000009005D0D5F81C0100280098F7D000B955 +:108C9000FFDFDAF8000000F07F0A94F83F0050454B +:108CA0003CBF002000F076FB84F83EA0C5F81C61B4 +:108CB000C5F808731348006800902F64AF6326E07E +:108CC00022E0000000000E0408F50140280C0020FE +:108CD000001000403C150040100C0020C400002093 +:108CE00004150040008000404485004004F5014028 +:108CF000101500401414004004110040601500409D +:108D0000481500401C110040B9F1000F03D0B9F123 +:108D1000000F2ED05CE0DAF8000000F07F0084F84D +:108D20003E00C5F81C6194F83D1061B194F83F1005 +:108D300081421BD2002000F02DFB2F64AF6315E0B1 +:108D400064E04CE04EE0FE49096894F83F308AB296 +:108D5000090C984203D30F2A06D9022904D2012014 +:108D600000F018FB2F6401E02F64AF63F548006842 +:108D700000908022C5F80423F3498F64F348036808 +:108D8000A0F1040CDCF800C043F698273B4463458F +:108D900015D2026842F210731A440260C1F84861A9 +:108DA000EC49EB480860091FEB480860EB48C0F845 +:108DB00000B0A06B40F40020A063BDE8F88F06600F +:108DC000C1F84861C5F80823C8F800B0C1F8486187 +:108DD0008020C5F80803C8F800B0BDE8F88F207EF1 +:108DE00010B913E0607E88B1A07FE17F07FA00F040 +:108DF00007FA01F10843C8F8000094F82000800049 +:108E000000F1804000F5C040C0F81065C9F84C7012 +:108E1000D34800682064D34800686064D248A16BDE +:108E20000160A663217C002019B1D9F84411012901 +:108E300000D00021A27A012A6ED0022A74D000BF8D +:108E4000D5F8101101290CBF1021002141EA0008BA +:108E5000C648016811F0FF0F03D0D5F8141101299D +:108E600000D0002184F83210006810F0FF0F03D00A +:108E7000D5F81801012800D0002084F83300BC4840 +:108E8000006884F83400FEF774FF012818BF002042 +:108E900084F83500C5F80061C5F80C61C5F81061AB +:108EA000C5F80461C5F81461C5F81861B1480068D7 +:108EB0000090A548C0F84461AF480068DFF8BC9254 +:108EC0000090D9F80000A062A9F104000068E062F7 +:108ED000AB48016801F00F01032908BF012013D03E +:108EE000016801F00F01042908BF02200CD00168BD +:108EF00001F00F01052926D0006800F00F000628B8 +:108F00001CBFFFDF01201ED084F83000A07A84F857 +:108F1000310002282CD11EE0D5F80C01012814BF25 +:108F2000002008208CE7FFE7D5F80C01012814BFCA +:108F300000200220934A1268012A14BF0422002252 +:108F4000104308437CE79048006810F0060F0CBF00 +:108F500008200420D8E7607850B18C490968097866 +:108F60000840217831EA000008BF84F8247001D05D +:108F700084F82460DFF818A218F0020F06D0E9F791 +:108F800097FEA16A081ADAF81010884718F0010F46 +:108F900018BF4FF0000B0DD0E9F78AFEE16ADAF84E +:108FA0001420081A594690477A48007810F0010FAB +:108FB0002FD10CE018F0020F18BF4FF0010BEBD1CE +:108FC00018F0080F18BF4FF0020BE5D1ECE7DFF8FF +:108FD000BCB1DBF80000007800F00F00072828BFC4 +:108FE00084F8256015D2DBF80000062200F10901A3 +:108FF000A01CF5F7F5F940B9207ADBF800100978E4 +:10900000B0EBD11F08BF012001D04FF0000084F861 +:109010002500E17A4FF0000011F0020F1CBF18F09C +:10902000020F18F0040F19D111F0100F1CBF94F8A3 +:109030003320002A02D094F835207AB111F0080FBD +:109040001CBF94F82420002A08D111F0040F02D08C +:1090500094F8251011B118F0010F01D04FF0010064 +:10906000617A19B168B1FFF7F5FB10E03E484A4953 +:109070000160D5F8000220F00300C5F80002E77295 +:1090800005E001290AD0022918BFFFDF0DD018F032 +:10909000010F14D0DAF80000804745E06672E772ED +:1090A000A7729621227B002006E06672E7720220FA +:1090B000A072227B96210120FFF78FFBE7E718F0D3 +:1090C000020F2AD018F0040F21D1FEF74FF9F0B9A2 +:1090D000FEF75CF9D8B931480168001F0068C0F399 +:1090E000006CC0F3425500F00F03C0F30312C0F34D +:1090F0000320BCF1000F0AD0002B1CBF002A00285F +:1091000005D1002918BF032D38BF48F0040827EA0D +:109110009800DAF80410884706E018F0080F18BF26 +:10912000DAF8080056D08047A07A022818BFBDE8B8 +:10913000F88F207C002808BFBDE8F88F02492FE097 +:10914000741500401C11004000800040488500401C +:1091500014100040ACF501404881004004F5014086 +:1091600004B500404C85004008F501404016004021 +:109170001014004018110040448100404485004014 +:109180001015004000140040141400400415004065 +:10919000100C0020C40000200000040454140040FF +:1091A000C1F8446102281DD0012818BFFFDFE16A21 +:1091B0006069884298BFFFDFD4F81400C9F8000046 +:1091C000A06B4FF4800140F48000A06382480160EE +:1091D000BDE8F88F18F0100F14BFDAF80C00FFDFAD +:1091E000A1D1A1E76169E06A0844E7E738B57B49A6 +:1091F00004460220887201212046FFF763F9784A6D +:1092000004F13D001060774B0020C3F8440176491B +:10921000C1F80001C1F80C01C1F81001C1F8040146 +:10922000C1F81401C1F818017048006800900120CD +:109230009864101D00681168884228BFFFDF38BDA0 +:109240002DE9F843654A88460024917A0125684F44 +:10925000012902D0022903D015E0117E11B912E0D4 +:10926000517E81B1917FD37F05FA01F105FA03F3B5 +:109270001943396092F82010890001F1804101F50D +:10928000C041C1F8104506460220907201213046C7 +:10929000FFF718F9524906F13D000860514AC2F83B +:1092A00044415148C0F80041C0F80C41C0F8104199 +:1092B000C0F80441C0F81441C0F818414B48006898 +:1092C00000909564081D00680968884228BFFFDF88 +:1092D000B8F1000F1CBF4FF400303860BDE8F883D0 +:1092E000022810B50DD0012804BF42F6CE3010BDC3 +:1092F000042817BF082843F6A440FFDF41F66A00A0 +:1093000010BDFDF7E5FF30B9FDF7F9FF002808BFF4 +:1093100041F6583001D041F2643041F29A010844DC +:1093200010BD314910B50020C1F800023049314864 +:109330000860324930480860091D31480860091D3D +:1093400030480860091D30480860091D2F48086032 +:10935000091D2F48086001200BF058FD1E494FF4ED +:109360003810086010BD22494FF43810086070476B +:109370002848016803291BBF00680228012000203B +:109380007047244801680B291BBF00680A28012088 +:109390000020704720490968C9B9204A204913684C +:1093A00070B123F0820343F07D0343F00043136068 +:1093B0000A6822F0100242F0600242F0004205E02A +:1093C00023F0004313600A6822F000420A60034958 +:1093D00081F83D007047000004F50140280C002092 +:1093E00044850040008000400010004018110040FB +:1093F00008F50140000004041011004098F50140F8 +:109400000410004044810040141000401C11004032 +:109410001010004050150040881700403C170040D5 +:109420007C17004010B5404822220021F5F72FF8A4 +:109430003D480024017821F010010170012104F061 +:10944000FFFE3A494FF6FF7081F822408884384980 +:109450000880488010BD704734498A8C824218BF0A +:109460007047002081F822004FF6FF708884704713 +:109470002D49016070472E49088070472B498A8C1E +:10948000A2F57F43FF3B03D00021016008467047EF +:1094900091F822202549012A1ABF016001200020ED +:1094A0007047224901F1220091F82220012A04BFCD +:1094B00000207047012202701D48008888841046F1 +:1094C00070471B49488070471849194B8A8C5B8844 +:1094D0009A4206D191F82220002A1EBF0160012085 +:1094E0007047002070471148114A818C5288914280 +:1094F00009D14FF6FF71818410F8221F19B10021A4 +:10950000017001207047002070470848084A818C8C +:109510005288914205D190F8220000281CBF0020FB +:109520007047012070470000960C0020700C00204E +:10953000CC0000207047584A012340B1012818BFD1 +:1095400070471370086890608888908170475370E6 +:109550000868C2F802008888D08070474E4A10B16F +:10956000012807D00EE0507860B1D2F80200086000 +:10957000D08804E0107828B19068086090898880CD +:109580000120704700207047434910B1012803D0E3 +:1095900006E0487810B903E0087808B10120704768 +:1095A0000020704730B58DB00C4605460D220021D5 +:1095B00004A8F4F76CFFE0788DF81F0020798DF88F +:1095C0001E0060798DF81D00286800906868019081 +:1095D000A8680290E868039068460AF087FF207840 +:1095E0009DF82F1088420CD160789DF82E1088428B +:1095F00007D1A0789DF82D10884202BF01200DB040 +:1096000030BD00200DB030BD30B50C4605468DB0E4 +:109610004FF0030104F1030012B1FDF749FF01E02F +:10962000FDF765FF60790D2220F0C00040F040009A +:109630006071002104A8F4F72AFFE0788DF81F007C +:1096400020798DF81E0060798DF81D002868009043 +:1096500068680190A8680290E868039068460AF07C +:1096600045FF9DF82F0020709DF82E0060709DF83A +:109670002D00A0700DB030BD10B5002904464FF08C +:10968000060102D0FDF714FF01E0FDF730FF60791D +:1096900020F0C000607110BDD0000020FE4840687E +:1096A00070472DE9F0410F46064601461446012059 +:1096B00005F06FF8054696F86500FEF795FC4AF24E +:1096C000B12108444FF47A71B0FBF1F0718840F297 +:1096D00071225143C0EB4100001BA0F55A7402F007 +:1096E0005AFF002818BF1E3CAF4234BF28463846F8 +:1096F000A04203D2AF422CBF3C462C467462BDE868 +:10970000F0812DE9FF4F8BB0044690F86500884644 +:109710000390DDE90D1008430A90E0480027057822 +:109720000C2D28BFFFDFDE4E36F8159094F88851D7 +:109730000C2D28BFFFDFDA4830F81500484480B20E +:10974000009094F87D000D280CBF012000200790A8 +:109750000D98002804BF94F82C0103282BD10798FA +:1097600048B3B4F8AA01404525D1D4F83401C4F86F +:109770002001608840F2E2414843C4F82401B4F873 +:109780007A01B4F806110844C4F82801204602F012 +:109790000CFFB4F8AE01E08294F8AC016075B4F847 +:1097A000B0016080B4F8B201A080B4F8B401E080E8 +:1097B000022084F82C01D4F884010990D4F88001A7 +:1097C0000690B4F80661B4F87801D4F874110191E8 +:1097D0000D9921B194F8401151B100F0D6B804F5BB +:1097E000807104917431059104F5B075091D07E08D +:1097F00004F5AA710491091D059104F5A275091DCE +:109800000891B4F87010A8EB0000A8EB01010FFA62 +:1098100080F90FFA81FBB9F1000F05DAD4F8700175 +:1098200001900120D9460A909C484FF0000A007927 +:10983000A8B3F2F77FFB90B3B4F8180102282ED337 +:1098400094F82C0102282AD094F8430138BB94F8EC +:10985000880100900C2828BFFFDF9148009930F85C +:10986000110000F5C86080B2009094F82C01012826 +:109870007ED0608840F2E2414843009901F0E6F86A +:10988000D4F8342180B206EB0B01A1EB0901821A56 +:1098900001FB02AAC4F83401012084F8430194F8C2 +:1098A0002C01002865D0012800F01482022800F065 +:1098B0007181032818BFFFDF00F04782A7EB0A0180 +:1098C0000198FCF738F90599012640F271220860E9 +:1098D0000898A0F80080002028702E710598006874 +:1098E000A8606188D4F834015143C0EB41006B4952 +:1098F000A0F54E70C8618969814287BF04990860EC +:10990000049801600498616A0068084400F5D47006 +:10991000E86002F040FE10B1E8681E30E8606E7149 +:10992000B4F8F000A0EB080000B20028C4BF032088 +:109930006871079800280E9800F06982E0B100BFB6 +:10994000B4F8181100290CBF0020B4F81A01A4F8CB +:109950001A0194F81C21401C504388420CD26879AB +:10996000401E002808DD6E71B4F81A01401C01E0A9 +:109970000FE05AE0A4F81A010D98002800F06A825E +:1099800094F84001002800F061820FB00220BDE889 +:10999000F08F94F8800003283DD03F4894F865107C +:1099A00090F82C00F7F78DFDE18A40F271225143C7 +:1099B00000EB4100CDF80800D4F82401009901F033 +:1099C00045F8D4F82021D4F82811821A01FB02AA04 +:1099D000C4F820010099029801F038F8D4F8301149 +:1099E000C4F83001411A8A44608840F2E241484399 +:1099F000009901F02BF806EB0B01D4F82821A1EB1C +:109A00000901891AD4F83421C4F83401821A491E94 +:109A100001FB02AA40E7E18A40F27122D4F8240156 +:109A2000514300EB41000290C6E70698002808BFAA +:109A3000FFDF94F86510184890F82C00F7F741FD07 +:109A40000990E08A40F271214143099800EB4100FE +:109A5000009900F0FBFFC4F83001608840F2E24159 +:109A60004843009900F0F2FFC4F8340103A902A8AA +:109A7000FFF7BBF8DDE90160039FE9F7F0F8014665 +:109A80003046FDF769F800F10F06E9F711F9381AC9 +:109A9000801B009006E00000B80C0020E0000020D1 +:109AA000E4620200B4F83401214686B20120D4F801 +:109AB000289004F06EFE074694F86500FEF794FACD +:109AC0004AF2B12108444FF47A7BB0FBFBF0618885 +:109AD00040F271225143C0EB4100801BA0F55A7641 +:109AE00002F059FD002818BF1E3EB94534BF384664 +:109AF0004846B04203D2B9452CBF4E463E46666248 +:109B000094F86500FEF7E9FA00F2E140B0FBFBF1E2 +:109B100006980F1894F86500FEF7DFFA064694F8E9 +:109B20006500FEF761FA30444AF2AB310844B0FBFD +:109B3000FBF1E08A40F2712242430998D4F8306187 +:109B400000EB4200401A801B384400993138471A14 +:109B5000607D40F2E24110FB01F994F8650000904D +:109B600010F00C0F0ABF00984EF62830FEF73CFAB2 +:109B70004AF2B1210844B0FBFBF000EB460000EBD9 +:109B800009060098FEF7B8FA304400F18401FE4857 +:109B9000816193E6E18A40F27122D4F824015143B5 +:109BA00000EB4100009900F051FFC4F830016188DA +:109BB00040F2E2404843009900F048FFC4F8340105 +:109BC00087B221460120D4F828B004F0E2FD814696 +:109BD00094F86500FEF708FA4AF2B12101444FF407 +:109BE0007A70B1FBF0F0618840F271225143C0EB12 +:109BF0004100C01BA0F55A7702F0CDFC002818BF29 +:109C00001E3FCB4534BF48465846B84203D2CB45E9 +:109C10002CBF5F464F4667621EBB0E9808B394F890 +:109C200065603046FEF7E0F94AF2B12101444FF495 +:109C30007A70B1FBF0F0D4F83011E28A084440F2B7 +:109C40007123D4F824115A4301EB42010F1A304614 +:109C5000FEF752FA01460998401A3844A0F120074D +:109C60000AE0E18A40F27122D4F82401514300EB6A +:109C70004100D4F83011471AD4F82821D4F8201123 +:109C8000D4F8300101FB0209607D40F2E24110FB93 +:109C900001FB94F8656016F00C0F0ABF30464EF6D3 +:109CA0002830FEF7A1F94AF2B12101444FF47A704D +:109CB000B1FBF0F000EB490000EB0B093046FEF77A +:109CC0001BFA484400F16001AF488161012084F82B +:109CD0002C01F3E5618840F271225143D4F834013C +:109CE000D4F82821C0EB410101FB09F706EB0B0179 +:109CF000891AD4F820C1D4F83031491E0CFB023245 +:109D000001FB0029607D40F2E24110FB01FB94F869 +:109D1000656016F00C0F0ABF30464EF62830FEF78D +:109D200063F94AF2B12101444FF47A70B1FBF0F0CB +:109D300000EB490000EB0B093046FEF7DDF9484423 +:109D400000F1600190488161B8E5618840F27122BC +:109D5000D4F834015143C0EB410000FB09F794F8FB +:109D60007C0024281CBF94F87D0024280BD1B4F873 +:109D7000AA01A8EB000000B2002804DB94F8AD01B2 +:109D8000002818BF03900A9800B3FEB9099800286C +:109D90001ABF06980028FFDF94F8650010F00C0F3A +:109DA00014BF4EF62830FEF71FF94AF2B1210144E4 +:109DB0004FF47A70B1FBF0F03F1A94F86500FEF7AB +:109DC0009BF90999081A3844A0F12007D4F83411F6 +:109DD00006EB0B0000FB01F6039810F00C0F0ABF16 +:109DE00003984EF62830FEF7FFF84AF2B1210144FD +:109DF0004FF47A70B1FBF0F000EB46060398FEF7E3 +:109E00007BF9304400F160015F48816156E500282C +:109E10007FF496AD94F82C0100283FF4ADAD618835 +:109E200040F27122D4F834015143C0EB410128467D +:109E3000F7F712F90004000C3FF49EAD18990029C1 +:109E400018BF088001200FB0BDE8F08F94F87C01A6 +:109E5000FCF7D1FC94F87C012946FCF7B0FB20B15B +:109E60000D9880F0010084F841010FB00020BDE89A +:109E7000F08F2DE9F843454C0246434F00266168B8 +:109E8000606A052A60D2DFE802F003464B4F5600B5 +:109E9000A07A002560B101216846FDF709FB9DF815 +:109EA000000042F210710002B0FBF1F201FB12055A +:109EB000F4F720FE4119A069FBF73DFEA06126746E +:109EC000032060754FF0010884F81480607AD0B9DF +:109ED000A06A80B1F4F70EFE0544F4F785FC411941 +:109EE000A06A884224BF401BA06204D2C4F8288024 +:109EF000F5F72BFE07E0207B04F11001FCF75FFB78 +:109F0000002808BFFFDF2684FCF739F87879BDE820 +:109F1000F843E8F7F9BFBDE8F843002100F0B3BD0E +:109F2000C1F88001BDE8F883D1F88001BDE8F843AD +:109F3000012100F0A8BD84F83060FCF720F87879A2 +:109F4000BDE8F843E8F7E0BFFFDFBDE8F8832DE99F +:109F5000F04F0E4C824683B020788B4601270025B7 +:109F6000094E4FF00209032804BF207B50457DD1E4 +:109F7000606870612078032818BFFFDF4FF0030886 +:109F8000BBF1080F73D203E0E0000020B80C002002 +:109F9000DFE80BF0040F32322D9999926562F5F7E4 +:109FA000ABF9002818BFFFDF86F8028003B0BDE8D8 +:109FB000F08FF4F77AFF68B9F4F716FC0546E0690C +:109FC000A84228BFE56105D2281A0421FCF7F7FD55 +:109FD000E56138B1F5F723FD002818BFFFDF03B0B6 +:109FE000BDE8F08F03B00020BDE8F04F41E703B0BB +:109FF000BDE8F04FFEF7FFBD2775257494F83000DB +:10A000004FF0010A58B14FF47A71A069FBF793FD44 +:10A01000A061002104F11000F7F71EF80EE0F4F73C +:10A0200069FD82465146A069FBF785FDA061514656 +:10A0300004F11000F7F710F800F1010A208C411C20 +:10A040000A293CBF50442084606830B1208C401CF9 +:10A050000A2828BF84F8159001D284F81580607A08 +:10A06000A8B9A06AE8B1F4F745FD01E02FE02AE0C5 +:10A070008046F4F7B9FB00EB0801A06A884224BFD0 +:10A08000A0EB0800A0620CD2A762F5F75EFD207B72 +:10A09000FCF74BF82570707903B0BDE8F04FE8F796 +:10A0A00033BF207B04F11001FCF789FA002808BFB8 +:10A0B000FFDF03B0BDE8F08F207BFCF736F825709A +:10A0C00003B0BDE8F08FFFDF03B0BDE8F08FBAF159 +:10A0D000200F28BFFFDFDFF8E886072138F81A00D5 +:10A0E000F9F7E4FE040008BFFFDFBAF1200F28BF34 +:10A0F000FFDF38F81A002188884218BFFFDF4FF0D1 +:10A10000200A7461BBF1080F80F06181DFE80BF079 +:10A110000496A0A099FEFDFCC4F88051F580C4F817 +:10A12000845194F8410138B9FCF71EF8D4F84C1169 +:10A13000FCF712FD00281BDCB4F83E11B4F87000E7 +:10A14000814206D1B4F8F410081AA4F8F6002046AB +:10A1500005E0081AA4F8F600B4F83E112046A4F869 +:10A160007010D4F86811C4F84C11C0F870111DE0DB +:10A17000B4F83C11B4F87000081AA4F8F600B4F86A +:10A180003C112046A4F87010D4F84C11C4F86811A2 +:10A19000C4F87011D4F85411C4F80011D4F858114F +:10A1A000C4F87411B4F85C11A4F8781102F008F93D +:10A1B000FBF7B4FF804694F86500FDF715FF4AF2FF +:10A1C000B12108444FF47A71B0FBF1F0D4F83411A6 +:10A1D00040F27122084461885143C0EB4100A0F174 +:10A1E000300AB8F1B70F98BF4FF0B70821460120E9 +:10A1F00004F0CFFA4044AAEB0000A0F21D38A246BA +:10A200002146012004F0C5FADAF824109C3081427E +:10A2100088BF0D1AC6F80C80454528BF4546B56075 +:10A22000D4F86C01A0F5D4703061FCF762FC84F8BE +:10A23000407186F8029003B0BDE8F08F02F0A6F9F5 +:10A2400001E0FEF7D8FC84F8407103B0BDE8F08F60 +:10A25000FBF78AFFD4F8702101461046FCF77CFC1E +:10A2600048B1628840F27123D4F834115A43C1EBEB +:10A270004201B0FBF1F094F87D100D290FD0B4F835 +:10A280007010B4F83E210B189A42AEBF501C401C0F +:10A290000844A4F83E0194F8420178B905E0B4F806 +:10A2A0003E01401CA4F83E0108E0B4F83E01B4F8B9 +:10A2B000F410884204BF401CA4F83E01B4F87A01AF +:10A2C0000DF1040B401CA4F87A01B4F89A00B4F81C +:10A2D0009810401AB4F87010401E08441FFA80F914 +:10A2E0000BE000231A462046CDF800B0FFF709FA2C +:10A2F00068B3012818BFFFDF48D0B4F83E11A9EBBE +:10A30000010000B2002802E053E047E05FE0E8DA35 +:10A31000082084F88D0084F88C70204601F012FE2D +:10A3200084F82C5194F87C514FF6FF77202D00D300 +:10A33000FFDF28F8157094F87C01FBF7F6FE84F82F +:10A340007CA1707903B0BDE8F04FE8F7DDBDA06EE9 +:10A35000002804BF03B0BDE8F08FB4F83E01B4F8A4 +:10A360009420801A01B20029DCBF03B0BDE8F08F51 +:10A37000B4F86C000144491E91FBF0F189B201FB75 +:10A380000020A4F8940003B0BDE8F08FB4F83E01BB +:10A39000BDF804100844A4F83E01AEE7FEF7E4FA65 +:10A3A000FEF729FC4FF0E020C0F8809203B0BDE832 +:10A3B000F08F94F82C01042818BFFFDF84F82C518B +:10A3C00094F87C514FF6FF77202DB2D3B0E7FFDF32 +:10A3D00003B0BDE8F08F10B5FA4C207850B10120E1 +:10A3E0006072F5F7D8FB2078032805D0207A002882 +:10A3F00008BF10BD0C2010BD207BFCF7FCF9207BB2 +:10A40000FCF765FC207BFBF790FE002808BFFFDF10 +:10A410000020207010BD2DE9F04FEA4F83B038784E +:10A4200001244FF0000840B17C720120F5F7B3FB26 +:10A430003878032818BF387A0DD0DFF88C9389F864 +:10A44000034069460720F9F7BAFC002818BFFFDF70 +:10A450004FF6FF7440E0387BFCF7CDF9387BFCF712 +:10A4600036FC387BFBF761FE002808BFFFDF87F86A +:10A470000080E2E7029800281CBF90F82C11002908 +:10A480002AD00088A0421CBFDFF834A34FF0200B75 +:10A490003AD00721F9F70AFD040008BFFFDF94F85E +:10A4A0007C01FCF714FC84F82C8194F87C514FF665 +:10A4B000FF76202D28BFFFDF2AF8156094F87C0175 +:10A4C000FBF733FE84F87CB169460720F9F777FC87 +:10A4D000002818BFFFDF12E06846F9F74EFC00289D +:10A4E000C8D011E0029800281CBF90F82C11002958 +:10A4F00005D00088A0F57F41FF39CAD104E0684645 +:10A50000F9F73BFC0028EDD089F8038087F830800C +:10A5100087F80B8003B00020BDE8F08FAA4948718E +:10A520000020887001220A7048700A71C870A5491D +:10A53000087070E7A449087070472DE9F84FA14CE6 +:10A5400006460F462078002862D1A048FBF792FD0E +:10A55000207320285CD04FF00308666084F80080E8 +:10A56000002565722572AEB1012106F58E70FCF7EB +:10A57000BEFF0620F9F742FC81460720F9F73EFCB2 +:10A5800096F81C114844B1FBF0F200FB1210401C7D +:10A5900086F81C01FBF7C2FD40F2F651884238BF35 +:10A5A00040F2F65000F5A0701FFA80F9F4F7A2FA15 +:10A5B000012680B3A672F4F717F9E061FBF7D4FD2A +:10A5C000824601216846FCF769FF9DF8000042F2CF +:10A5D00010710002B0FBF1F201FB120000EB090167 +:10A5E0005046FBF7A8FAA762A061267584F815808B +:10A5F0002574207B04F11001FBF7E1FF002808BF60 +:10A60000FFDF25840020F5F7C6FA0020BDE8F88FAB +:10A610000C20BDE8F88FFFE7E761FBF7A5FD494691 +:10A62000FBF789FAA061A57284F830600120FDF77C +:10A6300054FD4FF47A7100F2E140B0FBF1F0381AAA +:10A64000A0F5AB60A5626063CFE75F4948707047D3 +:10A650005D49087170475B4810B5417A00291CBFFD +:10A66000002010BD816A51B990F8301039B1416AAB +:10A67000406B814203D9F5F768FA002010BD012034 +:10A6800010BD2DE9F041504C0646E088401CE080AA +:10A69000D4E902516078D6F8807120B13A46284654 +:10A6A000F6F705FD0546A068854205D02169281A00 +:10A6B00008442061FCF71DFAA560AF4209D896F85E +:10A6C0002C01012805D0E078002804BF0120BDE856 +:10A6D000F0810020BDE8F08110B504460846FDF782 +:10A6E00083FC4AF2B12108444FF47A71B0FBF1F0D7 +:10A6F00040F2E241614300F54E7081428CBF081A7E +:10A70000002010BD70B5044682B0002084F84001DE +:10A7100094F8FB00002807BF94F82C01032802B02E +:10A7200070BDFBF721FDD4F8702101461046FCF7FF +:10A7300013FA0028DCBF02B070BD628840F27123BA +:10A74000D4F834115A43C1EB4201B0FBF1F0B4F834 +:10A750007010401C0844A4F83C01B4F8F400B4F8AC +:10A760003C21801A00B20028DCBF02B070BD01207D +:10A7700084F84201B4F89A00B4F8982001AE801A27 +:10A78000401E084485B212E00096B4F83C11002344 +:10A7900001222046FEF7B5FF002804BF02B070BDBD +:10A7A000012815D0022812BFFFDF02B070BDB4F837 +:10A7B0003C01281A00B20028BCBF02B070BDE3E71C +:10A7C000F00C0020B80C0020E00000204F9F01009A +:10A7D000B4F83C01BDF804100844A4F83C01E6E7D5 +:10A7E000F8B50422002506295BD2DFE801F0072630 +:10A7F0000319192A044680F82C2107E00446C948A9 +:10A80000C078002818BF84F82C210AD0FBF7B7FBCA +:10A81000A4F87A51B4F87000A4F83E0184F84251CB +:10A82000F8BD0095B4F8F410012300222046FEF78D +:10A8300068FF002818BFFFDFE8E7032180F82C112C +:10A84000F8BD0646876AB0F83401314685B201206A +:10A8500003F09FFF044696F86500FDF7C5FB4AF23A +:10A86000B12108444FF47A71B0FBF1F0718840F2E5 +:10A8700071225143C0EB4100401BA0F55A7501F015 +:10A880008AFE002818BF1E3DA74234BF2046384626 +:10A89000A84228BF2C4602D2A74228BF3C46746279 +:10A8A000F8BDFFDFF8BD2DE9F05F9E4EB1780229BB +:10A8B00006BFF1880029BDE8F09F7469C4F88401DF +:10A8C00094F86500FDF718FCD4F88411081AB168F3 +:10A8D0000144B160F1680844F060746994F8430180 +:10A8E000002808BFBDE8F09F94F82C01032818BF8A +:10A8F000BDE8F09F94F8655037780C2F28BFFFDF34 +:10A90000894E36F8178094F888710C2F28BFFFDF26 +:10A9100036F81700404494F8888187B2B8F10C0FDC +:10A9200028BFFFDF36F8180000F5C8601FFA80F86E +:10A930002846FDF7E1FBD4F884114FF0000A0E1A07 +:10A9400015F00C0F0ABF28464EF62830FDF74CFBD9 +:10A950004FF47A7900F2E730B0FBF9F0361A284666 +:10A96000FDF7CAFBD4F8001115F00C0FA1EB000B9A +:10A970000ABF28464EF62830FDF736FB4AF2B121D1 +:10A980000844B0FBF9F0ABEB0000A0F160017943A3 +:10A99000B1FBF8F1292202EB50006031A0EB51022B +:10A9A00000EB5100B24201D8B04201D8F1F774FB7C +:10A9B000608840F2E2414843394600F047F8C4F865 +:10A9C000340184F843A1BDE8F09F70B505465548B1 +:10A9D00090F802C0BCF1020F07BF406900F5C074D7 +:10A9E000524800F12404002904BF256070BD4FF4D3 +:10A9F0007A7601290DD002291CBFFFDF70BD1046F9 +:10AA0000FEF76EFC00F2E140B0FBF6F0281A206081 +:10AA100070BD1846FDF761FB00F2E140B0FBF6F0B7 +:10AA2000281A206070BD4148007800281CBF002013 +:10AA3000704710B50720F9F7D3F980F0010010BD79 +:10AA40003A480078002818BF0120704730B5024608 +:10AA50000020002908BF30BDA2FB0110490A41EACD +:10AA6000C051400A4C1C40F100000022D4F1FF31DB +:10AA700040F2A17572EB000038BFFFDF04F5F4600F +:10AA8000B0FBF5F030BD2DE9F843284C0025814698 +:10AA900084F83050D4F8188084F82C10E5722570B2 +:10AAA0000127277239466068F5F792FD6168C1F8A1 +:10AAB0007081267B81F87C61C1F88091C1F8748136 +:10AAC000B1F80080202E28BFFFDF194820F816803B +:10AAD000646884F82C510023A4F878511A4619466A +:10AAE00020460095FEF70DFE002818BFFFDFC4F8D2 +:10AAF0002851C4F8205184F82C71A4F83E51A4F8D0 +:10AB00003C5184F84251B4F87000401EA4F8700023 +:10AB1000A4F87A51FBF733FA02484079BDE8F843CC +:10AB2000E8F7F2B9E0000020E4620200B80C00206F +:10AB3000F00C0020012804D0022805D0032808D1F9 +:10AB400005E0012907D004E0022904D001E004292E +:10AB500001D000207047012070472DE9F0410E46DA +:10AB6000044603F08AFC0546204603F08AFC0446AE +:10AB7000F6F770FBFB4F010015D0386990F86420A0 +:10AB80008A4210D090F8C0311BB190F8C2312342F4 +:10AB90001FD02EB990F85D30234201D18A4218D8D7 +:10ABA00090F8C001A8B12846F6F754FB70B1396996 +:10ABB00091F86520824209D091F8C00118B191F84E +:10ABC000C301284205D091F8C00110B10120BDE8B1 +:10ABD000F0810020FBE730B5E24C85B0E069002849 +:10ABE0005FD0142200216846F3F751FC206990F8E9 +:10ABF0006500FDF7F9F94FF47A7100F5FA70B0FBD2 +:10AC0000F1F5206990F86500FDF776FA2844ADF873 +:10AC1000060020690188ADF80010B0F87010ADF89A +:10AC200004104188ADF8021090F8A20130B1A0697B +:10AC3000C11C039103F002FB8DF81000206990F80D +:10AC4000A1018DF80800E169684688472069002164 +:10AC500080F8A21180F8A1110399002921D090F861 +:10AC6000A01100291DD190F87C10272919D09DF83A +:10AC70001010039A002914D013780124FF2B12D04E +:10AC8000072B0ED102290CD15178FF2909D100BF21 +:10AC900080F8A0410399C0F8A4119DF8101080F825 +:10ACA000A31105B030BD1B29F2D9FAE770B5AD4C40 +:10ACB000206990F87D001B2800D0FFDF2069002567 +:10ACC00080F8A75090F8D40100B1FFDF206990F818 +:10ACD000A81041B180F8A8500188A0F8D81180F8D8 +:10ACE000D6510E2108E00188A0F8D81180F8D6517D +:10ACF000012180F8DA110D2180F8D4110088F9F7CC +:10AD000006FAF8F79FFE2079E8F7FEF8206980F848 +:10AD10007D5070BD70B5934CA07980072CD5A0787C +:10AD2000002829D162692046D37801690D2B01F1F1 +:10AD300070005FD00DDCA3F102034FF001050B2B77 +:10AD400019D2DFE803F01A1844506127182C183A7A +:10AD50006400152B6FD008DC112B4BD0122B5AD06E +:10AD6000132B62D0142B06D166E0162B71D0172B53 +:10AD700070D0FF2B6FD0FFDF70BD91F87F200123D3 +:10AD80001946F6F7FFF80028F6D12169082081F866 +:10AD90007F0070BD1079BDE8704001F090BC91F863 +:10ADA0007E00C00700D1FFDF01F048FC206910F8E9 +:10ADB0007E1F21F00101017070BD91F87D00102807 +:10ADC00000D0FFDF2069112180F8A75008E091F83A +:10ADD0007D00142800D0FFDF2069152180F8A750DE +:10ADE00080F87D1070BD91F87D00152800D0FFDF40 +:10ADF000172005E091F87D00152800D0FFDF19200D +:10AE0000216981F87D0070BDBDE870404EE7BDE866 +:10AE1000704001F028BC91F87C2001230021F6F756 +:10AE2000B1F800B9FFDF0E200FE011F87E0F20F01F +:10AE3000040008701DE00FE091F87C200123002140 +:10AE4000F6F7A0F800B9FFDF1C20216981F87C002B +:10AE500070BD12E01BE022E091F87E00C0F301100B +:10AE6000012800D0FFDF206910F87E1F21F01001BB +:10AE70000170BDE8704001F0E1BB91F87C20012336 +:10AE80000021F6F77FF800B9FFDF1F20DDE791F81A +:10AE90007D00212801D000B1FFDF2220B0E7BDE80E +:10AEA000704001F0D7BB2F48016991F87E2013074D +:10AEB00002D501218170704742F0080281F87E209E +:10AEC0008069C07881F8E10001F0AFBB10B5254C76 +:10AED00021690A88A1F8162281F8140291F8640009 +:10AEE00001F091FB216981F8180291F8650001F0E9 +:10AEF0008AFB216981F81902012081F812020020E1 +:10AF000081F8C0012079BDE81040E7F7FDBF10B51A +:10AF1000144C05212069FFF763FC206990F85A1052 +:10AF2000012908D000F5F57103F001FC2079BDE896 +:10AF30001040E7F7E9BF022180F85A1010BD10B5A4 +:10AF4000084C01230921206990F87C207030F6F725 +:10AF500019F848B12169002001F8960F087301F82B +:10AF60001A0C10BD000100200120A070F9E770B597 +:10AF7000F74D012329462869896990F87C200979D1 +:10AF80000E2A01D1122903D000241C2A03D004E088 +:10AF9000BDE87040D3E7142902D0202A07D008E08A +:10AFA00080F87C4080F8A240BDE87040AFE71629E9 +:10AFB00006D0262A01D1162902D0172909D00CE083 +:10AFC00000F87C4F80F82640407821280CD01A20C9 +:10AFD00017E090F87D20222A07D0EA69002A03D0E2 +:10AFE000FF2901D180F8A23132E780F87D4001F0DD +:10AFF00025FB286980F8974090F8C0010028F3D01D +:10B000000020BDE8704061E710B5D14C216991F88E +:10B010007C10202902D0262902D0A2E7FFF756FF94 +:10B020002169002081F87C0081F8A20099E72DE9D0 +:10B03000F843C74C206990F87C10202908D00027DD +:10B0400090F87D10222905D07FB300F17C0503E044 +:10B050000127F5E700F17D0510F8B01F41F004016C +:10B060000170A06903F015FA4FF00108002608B33B +:10B070003946A069FFF771FDE0B16A46A169206910 +:10B08000F6F7F7F890B3A06903F001FA2169A1F887 +:10B09000AA01B1F8701001F0AAFA40B32069282182 +:10B0A00080F88D1080F88C8058E0FFE70220A070B7 +:10B0B000BDE8F883206990F8C00110B11E20FFF7A9 +:10B0C00005FFAFB1A0692169C07881F8E20008FAF4 +:10B0D00000F1C1F3006000B9FFDF20690A2180F8A8 +:10B0E0007C1090F8A20040B9FFDF06E009E02AE0FA +:10B0F0002E7001F0A3FAFFF7D6FE206980F8976062 +:10B10000D6E7226992F8C00170B1B2F8703092F8B7 +:10B110006410B2F8C40102F5D572F6F79BF968B174 +:10B120002169252081F87C00206900F17D0180F8EB +:10B1300097608D4212D180F87D600FE00020FFF70C +:10B14000C5FE2E70F0E720699DF8001080F8AC1164 +:10B150009DF8011080F8AD1124202870206900F1BD +:10B160007D018D4203D1BDE8F84301F067BA80F854 +:10B17000A2609DE770B5764C01230B21206990F801 +:10B180007D207030F5F7FEFE202650BB206901239C +:10B19000002190F87D207030F5F7F4FE0125F0B124 +:10B1A000206990F87C0024281BD0A06903F04FF997 +:10B1B000C8B1206990F8B01041F0040180F8B010D7 +:10B1C000A1694A7902F0070280F85D20097901F04F +:10B1D000070180F85C1090F8C1311BBB06E0A57038 +:10B1E00036E6A67034E6BDE870405CE690F8C03103 +:10B1F000C3B900F164035E788E4205D1197891429B +:10B2000002D180F897500DE000F503710D700288AF +:10B210004A8090F85C200A7190F85D0048712079AE +:10B22000E7F772FE2169212081F87D00BDE87040BA +:10B2300001F0FBB9F8B5464C206990F87E0010F09B +:10B24000300F04D0A07840F00100A070F8BDA069D4 +:10B2500003F0E2F850B3A06903F0D8F80746A069FC +:10B2600003F0D8F80646A06903F0CEF80546A069B9 +:10B2700003F0CEF801460097206933462A46303065 +:10B2800003F0BFF9A079800703D56069C07814285E +:10B290000FD0216991F87C001C280AD091F85A003F +:10B2A00001280ED091F8B70158B907E0BDE8F84081 +:10B2B000F9E52169012081F85A0002E091F8B60110 +:10B2C00030B1206910F87E1F41F0100101700EE0CE +:10B2D00091F87E0001F5FC7240F0200081F87E00BC +:10B2E00031F8300B03F017FA2079E7F70DFEBDE8CF +:10B2F000F84001F09AB970B5154C206990F87E10AD +:10B30000890707D590F87C20012308217030F5F7D4 +:10B3100039FEF8B1206990F8AA00800712D4A0691C +:10B3200003F056F8216981F8AB00A06930F8052FC9 +:10B33000A1F8AC204088A1F8AE0011F8AA0F40F0A7 +:10B3400002000870206990F8AA10C90705D011E022 +:10B35000000100200120A0707AE590F87E008007AF +:10B3600000D5FFDF206910F87E1F41F00201017057 +:10B3700001F05BF92069002590F87C10062906D1C0 +:10B3800080F87C5080F8A2502079E7F7BDFD206955 +:10B3900090F8A8110429DFD180F8A8512079E7F7A7 +:10B3A000B3FD206990F87C100029D5D180F8A25017 +:10B3B0004EE570B5FB4C01230021206990F87D20FB +:10B3C0007030F5F7DFFD012578B9206990F87D2010 +:10B3D000122A0AD0012305217030F5F7D3FD10B1F0 +:10B3E0000820A07034E5A57032E5206990F8A80027 +:10B3F00008B901F01AF92169A06901F5847102F018 +:10B40000C8FF2169A069D83102F0CEFF206990F809 +:10B41000DC0100B1FFDF21690888A1F8DE0101F538 +:10B42000F071A06902F0A3FF2169A06901F5F47130 +:10B4300002F0A5FF206980F8DC51142180F87D100E +:10B440002079BDE87040E7F75FBD70B5D54C0123AA +:10B450000021206990F87D207030F5F793FD0125DB +:10B46000A8B1A06902F04FFF98B1A0692169B0F8B6 +:10B470000D00A1F8AA01B1F8701001F0B8F858B1A8 +:10B480002069282180F88D1080F88C50E0E4A570A8 +:10B49000DEE4BDE8704006E5A0692169027981F823 +:10B4A000AC21B0F80520A1F8AE2102F01FFF216900 +:10B4B000A1F8B001A06902F01CFF2169A1F8B20156 +:10B4C000A06902F01DFF2169A1F8B4010D2081F8E7 +:10B4D0007D00BDE47CB5B34CA079C00738D0A0692D +:10B4E00001230521C578206990F87D207030F5F79B +:10B4F00049FD68B1AD1E0A2D06D2DFE805F0090945 +:10B500000505090905050909A07840F00800A070A3 +:10B51000A07800281CD1A06902F0BEFE00286ED0E1 +:10B52000A0690226C5781DB1012D01D0162D18D1B4 +:10B53000206990F87C00F5F70DFD90B1216991F834 +:10B540007C001F280DD0202803D0162D16D0A67001 +:10B550007CBD262081F87C00162D02D02A20FFF722 +:10B56000B5FC0C2D5BD00CDC0C2D48D2DFE805F0CF +:10B5700036331F48BEBE4BB55ABE393C2020A070A2 +:10B580007CBD0120142D6ED008DC0D2D6CD0112D4A +:10B590006BD0122D6ED0132D31D168E0152D7FD0D8 +:10B5A000162D6FD0182D6ED0FF2D28D198E0206970 +:10B5B0000123194690F87F207030F5F7E3FC00284E +:10B5C00008D1A06902F0CCFE216981F88E01072024 +:10B5D00081F87F008CE001F0EDF889E0FFF735FF9E +:10B5E00086E001F0C7F883E0206990F87D1011290A +:10B5F00001D0A6707CE0122180F87D1078E075E023 +:10B60000FFF7D7FE74E0206990F87D001728F0D18D +:10B6100001F014F821691B2081F87D0068E0FFF734 +:10B620006AFE65E0206990F87E00C00703D0A0782C +:10B6300040F0010023E06946A06902F0D0FE9DF8C9 +:10B64000000000F02501206900F8B01F9DF80110EE +:10B6500001F04901417000F0E8FF206910F87E1FF9 +:10B6600041F0010117E018E023E025E002E0FFF7D8 +:10B6700066FC3DE0216991F87E10490704D5A07071 +:10B6800036E00DE00FE011E000F0CFFF206910F888 +:10B690007E1F41F0040101702AE0FFF7CBFD27E097 +:10B6A00001F030F824E0FFF765FD21E0FFF7BFFC73 +:10B6B0001EE0A06900790DE0206910F8B01F41F08C +:10B6C00004010170A06902F0F7FE162810D1A069EC +:10B6D00002F0F6FEFFF798FC0AE0FFF748FC07E0EF +:10B6E000E16919B1216981F8A20101E0FFF7DBFBF3 +:10B6F0002169F1E93002401C42F10002C1E9000277 +:10B700007CBD70B5274CA07900074AD5A0780028E9 +:10B7100047D1206990F8E400FE2800D1FFDF2069BE +:10B72000FE21002580F8E41090F87D10192906D13B +:10B7300080F8A75000F082FF206980F87D502069D2 +:10B7400090F87C101F2902D0272921D119E090F808 +:10B750007D00F5F7FFFB78B120692621012380F8F1 +:10B760007C1090F87D200B217030F5F70BFC78B938 +:10B770002A20FFF7ABFB0BE02169202081F87C0039 +:10B7800006E0012180F8A11180F87C5080F8A250D9 +:10B79000206990F87F10082903D10221217080F8D8 +:10B7A000E41021E40001002010B5FD4C216991F85E +:10B7B000AC210AB991F8642081F8642091F8AD2198 +:10B7C0000AB991F8652081F8652010B10020FFF7D3 +:10B7D0007DFB206902F041FF002806D02069BDE80A +:10B7E000104000F5F57102F0A2BF16E470B5EC4C04 +:10B7F00006460D46206990F8E400FE2800D0FFDFE1 +:10B800002269002082F8E46015B1A2F8A400E7E400 +:10B8100022F89E0F01201071E2E470B5E04C012384 +:10B820000021206990F87C207030F5F7ABFB0028F0 +:10B830007BD0206990F8B61111B190F8B71139B1E9 +:10B8400090F8C01100296FD090F8C11119B36BE0C6 +:10B8500090F87D1024291CD090F87C10242918D051 +:10B860005FF0000300F5D67200F5DB7102F096FE82 +:10B870002169002081F8B60101461420FFF7B6FFC8 +:10B88000216901F13000C28A21F8E62F408B4880FF +:10B8900050E00123E6E790F87D2001230B21703072 +:10B8A000F5F770FB68BB206990F8640000F0ABFE10 +:10B8B0000646206990F8650000F0A5FE054620695F +:10B8C00090F8C2113046FFF735F9D8B1206990F8E9 +:10B8D000C3112846FFF72EF9A0B12269B2F87030E3 +:10B8E00092F86410B2F8C40102F5D572F5F7B2FD12 +:10B8F00020B12169252081F87C001BE00020FFF7A2 +:10B90000E5FA11E020690123032190F87D207030D1 +:10B91000F5F738FB40B920690123022190F87D201A +:10B920007030F5F72FFB08B1002059E400211620F4 +:10B93000FFF75CFF012053E410B5E8BB984C206989 +:10B9400090F87E10CA0702D00121092052E08A0730 +:10B950000AD501210C20FFF749FF206910F8AA1F22 +:10B9600041F00101017047E04A0702D5012113208F +:10B9700040E00A0705D510F8E11F417101210720B9 +:10B9800038E011F0300F3BD090F8B711A1B990F822 +:10B99000B611E1B190F87D1024292FD090F87C10D9 +:10B9A00024292BD05FF0000300F5D67200F5DB717F +:10B9B00002F0F4FD216900E022E011F87E0F20F092 +:10B9C000200040F010000870002081F83801206944 +:10B9D00090F87E10C90613D502F03FFEFFF797FAE4 +:10B9E000216901F13000C28A21F8E62F408B48809E +:10B9F00001211520FFF7FAFE0120F6E60123D3E727 +:10BA00000020F2E670B5664C206990F8E410FE293B +:10BA100078D1A178002975D190F87F2001231946AB +:10BA20007030F5F7AFFA00286CD1206990F88C11CE +:10BA300049B10021A0F89C1090F88D1180F8E61013 +:10BA4000002102205BE090F87D200123042170306A +:10BA5000F5F798FA0546FFF76FFF002852D1284600 +:10BA600000F00CFF00284DD120690123002190F83F +:10BA70007C207030F5F786FA78B120690123042123 +:10BA800090F87D207030F5F77DFA30B9206990F894 +:10BA9000960010B10021122031E0206990F87C203E +:10BAA0000A2A0DD0002D2DD1012300217030F5F789 +:10BAB00069FA78B1206990F8A81104290AD105E043 +:10BAC00010F8E21F01710021072018E090F8AA0089 +:10BAD000800718D0FFF7A1FE002813D120690123A9 +:10BAE000002190F87C207030F5F74CFA002809D03E +:10BAF000206990F8A001002804D00021FF20BDE8B3 +:10BB0000704073E609E000210C20FFF76FFE20690A +:10BB100010F8AA1F41F0010101701DE43EB5054671 +:10BB20006846FDF7ABFC00B9FFDF22220021009838 +:10BB3000F2F7ADFC0321009802F096FB0098017823 +:10BB400021F010010170294602F0B3FB144C0D2DB9 +:10BB500043D00BDCA5F102050B2D19D2DFE805F06F +:10BB600022184B191922185718192700152D5FD0C4 +:10BB700008DC112D28D0122D0BD0132D09D0142D37 +:10BB800006D155E0162D2CD0172D6AD0FF2D74D07C +:10BB9000FFDFFDF786FC002800D1FFDF3EBD00007F +:10BBA000000100202169009891F8E61017E0E26892 +:10BBB00000981178017191884171090A8171518849 +:10BBC000C171090A0172E4E70321009802F072FCD6 +:10BBD0000621009802F072FCDBE700980621017153 +:10BBE000D7E70098D4F8101091F8C221027191F8AB +:10BBF000C3114171CDE72169009801F5887102F008 +:10BC0000D7FB21690098DC3102F0DCFBC1E7FA497F +:10BC1000D1E90001CDE90101206901A990F8B00046 +:10BC200000F025008DF80400009802F006FCB0E753 +:10BC30002069B0F84810009802F0D6FB2069B0F8EF +:10BC4000E810009802F0D4FB2069B0F84410009886 +:10BC500002F0D2FB2069B0F8E610009802F0D0FBA9 +:10BC600097E7216991F8C00100280098BCD111F82C +:10BC7000642F02714978BCE7FFE7206990F8A3219F +:10BC8000D0F8A411009802F022FB82E7DB4810B53F +:10BC9000006990F8821041B990F87D2001230621B7 +:10BCA0007030F5F76FF9002800D001209DE570B5E0 +:10BCB000D24D286990F8801039B1012905D00229A8 +:10BCC00006D0032904D0FFDF03E4B0F8F41037E016 +:10BCD00090F87F10082936D0B0F89810B0F89A2064 +:10BCE00000248B1C9A4206D3511A891E0C04240C82 +:10BCF00001D0641EA4B290F8961039B190F87C205F +:10BD0000012309217030F5F73DF940B3FFF7BEFF7D +:10BD100078B129690020B1F89020B1F88E108B1C01 +:10BD20009A4203D3501A801E00D0401EA04200D277 +:10BD300084B20CB1641EA4B22869B0F8F410214496 +:10BD4000A0F8F0102DE5B0F898100329BDD330F815 +:10BD5000701F428D1144491CA0F8801021E5002479 +:10BD6000EAE770B50C4605464FF4087200212046FC +:10BD7000F2F78DFB258014E5F8F7A2B92DE9F04123 +:10BD80000D4607460721F8F791F8041E3CD094F8B9 +:10BD9000C8010026A8B16E70092028700BE0268427 +:10BDA00084F8C861D4F8CA016860D4F8CE01A860EC +:10BDB000B4F8D201A88194F8C8010028EFD12E71FF +:10BDC000AEE094F8D40190B394F8D4010D2813D0C8 +:10BDD0000E2801D0FFDFA3E02088F8F798F9074686 +:10BDE000F7F745FE78B96E700E20287094F8D601EA +:10BDF00028712088E88014E02088F8F788F9074641 +:10BE0000F7F735FE10B10020BDE8F0816E700D200F +:10BE1000287094F8D60128712088E88094F8DA0117 +:10BE2000287284F8D4613846F7F71BFE78E0FFE704 +:10BE300094F80A0230B16E701020287084F80A62FB +:10BE4000AF806DE094F8DC0190B16E700A2028702C +:10BE50002088A880D4F8E011C5F80610D4F8E411C1 +:10BE6000C5F80A10B4F8E801E88184F8DC6157E00D +:10BE700094F8040270B16E701A20287005E000BFBB +:10BE800084F80462D4F80602686094F8040200287A +:10BE9000F6D145E094F8EA0188B16E70152028705B +:10BEA00008E000BF84F8EA6104F5F6702B1D07C8AE +:10BEB00083E8070094F8EA010028F3D130E094F811 +:10BEC000F80170B16E701C20287084F8F861D4F805 +:10BED000FA016860D4F8FE01A860B4F80202A881F3 +:10BEE0001EE094F80C0238B11D20287084F80C6212 +:10BEF000D4F80E02686013E094F81202002883D090 +:10BF00006E701620287007E084F81262D4F81402CC +:10BF10006860B4F81802288194F812020028F3D15E +:10BF2000012071E735480021C16101620846704770 +:10BF300030B5324D0C46E860FFF7F4FF00B1FFDF8B +:10BF40002C7130BD002180F87C1080F87D1080F8C5 +:10BF5000801090F8FB1009B1022100E00321FEF7E8 +:10BF60003FBC2DE9F041254C0546206909B100216F +:10BF700004E0B0F80611B0F8F6201144A0F806115C +:10BF800090F88C1139B990F87F2001231946703050 +:10BF9000F4F7F8FF30B1206930F89C1FB0F85A2050 +:10BFA00011440180206990F8A23033B1B0F89E109E +:10BFB000B0F8F6201144A0F89E1090F9A670002F5A +:10BFC00006DDB0F8A410B0F8F6201144A0F8A410D3 +:10BFD00001213D2615B180F88D6017E02278022AF4 +:10BFE0000ED0012A15D0A2784AB380F88C1012F036 +:10BFF000140F11D01E2117E0FC6202000001002086 +:10C0000090F8E620062A3CD016223AE080F88C1000 +:10C0100044E090F88E2134E0110702D580F88D605D +:10C020003CE0910603D5232180F88D1036E090077F +:10C0300000D1FFDF21692A2081F88D002AE02BB191 +:10C04000B0F89E20B0F8A0309A4210D2002F05DD43 +:10C05000B0F8A420B0F8A0309A4208D2B0F89C30D2 +:10C06000B0F89A20934204D390F88C310BB122227D +:10C0700007E090F880303BB1B0F89830934209D394 +:10C08000082280F88D20C1E7B0F89820062A01D355 +:10C090003E22F6E7206990F88C1019B12069BDE8BE +:10C0A000F0414FE7BDE8F0410021FEF799BB2DE9D3 +:10C0B000F047FF4C81460D4620690088F8F739F8B3 +:10C0C000060000D1FFDFA0782843A070A0794FF0D0 +:10C0D00000058006206904D5A0F8985080F8045126 +:10C0E00003E030F8981F491C0180FFF7CFFD4FF0A7 +:10C0F000010830B3E088000506D5206990F8821069 +:10C1000011B1A0F88E501CE02069B0F88E10491CC7 +:10C1100089B2A0F88E10B0F890208A4201D3531A49 +:10C1200000E0002327897F1DBB4201D880F896805C +:10C13000914206D3A0F88E5080F80A822079E6F763 +:10C14000E3FEA0794FF0020710F0600F0ED02069D7 +:10C1500090F8801011B1032908D102E080F88080A6 +:10C1600001E080F880700121FEF73AFB206990F829 +:10C170008010012904D1E188C90501D580F88070BB +:10C18000B9F1000F72D1E188890502D5A0F81851E4 +:10C1900004E0B0F81811491CA0F8181100F035FBA4 +:10C1A000FEF719FDFFF72EFC2769B7F8F800401CD1 +:10C1B000A7F8F80097F8FC0028B100F01BFFA8B121 +:10C1C000A7F8F85012E000F012FF08B1A7F8F850F5 +:10C1D00000F015FF50B197F80401401CC0B287F879 +:10C1E0000401022802D927F8F85F3D732069012372 +:10C1F000002190F87D207030F4F7C4FE20B920694A +:10C2000090F87D000C2859D120690123002190F875 +:10C210007C207030F4F7B6FE48B32069012300217A +:10C2200090F87F207030F4F7ADFE00B3206990F8ED +:10C230008010022942D190F80401C0B93046F7F7C6 +:10C24000E6F9A0B1216991F8E400FE2836D1B1F8F1 +:10C25000F200012832D981F8FA80B1F89A00B1F8D9 +:10C260009820831E9A4203DB012004E032E025E09F +:10C27000801A401E80B2B1F8F82023899A4201D377 +:10C28000012202E09A1A521C92B2904200D9104642 +:10C29000012801D181F8FA5091F86F2092B98A6E85 +:10C2A00082B1B1F89420B1F87010511A09B2002986 +:10C2B00008DD884200DB084680B203E021690120E6 +:10C2C00081F8FA502169B1F870201044A1F8F40007 +:10C2D000FFF7EDFCE088C0F340214846FFF741FE40 +:10C2E000206980F8FB50BDE8F047FDF7FCB87049C5 +:10C2F00002468878CB78184312D10846006942B1CB +:10C300008979090703D590F87F00082808D0012013 +:10C310007047B0F84C10028E914201D8FEF7B1B9C7 +:10C320000020704770B5624C05460E46E0882843F1 +:10C33000E080A80703D5E80700D0FFDF6661EA07C1 +:10C340004FF000014FF001001AD0A661F278062AE2 +:10C3500002D00B2A14D10AE0226992F87D30172B03 +:10C360000ED10023E2E92E3302F8370C08E02269EF +:10C3700092F87D30112B03D182F8811082F8A80049 +:10C38000AA0718D56269D278052A02D00B2A12D1E1 +:10C390000AE0216991F87D20152A0CD10022E1E9FB +:10C3A000302201F83E0C06E0206990F87D20102A2A +:10C3B00001D180F88210280601D50820E07083E4BE +:10C3C0002DE9F84301273A4C002567F30701E58082 +:10C3D000A570E570257020618946804680F8FB7065 +:10C3E0000088F7F7A6FE00B9FFDF20690088FDF797 +:10C3F00042F820690088FDF764F82069B0F8F2106F +:10C4000071B190F8E410FE290FD190F88C1189B128 +:10C4100090F87F20012319467030F4F7B3FD78B10E +:10C42000206990F8E400FE2804D0206990F8E40028 +:10C43000FFF774FB206990F8FD1089B1258118E0A1 +:10C440002069A0F89C5090F88D1180F8E61000212A +:10C450000220FFF7CBF9206980F8FA500220E7E7C5 +:10C4600090F8C81119B9018C8288914200D881884E +:10C47000218130F8F61F491E8EB230F8021F314478 +:10C4800020F86019018831440180FFF7FFFB20B1DB +:10C49000206930F88E1F314401802069B0F8F21015 +:10C4A000012902D8491CA0F8F2102EB102E00000C8 +:10C4B0000001002080F8045180F8FA5090F87D10B7 +:10C4C0000B2901D00C2916D1B0F87020B0F8AA3190 +:10C4D000D21A12B2002A0EDBD0F8AC11816090F8AB +:10C4E000B01101730321F4F773F8206980F87D50CF +:10C4F00080F8B27026E0242910D1B0F87010B0F89E +:10C50000AA21891A09B2002908DB90F8C001FFF7B7 +:10C510004BF9206900F87D5F857613E090F87C1078 +:10C52000242901D025290DD1B0F87010B0F8AA0146 +:10C53000081A00B2002805DB0120FFF735F9206951 +:10C5400080F87C5020690146B0F8F6207030F4F78E +:10C55000B2FAFC480090FC4BFC4A4146484600F0C9 +:10C560007DFC216A11B16078FCF7B5FA20690123DE +:10C57000052190F87D207030F4F704FD002803D0E9 +:10C58000BDE8F84300F0FDB9BDE8F88300F015BD43 +:10C59000EF49C8617047EE48C069002800D001200B +:10C5A0007047EB4A50701162704710B5044600881E +:10C5B000A4F8CC01B4F8B001A4F8CE01B4F8B201EB +:10C5C000A4F8D001B4F8B401A4F8D201012084F891 +:10C5D000C801DF480079E6F797FC02212046F3F70F +:10C5E000F7FF002004F87D0F0320E07010BD401A13 +:10C5F00000B247F6FE71884201DC002801DC012010 +:10C6000070470020704710B5012808D0022808D0D4 +:10C61000042808D0082806D0FFDF204610BD0124DA +:10C62000FBE70224F9E70324F7E7C9480021006982 +:10C6300020F8A41F8178491C81707047C44800B558 +:10C64000016911F8A60F401E40B20870002800DAF8 +:10C65000FFDF00BDBE482721006980F87C10002163 +:10C6600080F8A011704710B5B94C206990F8A81156 +:10C67000042916D190F87C20012300217030F4F7B2 +:10C6800081FC00B9FFDF206990F8AA10890703D464 +:10C69000062180F87C1004E0002180F8A21080F8C8 +:10C6A000A811206990F87E00800707D5FFF7C6FF24 +:10C6B000206910F87E1F21F00201017010BDA4490D +:10C6C00010B5096991F87C200A2A09D191F8E22075 +:10C6D000824205D1002081F87C0081F8A20010BDC3 +:10C6E00091F87E20130706D522F0080081F87E001D +:10C6F000BDE81040A2E7FF2801D0FFDF10BDBDE874 +:10C700001040A7E7F8B5924C01230A21206990F860 +:10C710007C207030F4F736FC38B3A06901F07CFE61 +:10C72000C8B1A06901F072FE0746A06901F072FE6F +:10C730000646A06901F068FE0546A06901F068FEA2 +:10C7400001460097206933462A46303001F059FFF0 +:10C75000206901F082FF2169002081F8A20081F8A0 +:10C760007C00BDE8F840FEF7D2BBA07840F00100A5 +:10C77000A070F8BD10B5764C01230021206990F817 +:10C780007D207030F4F7FEFB30B1FFF74EFF2169DA +:10C79000102081F87D0010BD20690123052190F84B +:10C7A0007D207030F4F7EEFB08B1082000E0012096 +:10C7B000A07010BD70B5664C01230021206990F86F +:10C7C0007D207030F4F7DEFB012588B1A06901F00F +:10C7D000C4FD2169A1F8AA01B1F87010FFF707FFA5 +:10C7E00040B12069282180F88D1080F88C50E6E552 +:10C7F000A570E4E52169A06901F5D67101F0A8FDF5 +:10C8000021690B2081F87D00D9E510B5FEF779FF8D +:10C81000FEF760FE4E4CA079400708D5A07830B9ED +:10C82000206990F87F00072801D101202070FEF7D1 +:10C8300071FAA079C00609D5A07838B9206990F8B6 +:10C840007D100B2902D10C2180F87D10E0780007C3 +:10C850000ED520690123052190F87D207030F4F772 +:10C8600091FB30B10820A0702169002081F8D4012B +:10C8700010BDBDE81040002000F0C4BB10B5344C22 +:10C88000216991F87D2048B3102A06D0142A07D0D8 +:10C89000152A1AD01B2A2CD11AE001210B2019E0ED +:10C8A000FAF702FE0C2817D32069082100F58870DA +:10C8B000FAF7FEFD28B120690421DC30FAF7F8FD13 +:10C8C00000B9FFDF0121042004E000F017F803E0C5 +:10C8D00001210620FEF78AFF012010BD212A08D180 +:10C8E00091F8970038B991F8C00110B191F8C101E1 +:10C8F00008B1002010BD01211720EBE770B5144CE2 +:10C900000025206990F88F1101290AD002292ED123 +:10C9100090F8A810F1B1062180F8E610012102205C +:10C9200020E090F8D411002921D100F1C80300F5CE +:10C930008471002200F5C870F4F796FA01210520F1 +:10C9400010E00000AFC00100EFC2010025C30100EC +:10C950000001002090F8B000400701D5112000E050 +:10C960000D200121FEF742FF206980F88F5126E556 +:10C9700030B5FB4C05462078002818BFFFDFE57175 +:10C9800030BDF7490120887170472DE9F14FF54D11 +:10C990002846446804F1700794F86510608F94F895 +:10C9A0008280268F082978D0F4F797FBB8F1000F22 +:10C9B00004BF001D80B2864238BF304600F0FF0839 +:10C9C000DFF89C93E848C9F8240009F134006E6848 +:10C9D000406800F1700A90F882B096F86510358FC3 +:10C9E000708F08295DD0F4F778FB00BFBBF1000F12 +:10C9F00004BF001D80B2854238BF2846C0B29AF8F5 +:10CA00001210002918BF04210844C0B296F865101E +:10CA1000FBF735FCB87C002847D007F15801D24815 +:10CA200091E80E1000F5027585E80E10B96EC0F899 +:10CA30002112F96EC0F8251200F58170FBF7DBFFBB +:10CA4000C848007800280CBF0120002080F00101B8 +:10CA5000C6480176D7E91412C0E90412A0F5837222 +:10CA6000D9F82410FBF7F5F994F86500012808BF00 +:10CA700000220CD0022808BF012208D0042808BFD9 +:10CA8000032204D008281ABFFFDF002202224146F9 +:10CA90000120FBF7F9F90EE0FFE70421F4F71DFB95 +:10CAA00084E70421F4F719FBA0E7D9F82400FBF789 +:10CAB000A2FFFBF715FA009850B994F8650094F8B6 +:10CAC000661010F00C0F08BF00219620FBF7B4FF92 +:10CAD00094F8642001210020FCF76BF894F82C00F6 +:10CAE000012808BFFCF735F8022089F80000FCF7A0 +:10CAF0003FFC002818BFFFDFBDE8F88F2DE9F04F9D +:10CB0000DFF860A28BB050469AF800204068AAF186 +:10CB10001401059190F8751000F1700504464FF06E +:10CB200008080127AAF13406A1B3012900F0068103 +:10CB3000022900F00781032918BFFFDF00F01881E8 +:10CB4000306A0423017821F008010170AA7908EA0B +:10CB5000C202114321F004010170EA7903EA820262 +:10CB6000114321F01001017095F80590F06AF6F775 +:10CB70005EFD8046FCF7C9FCB9F1020F00F00081B0 +:10CB8000B9F1010F00F00081B9F1030F00F000814D +:10CB900000F003B9FFE795F80CC04FF002094FF021 +:10CBA000000BBCF1240F1CBF6B7B242B08D0BCF105 +:10CBB0001F0F18BFBCF1200F2AD0222B4DD077E0D9 +:10CBC00094F864109AB190F8AC01002874D0082948 +:10CBD00018BF042969D0082818BF042865D0012986 +:10CBE00018BF012853D000BF4FF0020164E090F855 +:10CBF0001201002860D0082918BF042955D0082840 +:10CC000018BF042851D0012918BF01283FD0EBE7F5 +:10CC1000222B22D0002A4BD090F8C20194F8641045 +:10CC200010F0040F18BF40460CD0082918BF042983 +:10CC30003BD0082818BF042837D0012918BF012885 +:10CC400025D0D1E710F0010F18BF3846EDD110F014 +:10CC5000020F18BF4846E8D12EE04AB390F8C2212F +:10CC600090F85D0094F8641002EA000010F0040FE0 +:10CC700018BF40460ED0082918BF042915D008282F +:10CC800018BF042811D0012918BF0128ACD14FF0DA +:10CC9000010111E010F0010F18BF3846EBD110F080 +:10CCA000020F18BF4846E6D106E04FF0080103E046 +:10CCB00094F864100429F8D0A08E11F00C0F18BF5E +:10CCC0004FF42960F4F709FA218E814238BF0846F3 +:10CCD000ADF80400A4F84C000598FCF7F5FB60B132 +:10CCE0007289316A42F48062728172694FF48060A5 +:10CCF000904703206871EF7022E709AA01A9F06A42 +:10CD0000F6F7CFFB306210B195F8371021B10598D6 +:10CD1000FCF7AEFB6F7113E79DF8241031B9A0F852 +:10CD200000B080F802B0012101F09EFABDF80410B5 +:10CD3000306A01F0C7FB85F8059001E70598FCF71C +:10CD400097FBFDE6B4F84C00ADF8040009AA01A970 +:10CD5000F06AF6F7A6FB3062002808BFFFDFEFE6B7 +:10CD60002401002058010020300D0020380F002041 +:10CD70000598FCF7A9FB002808BFFFDFE0E600BF2D +:10CD800030EA080009D106E030EA080005D102E0E7 +:10CD9000B8F1000F01D0012100E00021306A0278D3 +:10CDA00042EA01110170697C00291CBF69790129DF +:10CDB0003BD005F15801FD4891E80E1000F50278CE +:10CDC00088E80E10A96EC0F82112E96EC0F825128D +:10CDD00000F58170FBF70FFE9AF8000000280CBFE9 +:10CDE00001210021F2480176D5E91212C0E90412AE +:10CDF000A0F58371326AFBF72CF894F864000128DF +:10CE000008BF00220CD0022808BF012208D0042845 +:10CE100008BF032204D008281ABFFFDF0022022225 +:10CE2000FB210020FBF730F803E0FBF7E4FDFBF704 +:10CE300057F8012194F865200846FBF7BAFE3771D0 +:10CE4000306A0188F181807830743770FCF799FA84 +:10CE5000002818BFFFDF0BB0BDE8F08F2DE9F043CD +:10CE6000D44D87B081462878DDF838801E461746B5 +:10CE70000C4628B9002F1CBF002EB8F1000F00D1BE +:10CE8000FFDFC5F81C80C5E90D94C5E905764FF0B4 +:10CE90000000A8716871E870A8702871C64E68819A +:10CEA000A881307804F170072088F7F742F9E8622A +:10CEB0002088F7F72CF92863FBF705FA94F9670047 +:10CEC000FBF7DAFA04F11200FBF76CFD04F10E0037 +:10CED000FBF7D8FA307800280CBF03200120FBF7BD +:10CEE00087FDB64890E80E108DE80E10D0E90410CA +:10CEF000CDE90410307800280CBFB148B148049047 +:10CF00006846FBF763FDF87EFBF7C4FAFBF76AFDA2 +:10CF100094F86F0078B9A06E68B1B88C39888842EF +:10CF200009D1B4F86C1001220844B88494F86E005A +:10CF3000A16EF8F7D8FE3078002804BFFF2094F8DF +:10CF400064401AD094F8651097F81280258F608F8E +:10CF5000082926D0F4F7C1F8B8F1000F04BF001D6E +:10CF600080B2854238BF2846C0B2B97C002918BFBC +:10CF70000421084494F86540C0B22146FBF77FF9CC +:10CF80003078214688B10120FBF74BFB7068D0F860 +:10CF90000001FBF733FD0120FFF7F7FC07B0BDE808 +:10CFA000F0830421F4F799F8D6E70020FBF739FB6A +:10CFB000FFF7A4FD07B0BDE8F0837F4800B5017816 +:10CFC0003438007819B1022818BFFFDF00BD0128EE +:10CFD00018BFFFDF00BD774810B50078022818BFE2 +:10CFE000FFDFBDE8104000F070BA00F06EBA714883 +:10CFF000007970476F488089C0F3002070476D4802 +:10D00000C07870472DE9F04706006B48694D4068CD +:10D0100000F17004686A90F8019018BF012E03D1E6 +:10D02000296B07F0F1FF6870687800274FF001085E +:10D03000A0B101283CD0022860D003281CBFFFDF2C +:10D04000BDE8F087012E08BFBDE8F087286BF6F732 +:10D05000E3FCE879BDE8F047E5F756BF012E14D0B0 +:10D06000A86A002808BFFFDF2889C21CD5E909107B +:10D07000F1F7E3F9A86A686201224946286BF6F7DE +:10D0800047FB022E08BFBDE8F087D4E91401401C1D +:10D0900041F10001C4E91401E079012801D1E771EF +:10D0A00001E084F80780E879BDE8F047E5F72CBF98 +:10D0B000012E14D0A86A002808BFFFDF2889C21CEF +:10D0C000D5E90910F1F7B9F9A86A68620022494662 +:10D0D000286BF6F71DFB022E08BFBDE8F087D4E9E8 +:10D0E0001410491C40F10000C4E91410E079012833 +:10D0F0000CBFE77184F80780BDE8F087012E06D0E9 +:10D10000286BF6F789FC022E08BFBDE8F087D4E94A +:10D110001410491C40F10000C4E91410E079012802 +:10D12000BFD1BCE72DE9F041234D2846A5F13404D9 +:10D13000406800F170062078012818BFFFDFB07842 +:10D140000127002158B1B1706289042042F0040225 +:10D150006281626990472878002818BF3771216A78 +:10D160000322087832EA000009D1628912F4806F44 +:10D1700005D042F002026281626902209047A169F3 +:10D180000020884760B3607950BB287818B30E48F8 +:10D19000007810F0100F04D10449097811F0100F35 +:10D1A0001ED06189E1B9A16AA9B90FE0300D002054 +:10D1B000380F0020240100205801002004630200E1 +:10D1C000BB220200A7A8010032010020218911B171 +:10D1D00010F0100F04D0BDE8F0410020FFF7D5BBE0 +:10D1E000BDE8F04100F071B92DE9F05FCC4E044686 +:10D1F0003046A6F134054068002700F1700A28780F +:10D20000B846022818BFFFDFA889FF2240F400704B +:10D21000A881706890F864101046FBF730F89AF80F +:10D2200012004FF00109002C00F0F080FAF77DFEAB +:10D23000FAF76BFE90B99AF8120078B1686A4178F3 +:10D2400061B100789AF80710C0F3C000884205D198 +:10D2500085F80290BDE8F05F00F037B9686A417860 +:10D260002981002908BFAF6203D0286BF6F70AFABC +:10D27000A862A88940F02000A881EF70706800F1D2 +:10D28000700B044690F82C0001281BD1FBF757FCCB +:10D2900059462046F3F729FEA0B13078002870687F +:10D2A0000CBF00F59A7000F50170218841809BF851 +:10D2B000081001719BF80910417180F80090E8791D +:10D2C000E5F722FE686A9AF806100078C0F380003D +:10D2D00088423AD0706800F1700490F87500002818 +:10D2E0002FD002284AD06771307800281CBF2079DF +:10D2F000002809D027716A89394642F010026A81F4 +:10D300006A694FF010009047E078A0B1E770FCF731 +:10D31000EAF8002808BFFFDF08206A89002142F0F0 +:10D3200008026A816A699047D4E91210491C40F1E9 +:10D330000000C4E91210A07901280CBFA77184F87D +:10D340000690A88940F48070A881696A9AF807302D +:10D350000878C0F3C0029A424DD1726800F0030011 +:10D3600002F17004012818BF02282DD003281CBF29 +:10D37000687940F0040012D068713CE0E86AF6F782 +:10D38000BCF8002808BFFFDFD4E91210491C40F1A7 +:10D390000000C4E91210E879E5F7B6FDA3E784F8C8 +:10D3A0000290AA89484642F40062AA816A8942F042 +:10D3B00001026A816A699047E079012801D1E77129 +:10D3C00019E084F8079016E04878D8B1A98941F4AB +:10D3D0000061A981A96A71B1FB2884BF687940F016 +:10D3E0001000C9D8A879002808BFC84603D08020FB +:10D3F0006A69002190470120A9698847E0B36879EC +:10D40000A0B13AE0E0790128DBD1D8E7002818BFC5 +:10D41000FAF7C5FDA88940F04000A881E97801200D +:10D42000491CC9B2E97001292DD8E5E7307890B9D7 +:10D430003C48007810F0100F04D13B49097811F0F6 +:10D44000100F1AD06989B9B9A96A21B9298911B10E +:10D4500010F0100F11D0B8F1000F1CBF0120FFF722 +:10D46000D1FDFFF74BFBB8F1000F08BFBDE8F09FFF +:10D470000220BDE8F05FC5E5FFE7B8F1000F1CBF73 +:10D480000020FFF7BFFDBDE8F05F00F01EB870B5EB +:10D490000D4606462248224900784C6850B1FAF7FA +:10D4A000F7FD034694F8642029463046BDE87040F5 +:10D4B000FDF78BBAFAF7ECFD034694F86420294691 +:10D4C0003046BDE8704004F0FCBE154910B54C680C +:10D4D000FBF714FBFBF7F3FAFBF7BCF9FBF768FA71 +:10D4E000FAF7FEFC94F82C00012808BFFBF727FB95 +:10D4F00094F86F0038B9A06E28B1002294F86E003D +:10D500001146F8F7F0FB094C00216269A0899047A9 +:10D51000E2696179A07890470020207010BD00007A +:10D520005801002032010020300D0020240100208D +:10D530002DE9F047FA4F894680463D782C0014D0FB +:10D540000126012D11DB601EC4B207EBC40090F868 +:10D550005311414506D10622494600F5AA70F0F75D +:10D560003FFF28B1761CAE42EDDD1020BDE8F0870C +:10D570002046BDE8F087EA498A78824286BF08449F +:10D5800090F843010020704710B540F2D3120021FB +:10D59000E348F0F77CFF0822FF21E248F0F777FF2D +:10D5A000E1480021417081704FF46171818010BDAC +:10D5B0002DE9F0410E460546FFF7BAFFD84C10287A +:10D5C00016D004EBC00191F85A0110F0010F1CBFF6 +:10D5D0000120BDE8F081607808283CBF012081F877 +:10D5E0005A011CD26078401C60700120BDE8F081B7 +:10D5F0006078082813D222780127501C207004EB91 +:10D60000C2083068C8F85401B088A8F85801102A38 +:10D6100028BFFFDF88F8535188F85A71E2E70020ED +:10D62000BDE8F081C04988707047BF488078704776 +:10D630002DE9F041BA4D00272878401E44B2002C55 +:10D6400030DB00BF05EBC40090F85A0110F0010F69 +:10D6500024D06878E6B2401E687005EBC6083046F4 +:10D6600088F85A7100F0E8FA102817D12878401E7F +:10D67000C0B22870B04211D005EBC001D1F85301FF +:10D68000C8F85301D1F85701C8F85701287800F0BD +:10D69000D3FA10281CBF284480F80361601E44B2EE +:10D6A000002CCFDAA0488770BDE8F0819C498A78C9 +:10D6B000824286BF01EB0010C01C002070472DE99C +:10D6C000F0470127994690463D460026FFF730FF78 +:10D6D000102820D0924C04EBC00191F85A1101F0AF +:10D6E000010600F0A9FA102815D0B9F1000F18BFF3 +:10D6F00089F80000A17881420DD904EB001111F1E5 +:10D70000030F08D0204490F84B5190F83B010128BA +:10D710000CBF0127002748EA060047EA0501084038 +:10D72000BDE8F0872DE9F05F1F4690468946064622 +:10D73000FFF7FEFE7A4C054610282ED000F07CFA4A +:10D7400010281CBF1220BDE8F09FA07808283ED208 +:10D75000A6781022701CA07004EB061909F10300D2 +:10D760004146F3F768FB09F1830010223946F3F7CD +:10D7700062FB10213846F3F74BFB3444102184F848 +:10D7800043014046F3F744FB84F84B0184F803510E +:10D79000002084F83B01BDE8F09FA078082816D24D +:10D7A00025784FF0000A681C207004EBC50BD9F8EF +:10D7B0000000CBF85401B9F80400ABF85801102D63 +:10D7C00028BFFFDF8BF853618BF85AA1C0E7072011 +:10D7D000BDE8F09F2DE9F041514CA078401E45B2C4 +:10D7E000002DB8BFBDE8F081EAB2A078401EC1B2FA +:10D7F000A17054FA85F090F803618A423DD004EBA1 +:10D80000011004EB0213D0F803C0C3F803C0D0F832 +:10D8100007C0C3F807C0D0F80BC0C3F80BC0D0F8DE +:10D820000FC0C3F80FC0D0F883C0C3F883C0D0F8CE +:10D8300087C0C3F887C0D0F88BC0C3F88BC0D0F8BE +:10D840008F00C3F88F006318A01801EB410193F813 +:10D8500003C102EB420204EB410180F803C104EB77 +:10D860004202D1F80BC1C2F80BC1B1F80F11A2F8F6 +:10D870000F1193F83B1180F83B1104EBC60797F8A2 +:10D880005A0110F0010F1CD1304600F0D5F91028D4 +:10D8900017D12078401EC0B22070B04211D004EBE6 +:10D8A000C000D0F85311C7F85311D0F85701C7F88A +:10D8B0005701207800F0C0F910281CBF204480F8E0 +:10D8C0000361681E45B2002D8EDABDE8F08116496D +:10D8D0004870704714484078704738B14AF2B81120 +:10D8E000884203D810498880012070470020704783 +:10D8F0000D488088704710B5FFF71AFE102804D035 +:10D9000000F09AF9102818BF10BD082010BD044976 +:10D910008A78824286BF01EB001083300020704776 +:10D92000600F00206C01002060010020FE4B93F886 +:10D9300002C084459CBF00207047184490F8030142 +:10D9400003EBC00090F853310B70D0F85411116004 +:10D95000B0F85801908001207047F34A114491F8C3 +:10D960000321F2490A700268C1F8062080884881C4 +:10D97000704770B516460C460546FBF7D5F8FAF722 +:10D98000C4F9EA48407868B1E748817851B12A196A +:10D99000002E0CBF8330C01CFAF791F9FAF7D8F9C2 +:10D9A000012070BD002070BD10B5FAF7FFF9002806 +:10D9B00004BFFF2010BDBDE81040FAF71DBAFAF70A +:10D9C000F5B9D9498A7882429CBF00207047084443 +:10D9D00090F8030101EBC00090F85A0100F001003B +:10D9E00070472DE9F047D04D00273E4628780028A3 +:10D9F00086BF4FF01009DFF83883BDE8F087AC78B8 +:10DA000021000CD00122012909DB601EC4B22819B3 +:10DA100090F80331B34203D0521C8A42F5DD4C46E4 +:10DA2000A14286BF05EB0410C01C002005EBC60A0E +:10DA30009AF85A1111F0010F16D050B1102C04D0E1 +:10DA4000291991F83B11012903D01021F3F7E0F9CE +:10DA500050B108F8074038467B1C9AF853210AF564 +:10DA6000AA71DFB2FAF7B5FC701CC6B22878B042D2 +:10DA7000C5D8BDE8F0872DE9F041AB4C002635460E +:10DA8000A07800288CBFAA4FBDE8F0816119C0B210 +:10DA900091F80381A84286BF04EB0510C01C00204A +:10DAA00091F83B11012903D01021F3F7B1F958B1D6 +:10DAB00004EBC800BD5590F8532100F5AA7130461B +:10DAC000731CDEB2FAF785FC681CC5B2A078A842C8 +:10DAD000DCD8BDE8F0810144934810B500EB02109A +:10DAE0000A4601218330FAF7EAF8BDE81040FAF758 +:10DAF0002FB90A468D4910B5497841B18A4B9978BA +:10DB000029B10244D81CFAF7DAF8012010BD002030 +:10DB100010BD854A01EB410102EB41010268C1F8E9 +:10DB20000B218088A1F80F0170472DE9F0417E4D4F +:10DB300007460024A878002898BFBDE8F081C0B24D +:10DB4000A04217D905EB041010F1830612D0102162 +:10DB50003046F3F75DF968B904EB440005EB400883 +:10DB600008F20B113A463046FBF74EFDB8F80F01AC +:10DB7000A8F80F01601CC4B2A878A042DFD8BDE8A5 +:10DB8000F081014610226B48F3F755B96948704798 +:10DB900065498A78824203D90A1892F843210AB16A +:10DBA0000020704700EB400001EB400000F20B103A +:10DBB00070475D498A78824206D9084490F83B0153 +:10DBC000002804BF01207047002070472DE9F04174 +:10DBD0000E460746144606213046F3F719F9524D12 +:10DBE00098B1A97871B105F59D7011F0010F18BFBA +:10DBF00000F8014FA978490804D0447000F8024F9A +:10DC0000491EFAD10120BDE8F08138463146FFF7C0 +:10DC10008FFC10280CD000F00FF8102818BF08282F +:10DC200006D0284480F83B414FF00100BDE8F08168 +:10DC30004FF00000BDE8F0813B4B10B4844698786B +:10DC400001000ED0012201290BDB401EC0B21C18BE +:10DC500094F80341644504BF10BC7047521C8A42CB +:10DC6000F3DD10BC1020704770B52F4C01466218D0 +:10DC7000A078401EC0B2A07092F8035181423CD0FF +:10DC800004EB011304EB001C01EB4101DCF8036021 +:10DC9000C3F80360DCF80760C3F80760DCF80B60CA +:10DCA000C3F80B60DCF80F60C3F80F60DCF883602A +:10DCB000C3F88360DCF88760C3F88760DCF88B60AA +:10DCC000C3F88B60DCF88FC0C3F88FC0231800EB5B +:10DCD000400093F803C104EB400082F803C104EB59 +:10DCE0004101D0F80BC1C1F80BC1B0F80F01A1F888 +:10DCF0000F0193F83B0182F83B0104EBC50696F84F +:10DD00005A0110F0010F18BF70BD2846FFF794FFAD +:10DD1000102818BF70BD2078401EC0B22070A842E5 +:10DD200008BF70BD08E00000600F00206001002007 +:10DD30006C0100203311002004EBC000D0F8531117 +:10DD4000C6F85311D0F85701C6F857012078FFF7ED +:10DD500073FF10281CBF204480F8035170BD0000E1 +:10DD60004078704730B50546007801F00F0220F08A +:10DD70000F0010432870092912D2DFE801F00507CF +:10DD800005070509050B0F0006240BE00C2409E02C +:10DD9000222407E001240020E87003E00E2401E0C3 +:10DDA0000024FFDF6C7030BD007800F00F0070477A +:10DDB0000A68C0F803208988A0F807107047D0F8D7 +:10DDC00003200A60B0F80700888070470A68C0F82E +:10DDD00009208988A0F80D107047D0F809200A6042 +:10DDE000B0F80D00888070470278402322F040028E +:10DDF00003EA81111143017070470078C0F380106D +:10DE000070470278802322F0800203EAC111114397 +:10DE1000017070470078C009704770B514460E460F +:10DE200005461F2A88BFFFDF2246314605F109005B +:10DE3000F0F703FBA01D687070BD70B544780E4606 +:10DE40000546062C38BFFFDFA01F84B21F2C88BFF9 +:10DE50001F24224605F109013046F0F7EEFA20466C +:10DE600070BD70B514460E4605461F2A88BFFFDFF9 +:10DE70002246314605F10900F0F7DFFAA01D68706F +:10DE800070BD0968C0F80F1070470A88A0F8132009 +:10DE900089784175704790F8242001F01F0122F025 +:10DEA0001F02114380F824107047072988BF0721FB +:10DEB00090F82420E02322F0E00203EA411111430C +:10DEC00080F8241070471F3008F065B810B504467C +:10DED00000F000FB002818BF204410BDC17811F0ED +:10DEE0003F0F1BBF027912F0010F0022012211F037 +:10DEF0003F0F1BBF037913F0020F002301231A44C5 +:10DF000002EB4202530011F03F0F1BBF027912F0E7 +:10DF1000080F0022012203EB420311F03F0F1BBF49 +:10DF2000027912F0040F00220122134411F03F0F76 +:10DF30001BBF027912F0200F0022012202EBC20265 +:10DF400003EB420311F03F0F1BBF027912F0100FD9 +:10DF50000022012202EB42021A4411F03F0F1BBFC4 +:10DF6000007910F0400F00200120104410F0FF0055 +:10DF700014BF012100210844C0B2704770B5027877 +:10DF8000417802F00F02082A4DD2DFE802F00408BF +:10DF90000B4C4C4C0F14881F1F280AD943E00C2946 +:10DFA00007D040E0881F1F2803D93CE0881F1F28A6 +:10DFB00039D8012070BD4A1EFE2A34D88446C07864 +:10DFC00000258209032A09D000F03F04601C884222 +:10DFD00004D86046FFF782FFA04201D9284670BDF1 +:10DFE0009CF803004FF0010610F03F0F1EBF1CF11C +:10DFF0000400007810F0100F13D06446042160462E +:10E0000000F068FA002818BF14EB0000E6D0017891 +:10E0100001F03F012529E1D280780221B1EB501FA8 +:10E02000DCD3304670BD002070BD70B5017801258D +:10E0300001F00F01002404290AD007290DD0082976 +:10E040001CBF002070BD40780E2836D0204670BD21 +:10E050004078801F1F2830D9F8E7844640789CF824 +:10E0600003108A09032AF1D001F03F06711C814296 +:10E07000ECD86046FFF732FFB042E7D89CF80300C7 +:10E0800010F03F0F1EBF1CF10400007810F0100FBD +:10E0900013D066460421604600F01CFA002818BF21 +:10E0A00016EB0000D2D0017801F03F012529CDD236 +:10E0B00080780221B1EB501FC8D3284670BD10B440 +:10E0C000017801F00F01032920D0052921D14478DE +:10E0D000B0F81910B0F81BC0B0F81730827D222CB0 +:10E0E00017D1062915D3B1F5486F98BFBCF5FA7F53 +:10E0F0000FD272B1082A98BF8A420AD28B429CBFC3 +:10E10000B0F81D00B0F5486F03D805E040780C2842 +:10E1100002D010BC0020704710BC012070472DE9D0 +:10E12000F0411F4614460D00064608BFFFDF21469A +:10E13000304600F0CFF9040008BFFFDF30193A463F +:10E140002946BDE8F041F0F778B9C07800F03F000B +:10E150007047C02202EA8111C27802F03F021143E7 +:10E16000C1707047C07880097047C9B201F00102E0 +:10E17000C1F340031A4402EB4202C1F3800303EBF4 +:10E180004202C1F3C00302EB4302C1F3001303EBED +:10E1900043031A44C1F3401303EBC30302EB4302EE +:10E1A000C1F380131A4412F0FF0202D0521CD2B203 +:10E1B0000171C37802F03F0103F0C0031943C1703D +:10E1C000511C417070472DE9F0410546C078164654 +:10E1D00000F03F041019401C0F46FF2888BFFFDFE6 +:10E1E000281932463946001DF0F727F9A019401CBE +:10E1F0006870BDE8F081C178407801F03F01401AB5 +:10E20000401E80B2704710B590F803C00B460CF06A +:10E210003F0144780CF03F0CA4EB0C0CACF1010C6A +:10E220001FFA8CF4944288BF14462BB10844011D98 +:10E2300022461846F0F701F9204610BD4078704795 +:10E2400000B5027801F0030322F003021A430270C2 +:10E25000012914BF0229002104D0032916BFFFDFC2 +:10E26000012100BD417000BD00B5027801F003033B +:10E2700022F003021A430270012914BF022900216F +:10E2800004D0032916BFFFDF012100BD417000BD8E +:10E29000007800F003007047417841B1C078192838 +:10E2A00003D2BC4A105C884201D101207047002093 +:10E2B000704730B501240546C17019293CBFB548E7 +:10E2C000445C02D3FF2918BFFFDF6C7030BD70B50E +:10E2D00015460E4604461B2A88BFFFDF65702A4696 +:10E2E0003146E01CBDE87040F0F7A7B8B0F8070071 +:10E2F0007047B0F809007047C172090A017370478E +:10E30000B0F80B00704730B4B0F80720B0F809C07F +:10E31000B0F805300179941F40F67A45AC4298BFB9 +:10E32000BCF5FA7F0ED269B1082998BF914209D293 +:10E3300093429FBFB0F80B00B0F5486F012030BC8E +:10E3400098BF7047002030BC7047001D07F023BE07 +:10E35000021D0846114607F01EBEB0F809007047BE +:10E36000007970470A684260496881607047426876 +:10E370000A60806848607047098881817047808999 +:10E38000088070470A68C0F80E204968C0F812106B +:10E390007047D0F80E200A60D0F81200486070472D +:10E3A0000968C0F816107047D0F81600086070476A +:10E3B0000A68426049688160704742680A60806804 +:10E3C000486070470968C1607047C068086070475E +:10E3D000007970470A684260496881607047426806 +:10E3E0000A608068486070470171090A417170478E +:10E3F0008171090AC17170470172090A417270473F +:10E400008172090AC172704780887047C08870475E +:10E41000008970474089704701891B2924BF4189C1 +:10E42000B1F5A47F07D381881B2921BFC088B0F52F +:10E43000A47F01207047002070470A684260496845 +:10E440008160704742680A6080684860704701795F +:10E4500011F0070F1BBF407910F0070F00200120BB +:10E460007047017911F0070F1BBF407910F0070FBB +:10E470000020012070470171704700797047417199 +:10E480007047407970478171090AC1717047C0882F +:10E4900070470179407901F007023F498A5C012AFF +:10E4A00006D800F00700085C01289CBF01207047D7 +:10E4B00000207047017170470079704741717047C3 +:10E4C0004079704730B50C460546FB2988BFFFDF11 +:10E4D0006C7030BDC378024613F03F0008BF704730 +:10E4E0000520127903F03F0312F0010F37D0002905 +:10E4F00014BF0B20704700BF12F0020F32D0012969 +:10E5000014BF801D704700BF12F0040F2DD00229E8 +:10E5100014BF401C704700BF12F0080F28D0032919 +:10E5200014BF801C704700BF12F0100F23D00429C5 +:10E5300014BFC01C704700BF12F0200F1ED0052969 +:10E540001ABF1230C0B2704712F0400F19D006291E +:10E550001ABF401CC0B27047072918D114E0002927 +:10E56000CAD114E00129CFD111E00229D4D10EE0A3 +:10E570000329D9D10BE00429DED108E00529E3D134 +:10E5800005E00629E8D102E0834288BF70470020F9 +:10E5900070470000246302001C63020030B490F84E +:10E5A00064508C88B1F808C015F00C0F1BD000BF68 +:10E5B000B4F5296F98BF4FF4296490F8655015F0B1 +:10E5C0000C0F17D0BCF5296F98BF4FF4296C4A88FF +:10E5D000C988A0F84420A0F84810A0F84640A0F848 +:10E5E0004AC030BC7047002B1CBF157815F00C0FCB +:10E5F000DED1E2E7002B1CBF527812F00C0FE1D104 +:10E60000E5E7DDF800C08181C2810382A0F812C075 +:10E6100070471B2202838282C281828142800281F2 +:10E62000028042848284828359B14FF429614183FC +:10E63000C18241820182C18041818180C184018582 +:10E6400070474FF4A4714183C18241820182C1802D +:10E6500041818180C18401857047F0B4B0F84820C1 +:10E66000818F468EC58E8A4228BF0A4690F8651073 +:10E670004FF0000311F00C0F18BF4FF4296106D1C1 +:10E68000B0F84AC0B0F840108C4538BF61464286A9 +:10E69000C186048FB0F83AC0944238BF14468C4506 +:10E6A00038BF8C460487A0F83AC0B2420ABFA942DC +:10E6B0004FF0010C4FF0000C058EB0F84410C28FE3 +:10E6C000848E914228BF114690F8642012F00C0FFE +:10E6D00018BF4FF4296206D1B0F84660B0F8422066 +:10E6E000964238BF324690F85A60022E0AD0018610 +:10E6F0008286A9420ABFA2420120002040EA0C0003 +:10E70000F0BC70478D4238BF2946944238BF22463C +:10E7100080F85A30EBE7508088899080C889D08093 +:10E72000088A1081488A508101201070704730B4E7 +:10E7300002884A80B0F830C0A1F804C0838ECB8034 +:10E74000428E0A81C48E4C81B0F85650A54204BF57 +:10E75000B0F85240944208D1B0F858409C4202BFF1 +:10E76000B0F854306345002301D04FF001030B7320 +:10E7700000F13003A0F852201A464B89D3848B88CD +:10E780009384CA88A0F858204FF00100087030BC6C +:10E79000704730B404460A46088E91F864104FF46E +:10E7A000747311F00C0F1CBF03EB801080B21ED0ED +:10E7B000918E814238BF0846118F92F865C01CF0D7 +:10E7C0000C0F1CBF03EB811189B218D0538F8B4201 +:10E7D00038BF194692F866301CF00C0F08BF0023B2 +:10E7E000002C0CBF0122002230BCF2F798BC022999 +:10E7F00007BF80003C30C000703080B2D8E7BCF169 +:10E80000020F07BF89003C31C900703189B2DDE7D2 +:10E810002DE9F041044606F099FCC8B9FE4F78682E +:10E8200090F8221001260025012914D00178012931 +:10E830001BD090F8281001291CBF0020BDE8F081F2 +:10E84000657018212170D0F82A10616080F8285076 +:10E850000120BDE8F081657007212170416A616087 +:10E8600080F822500120BDE8F081657014212170EC +:10E87000811C2022201DEFF7E0FD257279680D70C4 +:10E8800081F82850E54882888284C26B527B80F8E8 +:10E89000262080F82260C86B0088F5F738FCF5F771 +:10E8A000E0F8D5E7DC4840680178002914BF80888B +:10E8B0004FF6FF70704730B5D74C83B00D462078C7 +:10E8C0007F2808BFFFDF94F900307F202070D4F844 +:10E8D00004C09CF85000062808BF002205D09CF810 +:10E8E000500008280CBF022201229CF85400CDE9F8 +:10E8F000000302929CF873309CF880200CF13201E6 +:10E90000284606F08FFC03B0BDE8304006F01FBE7D +:10E910002DE9F04106F05FFC002818BF06F0E4FB8B +:10E92000BD4C606800F1840290F87610895C80F834 +:10E930008010002003F07EF828B3FAF753F86068DF +:10E94000B74990F855000D5C2846F9F7A3FD6068BB +:10E950004FF0000680F8735090F8801011F00C0F03 +:10E960000CBF25200F20F9F76CFC606890F8801030 +:10E970000120F9F711FE606890F84010032918BFD4 +:10E9800002290FD103E0BDE8F04101F02FB990F862 +:10E9900076108430085C012804D101221146002041 +:10E9A000FAF707F9FAF7D5F8606890F88050012D6A +:10E9B00007BF0127032100270521A068FFF799F869 +:10E9C000616881F8520040B1002F18BF402521D066 +:10E9D000F9F787F92846FAF79DF86068806DFAF72D +:10E9E0000DF8606890F85410FF291CBF6D30FEF7D9 +:10E9F000B4FFFF21606880F8531080F8541080F84D +:10EA0000626080F8616080F87D60062180F85010B7 +:10EA1000BDE8F08115F00C0F14BF55255025D7E740 +:10EA200070B57D4C0646606800F150052046806850 +:10EA300041B1D0F80510C5F81D10B0F80900A5F8CF +:10EA4000210003E005F11D01FFF7B9F9A068FFF708 +:10EA5000D4F985F82400A0680021032E018002D09B +:10EA6000052E04D03DE00321FFF77CF939E00521B4 +:10EA7000FFF778F96068C06B00F10E01A068FFF73E +:10EA800000FA6068C06B00F11201A068FFF7FDF9A1 +:10EA9000D4E90110CA6B527D8275CA6BD28AC275E5 +:10EAA000120A0276CA6B52884276120A8276CA6BC2 +:10EAB0009288C276120A0277CA6BD2884277120A0B +:10EAC0008277C96B0831FFF7FEF96068C06B017E81 +:10EAD000A068FFF7E0F9606890F88610A068FFF77B +:10EAE000E4F905F11D01A068FFF770F995F824100D +:10EAF000A068FFF786F9606800F1320590F8316090 +:10EB000090F8511091B190F84010032906D190F877 +:10EB10003910002918BF90F8560001D190F8530021 +:10EB2000FFF736F800281CBF012605462946A068D5 +:10EB3000FFF73EF93146A068BDE87040FFF754B9D1 +:10EB40003549496881F84B00704770B5324D002453 +:10EB50000126A8606968A1F8814081F8834081F8A6 +:10EB6000506091F85020022A1FBF91F850100129DF +:10EB7000FFDF70BD06F0CDFA6868047080F82240AF +:10EB800080F8284090F8520030B1F9F7CDFFF9F73E +:10EB9000BCF8686880F852406868072180F84A40ED +:10EBA00080F8396080F8404080F8554080F84B404C +:10EBB00080F87D4080F8381070BD2DE9F041164C8A +:10EBC000054686B0606890F85000012818BF0228FA +:10EBD00005D003281EBF0C2006B0BDE8F081687A7E +:10EBE000022839D0F9F76FFB0220F9F701FF0D4930 +:10EBF00001F10C0090E80D108DE80D10D1E907012E +:10EC0000CDE904016846F9F7E1FE606890F94B0030 +:10EC1000F9F732FCA06807E07401002044110020DD +:10EC20004363020040630200F9F7E5FEFC48F9F790 +:10EC3000B9FEFC48F9F726FC606890F831103230D4 +:10EC4000F9F7A5FB0F210720F9F7BFFB606890F8E3 +:10EC50003900E0B1FEF70FFF6168287A01F1840204 +:10EC600081F87600287A805C81F880006868886581 +:10EC70002A68CA65687A68B1012824D00525022867 +:10EC800008BF81F850506FD0032878D080E0FEF79D +:10EC9000A8FEE1E7E44B91F83850002291F85500C6 +:10ECA000401CA3FB006C4FEA5C0CACEB8C0C60448A +:10ECB00081F8550025FA00F010F0010F03D1501C27 +:10ECC000C2B2032AEAD3002681F87D6091F8490098 +:10ECD000002804BF91F85100002841D0F7F744FA0A +:10ECE000074660683946406CF7F736FFDFF83C832B +:10ECF000054690FBF8F008FB105041423846F6F705 +:10ED00001AFF6168486495FBF8F08A6F10448867C1 +:10ED1000FEF7EEFD01466068826F914220D847649D +:10ED2000866790F8510000281CBF0120FEF7FDFE09 +:10ED30000121606890F84A20002A1CBF90F8492001 +:10ED4000002A0DD090F8313000F13202012B04D1AD +:10ED5000527902F0C002402A08D03230FAF78CFC17 +:10ED60006168042081F8500012E008E00125FEF7F8 +:10ED70000DFF61682A463231FAF746FCF0E7002AB7 +:10ED800018BFFFDF012000F089FF606880F8505055 +:10ED900006B00020BDE8F08170B5A54D686890F818 +:10EDA000501004292ED005291CBF0C2070BD90F8EE +:10EDB0007D100026002990F883104FEA511124D0CD +:10EDC000002908BF012407D0012908BF022403D06D +:10EDD000022914BF00240824C06D00281CBF002095 +:10EDE00000F05CFF6868806DF9F708FE686890F8CD +:10EDF0004010022943D0032904BF90F86C10012968 +:10EE000041D04DE0FFF784FD52E0002908BF012406 +:10EE100007D0012908BF022403D0022914BF00240F +:10EE20000824C06D00281CBF002000F037FF686870 +:10EE3000806DF9F7E3FD686890F84010022906D06C +:10EE4000032904BF90F86C10012904D010E090F859 +:10EE50006C1002290CD1224614F00C0F04D090F84B +:10EE60004C00012808BF042201210020F9F7A1FE6F +:10EE70006868072180F8804080F8616016E090F8AB +:10EE80006C1002290CD1224614F00C0F04D090F81B +:10EE90004C00012808BF042201210020F9F789FE57 +:10EEA0006868082180F8804080F8616080F8501020 +:10EEB000002070BD5E49002210F0010F496802D0A9 +:10EEC000012281F8842010F0080F03D0114408209B +:10EED00081F88400002070475549496881F848004E +:10EEE000704710B5524C636893F83030022B14BF52 +:10EEF000032B00280BD100291ABF02290120002072 +:10EF00001146FEF7F8FC08281CBF012010BD606800 +:10EF100090F83000002816BF022800200120BDE82C +:10EF20001040FAF731BB4248406890F830000028A2 +:10EF300016BF022800200120FAF726BB3C49496889 +:10EF400081F8300070473A49496881F84A007047B3 +:10EF500070B5374C616891F83000002816BF022860 +:10EF60000020012081F8310001F13201FAF7F6FAB0 +:10EF7000606890F83010022916BF03290121002192 +:10EF800080F8511090F8312000F132034FF0000565 +:10EF9000012A04BF5B7913F0C00F0AD000F13203DD +:10EFA000012A04D15A7902F0C002402A01D000227D +:10EFB00000E0012280F84920002A04BF002970BD2A +:10EFC0008567F7F7D1F86168486491F85100002827 +:10EFD0001CBF0020FEF7A9FD0026606890F84A10CB +:10EFE00000291ABF90F84910002970BD90F831200F +:10EFF00000F13201012A04D1497901F0C001402910 +:10F0000005D02946BDE870403230FAF735BBFEF72F +:10F01000BDFD61683246BDE870403231FAF7F4BA9E +:10F020004063020046630200ABAAAAAA40420F0056 +:10F030007401002070B5FF4D0C4600280CBF012361 +:10F040000023696881F8393081F842004FF00800E8 +:10F0500081F856000CD1002C1ABF022C0120002090 +:10F060001146FEF748FC6968082881F8560001D06F +:10F07000002070BD022C14BF032C1220F8D170BDEB +:10F08000002818BF112070470328EA4A526808BFB9 +:10F09000D16382F840000020704710B5E54C6068ED +:10F0A00090F8401003291CBF002180F8601001D0A7 +:10F0B000002010BD0123C16B1A460020F2F738F87A +:10F0C0006168CA6B526A904294BF0120002081F8A7 +:10F0D0006000EDE7D748416891F84000032804D06C +:10F0E000012818BF022807D004E091F84200012847 +:10F0F00008BF70470020704791F84100012814BFF5 +:10F1000003280120F6D1704770B5F9F7F7FCF9F73D +:10F11000D6FCF9F79FFBF9F74BFCC64C002560685D +:10F1200090F8520030B1F9F7FFFCF8F7EEFD606897 +:10F1300080F8525060680121A0F8815080F8835017 +:10F1400080F8501080F82850002070BDB94810B5E4 +:10F150004068643006F0B1FB002010BDB5480121C5 +:10F16000406890F84020032A03BF80F82A10C26B41 +:10F170001288002218BF80F82A20828580F8281083 +:10F180007047AC49496881F88600704701780023D0 +:10F1900011F0010FA749496809D04278032A08BF36 +:10F1A000CB6381F84020012281F884201346027845 +:10F1B00012F0040F0CD082784FF0000C032A08BF25 +:10F1C000C1F83CC081F840200B44082283F8842019 +:10F1D000C27881F830200279002A16BF022A012362 +:10F1E000002381F8393081F84120427981F83820B4 +:10F1F000807981F848004FF0000070478D484068E2 +:10F200008030704770B58B4C06460D46606890F8AC +:10F210005000032818BFFFDF022E1EBF032EFFDFA2 +:10F2200070BD002D18BF06F0A1F900216068A0F89C +:10F23000811080F88310012180F8501070BD00F01B +:10F24000D5BC2DE9F0477B4C0646894660684FF0F7 +:10F250000108072E90F8397038BF032540D3082ED7 +:10F2600084BF0020BDE8F08790F85010062908BF41 +:10F27000002105D090F8501008290CBF022101216F +:10F2800090F8800005F0AEFF002873D1A068C17827 +:10F2900011F03F0F12D0027912F0010F0ED0616809 +:10F2A0004FF0050591F85220002A18BFB9F1000F60 +:10F2B00016D091F88010012909D011E011F03F0F0C +:10F2C0001ABF007910F0100F002F53D14CE04FF00F +:10F2D00001024FF00501FEF74CFB616881F8520016 +:10F2E000A16808782944C0F3801030B1487900F053 +:10F2F000C000402808BF012000D00020616891F8BC +:10F300005210002918BF002807D0FEF74DFB014618 +:10F31000606880F8531080F86180606890F853103E +:10F32000FF292AD080F854100846FEF74AFB40EA2D +:10F330000705606890F85320FF2A18BF002D10D0F1 +:10F34000072E0ED3A068C17811F03F0F09D00179C4 +:10F3500011F0020F05D00B21FEF7BDFB606880F8AD +:10F3600062802846BDE8F087FEF75FF9002808BFF5 +:10F37000BDE8F0870120BDE8F087A36890F8392048 +:10F3800059191B78C3F3801C00F153036046FEF744 +:10F3900096F90546CDE72DE9F043264C87B0A068E5 +:10F3A000FEF7E0FE7F264FF00108002558B1022746 +:10F3B00001287DD0022800F0EF80F9F74BFA07B062 +:10F3C0000620BDE8F083F9F745FA616891F840003E +:10F3D000032800F01581A068C27812F03F0F05D015 +:10F3E000037913F0100F18BF012700D10027002F59 +:10F3F00014BF0823012312F03F0F00F001810079B0 +:10F4000033EA000240F0FC8010F0020F08D091F8BF +:10F410008000002105F064FE002808BF012000D014 +:10F4200000208DF80C508DF810508DF814504FF0CE +:10F43000FF0801E074010020D0B105AA03A904A8C7 +:10F4400000F07AFC606890F831809DF80C0000288C +:10F4500018BF48F002080BD1A068FEF7DBFC81461C +:10F460000121A068FEF732FD4946F8F79AFF28B35C +:10F47000FFB1012000F0DDFB002852D020787F286A +:10F4800008BFFFDF94F900102670606890F85420E0 +:10F49000CDE90021029590F8733090F8802000F1BA +:10F4A0003201404605F0BEFE606880F86C50A3E073 +:10F4B00038E041460020FFF7FEF9A1E0606890F8CF +:10F4C0004100032818BF02282BD19DF81000002806 +:10F4D00027D09DF80C00002823D1F7B1012000F0BF +:10F4E000A8FB00281DD020787F2808BFFFDF94F9F3 +:10F4F00000102670606890F85420CDE90021029534 +:10F5000090F8733090F8802000F13201FE2005F071 +:10F5100089FE606880F86C506EE0FE210020FFF7E5 +:10F52000CAF96DE0F9F796F9A0681821C27812F0CF +:10F530003F0F65D00279914362D10421FEF7C6FCEA +:10F54000616891F84020032A01BF8078B7EB501F13 +:10F5500091F86000002853D04FF0010000F069FBE3 +:10F56000E8B320787F2808BFFFDF94F900102670E9 +:10F57000606890F85420CDE90021029590F873302E +:10F5800090F8802000F13201FF2005F04BFE60680A +:10F5900080F86C8030E000BFF9F75CF9606890F8A3 +:10F5A000400003282CD0A0681821C27812F03F0F29 +:10F5B00026D0007931EA000022D1012000F039FB89 +:10F5C00068B120787F2808BFFFDF94F9001026700B +:10F5D000606890F85420CDE90021029500E00FE02A +:10F5E00090F8733090F8802000F13201FF2005F090 +:10F5F00019FE606880F86C7007B00320BDE8F083E6 +:10F6000007B00620BDE8F083F0B5FE4C074683B096 +:10F6100060686D460078002818BFFFDF002661682B +:10F620008E70C86B02888A8042884A8382888A8367 +:10F63000C088C88381F8206047B10121A068FEF727 +:10F6400045FC0546A0680078C10907E06946A06846 +:10F65000FEF7B5FBA0680078C0F380116068012751 +:10F6600090F85120002A18BF002904D06A7902F0CE +:10F67000C002402A26D090F84A20002A18BF00294C +:10F6800003D0697911F0C00F1CD000F10E00E3F730 +:10F69000B3FC616891F85400FF2819D001F1080209 +:10F6A000C91DFEF743F9002808BFFFDF6068C17974 +:10F6B00041F00201C171D0F86D104161B0F87110D4 +:10F6C00001830FE02968C0F80E10A9884182E0E7A5 +:10F6D000C86B427ECA71D0F81A208A60C08B8881BC +:10F6E0004E610E8360680770C26B90F84B1082F811 +:10F6F0006710C06B0088F4F70AFDF4F7A3F903B0B4 +:10F70000F0BD2DE9F041BF4C0546002760684FF081 +:10F7100001083E4690F84000012818BF022802D098 +:10F72000032818BFFFDF5DB1A068FEF727FC18B9FA +:10F73000A068FEF77AFC18B100F08FFB074645E0A1 +:10F74000606890F850007F25801F06283ED2DFE8D1 +:10F7500000F003191924352FAA48F9F709FA0028EF +:10F7600008BF2570F9F7EBF9606890F8520030B1E6 +:10F77000F9F7DAF9F8F7C9FA606880F85260F9F732 +:10F7800069F830E09F48F9F7F3F9002808BF2570C1 +:10F79000F9F7D5F905F0EAFEC3E09A48F9F7E8F978 +:10F7A000002808BF2570F9F7CAF9F9F753F81AE0ED +:10F7B0009448F9F7DDF930B9257004E09148F9F77C +:10F7C000D7F90028F8D0F9F7BAF9AAE0102F80F09D +:10F7D0003881DFE807F01E9DA6AAF1F108B3F2F127 +:10F7E000F1F10C832051BDE8F041FFF791B80320FF +:10F7F00002F020F9002870D000210320FFF710F953 +:10F80000012211461046F9F7D4F961680C2081F8FD +:10F810005000BDE8F081606800F15005042002F05E +:10F8200009F900287DD00E202870012002F0FDFC8F +:10F83000A06861680078C0F3401081F8750000216D +:10F840000520FFF7EDF87048A1684FF0200CC26B5F +:10F850000B78527B23F020030CEA42121A430A7001 +:10F86000C16B95F825304A7B1A404A73C06B28213A +:10F8700080F86610BDE8F081062002F0DBF8002871 +:10F880004FD0614D0F2085F85000022002F0CDFCD2 +:10F890006068012190F880200846F9F78AF9A0688D +:10F8A00061680078C0F3401081F8750001210520DF +:10F8B000FFF7B6F8E86B80F80D80A068017821F0BA +:10F8C00020010170F9F75DFD002818BFFFDF282037 +:10F8D000E96B81F86600BDE8F08122E0052002F0C6 +:10F8E000A9F8F0B101210320FFF79AF8F9F749FDD3 +:10F8F000002818BFFFDF6068012190F880200846CB +:10F90000F9F757F961680D2081F85000BDE8F081E2 +:10F910006068A0F8816080F8836080F85080BDE85E +:10F92000F081BDE8F04100F061B96168032081F821 +:10F930005000BDE8F041082002F077BC606890F804 +:10F940008310490908BF012507D0012908BF0225F6 +:10F9500003D0022914BF00250825C06D00281CBF54 +:10F96000002000F09BF96068806DF9F747F8606847 +:10F9700090F84010022906D0032904BF90F86C10BB +:10F98000012904D010E090F86C1002290CD12A460D +:10F9900015F00C0F04D090F84C00012808BF042289 +:10F9A00001210020F9F705F96068072180F88050EF +:10F9B00080F8616041E000E043E0606890F8831007 +:10F9C000490908BF012507D0012908BF022503D036 +:10F9D000022914BF00250825C06D00281CBF002087 +:10F9E00000F05CF96068806DF9F708F8606890F8DD +:10F9F000401002290AD0032904BF90F86C10012995 +:10FA000008D014E0740100204411002090F86C101C +:10FA100002290CD12A4615F00C0F04D090F84C00A6 +:10FA2000012808BF042201210020F9F7C2F860680C +:10FA3000082180F8805080F8616080F85010BDE89F +:10FA4000F081FFDFBDE8F08170B5FE4C606890F892 +:10FA5000503000210C2B38D001220D2B40D00E2B22 +:10FA600055D00F2B1CBFFFDF70BD042002F0DDFB63 +:10FA7000606890F880100E20F8F7E3FB606890F85B +:10FA8000800010F00C0F14BF282100219620F8F7F9 +:10FA9000D3FFF9F75EF86068052190F88050A06800 +:10FAA000FEF727F8616881F8520048B115F00C0F95 +:10FAB0000CBF50255525F8F714F92846F9F72AF810 +:10FAC00061680B2081F8500070BDF9F742F8002101 +:10FAD0009620F8F7B1FF6168092081F8500070BDE9 +:10FAE00090F88010FF20F8F7ACFB606890F8800079 +:10FAF00010F00C0F14BF282100219620F8F79CFF6E +:10FB0000F9F727F861680A2081F8500070BDA0F865 +:10FB1000811080F8831080F850200020FFF774FDDA +:10FB2000BDE87040032002F080BB70B5C54C606832 +:10FB300090F850007F25801F062828BF70BDDFE8A1 +:10FB400000F0171F1D032A11BE48F9F711F800280D +:10FB500008BF2570F8F7F3FFF8F77CFEBDE87040AA +:10FB6000FEF7D6BEB748F9F703F8C8B9257017E015 +:10FB7000B448F8F7FDFF40B9257006E005F0F6FC43 +:10FB8000B048F8F7F5FF0028F6D0F8F7D8FFBDE841 +:10FB9000704000F02BB8AB48F8F7EAFF0028E5D03A +:10FBA000F8F7CDFF60680021643005F037FEBDE84E +:10FBB000704000F01BB870B5A24C06460D460129F6 +:10FBC00008D0606890F880203046BDE87040134649 +:10FBD00002F077BBF8F75CFA61680346304691F8AB +:10FBE00080202946BDE8704002F06BBB70B5F8F785 +:10FBF00085FFF8F764FFF8F72DFEF8F7D9FE914C72 +:10FC00000025606890F8520030B1F8F78DFFF8F7E2 +:10FC10007CF8606880F852506068022180F85010CB +:10FC2000A0F8815080F88350BDE87040002002F0B9 +:10FC3000FCBA70B5834D06460421A868FEF746F964 +:10FC4000044605F0C8FA002808BF70BD207800F00F +:10FC50003F00252814D2F8F761FA217811F0800FBF +:10FC60000CBF1E214FF49671B4F80120C2F30C02B0 +:10FC700012FB01F10A1AB2F5877F28BF814201D237 +:10FC8000002070BD68682188A0F88110A17880F8F4 +:10FC900083103046BDE8704001F0CCBE2DE9F04144 +:10FCA000684C0746606800F1810690F883004009BF +:10FCB00008BF012507D0012808BF022503D002286C +:10FCC00014BF00250825F8F78DFE307800F03F06B8 +:10FCD0003046F8F7DFFB606880F8736090F86C00DE +:10FCE00002280CBF4020FF202946F8F7AAFA27B1C6 +:10FCF00029460120F8F795FC05E060682A46C16DA9 +:10FD00000120F8F7E2FCF8F724FF0521A068FDF7D1 +:10FD1000F0FE6168002881F8520008BFBDE8F0815C +:10FD200015F00C0F0CBF50245524F7F7DAFF2046CE +:10FD3000BDE8F041F8F7EEBE2DE9F74F414C002544 +:10FD4000914660688A4690F8510000280CBF4FF039 +:10FD500001084FF00008A0680178CE090121FEF7E4 +:10FD6000B5F836B1407900F0C000402808BF012640 +:10FD700000D00026606890F85210002961D090F8F9 +:10FD800040104FF0000B032906D190F839100029DC +:10FD900018BF90F856700ED1A068C17811F03F0FCF +:10FDA0001CBF007910F0010F02D105F061F940B3DA +:10FDB000606890F85370FF2F18BF082F21D0384685 +:10FDC000FDF7D9FB002818BF4FF00108002E38D0EE +:10FDD000606890F8620030B1FDF7F1FD054660689B +:10FDE00080F862B02DE03846FDF791FD054601210F +:10FDF000A068FEF76BF801462846F9F7D3FB0546E5 +:10FE00001FE0F6B1606890F86100D0B9A068C178D1 +:10FE100011F03F0F05D0017911F0010F18BF0B2130 +:10FE200000D105210022FDF7A4FD616881F8520090 +:10FE300038B1FDF7B9FDFF2803D06168012581F8CD +:10FE4000530001E0740100208AF800500098067009 +:10FE500089F8008003B0BDE8F08F2DE9F04FFF4C2A +:10FE600087B00025606890F850002E46801F4FF044 +:10FE70007F08062880F0D581DFE800F00308088BB2 +:10FE8000FDDB00F0F8FB054600F0CCB9F348F8F7CD +:10FE90006FFE002808BF84F80080F8F750FEA068C5 +:10FEA000FDF782FF0546072861D1A068FEF75AF9E1 +:10FEB0000146606890F86C208A4258D190F8501042 +:10FEC000062908BF002005D090F8500008280CBF74 +:10FED0000220012005F08AF970B90321A068FDF71E +:10FEE000F5FF002843D001884078C1F30B010009D9 +:10FEF00005F07BFC00283AD000212846FFF7A1F945 +:10FF0000A0B38DF80C608DF808608DF8046062680D +:10FF1000FF2592F8500008280CBF02210121A0689B +:10FF2000C37813F03F0F1CBF007910F0020F12D0FE +:10FF300092F8800005F0D4F868B901AA03A902A8D4 +:10FF4000FFF7FAFE606890F831509DF80C00002829 +:10FF500018BF45F002052B469DF804209DF80810B7 +:10FF60009DF80C0000F0D5F9054603E0FFE705F029 +:10FF7000FDFA0225606890F85200002800F05281D6 +:10FF8000F8F7D2FDF7F7C1FE606880F8526000F024 +:10FF900049B9A068FDF708FF0646A1686068CA78FD +:10FFA00090F86D309A4221D10A7990F86E309A42D9 +:10FFB0001CD14A7990F86F309A4217D18A7990F81B +:10FFC00070309A4212D1CA7990F871309A420DD1AC +:10FFD0000A7A90F872309A4208D1097890F8740041 +:10FFE000C1F38011814208BF012500D00025F8F738 +:10FFF00031FC9A48F8F7BCFD002808BF84F800805F +:020000040002F8 +:10000000F8F79DFD042E11D185B120787F2808BF17 +:10001000FFDF94F9003084F80080606890F8732066 +:1000200090F87D1090F8540005F06EFB062500F066 +:10003000F9B802278948F8F79BFD002808BF84F823 +:100040000080F8F77CFDA068FDF7AEFE0546A068CD +:10005000FEF788F8082D08BF00287CD1A0684FF073 +:100060000301C27812F03F0F75D0007931EA000029 +:1000700071D1606800E095E000F1500890F8390017 +:10008000002814BF98F8066098F803604FF0000944 +:1000900098F8020078B1FDF787FC0546FF280AD0E2 +:1000A0000146A068401DFDF758FCB5420CBF4FF05B +:1000B00001094FF000090021A068FDF707FF0622A3 +:1000C00008F11D01EEF78CF940B9A068FDF795FE27 +:1000D00098F82410884208BF012000D0002059EA77 +:1000E00000095DD0606800F1320590F831A098F801 +:1000F000010038B13046FDF74BFD00281CBF054616 +:100100004FF0010A4FF00008A06801784FEAD11BB8 +:100110000121FDF7DBFEBBF1000F07D0407900F0B5 +:10012000C000402808BF4FF0010B01D04FF0000B7A +:100130000121A068FDF7CAFE06222946EEF750F914 +:1001400030B9A068FDF766FE504508BF012501D013 +:100150004FF0000500E023E03BEA050018BFFF2E4A +:100160000DD03046FDF7D3FB060008D00121A06872 +:10017000FDF7ACFE01463046F9F714FA804645EA31 +:10018000080019EA000F0BD060680121643005F007 +:1001900045FB01273846FFF737FA052002F045F8FE +:1001A0003D463FE002252D48F8F7E2FC002808BF55 +:1001B00084F80080F8F7C3FCA068FDF7F5FD06465B +:1001C000A068FDF7CFFF072E08BF00282AD1A0683E +:1001D0004FF00101C27812F03F0F23D00279914312 +:1001E00020D1616801F150060021FDF76FFE062263 +:1001F00006F11D01EEF7F4F8A0B9A068FDF7FDFDCA +:1002000096F8241088420DD160680121643005F011 +:1002100005FBFF21022000F009F8002818BF032584 +:1002200000E0FFDF07B02846BDE8F08F2DE9F0437E +:100230000A4C0F4601466068002683B090F87D2086 +:10024000002A35D090F8500008280CBF022501255F +:10025000A168C87810F03F0F02E000007401002090 +:10026000FD484FF000084FF07F0990F900001CBFD7 +:10027000097911F0100F22D07F2808BFFFDF94F911 +:10028000001084F80090606890F85420CDE90021B7 +:10029000029590F8733090F8802000F132013846D2 +:1002A00004F0C0FF05F0AAFA10B305F050F92CE0F5 +:1002B000002914BF0221012180F87D10C2E77F28A8 +:1002C00008BFFFDF94F9001084F80090606890F890 +:1002D0005420CDE90021029590F8733090F88020E9 +:1002E00000F13201384604F09DFF05F030F90CE0D2 +:1002F0000220FFF79EFC30B16068012680F86C8018 +:10030000F8F7A8FA01E005F031F903B03046BDE88E +:10031000F0832DE9F047D04C054684B09A46174645 +:100320000E46A068FDF71EFF4FF00109002800F0FF +:10033000CF804FF00208012808D0022800F00E817B +:1003400005F014F904B04046BDE8F087A068092123 +:10035000C27812F03F0F00F059810279914340F0CA +:100360005581616891F84010032906D012F0020F00 +:1003700008BFFF2118D05DB115E00021FDF7A6FDF3 +:1003800061680622C96B1A31EEF72AF848BB1EE0F5 +:10039000FDF740FD05460121A068FDF797FD2946C0 +:1003A000F7F7FFFF18B15146012000F051B960681E +:1003B00090F84100032818BF022840F02781002E42 +:1003C0001CBFFE21012040F0438100F01FB9A0684E +:1003D000FDF713FD6168C96B497E884208BF01269D +:1003E00000D00026A068C17811F03F0F05D0017938 +:1003F00011F0020F01D06DB338E0616891F842202E +:10040000012A01D096B11BE0D6B90021FDF75EFDAF +:1004100061680268C96BC1F81A208088C883A06827 +:10042000FDF7EBFC6168C96B487609E091F8530071 +:1004300091F85610884203D004B04046BDE8F087DA +:100440006068643005F02EFA002840D004B00F2018 +:10045000BDE8F08767B1FDF7DDFC05460121A06826 +:10046000FDF734FD2946F7F79CFF08B1012200E0B3 +:100470000022616891F84200012807D040B92EB9E6 +:1004800091F8533091F856108B4201D1012100E0D0 +:1004900000210A421BD0012808BF002E11D14FF0C5 +:1004A0000001A068FDF712FD61680268C96BC1F820 +:1004B0001A208088C883A068FDF79FFC6168C96B1B +:1004C00048766068643005F0EDF90028BED19DE003 +:1004D00060682F46554690F840104FF002080329F7 +:1004E000AAD0A168CA7812F03F0F1BBF097911F09A +:1004F000020F002201224FF0FF0A90F85010082945 +:100500000CBF0221012192B190F8800004F0E8FDB7 +:1005100068B95FB9A068FDF77DFC07460121A068B6 +:10052000FDF7D4FC3946F7F73CFF48B1AA465146DF +:100530000020FFF77BFE002818BF4FF003087BE781 +:10054000606890F84100032818BF02287FF474AF58 +:10055000002E18BF4FF0FE0AE9D16DE7616891F8EF +:100560004030032B52D0A0684FF0090CC27812F033 +:100570003F0F4BD002793CEA020C47D1022B06D048 +:1005800012F0020F08BFFF2161D0E5B35EE012F068 +:10059000020F4FF07F0801D04DB114E001F164006B +:1005A00005F080F980B320787F2842D013E067B34C +:1005B000FDF730FC05460121A068FDF787FC2946C0 +:1005C000F7F7EFFE08B36068643005F06BF9D8B157 +:1005D00020787F282DD094F9001084F8008060687E +:1005E00090F85420CDE90021CDF8089090F87330B0 +:1005F00090F8802000F13201504604F013FE0D20E7 +:1006000004B0BDE8F08716E000E001E00220F7E763 +:10061000606890F84100032818BF0228F6D1002E28 +:10062000F4D04FF0FE014FF00200FEF744F9022033 +:10063000E6E7FFDFCFE7FDF7EDFB05460121A06808 +:10064000FDF744FC2946F7F7ACFE38B151460220CD +:10065000FEF731F9DAE7000074010020606890F8D5 +:100660004100032818BF0228D0D1002E1CBFFE2154 +:100670000220EDD1CAE72DE9F84F4FF00008F74806 +:10068000F8F776FA7F27F54C002808BF2770F8F7AF +:1006900056FAA068FDF788FB81460121FEF7D1FDDF +:1006A000616891F88020012A14D0042A1CBF082A0E +:1006B000FFDF00F0D781606890F8520038B1F8F79A +:1006C00033FAF7F722FB6168002081F852004046B8 +:1006D000BDE8F88F0125E24EB9F1080F3AD2DFE804 +:1006E00009F03EC00439393914FC0546F8F7B2F870 +:1006F000002D72D0606890F84000012818BF0228D1 +:100700006BD120787F2869D122E018B391F840009E +:10071000022802D0012818D01CE020787F2808BFCA +:10072000FFDF94F90000277000906068FF2190F8C7 +:10073000733090F85420323004F02FFF61680020AD +:100740004FF00C0881F87D00B5E720787F2860D154 +:10075000FFDF5EE0F8F77EF84FF00608ABE74FF0FA +:100760000008002800F0508191F84000022836D09F +:1007700001284BD003289ED1A068CA6BC37892F899 +:100780001AC0634521D1037992F81BC063451CD17F +:10079000437992F81CC0634517D1837992F81DC044 +:1007A000634512D1C37992F81EC063450DD1037A17 +:1007B00092F81FC0634508D1037892F819C0C3F3BB +:1007C0008013634508BF012300D0002391F8421035 +:1007D00001292CD0C3B300F013B93FE019E0207811 +:1007E0007F2808BFFFDF94F9000027700090606841 +:1007F000FF2190F8733090F85420323004F0CDFE91 +:1008000060684FF00C0880F87D5054E720787F280E +:100810009ED094F90000277000906068FF2190F846 +:10082000733090F85420323004F0B7FE16E0002BFD +:100830007ED102F11A01FDF7C2FAA068FDF7DDFAD8 +:100840006168C96B4876DBE0FFE796F85600082838 +:1008500070D096F8531081426AD0D5E04FF0060868 +:1008600029E7054691F8510000280CBF4FF0010B15 +:100870004FF0000B4FF00008A06810F8092BD209C8 +:1008800007D0407900F0C000402808BF4FF0010AAF +:1008900001D04FF0000A91F84000032806D191F8EA +:1008A0003900002818BF91F8569001D191F8539063 +:1008B0004846FDF72CF80090D8B34846FCF75BFE9D +:1008C000002818BF4FF0010BBAF1000F37D0A06815 +:1008D000A14600F10901009800E0B6E0F8F762FED9 +:1008E0005FEA0008D9F8040090F8319018BF49F089 +:1008F0000209606890F84010032924D0F7F7AAFF96 +:10090000002DABD0F7F75DFD002808BFB8F1000F50 +:100910007DD020787F2808BFFFDF94F90000277082 +:1009200000906068494690F8733090F8542002E0D7 +:1009300066E004E068E0323004F02FFE8EE7606885 +:1009400090F83190D5E7A168C06BCA78837E9A424F +:100950001BD10A79C37E9A4217D14A79037F9A4202 +:1009600013D18A79437F9A420FD1CA79837F9A4201 +:100970000BD10A7AC37F9A4207D10978407EC1F32E +:100980008011814208BF012700D0002796F853004C +:10099000082806D096F85610884208BF4FF0010983 +:1009A00001D04FF00009B8F1000F05D1BBF1000FE5 +:1009B00004D0F7F706FD08B1012000E000204DB19A +:1009C00096F84210012903D021B957EA090101D054 +:1009D000012100E00021084216D0606890F8421022 +:1009E000012908BF002F0BD1C06B00F11A01A068CC +:1009F000FDF7E5F9A068FDF700FA6168C96B487674 +:100A00004FF00E0857E602E0F7F724FF26E760688C +:100A100090F84100032818BF02287FF41FAFBAF1F5 +:100A2000000F3FF41BAF20787F2808BFFFDF94F949 +:100A30000000277000906068FE2190F8733090F8F5 +:100A40005420323004F0A9FD08E791F8481000293D +:100A500018BF00283FF47EAE0BE0000074010020B8 +:100A600044110020B9F1070F7FF474AE00283FF461 +:100A700071AEFEF790FC80461DE60000D0F8001134 +:100A800049B1D0E941231A448B691A448A61D0E9FB +:100A90003F12D16003E0FE4AD0F8FC101162D0E9A9 +:100AA0003F1009B1086170470028FCD00021816126 +:100AB00070472DE9FF4F06460C46488883B040F248 +:100AC000E24148430190E08A002500FB01FA94F8D6 +:100AD0007C0090460D2822D00C2820D024281ED03F +:100AE00094F87D0024281AD000208346069818B177 +:100AF0000121204603F0C0F894F8641094F86500D2 +:100B0000009094F8F0200F464FF47A794AB1012A08 +:100B100061D0022A44D0032A5DD0FFDFB5E0012076 +:100B2000E3E7B8F1000F00D1FFDFD94814F8641FE4 +:100B3000243090F83400F0F7C4FC01902078F8F7E6 +:100B4000CFFB4D4600F2E730B0FBF5F1DFF8409304 +:100B5000D9F80C0001EB00082078F8F7C1FB01463A +:100B600014F86409022816D0012816D040F6340083 +:100B700008444AF2EF010844B0FBF5F10198D9F8B6 +:100B80001C20411A514402EB08000D18012084F882 +:100B9000F0002D1D78E02846EAE74FF4C860E7E74B +:100BA000DFF8EC92A8F10100D9F80810014300D158 +:100BB000FFDFB848B8F1000F016801EB0A0506D065 +:100BC000D9F8080000F22630A84200D9FFDF032040 +:100BD00084F8F00058E094F87C20019D242A05D088 +:100BE00094F87D30242B01D0252A3AD1B4F8702016 +:100BF000B4F81031D21A521C12B2002A31DB94F828 +:100C0000122172B3174694F8132102B110460090D6 +:100C1000022916D0012916D040F6340049F60852B0 +:100C20008118022F12D0012F12D040F63400104448 +:100C3000814210D9081A00F5FA70B0FBF9F00544AA +:100C40000FE04846EAE74FF4C860E7E74846EEE7BA +:100C50004FF4C860EBE7401A00F5FA70B0FBF9F00A +:100C60002D1AB8F1000F0FD0DFF82482D8F8080051 +:100C700018B9B8F8020000B1FFDFD8F8080000F298 +:100C80002630A84200D9FFDF05B9FFDF2946D4F896 +:100C9000F400F4F750FFC4F8F400B06000203070A6 +:100CA0004FF0010886F80480204603F040F8ABF1CD +:100CB0000101084202D186F8058005E094F8F000B1 +:100CC000012844D003207071606A3946009A01F00F +:100CD00042FBF060069830EA0B0035D029463046DA +:100CE000F0F7BAF987B2204603F021F8B8420FD8DE +:100CF000074686F8058005FB07F1D4F8F400F4F701 +:100D00001AFFB06029463046F0F7A6F9384487B29A +:100D10003946204602F0B0FFB068C4F8F400A06E77 +:100D2000002811D0B4F87000B4F89420801A01B2F1 +:100D3000002909DD34F86C0F0144491E91FBF0F1E4 +:100D400089B201FB0020208507B0BDE8F08F0220AA +:100D5000B9E72DE9F04106460C46012001F0DBFA27 +:100D6000C5B20B2001F0D7FAC0B2854200D0FFDF38 +:100D70000025082C7ED2DFE804F00461696965C6AD +:100D80008293304601F0DDFA0621F3F78FF8040074 +:100D900000D1FFDF304601F0D4FA2188884200D02C +:100DA000FFDF94F8F00000B9FFDF204602F00FFEED +:100DB000374E21460020B5607580F561FDF7E9FCEE +:100DC00000F19807606AB84217D994F86500F7F700 +:100DD0000BF9014694F864004FF47A72022828D087 +:100DE000012828D040F6340008444AF2473108442C +:100DF000B0FBF2F1606A0844C51B21460020356152 +:100E0000FDF7C7FC618840F2E24251439830081A6E +:100E1000A0F22630706194F8652094F86410606A3E +:100E200001F099FAA0F5CB70B061BDE8F041F5F79B +:100E300060BE1046D8E74FF4C860D5E7BDE8F04182 +:100E400002F02FBEBDE8F041F7F7D5BE304601F005 +:100E500078FA0621F3F72AF8040000D1FFDF3046C4 +:100E600001F06FFA2188884200D0FFDF01220021C3 +:100E7000204600E047E0BDE8F04101F089BAF7F70D +:100E800073FDF7F7B8FE02204FF0E02104E0000008 +:100E9000CC11002084010020C1F88002BDE8F0815F +:100EA000304601F04EFA0621F3F700F8040000D1B5 +:100EB000FFDF304601F045FA2188884200D0FFDF8D +:100EC00094F8F000042800D0FFDF84F8F05094F884 +:100ED000FA504FF6FF76202D00D3FFDFFA4820F8B6 +:100EE000156094F8FA00F5F720F900B9FFDF20202B +:100EF00084F8FA002046FFF7C1FDF4480078BDE809 +:100F0000F041E2F701B8FFDFC8E770B5EE4C00250D +:100F1000443C84F82850E07868B1E570FEF71EF98B +:100F20002078042803D0606AFFF7A8FD6562E748CF +:100F30000078E1F7E9FFBDE8704001F03ABA70B51A +:100F4000E14C0146443CE069F5F706FE6568A2788D +:100F500090FBF5F172B140F27122B5FBF2F292B260 +:100F6000A36B01FB02F6B34202D901FB123200E08F +:100F70000022A2634D43002800DAFFDF2946E06922 +:100F8000F4F7D9FDE06170BD2DE9F05FFEF736F9A9 +:100F90008246CD48683800F1240881684646D8F872 +:100FA0001800F4F7C8FD0146F069F5F7D5FD4FF0DC +:100FB0000009074686F835903C4640F28F254E469C +:100FC0001EE000BF0AEB06000079F7F70DF80146B6 +:100FD0004AF2B12001444FF47A70B1FBF0F008EB13 +:100FE0008602414692681044844207D3241A91F83D +:100FF0003500A4F28F24401C88F83500761CF6B228 +:1010000098F83600B042DDD8002C10DD98F8351085 +:10101000404608EB81018968A14208D24168C91B9A +:10102000B1F5247F00D30D466C4288F8359098F8CE +:101030003560C3460AEB060898F80400F6F7D4FFBB +:101040004AF2B12101444FF47A7AB1FBFAF298F8EE +:101050000410082909D0042909D0002013180429F4 +:101060000AD0082908D0252207E0082000E0022045 +:1010700000EB40002830F1E70F22521D4FF4A8701A +:10108000082914D0042915D0022916D04FF0080CD5 +:101090005FF0280012FB0C00184462190BEB86036A +:1010A00010449A68D84690420BD8791925E04FF041 +:1010B000400CEFE74FF0100CECE74FF0040C182059 +:1010C000E8E798F8352098F836604046B24210D2EA +:1010D000521C88F835203C1B986862198418084611 +:1010E000F6F782FF4AF2B1210144B1FBFAF001198F +:1010F00003E080F83590D8F80410D8F81C00BDE85B +:10110000F05FF4F718BD2DE9FE4F14460546FEF7D3 +:1011100075F8DFF8B4A10290AAF1440A50469AF893 +:1011200035604FF0000B0AEB86018968CAF83C1065 +:10113000F4B3044600780027042825D005283ED0C3 +:10114000FFDFA04639466069F4F7F5FC0746F5F77E +:101150000BF881463946D8F80440F5F7FDFC401EEF +:1011600090FBF4F0C14361433846F4F7E4FC0146D8 +:10117000C8F81C004846F5F7EFFC002800DDFFDF4B +:10118000012188F813108DE0D4F81490D4F804806D +:1011900001F07AF9070010D0387800B9FFDF7969DB +:1011A00078684A460844414601F05AF9074600E08B +:1011B0000BE04045C5D9FFDFC3E75F46C1E7606A82 +:1011C00001F004F940F6B837BBE7C1690AEB460005 +:1011D0000191408D10B35446DAF81400FFF7AFFECA +:1011E0006168E069F4F7A7FC074684F835B0019C14 +:1011F000D0462046DAF81410F5F7AEFC81463946A1 +:101200002046F5F7A9FCD8F804200146B9FBF2F016 +:10121000B1FBF2F1884242D0012041E0F4F7A4FF93 +:10122000FFF78DFEFFF7B0FE9AF83510DAF804905C +:101230000AEB81010746896800913946DAF81C00FB +:10124000F5F78AFC00248046484504DB98FBF9F456 +:1012500004FB09F41AE0002052469AF8351007E022 +:1012600002EB800304F28F249B68401C1C44C0B234 +:101270008142F5D851B10120F6F7B6FE4AF2B1210C +:1012800001444FF47A70B1FBF0F004440099A8EBEC +:1012900004000C1A00D5FFDFCAF83C40A7E7002085 +:1012A00088F813009AF802005446B8B13946E0694C +:1012B000F5F752FC0146A26B40F2712042438A428C +:1012C00006D2C4F83CB009E03412002080010020AE +:1012D000E06B511A884200D30846E063AF6085F89E +:1012E00000B001202871029F94F835003F1DC05DB9 +:1012F000F6F77AFE4AF23B5101444FF47A70B1FBA3 +:10130000F0F0E16BFE300844E8602078042808D152 +:1013100094F8350004EB4000408D0A2801D20320E8 +:1013200000E00220687104EB4600408DC0B1284601 +:101330006168EFF791FE82B20020761C0CE000BFDE +:1013400004EB4001B0424B8D13449BB24B8501D35B +:101350005B1C4B85401CC0B294F836108142EFD222 +:10136000A8686061A06194F8350004EB4001488DE5 +:10137000401C488594F83500C05D082803D0042837 +:1013800003D000210BE0082100E0022101EB410124 +:1013900028314FF4A872082804D0042802D002286B +:1013A00007D028220A44042805D0082803D0252184 +:1013B00002E01822F6E70F21491D08280CD0042866 +:1013C0000CD002280CD0082011FB0020E16B8842D1 +:1013D00008D20120BDE8FE8F4020F5E71020F3E79A +:1013E0000420F1E70020F5E770B5FE4C061D14F867 +:1013F000352F905DF6F7F8FD4FF47A7100F2E73083 +:10140000B0FBF1F0D4F8071045182078805DF6F7AE +:1014100073FE2178895D082903D0042903D00022B6 +:101420000BE0082200E0022202EB420228324FF4D5 +:10143000A873082904D0042902D0022907D0282340 +:101440001344042905D0082903D0252202E01823DB +:10145000F6E70F22521D08290AD004290AD00229D2 +:101460000AD0082112FB0131081A281A293070BD50 +:101470004021F7E71021F5E70421F3E72DE9FF41CB +:1014800007460C46012000F046FFC5B20B2000F0D5 +:1014900042FFC0B2854200D0FFDF20460126002572 +:1014A000D04C082869D2DFE800F004304646426894 +:1014B0006865667426746078002819D1FDF79EFE71 +:1014C000009594F835108DF808104188C90411D0A2 +:1014D000206C019003208DF80900C24824388560F3 +:1014E000C56125746846FDF768FB002800D0FFDF62 +:1014F000BDE8FF81FFF778FF0190E07C10B18DF827 +:101500000950EAE78DF80960E7E7607840B1207C90 +:1015100008B9FDF7F9FD6574BDE8FF41F4F72FBD8B +:10152000A674FDF739FC0028E2D0FFDFE0E7BDE854 +:10153000FF41F7F760BBFDF761FE4088C00407D0AC +:1015400001210320FDF75EFEA7480078E1F7DCFCEF +:10155000002239466846FFF7D6FD38B1694638465D +:1015600000F0EDFE0028C3D1FFDFC1E7E670FFF712 +:10157000CCFCBDE7BDE8FF41C7E4FFDFB8E7994910 +:1015800050B101228A704A6840F27123B2FBF3F233 +:1015900002EB0010886370470020887070472DE9C7 +:1015A000F05F894640F271218E4E48430025044683 +:1015B000706090462F46D0074AF2B12A4FF47A7BEA +:1015C0000FD0B9F800004843B0600120F6F70CFDD9 +:1015D00000EB0A01B1FBFBF0241AB7680125A4F265 +:1015E0008F245FEA087016D539F8151040F2712083 +:1015F000414306EB85080820C8F80810F6F7F4FC0C +:1016000000EB0A01B1FBFBF0241AD8F80800A4F2A1 +:101610008F2407446D1CA74219D9002D17D0391B00 +:10162000B1FBF5F0B268101AB1FBF5F205FB12122E +:10163000801AB060012008E0B1FBF5F306EB8002F0 +:101640009468E31A401CC0B29360A842F4D3BDE88A +:10165000F09F2DE9F041634C00262078042804D047 +:101660002078052801D00C2018E401206070607CEF +:10167000002538B1EFF3108010F0010F72B610D0D2 +:1016800001270FE0FDF7BAFD074694F82000F5F7B3 +:10169000B2F87888C00411D000210320FDF7B2FD14 +:1016A0000CE00027607C38B1A07C28B1FDF72CFD50 +:1016B0006574A574F4F763FC07B962B694F820006A +:1016C000F5F705FB94F8280030B184F8285020780D +:1016D000052800D0FFDF0C26657000F06AFE30465A +:1016E00012E4404810B5007808B1FFF7B2FF00F0EF +:1016F000D4FE3C4900202439086210BD10B53A4C94 +:1017000058B1012807D0FFDFA06841F66A0188427E +:1017100000D3FFDF10BD40F6C410A060F4E73249EB +:1017200008B508702F4900200870487081F828001B +:10173000C8700874487488742022486281F8202098 +:10174000243948704FF6FF7211F1680121F810201A +:10175000401CC0B22028F9D30020FFF7CFFFFFF7CD +:10176000C0FF1020ADF80000012269460420FFF7F9 +:1017700016FF08BD7FB51B4C05460E46207810B1FC +:101780000C2004B070BD95F8652095F86410686A67 +:1017900000F0C5FEC5F80401656295F8F00000B1DF +:1017A000FFDF104900202439C861052121706070D5 +:1017B00084F82800014604E004EB4102491C5085EE +:1017C000C9B294F836208A42F6D284F83500304601 +:1017D000FFF7D5FE0548F4F74DFC84F820002028DB +:1017E00007D105E0F0110020800100207D140200E7 +:1017F000FFDFF4F7B9FC606194F82010012268461D +:10180000FFF781FC00B9FFDF94F82000694600F083 +:1018100096FD00B9FFDF0020B3E7F94810B5007866 +:1018200008B1002010BD0620F2F7DAFA80F00100BE +:1018300010BDF8B5F24D0446287800B1FFDF002056 +:10184000009023780246DE0701466B4605D060888B +:10185000A188ADF80010012211462678760706D53A +:10186000E088248923F8114042F00802491C491EEF +:1018700085F836101946FFF792FE0020F8BD1FB517 +:1018800011B1112004B010BDDD4C217809B10C203C +:10189000F8E70022627004212170114605E000BFC4 +:1018A00004EB4103491C5A85C9B294F836308B4287 +:1018B000F6D284F83520FFF762FED248F4F7DAFB5F +:1018C00084F82000202800D1FFDF00F0DDFD10B1FA +:1018D000F4F74AFC05E0F4F747FC40F6B831F4F7BA +:1018E0002AF9606194F8201001226846FFF70BFC8A +:1018F00000B9FFDF94F82000694600F020FD00B930 +:10190000FFDF0020BEE770B5BD4C616A0160FFF7E4 +:10191000A0FE050002D1606AFFF7B0F80020606207 +:10192000284670BD7FB5B64C2178052901D00C2022 +:1019300027E7B3492439C860606A00B9FFDF606AED +:1019400090F8F00000B1FFDF606A90F8FA002028FC +:1019500000D0FFDFAC48F4F78DFB616A0546202814 +:1019600081F8FA000E8800D3FFDFA548443020F844 +:101970001560606A90F8FA00202800D1FFDF00238C +:1019800001226846616AFFF794F8606A694690F838 +:10199000FA0000F0D4FC00B9FFDF00206062F0E63E +:1019A000974924394870704710B540F2E24300FB74 +:1019B00003F4002000F0B3FD844201D9201A10BDC9 +:1019C000002010BD70B50D46064601460020FCF70C +:1019D000E0FE044696F86500F6F706FB014696F829 +:1019E00064004FF47A72022815D0012815D040F611 +:1019F000340008444AF247310844B0FBF2F17088E1 +:101A000040F271225043C1EB4000A0F22630A542C3 +:101A100006D2214605E01046EBE74FF4C860E8E740 +:101A20002946814204D2A54201D2204600E0284640 +:101A3000706270BD70B50546FDF7E0FB7049007837 +:101A400024398C689834072D30D2DFE805F004344F +:101A500034252C34340014214FF4A873042810D0FA +:101A60000822082809D02A2102280FD011FB0240A1 +:101A700000222823D118441819E0402211FB02400B +:101A8000F8E7102211FB02402E22F3E7042211FB9B +:101A9000024000221823EDE7282100F04BFC04440B +:101AA00004F5317403E004F5B07400E0FFDF54483E +:101AB000C06BA04201D9012070BD002070BD70B57F +:101AC0004F4C243C607870B1D4E904512846A26898 +:101AD000EFF7EDFA2061A84205D0A169401B084448 +:101AE000A061F5F706F82169A068884201D820783E +:101AF00008B1002070BD012070BD2DE9F04F0546F2 +:101B000085B016460F461C461846F6F7F5FA05EB63 +:101B100047014718204600F0F5FB4AF2C5714FF423 +:101B20007A7908444D46B0FBF5F0384400F160087E +:101B30003348761C24388068304404902046F6F7F9 +:101B4000DBFAA8EB0007204600F0DCFB0646204647 +:101B5000F6F74AFA301AB0FBF5F03A1A18252820A1 +:101B60004FF4C8764FF4BF774FF0020B082C30D0FB +:101B7000042C2BD00021022C2ED0082311F1280197 +:101B800003EB830C0CEB831319440A444FF0000A57 +:101B9000082C29D0042C22D00021022C29D0054663 +:101BA000082001F5B07100BF00EB0010284481420D +:101BB00032D2082C2AD0042C1ED00020022C28D08F +:101BC0000821283001EB0111084434E03946102384 +:101BD000D6E731464023D3E704231831D0E73D460A +:101BE00040F2EE311020DFE735464FF435614020FA +:101BF000DAE70420B431D7E738461021E2E70000E5 +:101C0000F01100207D140200530D020030464021E7 +:101C1000D8E704211830D5E7082C4FD0042C4AD03F +:101C20000021022C4DD0082311F12801C3EBC30081 +:101C300000EB4310084415182821204600F07AFBD9 +:101C400005EB4001082C42D0042C3DD00026022C8C +:101C50003FD0082016F1280600EB801006EB80002C +:101C60000E180120FA4D8DF804008DF800A08DF8B3 +:101C700005B0A86906F22A260499F3F75CFFCDE9BE +:101C800002062046F6F7B0F94AF23B510144B1FB97 +:101C9000F9F0301AFE38E8630298C5F84080A86170 +:101CA00095F82000694600F04AFB002800D1FFDFCC +:101CB00005B0BDE8F08F39461023B7E73146402321 +:101CC000B4E704231831B1E73E461020C4E74020B2 +:101CD000C2E704201836BFE72DE9FE4F06461C4632 +:101CE000174688464FF0010A1846F6F705FAD84D10 +:101CF000243DA9688A1907EB48011144471820467A +:101D000000F000FB4FF47A7BD84600F6FB00B0FBF6 +:101D1000F8F0384400F120092046F6F7EDF9A968FB +:101D20000246A9EB0100801B871A204600F0EAFA60 +:101D300005462046F6F758F9281AB0FBF8F03A1A8B +:101D4000182528204FF4C8774FF4BF78082C2DD0E1 +:101D5000042C28D00021022C2BD0082311F12801BB +:101D600003EB830C0CEB831319440A44082C28D092 +:101D7000042C21D00021022C28D00546082001F592 +:101D8000B07100BF00EB0010284481422AD2082C19 +:101D900022D0042C1DD00020022C20D00821283075 +:101DA00001EB01112CE041461023D9E739464023CD +:101DB000D6E704231831D3E7454640F2EE31102030 +:101DC000E0E73D464FF435614020DBE70420B431C5 +:101DD000D8E740461021E3E738464021E0E70421F8 +:101DE0001830DDE7082C48D0042C43D00020022C0A +:101DF00046D0082110F12800C1EBC10303EB4111CB +:101E0000084415182821204600F094FA05EB4001FB +:101E1000082C3BD0042C36D00027022C38D00820C8 +:101E200017F1280700EB801007EB80000C1804F571 +:101E300096740C98F6F7D8F84AF23B510144B1FB7E +:101E4000FBF0834DFE30A5F12407E96B06F1FE029D +:101E50000844B9680B191A44824224D93219114432 +:101E60000C1AFE342044B0F1807F37D2642C12D299 +:101E7000642011E040461021BEE738464021BBE710 +:101E800004211830B8E747461020CBE74020C9E7C7 +:101E900004201837C6E720460421F4F790FEE8B185 +:101EA000E86B2044E863E0F703FFB9682938314460 +:101EB0000844CDE9000995F835008DF808000220A6 +:101EC0008DF809006846FCF778FE00B1FFDFFCF7EB +:101ED00063FF00B1FFDF5046BDE8FE8F4FF0000A00 +:101EE000F9E71FB500F021FB594C607880B994F8F0 +:101EF000201000226846FFF706F938B194F8200058 +:101F0000694600F01CFA18B9FFDF01E00120E0701B +:101F1000F4F735F800206074A0741FBD2DE9F84F68 +:101F2000FDF76CF90646451CC07840090CD0012825 +:101F30000CD002280CD000202978824608064FF4E5 +:101F4000967407D41E2006E00120F5E70220F3E78F +:101F50000820F1E72046B5F80120C2F30C0212FB7D +:101F600000F7C80901D010B103E01E2401E0FFDF33 +:101F70000024F6F7D3F8A7EB00092878B77909EB26 +:101F80000408C0F3801010B120B1322504E04FF4F2 +:101F9000FA7501E0FFDF00250C2F00D3FFDF2D488D +:101FA0002D4A30F81700291801FB0821501CB1FBFD +:101FB000F0F5F6F76DF8F6F717F84FF47A7100F2CE +:101FC0007160B0FBF1F1A9EB0100471BA7F15900CB +:101FD000103FB0F5247F11D31D4E717829B9024608 +:101FE000534629462046FFF788FD00F09EFAF3F796 +:101FF000C6FF00207074B074BDE8F88F3078009090 +:102000005346224629463846FFF766FE0028F3D19C +:1020100001210220FDF7F6F8BDE8F84F61E710B5A1 +:102020000446012903D10A482438007830B104203D +:1020300084F8F000BDE81040F3F7A1BF00220121B1 +:10204000204600F0A5F934F8700F401C2080F1E71D +:10205000F0110020646302003F420F002DE9F041BF +:102060000746FDF7CBF8050000D1FFDF287810F018 +:102070000C0F01D0012100E00021F74C606A3030E4 +:10208000FCF7C7FA29783846EFF71BFAA4F12406C3 +:102090000146A069B26802446FB32878082803D0CB +:1020A000042803D000230BE0082300E0022303EB05 +:1020B000430328334FF4A877082804D0042802D01B +:1020C000022810D028273B4408280ED004280ED020 +:1020D00002280ED05FF00800C0EBC00707EB4010ED +:1020E0001844983009E01827EDE74020F4E7102065 +:1020F000F2E70420F0E74FF4FC701044471828780A +:102100003F1DF5F771FF014628784FF47A720228D7 +:102110001DD001281DD040F6340008444AF2EF01DA +:102120000844B0FBF2F03A1A606A40F2E241B0466D +:102130004788F0304F43316A81420DD03946206BD9 +:1021400000F08EF90646B84207D9FFDF05E01046D9 +:10215000E3E74FF4C860E0E70026C04880688642A5 +:1021600007D2616A40F271224888424306EB420678 +:1021700004E040F2E240B6FBF0F0616AC882606AB7 +:10218000297880F86410297880F865100521417558 +:10219000C08A6FF41C71484306EB400040F635419D +:1021A000C8F81C00B0EB410F00D3FFDFBDE8F081A1 +:1021B00010B5052937D2DFE801F00509030D31001C +:1021C000002100E00121BDE8104028E7032180F84C +:1021D000F01010BD0446408840F2E24148439F4958 +:1021E000091D0860D4F818010089E082D4F81801AC +:1021F00080796075D4F8180140896080D4F818019E +:102200008089A080D4F81801C089E0802046A16AA6 +:10221000FFF7D8FB022084F8F00010BD816ABDE80A +:102220001040FFF7CFBBFFDF10BD70B58A4C243CD8 +:102230000928A1683FD2DFE800F0050B0B15131544 +:1022400038380800BDE870404BE6BDE8704065E6F0 +:10225000022803D00020BDE87040FFE60120FAE725 +:10226000E16070BD032802D005281CD000E0E160C9 +:102270005FF0000600F059F9774D012085F828003D +:1022800085F83460686AA9690026C0F8F41080F8FF +:10229000F060E068FFF746FB00B1FFDFF3F76FFE89 +:1022A0006E74AE7470BD0126E4E76C480078BDE83A +:1022B0007040E0F729BEFFDF70BD674924394860F0 +:1022C000704770B5644D0446243DB1B14FF47A7641 +:1022D000012903D0022905D0FFDF70BD1846F5F7AC +:1022E000FCFE05E06888401C68801046F6F7F8FFA1 +:1022F00000F2E730B0FBF6F0201AA86070BD564837 +:1023000000787047082803D0042801D0F5F76CBE88 +:102310004EF628307047002804DB00F1E02090F8EA +:10232000000405E000F00F0000F1E02090F8140D2B +:102330004009704710F00C0000D008467047F4F7D1 +:102340003EB910B50446202800D3FFDF4248443090 +:1023500030F8140010BD70B505460C461046F5F770 +:1023600043FE4FF47A71022C0DD0012C0DD040F6B3 +:10237000340210444AF247321044B0FBF1F02844D2 +:1023800000F5CB7070BD0A46F3E74FF4C862F0E782 +:102390001FB513460A46044601466846FEF789FB08 +:1023A00094F8FA006946FFF7CAFF002800D1FFDF62 +:1023B0001FBD70B5284C0025257094F82000F3F758 +:1023C000B4FE00B9FFDF84F8205070BD2DE9F04164 +:1023D000050000D1FFDF204A0024243AD5F804612B +:1023E0002046631E116A08E08869B04203D3984210 +:1023F00001D203460C460846C9680029F4D104B945 +:1024000004460021C5F80041F035C4B1E068E5603C +:10241000E86000B105612E698846A96156B1B069CE +:1024200030B16F69B84200D2FFDFB069C01BA8614C +:10243000C6F81880084D5CB1207820B902E0E96048 +:102440001562E8E7FFDF6169606808442863ADE66C +:10245000C5F83080AAE60000F011002080010020BD +:1024600010B50C4601461046F4F776FB002806DA54 +:10247000211A491EB1FBF4F101FB040010BD90FBD1 +:10248000F4F101FB140010BD2E48016A002001E0A8 +:102490000846C9680029FBD170472DE9FE43294D44 +:1024A0000120287000264FF6FF7420E00621F1F786 +:1024B000FDFC070000D1FFDF97F8FA00F037F4F7D2 +:1024C00006FC07F80A6BA14617F8FA89B8F1200F45 +:1024D00000D3FFDF1B4A683222F8189097F8FA0001 +:1024E000F3F723FE00B9FFDF202087F8FA006946E2 +:1024F0000620F1F764FC50B1FFDF08E0029830B12C +:1025000090F8F01019B10088A042CFD104E06846DD +:10251000F1F733FC0028F1D02E70BDE8FE8310B532 +:10252000FFF719FF00F5C87010BD064800212430E0 +:1025300090F8352000EB4200418503480078E0F731 +:10254000E3BC0000CC11002080010020012804D051 +:10255000022805D0032808D105E0012907D004E0AE +:10256000022904D001E0042901D000207047012095 +:102570007047F748806890F8A21029B1B0F89E1013 +:10258000B0F8A020914215D290F8A61029B1B0F869 +:10259000A410B0F8A02091420CD2B0F89C20B0F862 +:1025A0009A108A4206D290F88020B0F898001AB1AA +:1025B000884203D3012070470628FBD200207047D1 +:1025C0002DE9F041E24D0746A86800F1700490F84B +:1025D000140130B9E27B002301212046EEF7D2FC42 +:1025E00010B1A08D401CA08501263D21AFB92878EF +:1025F000022808D001280AD06878C8B110F0140F5A +:1026000009D01E2039E0162037E026773EE0A86882 +:1026100090F8160131E0020701D56177F5E78107EF +:1026200001D02A2029E0800600D4FFDF232024E007 +:1026300094F8320028B1E08D411CE185218E88425A +:1026400013D294F8360028B1A08E411CA186218EA9 +:1026500088420AD2A18D608D814203D3AA6892F884 +:10266000142112B9228E914201D3222005E0217C4F +:1026700029B1218D814207D308206077C5E7208DDD +:10268000062801D33E20F8E7207FB0B10020207358 +:10269000607320740221A868FFF78AFDA86890F88B +:1026A000E410012904D1D0F81C110878401E0870EC +:1026B000E878BDE8F041E0F727BCA868BDE8F04144 +:1026C0000021FFF775BDA2490C28896881F8E40054 +:1026D00014D0132812D0182810D0002211280ED0A0 +:1026E00007280BD015280AD0012807D0002805D0CC +:1026F000022803D021F89E2F012008717047A1F80D +:10270000A420704710B5924CA1680A88A1F86021F6 +:1027100081F85E0191F8640001F046FBA16881F840 +:10272000620191F8650001F03FFBA16881F8630147 +:10273000012081F85C01002081F82E01E078BDE8DD +:102740001040E0F7E1BB70B5814C00231946A0684A +:1027500090F87C207030EEF715FC00283DD0A06882 +:1027600090F820110025C9B3A1690978B1BB90F890 +:102770007D00EEF7EFFB88BBA168B1F870000A2876 +:102780002DD905220831E069EBF72AFE10B3A068C5 +:10279000D0F81C11087858B10522491CE069EBF704 +:1027A0001FFE002819D1A068D0F81C01007840B99C +:1027B000A068E169D0F81C010A68C0F80120097915 +:1027C0004171A068D0F81C110878401C08700120E5 +:1027D000FFF779FFA06880F8205170BDFFE7A0687F +:1027E00090F8241111B190F82511C1B390F82E1171 +:1027F0000029F2D090F82F110029EED190F87D0039 +:10280000EEF7A8FB0028E8D1A06890F8640001F07A +:10281000CBFA0646A06890F8650001F0C5FA0546B7 +:10282000A06890F830113046FFF790FEA0B3A06882 +:1028300090F831112846FFF789FE68B3A268B2F814 +:10284000703092F86410B2F8320102F58872EEF737 +:1028500001FE20B3A168252081F87C00BDE7FFE7D9 +:1028600090F87D10242918D090F87C10242914D0D9 +:102870005FF0000300F5897200F59271FBF78EFEA0 +:10288000A16881F8245101F13000C28A21F8E62FB5 +:10289000408B4880142007E005E00123EAE7BDE80B +:1028A000704000202EE71620BDE870400BE710B501 +:1028B000F4F7FAFD0C2813D3254C0821A068D0F8B2 +:1028C00018011E30F4F7F4FD28B1A0680421D830B7 +:1028D000F4F7EEFD00B9FFDFBDE810400320F2E69B +:1028E00010BD10B51A4CA068D0F818110A78002A4B +:1028F0001FD04988028891421BD190F87C20002388 +:1029000019467030EEF73EFB002812D0A068D0F8D0 +:1029100018110978022907D003290BD0042919D0EE +:10292000052906D108200DE090F87D00EEF712FB96 +:1029300040B110BD90F8811039B190F8820000B913 +:10294000FFDF0A20BDE81040BDE6BDE81040AEE75D +:102950008C01002090F8AA008007EAD10C20FFF734 +:10296000B2FEA068002120F89E1F01210171017BA9 +:1029700041F00101017310BD70B5F74CA268556EAE +:10298000EEF702FDEBB2C1B200228B4203D0A36886 +:1029900083F8121102E0A16881F81221C5F3072122 +:1029A000C0F30720814203D0A16881F8130114E726 +:1029B000A06880F8132110E710B5E74C0421A06847 +:1029C000FFF7F6FBA06890F85A10012908D000F52F +:1029D0009E71FBF7ACFEE078BDE81040E0F794BADA +:1029E000022180F85A1010BD70B5DB4CA06890F839 +:1029F000E410FE2955D16178002952D190F87F204A +:102A0000002301217030EEF7BDFA002849D1A068FB +:102A100090F8141109B1022037E090F87C200023CF +:102A200019467030EEF7AEFA28B1A06890F896001B +:102A300008B1122029E0A068002590F87C20122A15 +:102A40001DD004DC032A23D0112A04D119E0182A4E +:102A50001AD0232A26D0002304217030EEF792FAF0 +:102A600000281ED1A06890F87D10192971D020DCB3 +:102A700001292AD0022935D0032932D120E00B20A8 +:102A800003E0BDE8704012E70620BDE870401AE69A +:102A900010F8E21F01710720FFF715FEA06880F80B +:102AA0007C509AE61820FFF70EFEA068A0F89E5012 +:102AB00093E61D2918D01E2916D0212966D149E098 +:102AC00010F8E11F4171072070E00C20FFF7FBFDBB +:102AD000A06820F8A45F817941F00101817100F8BC +:102AE000275C53E013202CE090F8252182BB90F85E +:102AF0002421B2B1242912D090F87C1024290ED0C0 +:102B00005FF0000300F5897200F59271FBF746FD56 +:102B1000A0681E2180F87D1080F8245103E0012375 +:102B2000F0E71E2932D1A068FBF797FDFFF744FFBD +:102B3000A16801F13000C28A21F8E62F408B48805D +:102B40001520FFF7C0FDA068A0F8A45080F87D50C4 +:102B50001CE02AE090F8971051B180F8125180F8EB +:102B600013511820FFF7AFFDA068A0F8A4500DE0A6 +:102B700090F82F1151B990F82E1139B1C16DD0F8DC +:102B80003001FFF7F9FE1820FFF79DFDA06890F8CF +:102B9000E400FE2885D1FFF7A4FEA06890F8E400C9 +:102BA000FE2885D1BDE87040CDE51120FFF78BFDF3 +:102BB000A068CBE7684A0129926819D0002302294E +:102BC0000FD003291ED010B301282BD0032807D122 +:102BD00092F87C00132803D0162801D0182804D1BD +:102BE000704792F8E4000028FAD0D2F8180117E0F4 +:102BF00092F8E4000128F3D0D2F81C110878401EA6 +:102C00000870704792F8E4000328EED17047D2F8BC +:102C10001801B2F870108288891A09B20029F5DB10 +:102C200003707047B2F87000B2F82211401A00B277 +:102C30000028F6DBD2F81C010178491E01707047AC +:102C400070B5044690F87C0000250C2810D00D28A3 +:102C50002ED1D4F81811B4F870008988401C88422D +:102C600026D1D4F864013C4E017811B3FFDF42E075 +:102C7000B4F87000B4F82211401C884218D1D4F87E +:102C80001C01D0F80110A160407920730321204677 +:102C9000EDF7F1FDD4F81C01007800B9FFDF012148 +:102CA000FE20FFF787FF84F87C50012084F8B200F3 +:102CB00093E52188C180D4F81801D4F864114089C3 +:102CC0000881D4F81801D4F8641180894881D4F8B7 +:102CD0001801D4F86411C0898881D4F864010571A1 +:102CE000D4F8641109200870D4F864112088488051 +:102CF000F078E0F709F902212046EDF7BCFD032149 +:102D00002046FFF755FAB068D0F81801007802287D +:102D100000D0FFDF0221FE20FFF74CFF84F87C503B +:102D20005BE52DE9F0410C4C00260327D4F808C0E0 +:102D3000012598B12069C0788CF8E20005FA00F00E +:102D4000C0F3C05000B9FFDFA06800F87C7F468464 +:102D500080F82650BDE8F0818C01002000239CF80B +:102D60007D2019460CF17000EEF70CF970B1607817 +:102D70000028EFD12069C178A06880F8E11080F8C0 +:102D80007D70A0F8A46080F8A650E3E76570E1E7E5 +:102D9000F0B5F74C002385B0A068194690F87D2067 +:102DA0007030EEF7EFF8012580B1A06890F87C0054 +:102DB00023280ED024280CD06846F6F785FB68B18E +:102DC000009801A9C0788DF8040008E0657005B08E +:102DD000F0BD607840F020006070F8E70021A06846 +:102DE00003AB162290F87C00EEF74FFB002648B1AB +:102DF000A0689DF80C20162180F80C2180F80D1198 +:102E0000192136E02069FBF722FB78B121690879A6 +:102E100000F00702A06880F85C20497901F0070102 +:102E200080F85D1090F82F310BBB03E00020FFF716 +:102E300078FFCCE790F82E31CBB900F164035F78CE +:102E4000974205D11A788A4202D180F897500EE055 +:102E500000F5AC71028821F8022990F85C200A7113 +:102E600090F85D0048710D70E078E0F74DF8A068CB +:102E7000212180F87D1080F8A650A0F8A460A6E774 +:102E8000F8B5BB4C00231946A06890F87D2070303F +:102E9000EEF778F840B32069FBF7BEFA48B3206933 +:102EA000FBF7B4FA07462069FBF7B4FA0646206937 +:102EB000FBF7AAFA05462069FBF7AAFA0146009734 +:102EC000A06833462A463030FBF79BFBA1680125FA +:102ED00091F87C001C2810D091F85A00012812D0DB +:102EE00091F8250178B90BE0607840F0010060703E +:102EF000F8BDBDE8F840002013E781F85A5002E021 +:102F000091F8240118B11E2081F87D000BE01D20EE +:102F100081F87D0001F5A57231F8300BFBF7FBFB62 +:102F2000E078DFF7F1FFA068002120F8A41F85708A +:102F3000F8BD10B58E4C00230921A06890F87C20C4 +:102F40007030EEF71FF848B16078002805D1A1680D +:102F500001F8960F087301F81A0C10BD012060707B +:102F600010BD7CB5824C00230721A06890F87C201E +:102F70007030EEF707F838B36078002826D169463C +:102F80002069FBF75FFA9DF80000002500F025019D +:102F9000A06880F8B0109DF8011001F0490180F898 +:102FA000B11080F8A250D0F81811008849888142E9 +:102FB00000D0FFDFA068D0F818110D70D0F86411B0 +:102FC0000A7822B1FFDF16E0012060707CBD30F886 +:102FD000E82BCA80C16F0D71C16F009A8A60019A97 +:102FE000CA60C26F0821117030F8E81CC06F4180C0 +:102FF000E078DFF789FFA06880F87C507CBD70B571 +:103000005B4C00231946A06890F87D207030EDF7E6 +:10301000B9FF012540B9A0680023082190F87C2061 +:103020007030EDF7AFFF10B36078002820D1A068B2 +:1030300090F8AA00800712D42069FBF7C9F9A168AB +:1030400081F8AB00206930F8052FA1F8AC2040884A +:10305000A1F8AE0011F8AA0F40F002000870A068B5 +:103060004FF0000690F8AA10C90702D011E0657071 +:103070009DE490F87D20002319467030EDF782FF23 +:1030800000B9FFDFA06880F87D5080F8A650A0F856 +:10309000A460A06890F87C10012906D180F87C60BB +:1030A00080F8A260E078DFF72FFFA168D1F818015F +:1030B000098842888A42DBD101780429D8D1067078 +:1030C000E078DFF721FFA06890F87C100029CFD1CD +:1030D00080F8A2606BE470B5254DA86890F87C106C +:1030E0001A2902D00220687061E469780029FBD1B6 +:1030F000002480F8A74080F8A240D0F8181100887A +:103100004988814200D0FFDFA868D0F818110C7000 +:10311000D0F864110A780AB1FFDF25E090F8A82002 +:1031200072B180F8A8400288CA80D0F864110C718E +:10313000D0F864210E2111700188D0F864010DE0EF +:1031400030F8E82BCA80C16F0C71C26F0121117277 +:10315000C26F0D21117030F8E81CC06F418000F083 +:10316000A1FEE878DFF7D0FEA86880F87C401EE476 +:103170008C01002070B5FA4CA16891F87C20162AC9 +:1031800001D0132A02D191F8A82012B10220607058 +:103190000DE46278002AFBD181F8E000002581F877 +:1031A000A75081F8A250D1F81801098840888842B8 +:1031B00000D0FFDFA068D0F818010078032800D005 +:1031C000FFDF0321FE20FFF7F5FCA068D0F86411B3 +:1031D0000A780AB1FFDF14E030F8E02BCA8010F85B +:1031E000081BC26F1171C16F0D72C26F0D2111707A +:1031F00030F8E81CC06F418000F054FEE078DFF743 +:1032000083FEA06880F87C504BE470B5D44C092153 +:103210000023A06890F87C207030EDF7B3FE002505 +:1032200018B12069007912281ED0A0680A21002355 +:1032300090F87C207030EDF7A5FE18B12069007978 +:10324000142814D02069007916281AD1A06890F8A3 +:103250007C101F2915D180F87C5080F8A250BDE861 +:1032600070401A20FFF74EBABDE8704061E6A068D2 +:1032700000F87C5F458480F82650BDE87040FFF779 +:103280009BBB0EE470B5B64C2079C00773D02069A3 +:1032900000230521C578A06890F87C207030EDF7F8 +:1032A00071FE98B1062D11D006DC022D0ED0042D32 +:1032B0000CD0052D06D109E00B2D07D00D2D05D022 +:1032C000112D03D0607840F008006070607800280D +:1032D00051D12069FAF7E0FF00287ED0206900254F +:1032E0000226C178891E162977D2DFE801F00B7615 +:1032F00034374722764D76254A457676763A5350CE +:103300006A6D7073A0680023012190F87F207030EF +:10331000EDF738FE08BB2069FBF722F8A16881F8B9 +:103320001601072081F87F0081F8A65081F8A2508D +:1033300056E0FFF76AFF53E0A06890F87C100F2971 +:1033400001D066704CE0617839B980F88150122163 +:1033500080F87C1044E000F0D0FD41E000F0ACFDCE +:103360003EE0FBF7A9F803283AD12069FBF7A8F85B +:10337000FFF700FF34E03BE00079F9E7FFF7ABFE31 +:103380002EE0FFF73CFE2BE0FFF7EBFD28E0FFF718 +:10339000D0FD25E0A0680023194690F87D2070300C +:1033A000EDF7F0FD012110B16078C8B901E061705E +:1033B00016E0A06820F8A45F817000F8276C0FE089 +:1033C0000BE0FFF75DFD0BE000F034FD08E0FFF7D8 +:1033D000DFFC05E000F0FAFC02E00020FFF7A1FCB2 +:1033E000A268F2E93001401C41F10001C2E900018C +:1033F0005EE42DE9F0415A4C2079800741D5607890 +:1034000000283ED1E06801270026C178204619290E +:10341000856805F170006FD2DFE801F04B3E0D6F5B +:10342000C1C1801C34C1556287C1C1C1C1BE8B9569 +:1034300098A4B0C1BA0095F87F2000230121EDF7D0 +:10344000A1FD00281DD1A068082180F87F1080F818 +:10345000A26090E0002395F87D201946EDF792FDDB +:1034600010B1A06880F8A660A0680023194690F803 +:103470007C207030EDF786FD002802D0A06880F82F +:10348000A26067E4002395F87C201946EDF77AFDE9 +:1034900000B9FFDF042008E0002395F87C201946DE +:1034A000EDF770FD00B9FFDF0C20A16881F87C000A +:1034B00050E4002395F87C201946EDF763FD00B930 +:1034C000FFDF0D20F1E7002395F87C201946EDF78A +:1034D00059FD00B9FFDFA0680F2180F8A77008E050 +:1034E00095F87C00122800D0FFDFA068112180F839 +:1034F000A87080F87C102DE451E0002395F87C2022 +:103500001946EDF73FFD20B9A06890F8A80000B972 +:10351000FFDFA068132180F8A770EAE795F87C0028 +:10352000182800D0FFDF1A20BFE7BDE8F04100F007 +:1035300063BD002395F87C201946EDF723FD00B903 +:10354000FFDF0520B1E785F8A66003E4002395F8C6 +:103550007C201946EDF716FD00B9FFDF1C20A4E71B +:103560008C010020002395F87D201946EDF70AFD17 +:1035700000B9FFDFA06880F8A66006E4002395F894 +:103580007C201946EDF7FEFC00B9FFDF1F208CE719 +:10359000BDE8F04100F0F8BC85F87D60D3E7FFDFBF +:1035A0006FE710B5F74C6078002837D120794007D5 +:1035B0000FD5A06890F87C00032800D1FFDFA06839 +:1035C00090F87F10072904D101212170002180F893 +:1035D0007F10FFF70EFF00F0B5FCFFF753FEA07859 +:1035E000000716D5A0680023052190F87C207030D4 +:1035F000EDF7C8FC50B108206070A068D0F86411E5 +:1036000008780D2800D10020087002E00020F9F7AA +:10361000F9FCA068BDE81040FFF712BB10BD2DE912 +:10362000F041D84C07464FF00005607808436070C1 +:10363000207981062046806802D5A0F8985004E0E1 +:10364000B0F89810491CA0F8981000F018FD012659 +:10365000F8B1A088000506D5A06890F8821011B1D5 +:10366000A0F88E5015E0A068B0F88E10491CA0F8A4 +:103670008E1000F0F3FCA068B0F88E10B0F8902027 +:10368000914206D3A0F88E5080F83A61E078DFF7D7 +:103690003BFC207910F0600F08D0A06890F88010F3 +:1036A00021B980F880600121FEF782FD1FB9FFF784 +:1036B00078FFFFF799F93846FEF782FFBDE8F04141 +:1036C000F5F711BFAF4A51789378194313D11146DA +:1036D0000128896808D01079400703D591F87F0048 +:1036E000072808D001207047B1F84C00098E8842A5 +:1036F00001D8FEF7E4B900207047A249C278896872 +:10370000012A06D05AB1182A08D1B1F81011FAF7D7 +:10371000BABEB1F822114172090A81727047D1F81C +:10372000181189884173090A8173704770B5954CE7 +:1037300005460E46A0882843A080A80703D5E807C1 +:1037400000D0FFDFE660E80700D02661A80719D5A2 +:10375000F078062802D00B2814D10BE0A06890F86E +:103760007C1018290ED10021E0E93011012100F868 +:103770003E1C07E0A06890F87C10122902D10021BD +:1037800080F88210280601D50820A07068050AD5A7 +:10379000A0688288B0F87010304600F07FFC304698 +:1037A000BDE87040A9E763E43EB505466846F5F715 +:1037B00065FE00B9FFDF222200210098EAF767FECC +:1037C00003210098FAF750FD0098017821F01001CC +:1037D00001702946FAF76DFD6A4C192D71D2DFE8A8 +:1037E00005F020180D3EC8C8C91266C8C9C959C815 +:1037F000C8C8C8BBC9C971718AC89300A1680098BC +:1038000091F8151103E0A168009891F8E610017194 +:10381000B0E0A068D0F81C110098491CFAF795FD9B +:10382000A8E0A1680098D1F8182192790271D1F826 +:10383000182112894271120A8271D1F81821528915 +:10384000C271120A0272D1F8182192894272120AC8 +:103850008272D1F81811C989FAF74EFD8AE0A06882 +:10386000D0F818110098091DFAF77CFDA068D0F86F +:10387000181100980C31FAF77FFDA068D0F81811E4 +:1038800000981E31FAF77EFDA1680098D831FAF74A +:1038900087FD6FE06269009811780171918841712C +:1038A000090A81715188C171090A017262E03649C1 +:1038B000D1E90001CDE9010101A90098FAF78AFDDB +:1038C00058E056E0A068B0F844100098FAF794FD6C +:1038D000A068B0F8E6100098FAF792FDA068B0F87A +:1038E00048100098FAF780FDA068B0F8E81000983A +:1038F000FAF77EFD3EE0A168009891F83021027150 +:1039000091F83111417135E0A06890F81301EDF79D +:1039100032FD01460098FAF7B2FDA06890F8120156 +:1039200000F03DFA70B1A06890F8640000F037FA3A +:1039300040B1A06890F8121190F86400814201D063 +:10394000002002E0A06890F81201EDF714FD014696 +:103950000098FAF790FD0DE0A06890F80D1100981E +:10396000FAF7A8FDA06890F80C110098FAF7A6FDE8 +:1039700000E0FFDFF5F795FD00B9FFDF0098FFF7E6 +:10398000BCFE3EBD8C0100207C63020010B5F94CEA +:10399000A06890F8121109B990F8641080F86410CA +:1039A00090F8131109B990F8651080F8651000209F +:1039B000FEF7A8FEA068FAF750FE002806D0A0681F +:1039C000BDE8104000F59E71FAF7B1BE10BDF8B524 +:1039D000E84E00250446B060B5807570B57035704E +:1039E0000088F5F748FDB0680088F5F76AFDB4F87F +:1039F000F800B168401C82B201F17000EDF75BF88D +:103A000000B1FFDF94F87D00242809D1B4F87010CC +:103A1000B4F81001081A00B2002801DB707830B148 +:103A200094F87C0024280AD0252808D015E0FFF758 +:103A3000ADFF84F87D50B16881F897500DE0B4F87F +:103A40007010B4F81001081A00B2002805DB707875 +:103A500018B9FFF79BFF84F87C50A4F8F850FEF7E4 +:103A600088FD00281CD1B06890F8E400FE2801D041 +:103A7000FFF79AFEC0480090C04BC14A2146284635 +:103A8000F9F7ECF9B0680023052190F87C2070303C +:103A9000EDF778FA002803D0BDE8F840F8F771BFD9 +:103AA000F8BD10B5FEF765FD20B10020BDE810405F +:103AB0000146B4E5BDE81040F9F77FBA70B50C4691 +:103AC000154606464FF4B47200212046EAF7DFFCA3 +:103AD000268005B9FFDF2868C4F818016868C4F8B3 +:103AE0001C01A868C4F8640182E4F0F7E9BA2DE982 +:103AF000F0410D4607460621F0F7D8F9041E3DD0E7 +:103B0000D4F864110026087858B14A8821888A427E +:103B100007D109280FD00E2819D00D2826D0082843 +:103B20003ED094F83A01D0B36E701020287084F81B +:103B30003A61AF809AE06E7009202870D4F8640171 +:103B4000416869608168A9608089A88133E008467E +:103B5000F0F7DDFA0746EFF78AFF70B96E700E20B6 +:103B60002870D4F864014068686011E00846F0F7F6 +:103B7000CEFA0746EFF77BFF08B1002081E46E70B4 +:103B80000D202870D4F8640141686960008928819B +:103B9000D4F8640106703846EFF763FF66E00EE084 +:103BA0006E7008202870D4F86401416869608168EB +:103BB000A960C068E860D4F86401067056E094F823 +:103BC0003C0198B16E70152028700AE084F83C61C1 +:103BD000D4F83E016860D4F84201A860D4F84601E8 +:103BE000E86094F83C010028F0D13FE094F84A01E5 +:103BF00058B16E701C20287084F84A610A2204F5BE +:103C0000A671281DEAF719FC30E094F8560140B17E +:103C10006E701D20287084F85661D4F858016860D1 +:103C200024E094F8340168B16E701A20287004E022 +:103C300084F83461D4F83601686094F834010028BF +:103C4000F6D113E094F85C01002897D06E7016202E +:103C5000287007E084F85C61D4F85E016860B4F80D +:103C60006201288194F85C010028F3D1012008E466 +:103C7000404A5061D170704770B50D4604464EE021 +:103C8000B4F8F800401CA4F8F800B4F89800401C00 +:103C9000A4F89800204600F0F2F9B8B1B4F88E000C +:103CA000401CA4F88E00204600F0D8F9B4F88E002D +:103CB000B4F89010884209D30020A4F88E000120A7 +:103CC00084F83A012B48C078DFF71EF994F8A20077 +:103CD00020B1B4F89E00401CA4F89E0094F8A60001 +:103CE00020B1B4F8A400401CA4F8A40094F8140176 +:103CF00040B994F87F200023012104F17000EDF712 +:103D000041F920B1B4F89C00401CA4F89C00204666 +:103D1000FEF796FFB4F87000401CA4F870006D1E0A +:103D2000ADB2ADD23FE5134AC2E90601704770B5A6 +:103D30000446B0F8980094F88010D1B1B4F89A1005 +:103D40000D1A2D1F94F8960040B194F87C200023A2 +:103D5000092104F17000EDF715F9B8B1B4F88E60DF +:103D6000204600F08CF980B1B4F89000801B001F51 +:103D70000CE007E08C0100201F360200C53602006F +:103D80002D370200C0F10205DCE72846A84200DA20 +:103D90000546002D01DC002005E5A8B203E510F082 +:103DA0000C0000D00120704710B5012808D002286F +:103DB00008D0042808D0082806D0FFDF204610BD10 +:103DC0000124FBE70224F9E70324F7E770B5CC4CA4 +:103DD000A06890F87C001F2804D0607840F00100B3 +:103DE0006070E0E42069FAF73CFBD8B12069012259 +:103DF0000179407901F0070161F30705294600F0D8 +:103E0000070060F30F21A06880F8A2200022A0F82C +:103E10009E20232200F87C2FD0F8B400BDE870402B +:103E2000FEF7AABD0120FEF77CFFBDE870401E2012 +:103E3000FEF768BCF8B5B24C00230A21A06890F8E0 +:103E40007C207030EDF79EF838B32069FAF7E4FA79 +:103E5000C8B12069FAF7DAFA07462069FAF7DAFA00 +:103E600006462069FAF7D0FA05462069FAF7D0FA33 +:103E700001460097A06833462A463030FAF7C1FB66 +:103E8000A068FAF7EAFBA168002081F8A20081F897 +:103E90007C00BDE8F840FEF78FBD607840F001007F +:103EA0006070F8BD964810B580680088F0F72FF96B +:103EB000BDE81040EFF7C6BD10B5914CA36893F86C +:103EC0007C00162802D00220607010BD60780028A7 +:103ED000FBD1D3F81801002200F11E010E30C833C7 +:103EE000ECF7C2FFA0680021C0E92E11012180F883 +:103EF0008110182180F87C1010BD10B5804CA0688E +:103F000090F87C10132902D00220607010BD6178F7 +:103F10000029FBD1D0F8181100884988814200D0CF +:103F2000FFDFA068D0F8181120692631FAF745FAAA +:103F3000A1682069DC31FAF748FAA168162081F8F7 +:103F40007C0010BD10B56E4C207900071BD5607841 +:103F5000002818D1A068002190F8E400FEF72AFE9E +:103F6000A06890F8E400FE2800D1FFDFA068FE21E1 +:103F700080F8E41090F87F10082904D10221217004 +:103F8000002180F87F1010BD70B55D4D2421002404 +:103F9000A86890F87D20212A05D090F87C20232A5B +:103FA00018D0FFDFA0E590F8122112B990F8132184 +:103FB0002AB180F87D10A86880F8A64094E500F842 +:103FC0007D4F847690F8B1000028F4D00020FEF7F1 +:103FD00099FBF0E790F8122112B990F813212AB159 +:103FE00080F87C10A86880F8A2407DE580F87C40CD +:103FF0000020FEF787FBF5E770B5414C0025A0686F +:10400000D0F8181103884A889A4219D109780429EE +:1040100016D190F87C20002319467030ECF7B2FFDF +:1040200000B9FFDFA06890F8AA10890703D4012126 +:1040300080F87C1004E080F8A250D0F818010570D8 +:10404000A0680023194690F87D207030ECF79AFFA5 +:10405000002802D0A06880F8A65045E5B0F890206E +:10406000B0F88E108A4201D3511A00E000218288F4 +:10407000521D8A4202D3012180F89610704710B574 +:1040800090F8821041B990F87C200023062170300E +:10409000ECF778FF002800D0012010BD70B5114466 +:1040A000174D891D8CB2C078A968012806D040B18F +:1040B000182805D191F8120138B109E0A1F8224180 +:1040C00012E5D1F8180184800EE591F8131191B131 +:1040D000FFF765FE80B1A86890F86400FFF75FFE07 +:1040E00050B1A86890F8121190F86420914203D062 +:1040F00090F8130100B90024A868A0F81041F3E477 +:104100008C01002070B58F4C0829207A6CD2DFE832 +:1041100001F004176464276B6B6458B1F4F7D3F8AB +:10412000F5F7FFF80020A072F4F7B4F9BDE870408D +:10413000F4F758BCF5F717F9BDE87040F1F71FBF69 +:10414000DEF7B6FDF5F752F8D4E90001F1F7F3FC1C +:104150002060A07A401CC0B2A072282824D370BD71 +:10416000A07A0025401EC6B2E0683044F4F700FD96 +:1041700010B9E1687F208855A07A272828BF01253B +:10418000DEF796FDA17A01EB4102C2EB81110844F2 +:104190002946F5F755F8A07A282809D2401CC0B264 +:1041A000A072282828BF70BDBDE87040F4F772B92E +:1041B000207A002818BF00F086F8F4F74BFBF4F7DC +:1041C000F7FBF5F7D0F80120E0725F480078DEF7E2 +:1041D0009BFEBDE87040F1F7D2BE002808BF70BD5D +:1041E000BDE8704000F06FB8FFDF70BD10B5554CF2 +:1041F000207A002804BF0C2010BD00202072E0723D +:10420000607AF2F7F8FA607AF2F761FD607AF1F716 +:104210008CFF00280CBF1F20002010BD002270B5AD +:10422000484C06460D46207A68B12272E272607AE6 +:10423000F2F7E1FA607AF2F74AFD607AF1F775FF7A +:10424000002808BFFFDF4048E560067070BD70B50C +:10425000050007D0A5F5E8503C494C3881429CBF89 +:10426000122070BD374CE068002804BF092070BDE3 +:10427000207A00281CBF0C2070BD3548F1F7FAFEEB +:104280006072202804BF1F2070BDF1F76DFF206011 +:104290001DB12946F1F74FFC2060012065602072B6 +:1042A00000F011F8002070BD2649CA7A002A04BF28 +:1042B000002070471E22027000224270CB684360CB +:1042C000CA7201207047F0B585B0F1F74DFF1D4D62 +:1042D0000746394668682C6800EB80004600204697 +:1042E000F2F73AFCB04206DB6868811B3846F1F70A +:1042F00022FC0446286040F2367621463846F2F722 +:104300002BFCB04204DA31463846F1F714FC04467F +:1043100000208DF8000040F6E210039004208DF894 +:10432000050001208DF8040068460294F2F7CAF8EF +:10433000687A6946F2F743F9002808BFFFDF05B045 +:10434000F0BD000074120020AC010020B5EB3C0071 +:10435000054102002DE9F0410C4612490D68114A51 +:10436000114908321160A0F12001312901D3012047 +:104370000CE0412810D040CC0C4F94E80E0007EB25 +:104380008000241F50F8807C3046B84720600548E4 +:10439000001D0560BDE8F081204601F0EBFCF5E76B +:1043A00006207047100502400100000184630200EE +:1043B00010B55548F2F7FAFF00B1FFDF5248401C34 +:1043C000F2F7F4FF002800D0FFDF10BD2DE9F14F18 +:1043D0004E4E82B0D6F800B001274B48F2F7EEFF00 +:1043E000DFF8248120B9002708F10100F2F7FCFF73 +:1043F000474C00254FF0030901206060C4F80051CC +:10440000C4F80451029931602060DFF808A11BE074 +:10441000DAF80000C00617D50E2000F068F8EFF3B8 +:10442000108010F0010072B600D001200090C4F896 +:104430000493D4F8000120B9D4F8040108B901F0BC +:10444000A3FC009800B962B6D4F8000118B9D4F8FA +:1044500004010028DCD0D4F804010028CCD137B105 +:10446000C6F800B008F10100F2F7A8FF11E008F16A +:104470000100F2F7A3FF0028B6D1C4F80893C4F8EE +:104480000451C4F800510E2000F031F81E48F2F734 +:10449000ABFF0020BDE8FE8F2DE9F0438DB00D4647 +:1044A000064600240DF110090DF1200818E000BFA8 +:1044B00004EB4407102255F827106846E9F7BDFFC2 +:1044C00005EB8707102248467968E9F7B6FF68468A +:1044D000FFF77CFF10224146B868E9F7AEFF641C85 +:1044E000B442E5DB0DB00020BDE8F0836EE70028A4 +:1044F00009DB00F01F02012191404009800000F11A +:10450000E020C0F880127047AD01002004E50040B3 +:1045100000E0004010ED00E0B54900200870704751 +:1045200070B5B44D01232B60B34B1C68002CFCD03C +:10453000002407E00E6806601E68002EFCD0001DF7 +:10454000091D641C9442F5D30020286018680028D7 +:10455000FCD070BD70B5A64E0446A84D3078022838 +:1045600000D0FFDFAC4200D3FFDF7169A44801290E +:1045700003D847F23052944201DD03224271491CB4 +:104580007161291BC1609E49707800F02EF90028E6 +:1045900000D1FFDF70BD70B5954C0D466178884243 +:1045A00000D0FFDF954E082D4BD2DFE805F04A041E +:1045B0001E2D4A4A4A382078022800D0FFDF032007 +:1045C0002070A078012801D020B108E0A06801F097 +:1045D00085F904E004F1080007C8FFF7A1FF0520F2 +:1045E0002070BDE87040F1F7CABCF1F7BDFD01468F +:1045F0006068F2F7B1FAB04202D2616902290BD3C6 +:104600000320F2F7FAFD12E0F1F7AEFD0146606813 +:10461000F2F7A2FAB042F3D2BDE870409AE72078F0 +:1046200002280AD0052806D0FFDF04202070BDE84C +:10463000704000F0D0B8022000E00320F2F7DDFD6A +:10464000F3E7FFDF70BD70B50546F1F78DFD684CEF +:1046500060602078012800D0FFDF694901200870E0 +:104660000020087104208D6048716448C8600220F1 +:104670002070607800F0B9F8002800D1FFDF70BD2D +:1046800010B55B4C207838B90220F2F7CCFD18B990 +:104690000320F2F7C8FD08B1112010BD5948F1F709 +:1046A000E9FC6070202804D00120207000206061A7 +:1046B00010BD032010BD2DE9F0471446054600EB60 +:1046C00084000E46A0F1040801F01BF907464FF0E4 +:1046D000805001694F4306EB8401091FB14201D2AA +:1046E000012100E0002189461CB10069B4EB900F64 +:1046F00002D90920BDE8F0872846DCF7A3FD90B970 +:10470000A84510D3BD4205D2B84503D245EA0600FC +:10471000800701D01020EDE73046DCF793FD10B99B +:10472000B9F1000F01D00F20E4E73748374900689E +:10473000884205D0224631462846FFF7F1FE1AE0AE +:10474000FFF79EFF0028D5D1294800218560C0E9E8 +:1047500003648170F2F7D3FD08B12D4801E04AF2FD +:10476000F87060434FF47A7100F2E730B0FBF1F07B +:104770001830FFF768FF0020BCE770B505464FF022 +:10478000805004696C432046DCF75CFD08B10F20C3 +:1047900070BD01F0B6F8A84201D8102070BD1A48CB +:1047A0001A490068884203D0204601F097F810E0CB +:1047B000FFF766FF0028F1D10D4801218460817068 +:1047C000F2F79DFD08B1134800E013481830FFF7D9 +:1047D0003AFF002070BD10B5054C6078F1F7A5FCDC +:1047E00000B9FFDF0020207010BDF1F7E8BE000027 +:1047F000B001002004E5014000E40140105C0C0021 +:1048000084120020974502005C000020BEBAFECA58 +:1048100050280500645E0100A85B01007E4909681C +:104820000160002070477C4908600020704701212A +:104830008A0720B1012804D042F204007047916732 +:1048400000E0D1670020704774490120086042F2FF +:104850000600704708B50423704A1907103230B1BA +:10486000C1F80433106840F0010010600BE01068DC +:1048700020F001001060C1F808330020C1F80801E1 +:10488000674800680090002008BD011F0B2909D867 +:10489000624910310A6822F01E0242EA40000860B4 +:1048A0000020704742F2050070470F2809D85B4985 +:1048B00010310A6822F4706242EA00200860002089 +:1048C000704742F205007047000100F18040C0F8D7 +:1048D000041900207047000100F18040C0F8081959 +:1048E00000207047000100F18040D0F80009086006 +:1048F00000207047012801D907207047494A52F823 +:10490000200002680A43026000207047012801D994 +:1049100007207047434A52F8200002688A43026029 +:1049200000207047012801D9072070473D4A52F8FE +:104930002000006808600020704702003A494FF0EC +:10494000000003D0012A01D0072070470A60704799 +:10495000020036494FF0000003D0012A01D00720A1 +:1049600070470A60704708B54FF40072510510B1E6 +:10497000C1F8042308E0C1F808230020C1F824018D +:1049800027481C3000680090002008BD08B5802230 +:10499000D10510B1C1F8042308E0C1F808230020B4 +:1049A000C1F81C011E48143000680090002008BDAA +:1049B00008B54FF48072910510B1C1F8042308E0E6 +:1049C000C1F808230020C1F82001154818300068FC +:1049D0000090002008BD10493831096801600020AE +:1049E000704770B54FF080450024C5F80841F2F7D4 +:1049F00092FC10B9F2F799FC28B1C5F82441C5F82A +:104A00001C41C5F820414FF0E020802180F80014BF +:104A10000121C0F8001170BD0004004000050040F5 +:104A2000080100404864020078050040800500400D +:104A30006249634B0A6863499A42096801D1C1F32C +:104A400010010160002070475C495D4B0A685D49B8 +:104A5000091D9A4201D1C0F3100008600020704780 +:104A60005649574B0A68574908319A4201D1C0F359 +:104A7000100008600020704730B5504B504D1C6846 +:104A800042F20803AC4202D0142802D203E01128FB +:104A900001D3184630BDC3004B481844C0F8101568 +:104AA000C0F81425002030BD4449454B0A6842F245 +:104AB00009019A4202D0062802D203E0042801D359 +:104AC00008467047404A012142F8301000207047E4 +:104AD0003A493B4B0A6842F209019A4202D0062841 +:104AE00002D203E0042801D308467047364A012168 +:104AF00002EBC00041600020704770B52F4A304E75 +:104B0000314C156842F2090304EB8002B54204D02F +:104B1000062804D2C2F8001807E0042801D318467A +:104B200070BDC1F31000C2F80008002070BD70B560 +:104B3000224A234E244C156842F2090304EB8002FA +:104B4000B54204D0062804D2D2F8000807E00428B1 +:104B500001D3184670BDD2F80008C0F310000860F9 +:104B6000002070BD174910B50831184808601120A1 +:104B7000154A002102EBC003C3F81015C3F8141541 +:104B8000401C1428F6D3002006E0042804D302EBCE +:104B90008003C3F8001807E002EB8003D3F8004855 +:104BA000C4F31004C3F80048401C0628EDD310BD20 +:104BB0000449064808310860704700005C00002086 +:104BC000BEBAFECA00F5014000F001400000FEFF41 +:104BD000814B1B6803B19847BFF34F8F7F48016833 +:104BE0007F4A01F4E06111430160BFF34F8F00BFC2 +:104BF000FDE710B5EFF3108010F0010F72B601D091 +:104C0000012400E0002400F0DDF850B1DCF7BFFB28 +:104C1000F1F755F8F2F793FAF2F7BEFF7149002069 +:104C2000086004B962B6002010BD2DE9F0410C46C1 +:104C30000546EFF3108010F0010F72B601D0012687 +:104C400000E0002600F0BEF820B106B962B60820E8 +:104C5000BDE8F08101F01EF9DCF79DFB0246002063 +:104C600001234709BF0007F1E02700F01F01D7F833 +:104C70000071CF40F9071BD0202803D222FA00F19F +:104C8000C90727D141B2002904DB01F1E02191F8E5 +:104C9000001405E001F00F0101F1E02191F8141D6D +:104CA0004909082916D203FA01F717F0EC0F11D0C1 +:104CB000401C6428D5D3F2F74DFF4B4A4B490020E6 +:104CC000F2F790FF47494A4808602046DCF7C1FAEE +:104CD00060B904E006B962B641F20100B8E73E48A7 +:104CE00004602DB12846DCF701FB18B1102428E040 +:104CF000404D19E02878022802D94FF4805420E072 +:104D000007240028687801D0D8B908E0C8B1202865 +:104D100017D8A878212814D8012812D001E0A87843 +:104D200078B9E8780B280CD8DCF735FB2946F2F780 +:104D3000ECF9F0F783FF00F017FE2846DCF7F4FAF1 +:104D4000044606B962B61CB1FFF753FF20467FE761 +:104D500000207DE710B5044600F034F800B10120D2 +:104D60002070002010BD244908600020704770B5F5 +:104D70000C4622490D682149214E08310E60102849 +:104D800007D011280CD012280FD0132811D00120E1 +:104D900013E0D4E90001FFF748FF354620600DE03D +:104DA000FFF727FF0025206008E02068FFF7D2FF0B +:104DB00003E0114920680860002020600F48001DB2 +:104DC000056070BD07480A490068884201D101208A +:104DD0007047002070470000C80100200CED00E083 +:104DE0000400FA055C0000204814002000000020A8 +:104DF000BEBAFECA50640200040000201005024042 +:104E0000010000017D49C0B20860704700B57C49CF +:104E1000012808BF03200CD0022808BF042008D0B6 +:104E2000042808BF062004D0082816BFFFDF05208D +:104E300000BD086000BD70B505460C46164610461C +:104E4000F3F7D2F8022C08BF4FF47A7105D0012C89 +:104E50000CBF4FF4C86140F6340144183046F3F7F4 +:104E60003CF9204449F6797108444FF47A71B0FB5B +:104E7000F1F0281A70BD70B505460C460846F4F7E7 +:104E80002FFA022C08BF40F24C4105D0012C0CBF78 +:104E900040F634014FF4AF5149F6CA62511A084442 +:104EA0004FF47A7100F2E140B0FBF1F0281A801E55 +:104EB00070BD70B5064615460C460846F4F710FA64 +:104EC000022D08BF4FF47A7105D0012D0CBF4FF4AD +:104ED000C86140F63401022C08BF40F24C4205D0B4 +:104EE000012C0CBF40F634024FF4AF52891A08442B +:104EF00049F6FC6108444FF47A71B0FBF1F0301AC6 +:104F000070BD70B504460E460846F3F76DF80546C9 +:104F10003046F3F7E2F828444AF2AB3108444FF444 +:104F20007A71B0FBF1F0201A801E70BD2DE9F041BE +:104F300007461E460D4614461046082A16BF04288A +:104F40004EF62830F3F750F807EB4701C1EBC711D5 +:104F500000EBC100022D08BF40F24C4105D0012DED +:104F60000CBF40F634014FF4AF5147182846F4F710 +:104F7000B7F9381A4FF47A7100F6B730B0FBF1F593 +:104F80002046F3F7B9F828443044401DBDE8F081CD +:104F900070B5054614460E460846F3F725F805EBAE +:104FA0004502C2EBC512C0EBC2053046F3F795F8D7 +:104FB0002D1A2046082C16BF04284EF62830F3F789 +:104FC00013F828444FF47A7100F6B730B0FBF1F5CE +:104FD0002046F3F791F82844401D70BD0949082880 +:104FE00018BF0428086803BF20F46C5040F4444004 +:104FF00040F0004020F00040086070470C15004071 +:105000001015004040170040F0B585B00C4605462D +:10501000F9F73EF907466E78204603A96A46EEF78F +:1050200002FD81198EB258B1012F02D0032005B0C4 +:10503000F0BD204604AA0399EEF717FC049D01E099 +:10504000022F0FD1ED1C042E0FD32888BDF80010BD +:10505000001D80B2884201D8864202D14FF0000084 +:10506000E5E702D34FF00200E1E74FF00100DEE791 +:10507000FA48C078FF2814BF0120002070472DE9AE +:10508000F041F74C0746160060680D4603D0F9F76B +:1050900069F8A0B121E0F9F765F8D8B96068F9F7C7 +:1050A00061F8D0B915F00C0F17D06068C17811F015 +:1050B0003F0F1CBF007910F0100F0ED00AE0022E37 +:1050C00008D0E6481FB1807DFF2806D002E0C078F6 +:1050D000FF2802D00120BDE8F0810020BDE8F0816A +:1050E0000A4601460120CAE710B5DC4C1D2200210A +:1050F000A01CE9F7CCF97F206077FF202074E070D6 +:10510000A075A08920F060002030A08100202070D0 +:1051100010BD70B5D249486001200870D248D1490D +:10512000002541600570CD4C1D222946A01CE9F7E1 +:10513000AEF97F206077FF202074E070A075A08911 +:1051400020F060002030A081257070BD2DE9F0476F +:10515000C24C06462078C24F4FF0010907F10808FB +:10516000002520B13878D0B998F80000B8B198F887 +:10517000000068B387F80090D8F804103C2239B3D7 +:105180007570301DE9F759F90520307086F80490E4 +:105190003878002818BF88F8005005D015E03D7019 +:1051A000A11C4FF48E72EAE71D220021A01CE9F732 +:1051B0006EF97F206077FF202074E070A075A089D1 +:1051C00020F060002030A08125700120BDE8F0872C +:1051D0000020BDE8F087A148007800280CBF01201E +:1051E000002070470A460146002048E710B510B17C +:1051F000022810D014E09A4C6068F8F7B3FF78B931 +:105200006068C17811F03F0F1CBF007910F0100FDB +:1052100006D1012010BD9148007B10F0080FF8D195 +:10522000002010BD2DE9FF4F81B08C4D8346DDE994 +:105230000F042978DDF838A09846164600291CBFCF +:1052400005B0BDE8F08F8849097800291CBF05B07A +:10525000BDE8F08FE872B4B1012E08BF012708D075 +:10526000022E08BF022704D0042E16BF082E0327E3 +:10527000FFDFEF7385F81E804FF00008784F8CB188 +:10528000022C1DD020E0012E08BF012708D0022EDD +:1052900008BF022704D0042E16BF082E0327FFDF05 +:1052A000AF73E7E77868F8F75DFF68B97868C178A9 +:1052B00011F03F0F1CBF007910F0100F04D110E067 +:1052C000287B10F0080F0CD14FF003017868F8F735 +:1052D000FDFD30B14178090929740088C0F30B0045 +:1052E0006882CDF800807868F8F73CFF0146012815 +:1052F000BDF8000005F102090CBF40F0010020F0EC +:105300000100ADF8000099F80A2012F0020F4ED10A +:10531000022918BF20F0020049D000BFADF80000FC +:1053200010F0020F04D0002908BF40F0080801D097 +:1053300020F00808ADF800807868C17811F03F0FC0 +:105340001CBF007910F0020F0CD0314622464FF0FE +:105350000100FFF794FE002804BF48F00400ADF8F8 +:10536000000006D099F80A00800860F38208ADF8C2 +:10537000008099F80A004109BDF8000061F3461069 +:10538000ADF8000080B20090BDF80000A8810421B3 +:105390007868F8F79BFD002804BFA88920F060001A +:1053A0000CD0B0F80100C004C00C03D007E040F0FE +:1053B0000200B3E7A88920F060004030A8815CB902 +:1053C00016F00C0F08D07868C17811F03F0F1CBFA1 +:1053D000007910F0100F0DD17868C17811F03F0FEF +:1053E00008D0017911F0400F04D00621F8F76EFDC6 +:1053F00000786877314622460020FFF740FE60BB08 +:105400007968C87810F03F0F3FD0087910F0010F8D +:105410003BD0504605F1040905F10308BAF1FF0F2E +:105420000DD04A464146F8F781FA002808BFFFDF51 +:1054300098F8000040F0020088F8000025E00846D7 +:10544000F8F7DBFC88F800007868F8F7ADFC07286F +:105450000CD249467868F8F7B2FC16E094120020A6 +:10546000CC010020D2120020D40100207868F8F787 +:105470009BFC072809D100217868F8F727FD01680F +:10548000C9F800108088A9F804003146224601209E +:10549000FFF7F5FD80BB7868C17811F03F0F2BD086 +:1054A000017911F0020F27D005F1170605F1160852 +:1054B000BBF1020F18BFBBF1030F08D0F8F774FC63 +:1054C00007280AD231467868F8F787FC12E002987C +:1054D000016831608088B0800CE07868F8F764FC7F +:1054E000072807D101217868F8F7F0FC01683160DE +:1054F0008088B08088F800B0002C04BF05B0BDE8FB +:10550000F08F7868F8F72EFE022804BF05B0BDE8DA +:10551000F08F05F11F047868F8F76DFEAB7AC3F1E0 +:10552000FF01884228BF084605D9A98921F06001FA +:1055300001F14001A981C2B203EB04017868F8F7D8 +:1055400062FEA97A0844A87205B0BDE8F08FB048A1 +:105550000178002918BF704701220270007B10F00B +:10556000080F14BF07200620FCF75FBEA848C17BC8 +:10557000002908BF70470122818921F06001403174 +:1055800081810378002B18BF7047027011F0080F5B +:1055900014BF07200620FCF748BE2DE9FF5F9C4F93 +:1055A000DDF838B0914638780E4600281CBF04B0AC +:1055B000BDE8F09FBC1C1D2200212046E8F767FFD4 +:1055C000944D4FF0010A84F800A06868F8F7ECFBEE +:1055D00018B3012826D0022829D0062818BFFFDFDB +:1055E0002AD000BF04F11D016868F8F726FC20727C +:1055F000484604F1020904F10108FF2821D04A4677 +:105600004146F8F793F9002808BFFFDF98F800003B +:1056100040F0020088F8000031E0608940F013009B +:105620006081DFE7608940F015006081E0E7608914 +:1056300040F010006081D5E7608940F01200608181 +:10564000D0E76868F8F7D9FB88F800006868F8F7D1 +:10565000ABFB072804D249466868F8F7B0FB0EE0B8 +:105660006868F8F7A1FB072809D100216868F8F7F6 +:105670002DFC0168C9F800108088A9F8040084F89E +:1056800009B084F80CA000206073FF20A073A17AF9 +:1056900011F0040F08BF20752AD004F1150804F199 +:1056A0001409022E18BF032E09D06868F8F77CFB96 +:1056B00007280CD241466868F8F78FFB16E000987F +:1056C0000168C8F800108088A8F804000EE0686837 +:1056D000F8F76AFB072809D101216868F8F7F6FB9B +:1056E0000168C8F800108088A8F8040089F80060F4 +:1056F0007F20E0760398207787F800A004B006208A +:10570000BDE8F05FFCF791BD2DE9FF5F424F814698 +:105710009A4638788B4600281CBF04B0BDE8F09F3D +:105720003B48017831B1007B10F0100F04BF04B08A +:10573000BDE8F09F1D227C6800212046E8F7A7FE07 +:1057400048464FF00108661C324D84F8008004F191 +:105750000209FF280BD04A463146F8F7E7F800283F +:1057600008BFFFDF307840F0020030701CE068684E +:10577000F8F743FB30706868F8F716FB072804D287 +:1057800049466868F8F71BFB0EE06868F8F70CFB01 +:10579000072809D100216868F8F798FB0168C9F863 +:1057A00000108088A9F8040004F11D016868F8F76A +:1057B00044FB207284F809A060896BF3000040F07C +:1057C0001A00608184F80C8000206073FF20A073B1 +:1057D00020757F20E0760298207787F8008004B05B +:1057E0000720BDE8F05FFCF720BD094A137C834227 +:1057F00005BF508A88420020012070470448007B82 +:10580000C0F3411002280CBF0120002070470000A7 +:1058100094120020CC010020D4010020C2790D2375 +:1058200041B342BB8188012904D94908818004BF62 +:10583000012282800168012918BF002930D0016847 +:105840006FEA0101C1EBC10202EB011281796FEA3B +:10585000010101EB8103C3EB811111444FEA914235 +:1058600001608188B2FBF1F301FB132181714FF0DC +:10587000010102E01AB14FF00001C1717047818847 +:10588000FF2908D24FF6FF7202EA41018180FF2909 +:1058900084BFFF2282800168012918BF0029CED170 +:1058A0000360CCE7817931B1491E11F0FF018171AC +:1058B0001CBF002070470120704710B50121C17145 +:1058C0008171818004460421F1F7E8FD002818BFAA +:1058D00010BD2068401C206010BD00000B4A022152 +:1058E00011600B490B68002BFCD0084B1B1D186086 +:1058F00008680028FCD00020106008680028FCD050 +:1059000070474FF0805040697047000004E5014047 +:1059100000E4014002000B464FF00000014620D099 +:10592000012A04D0022A04D0032A0DD103E0012069 +:1059300002E0022015E00320072B05D2DFE803F088 +:105940000406080A0C0E100007207047012108E029 +:10595000022106E0032104E0042102E0052100E029 +:105960000621F0F7A4BB0000E24805218170002168 +:10597000017041707047E0490A78012A05D0CA6871 +:105980001044C8604038F1F7B4B88A6810448860A1 +:10599000F8E7002819D00378D849D94A13B1012B68 +:1059A0000ED011E00379012B00D06BB943790BB114 +:1059B000012B09D18368643B8B4205D2C0680EE09D +:1059C0000379012B02D00BB10020704743790BB152 +:1059D000012BF9D1C368643B8B42F5D280689042B9 +:1059E000F2D801207047C44901220A70027972B1CD +:1059F00000220A71427962B104224A7182685232ED +:105A00008A60C068C860BB49022088707047032262 +:105A1000EFE70322F1E770B5B74D04460020287088 +:105A2000207988B100202871607978B10420B14EC6 +:105A30006871A168F068F0F77EF8A860E0685230FD +:105A4000E8600320B07070BD0120ECE70320EEE7B2 +:105A50002DE9F04105460226F0F777FF006800B116 +:105A6000FFDFA44C01273DB12878B8B1012805D04B +:105A7000022811D0032814D027710DE06868C828C7 +:105A800008D30421F1F79BF820B16868FFF773FF92 +:105A9000012603E0002601E000F014F93046BDE8DD +:105AA000F08120780028F7D16868FFF772FF00289E +:105AB000E2D06868017879B1A078042800D0FFDFCF +:105AC00001216868FFF7A7FF8B49E07800F003F930 +:105AD0000028E1D1FFDFDFE7FFF785FF6770DBE735 +:105AE0002DE9F041834C0F46E178884200D0FFDF7A +:105AF00000250126082F7DD2DFE807F0040B2828B7 +:105B00003D434F57A0780328C9D00228C7D0FFDFF4 +:105B1000C5E7A078032802D0022800D0FFDF0420C8 +:105B2000A07025712078B8BB0020FFF724FF7248D1 +:105B30000178012906D08068E06000F0EDF820616E +:105B4000002023E0E078F0F734FCF5E7A0780328A4 +:105B500002D0022800D0FFDF207880BB022F08D0BF +:105B60005FF00500F1F749FBA078032840D0A5704D +:105B700095E70420F6E7A078042800D0FFDF022094 +:105B800004E0A078042800D0FFDF0120A168884746 +:105B9000FFF75EFF054633E003E0A078042800D05D +:105BA000FFDFBDE8F04100F08DB8A078042804D0F4 +:105BB000617809B1022800D0FFDF207818B1BDE874 +:105BC000F04100F08AB8207920B10620F1F715FBEA +:105BD00025710DE0607840B14749E07800F07BF82E +:105BE00000B9FFDF65705AE704E00720F1F705FB15 +:105BF000A67054E7FFDF52E73DB1012D03D0FFDF70 +:105C0000022DF9D14BE70420C0E70320BEE770B5B1 +:105C1000050004D0374CA078052806D101E01020FB +:105C200070BD0820F1F7FFFA08B1112070BD3548AA +:105C3000F0F720FAE070202806D00121F1F7DCF817 +:105C40000020A560A07070BD032070BD294810B56C +:105C5000017809B1112010BD8178052906D00129EC +:105C600006D029B101210170002010BD0F2010BD08 +:105C700000F033F8F8E770B51E4C0546A07808B17F +:105C8000012809D155B12846FFF783FE40B1287895 +:105C900040B1A078012809D00F2070BD102070BD40 +:105CA000072070BD2846FFF79EFE03E0002128462E +:105CB000FFF7B1FE1049E07800F00DF800B9FFDF02 +:105CC000002070BD0B4810B5006900F01DF8BDE85C +:105CD0001040F0F754B9F0F772BC064810B5C07820 +:105CE000F0F723FA00B9FFDF0820F1F786FABDE8E4 +:105CF000104039E6DC010020B41300203D8601008D +:105D0000FF1FA107E15A02000C490A6848F202137A +:105D10009A4302430A607047084A116848F2021326 +:105D200001EA03009943116070470246044B1020BA +:105D30001344FC2B01D8116000207047C8060240B4 +:105D40000018FEBF1EF0040F0CBFEFF30880EFF346 +:105D50000980014A10470000FF7B010001B41EB416 +:105D600000B5F1F76DFC01B40198864601BC01B0A5 +:105D70001EBD00008269034981614FF0010010449B +:105D8000704700005D5D02000FF20C0000F10000A2 +:105D9000694641F8080C20BF70470000FEDF184933 +:105DA0000978F9B90420714608421BD10699154AB1 +:105DB000914217DC0699022914DB02394878DF2862 +:105DC00010D10878FE2807D0FF280BD14FF0010032 +:105DD0004FF000020C4B184741F201000099019A64 +:105DE000094B1847094B002B02D01B68DB6818478A +:105DF0004FF0FF3071464FF00002034B1847000090 +:105E000028ED00E000700200D14B020004000020E9 +:105E1000174818497047FFF7FBFFDBF7CFF900BDC4 +:105E2000154816490968884203D1154A13605B6812 +:105E3000184700BD20BFFDE70F4810490968884298 +:105E400010D1104B18684FF0FF318842F2D080F328 +:105E500008884FF02021884204DD0B4802680321A6 +:105E60000A4302600948804709488047FFDF000075 +:105E7000C8130020C81300200010000000000020FC +:105E8000040000200070020014090040B92F000037 +:105E9000215E0200F0B44046494652465B460FB4CC +:105EA00002A0013001B50648004700BF01BC86468C +:105EB0000FBC8046894692469B46F0BC7047000066 +:105EC0000911000004207146084202D0EFF3098155 +:105ED00001E0EFF30881886902380078102813DBAD +:105EE00020280FDB2C280BDB0A4A12680A4B9A4247 +:105EF00003D1602804DB094A10470220086070477C +:105F0000074A1047074A1047074A12682C3212689E +:105F1000104700005C000020BEBAFECA9B130000C0 +:105F2000554302006F4D0200040000200D4B0E4946 +:105F300008470E4B0C4908470D4B0B4908470D4BC2 +:105F4000094908470C4B084908470C4B06490847C4 +:105F50000B4B054908470B4B034908470A4B0249BD +:105F60000847000041BF000079C10000792D000002 +:105F7000F32B0000812B0000012E0000B71300005E +:105F80003F2900007D2F0000455D020000210160D7 +:105F90004160017270470A6802600B7903717047B3 +:105FA00089970000FF9800005B9A0000C59A0000E6 +:105FB000FF9A0000339B0000659B00009D9B000042 +:105FC0003D9C00007D980000859A0000331200007F +:105FD0000744000053440000B94400004745000056 +:105FE0006146000037470000694700004148000053 +:105FF000DB4800002F490000154A0000354A000028 +:10600000AD160000D1160000F11500004D1600007D +:10601000031700009717000003610000C36200002F +:10602000A1660000BB67000043680000C168000073 +:10603000256900004D6A00001D6B0000896B00009F +:10604000574A00005D4A0000674A0000CF4A00003E +:10605000FB4A0000B74C0000E14C0000194D000065 +:10606000834D00006D4E0000834E00007744000019 +:10607000974E0000B94E0000FF4E000033120000A2 +:10608000331200003312000033120000C12500005B +:1060900047260000632600007F2600000D28000030 +:1060A000A9260000B3260000F526000017270000EF +:1060B000F3270000352800003312000033120000DF +:1060C00097840000B7840000B9840000FD840000BC +:1060D0002B8500001B860000A7860000BB86000001 +:1060E000098700001F880000C1890000E98A0000BC +:1060F0003D740000018B00003312000033120000D9 +:10610000EBB700004DB90000A7B9000021BA0000AC +:10611000CDBA0000010000000000000010011001D5 +:106120003A0200001A020000020004050600000006 +:1061300007111102FFFFFFFF0000FFFFF3B3000094 +:10614000273D0000532100008774000001900000EB +:1061500000000000BF9200009B920000AD92000082 +:10616000000002000000000000020000000000002B +:1061700000010000000000004382000023820000B4 +:10618000918200002D250000EF2400000F25000063 +:10619000DBAA000007AB00000FAD0000FD590000B6 +:1061A000B182000000000000E18200007B250000B9 +:1061B000000000000000000000000000F1AB000043 +:1061C00000000000915A00000300000001555555E1 +:1061D000D6BE898E00006606660C661200000A03B1 +:1061E000AE055208000056044608360CC7FD0000F4 +:1061F0005BFF0000A1FB0000C3FD0000A7A8010099 +:106200009B040100AAAED7AB15412010000000008E +:10621000900A0000900A00007B5700007B570000A6 +:10622000E143000053B200000B7700006320000040 +:10623000BD3A020063BD0100BD570000BD5700001C +:1062400005440000E5B2000093770000D72000006D +:10625000EB3A020079BD0100700170014000380086 +:106260005C0024006801200200000300656C746279 +:10627000000000000000000000000000000000001E +:106280008700000000000000000000000000000087 +:10629000BE83605ADB0B376038A5F5AA9183886C02 +:1062A000010000007746010049550100000000018F +:1062B0000206030405000000070000FB349B5F801A +:1062C000000080001000000000000000000000003E +:1062D000060000000A000000320000007300000009 +:1062E000B4000000F401FA00960064004B00320094 +:1062F0001E0014000A000500020001000049000011 +:1063000000000000D7CF0100E9D1010025D1010034 +:10631000EBCF0100000000008FD40100000101025A +:10632000010202030C0802170D0101020909010113 +:1063300006020918180301010909030305000000FA +:10634000555555252627D6BE898E00002BFB01000A +:1063500003F7010049FA01003FF20100BB220200ED +:10636000B7FB0100F401FA00960064004B00320014 +:106370001E0014000A00050002000100254900006B +:1063800000000000314A0200494A0200614A02004E +:10639000794A0200A94A0200D14A0200FB4A0200DF +:1063A0002F4B02007B470200B7460200A1430200C8 +:1063B0002B5D0200AD730100BD730100E9730100A4 +:1063C000BB740100C3740100D57401002F480200A2 +:1063D000494802001D4802002748020055480200B3 +:1063E0008B480200AB480200C9480200D7480200AF +:1063F000E5480200F54802000D4902002549020067 +:106400003B4902005149020000000000DFBC0000CF +:1064100035BD00004BBD000015590200CD43020000 +:10642000994402000F5C02004D5C0200775C0200A0 +:106430009D710100FD760100674902008D4902004F +:10644000B1490200D74902001C0500402005004068 +:10645000001002007464020008000020E80100003F +:106460004411000098640200F0010020D8110000DF +:10647000A011000001181348140244200B440C061C +:106480004813770B1B2034041ABA0401A40213101A +:08649000327F0B744411C000BF +:00000001FF diff --git a/bin/setup-python-for-esp-debug.sh b/bin/setup-python-for-esp-debug.sh new file mode 100644 index 0000000000..edba43e72b --- /dev/null +++ b/bin/setup-python-for-esp-debug.sh @@ -0,0 +1,12 @@ +# shellcheck shell=bash +# (this minor script is actually shell agnostic, and is intended to be sourced rather than run in a subshell) + +# This is a little script you can source if you want to make ESP debugging work on a modern (24.04) ubuntu machine +# It assumes you have built and installed python 2.7 from source with: +# ./configure --enable-optimizations --enable-shared --enable-unicode=ucs4 +# sudo make clean +# make +# sudo make altinstall + +export LD_LIBRARY_PATH=$HOME/packages/python-2.7.18/ +export PYTHON_HOME=/usr/local/lib/python2.7/ diff --git a/boards/wio-sdk-wm1110.json b/boards/wio-sdk-wm1110.json index 9db60e2036..f45b030d1f 100644 --- a/boards/wio-sdk-wm1110.json +++ b/boards/wio-sdk-wm1110.json @@ -27,7 +27,7 @@ "jlink_device": "nRF52840_xxAA", "svd_path": "nrf52840.svd" }, - "frameworks": ["arduino"], + "frameworks": ["arduino", "freertos"], "name": "Seeed WIO WM1110", "upload": { "maximum_ram_size": 248832, diff --git a/boards/wio-tracker-wm1110.json b/boards/wio-tracker-wm1110.json index b4ab8db118..37a9186abb 100644 --- a/boards/wio-tracker-wm1110.json +++ b/boards/wio-tracker-wm1110.json @@ -23,7 +23,7 @@ "sd_flags": "-DS140", "sd_name": "s140", "sd_version": "7.3.0", - "sd_fwid": "0x00B6" + "sd_fwid": "0x0123" }, "bootloader": { "settings_addr": "0xFF000" diff --git a/boards/wiscore_rak4631.json b/boards/wiscore_rak4631.json index 6dec3f7cb4..c783f33a69 100644 --- a/boards/wiscore_rak4631.json +++ b/boards/wiscore_rak4631.json @@ -35,7 +35,7 @@ "svd_path": "nrf52840.svd", "openocd_target": "nrf52840-mdk-rs" }, - "frameworks": ["arduino"], + "frameworks": ["arduino", "freertos"], "name": "WisCore RAK4631 Board", "upload": { "maximum_ram_size": 248832, diff --git a/platformio.ini b/platformio.ini index 23ff53a102..bcdcc0034b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -77,10 +77,11 @@ build_flags = -Wno-missing-field-initializers -DMESHTASTIC_EXCLUDE_DROPZONE=1 monitor_speed = 115200 +monitor_filters = direct lib_deps = jgromes/RadioLib@~6.6.0 - https://github.com/meshtastic/esp8266-oled-ssd1306.git#2b40affbe7f7dc63b6c00fa88e7e12ed1f8e1719 ; ESP8266_SSD1306 + https://github.com/meshtastic/esp8266-oled-ssd1306.git#e16cee124fe26490cb14880c679321ad8ac89c95 ; ESP8266_SSD1306 mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4 @@ -150,5 +151,4 @@ lib_deps = mprograms/QMC5883LCompass@^1.2.0 - https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee - + https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee \ No newline at end of file diff --git a/protobufs b/protobufs index 1c3029f286..1198b7dbab 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 1c3029f2868e5fc49809fd378f6c0c66aee0eaf4 +Subproject commit 1198b7dbabf9768cb0143d2897707b4c7a51a5da diff --git a/pyocd.yaml b/pyocd.yaml new file mode 100644 index 0000000000..84bd9336b9 --- /dev/null +++ b/pyocd.yaml @@ -0,0 +1,7 @@ +# This is a config file to control pyocd ICE debugger probe options (only used for NRF52 targets with hardware debugging connections) +# for more info see FIXMEURL + +# console or telnet +semihost_console_type: telnet +enable_semihosting: True +telnet_port: 4444 diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h index f45511cca3..c2910007e3 100644 --- a/src/AccelerometerThread.h +++ b/src/AccelerometerThread.h @@ -16,6 +16,8 @@ #include #ifdef RAK_4631 #include "Fusion/Fusion.h" +#include "graphics/Screen.h" +#include "graphics/ScreenFonts.h" #include #endif @@ -101,7 +103,11 @@ class AccelerometerThread : public concurrency::OSThread bmx160.getAllData(&magAccel, NULL, &gAccel); // expirimental calibrate routine. Limited to between 10 and 30 seconds after boot - if (millis() > 10 * 1000 && millis() < 30 * 1000) { + if (millis() > 12 * 1000 && millis() < 30 * 1000) { + if (!showingScreen) { + showingScreen = true; + screen->startAlert((FrameCallback)drawFrameCalibration); + } if (magAccel.x > highestX) highestX = magAccel.x; if (magAccel.x < lowestX) @@ -114,6 +120,9 @@ class AccelerometerThread : public concurrency::OSThread highestZ = magAccel.z; if (magAccel.z < lowestZ) lowestZ = magAccel.z; + } else if (showingScreen && millis() >= 30 * 1000) { + showingScreen = false; + screen->endAlert(); } int highestRealX = highestX - (highestX + lowestX) / 2; @@ -255,11 +264,34 @@ class AccelerometerThread : public concurrency::OSThread Adafruit_LIS3DH lis; Adafruit_LSM6DS3TRC lsm; SensorBMA423 bmaSensor; + bool BMA_IRQ = false; #ifdef RAK_4631 + bool showingScreen = false; RAK_BMX160 bmx160; float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0; + + static void drawFrameCalibration(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) + { + int x_offset = display->width() / 2; + int y_offset = display->height() <= 80 ? 0 : 32; + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(FONT_MEDIUM); + display->drawString(x, y, "Calibrating\nCompass"); + int16_t compassX = 0, compassY = 0; + uint16_t compassDiam = graphics::Screen::getCompassDiam(display->getWidth(), display->getHeight()); + + // coordinates for the center of the compass/circle + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { + compassX = x + display->getWidth() - compassDiam / 2 - 5; + compassY = y + display->getHeight() / 2; + } else { + compassX = x + display->getWidth() - compassDiam / 2 - 5; + compassY = y + FONT_HEIGHT_SMALL + (display->getHeight() - FONT_HEIGHT_SMALL) / 2; + } + display->drawCircle(compassX, compassY, compassDiam / 2); + screen->drawCompassNorth(display, compassX, compassY, screen->getHeading() * PI / 180); + } #endif - bool BMA_IRQ = false; }; #endif \ No newline at end of file diff --git a/src/BluetoothCommon.cpp b/src/BluetoothCommon.cpp index 53faae997c..d9502e4f51 100644 --- a/src/BluetoothCommon.cpp +++ b/src/BluetoothCommon.cpp @@ -10,4 +10,8 @@ const uint8_t TORADIO_UUID_16[16u] = {0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, const uint8_t FROMRADIO_UUID_16[16u] = {0x02, 0x00, 0x12, 0xac, 0x42, 0x02, 0x78, 0xb8, 0xed, 0x11, 0x93, 0x49, 0x9e, 0xe6, 0x55, 0x2c}; const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6, - 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed}; \ No newline at end of file + 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed}; +const uint8_t LEGACY_LOGRADIO_UUID_16[16u] = {0xe2, 0xf2, 0x1e, 0xbe, 0xc5, 0x15, 0xcf, 0xaa, + 0x6b, 0x43, 0xfa, 0x78, 0x38, 0xd2, 0x6f, 0x6c}; +const uint8_t LOGRADIO_UUID_16[16u] = {0x47, 0x95, 0xDF, 0x8C, 0xDE, 0xE9, 0x44, 0x99, + 0x23, 0x44, 0xE6, 0x06, 0x49, 0x6E, 0x3D, 0x5A}; \ No newline at end of file diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h index 586ffaa3c1..440d138441 100644 --- a/src/BluetoothCommon.h +++ b/src/BluetoothCommon.h @@ -11,10 +11,12 @@ #define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7" #define FROMRADIO_UUID "2c55e69e-4993-11ed-b878-0242ac120002" #define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453" +#define LEGACY_LOGRADIO_UUID "6c6fd238-78fa-436b-aacf-15c5be1ef2e2" +#define LOGRADIO_UUID "5a3d6e49-06e6-4423-9944-e9de8cdf9547" // NRF52 wants these constants as byte arrays // Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER -extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[]; +extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[], LOGRADIO_UUID_16[]; /// Given a level between 0-100, update the BLE attribute void updateBatteryLevel(uint8_t level); diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index dc062fce46..a81518f313 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -187,8 +187,9 @@ int32_t ButtonThread::runOnce() case BUTTON_EVENT_LONG_PRESSED: { LOG_BUTTON("Long press!\n"); powerFSM.trigger(EVENT_PRESS); - if (screen) - screen->startShutdownScreen(); + if (screen) { + screen->startAlert("Shutting down..."); + } playBeep(); break; } diff --git a/src/DebugConfiguration.cpp b/src/DebugConfiguration.cpp index 9df402e77b..d9ecd9fe39 100644 --- a/src/DebugConfiguration.cpp +++ b/src/DebugConfiguration.cpp @@ -26,7 +26,7 @@ SOFTWARE.*/ #include "DebugConfiguration.h" -#if HAS_WIFI || HAS_ETHERNET +#if HAS_NETWORKING Syslog::Syslog(UDP &client) { diff --git a/src/DebugConfiguration.h b/src/DebugConfiguration.h index ca908197ed..ebe9da8d44 100644 --- a/src/DebugConfiguration.h +++ b/src/DebugConfiguration.h @@ -1,5 +1,6 @@ -#ifndef SYSLOG_H -#define SYSLOG_H +#pragma once + +#include "configuration.h" // DEBUG LED #ifndef LED_INVERTED @@ -25,6 +26,14 @@ #include "SerialConsole.h" +// If defined we will include support for ARM ICE "semihosting" for a virtual +// console over the JTAG port (to replace the normal serial port) +// Note: Normally this flag is passed into the gcc commandline by platformio.ini. +// for an example see env:rak4631_dap. +// #ifndef USE_SEMIHOSTING +// #define USE_SEMIHOSTING +// #endif + #define DEBUG_PORT (*console) // Serial debug port #ifdef USE_SEGGER @@ -117,7 +126,7 @@ #include #endif // HAS_WIFI -#if HAS_WIFI || HAS_ETHERNET +#if HAS_NETWORKING class Syslog { @@ -152,6 +161,4 @@ class Syslog bool vlogf(uint16_t pri, const char *appName, const char *fmt, va_list args) __attribute__((format(printf, 3, 0))); }; -#endif // HAS_ETHERNET || HAS_WIFI - -#endif // SYSLOG_H \ No newline at end of file +#endif // HAS_ETHERNET || HAS_WIFI \ No newline at end of file diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index 96aad1a9a4..7d3788c4d9 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -84,6 +84,58 @@ bool renameFile(const char *pathFrom, const char *pathTo) #endif } +#include + +/** + * @brief Get the list of files in a directory. + * + * This function returns a list of files in a directory. The list includes the full path of each file. + * + * @param dirname The name of the directory. + * @param levels The number of levels of subdirectories to list. + * @return A vector of strings containing the full path of each file in the directory. + */ +std::vector getFiles(const char *dirname, uint8_t levels) +{ + std::vector filenames = {}; +#ifdef FSCom + File root = FSCom.open(dirname, FILE_O_READ); + if (!root) + return filenames; + if (!root.isDirectory()) + return filenames; + + File file = root.openNextFile(); + while (file) { + if (file.isDirectory() && !String(file.name()).endsWith(".")) { + if (levels) { +#ifdef ARCH_ESP32 + std::vector subDirFilenames = getFiles(file.path(), levels - 1); +#else + std::vector subDirFilenames = getFiles(file.name(), levels - 1); +#endif + filenames.insert(filenames.end(), subDirFilenames.begin(), subDirFilenames.end()); + file.close(); + } + } else { + meshtastic_FileInfo fileInfo = {"", file.size()}; +#ifdef ARCH_ESP32 + strcpy(fileInfo.file_name, file.path()); +#else + strcpy(fileInfo.file_name, file.name()); +#endif + if (!String(fileInfo.file_name).endsWith(".")) { + filenames.push_back(fileInfo); + } + file.close(); + } + file = root.openNextFile(); + } + root.close(); +#endif + return filenames; +} + /** * Lists the contents of a directory. * diff --git a/src/FSCommon.h b/src/FSCommon.h index ef1d3e4c17..8fbabd9526 100644 --- a/src/FSCommon.h +++ b/src/FSCommon.h @@ -1,6 +1,7 @@ #pragma once #include "configuration.h" +#include // Cross platform filesystem API @@ -49,6 +50,7 @@ using namespace Adafruit_LittleFS_Namespace; void fsInit(); bool copyFile(const char *from, const char *to); bool renameFile(const char *pathFrom, const char *pathTo); +std::vector getFiles(const char *dirname, uint8_t levels); void listDir(const char *dirname, uint8_t levels, bool del); void rmDir(const char *dirname); void setupSDCard(); \ No newline at end of file diff --git a/src/GPSStatus.h b/src/GPSStatus.h index 1245d5e5dc..c2ab16c86f 100644 --- a/src/GPSStatus.h +++ b/src/GPSStatus.h @@ -124,7 +124,7 @@ class GPSStatus : public Status if (isDirty) { if (hasLock) { // In debug logs, identify position by @timestamp:stage (stage 3 = notify) - LOG_DEBUG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, speed=%.2f, sats=%d\n", p.timestamp, + LOG_DEBUG("New GPS pos@%x:3 lat=%f lon=%f alt=%d pdop=%.2f track=%.2f speed=%.2f sats=%d\n", p.timestamp, p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5, p.ground_speed * 1e-2, p.sats_in_view); } else { diff --git a/src/Power.cpp b/src/Power.cpp index 18a527cee7..cea373806c 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -27,7 +27,7 @@ #if defined(DEBUG_HEAP_MQTT) && !MESHTASTIC_EXCLUDE_MQTT #include "mqtt/MQTT.h" #include "target_specific.h" -#if !MESTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include #endif #endif diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index a7bc18f1a3..72e00810bb 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -11,6 +11,7 @@ #include "Default.h" #include "MeshService.h" #include "NodeDB.h" +#include "PowerMon.h" #include "configuration.h" #include "graphics/Screen.h" #include "main.h" @@ -49,6 +50,7 @@ static bool isPowered() static void sdsEnter() { LOG_DEBUG("Enter state: SDS\n"); + powerMon->setState(meshtastic_PowerMon_State_CPU_DeepSleep); // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false); } @@ -68,6 +70,7 @@ static uint32_t secsSlept; static void lsEnter() { LOG_INFO("lsEnter begin, ls_secs=%u\n", config.power.ls_secs); + powerMon->clearState(meshtastic_PowerMon_State_Screen_On); screen->setOn(false); secsSlept = 0; // How long have we been sleeping this time @@ -87,8 +90,10 @@ static void lsIdle() // Briefly come out of sleep long enough to blink the led once every few seconds uint32_t sleepTime = SLEEP_TIME; + powerMon->setState(meshtastic_PowerMon_State_CPU_LightSleep); setLed(false); // Never leave led on while in light sleep esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL); + powerMon->clearState(meshtastic_PowerMon_State_CPU_LightSleep); switch (wakeCause2) { case ESP_SLEEP_WAKEUP_TIMER: @@ -144,6 +149,7 @@ static void lsExit() static void nbEnter() { LOG_DEBUG("Enter state: NB\n"); + powerMon->clearState(meshtastic_PowerMon_State_BT_On); screen->setOn(false); #ifdef ARCH_ESP32 // Only ESP32 should turn off bluetooth @@ -155,6 +161,8 @@ static void nbEnter() static void darkEnter() { + powerMon->clearState(meshtastic_PowerMon_State_BT_On); + powerMon->clearState(meshtastic_PowerMon_State_Screen_On); setBluetoothEnable(true); screen->setOn(false); } @@ -162,6 +170,8 @@ static void darkEnter() static void serialEnter() { LOG_DEBUG("Enter state: SERIAL\n"); + powerMon->clearState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); setBluetoothEnable(false); screen->setOn(true); screen->print("Serial connected\n"); @@ -170,6 +180,7 @@ static void serialEnter() static void serialExit() { // Turn bluetooth back on when we leave serial stream API + powerMon->setState(meshtastic_PowerMon_State_BT_On); setBluetoothEnable(true); screen->print("Serial disconnected\n"); } @@ -182,6 +193,8 @@ static void powerEnter() LOG_INFO("Loss of power in Powered\n"); powerFSM.trigger(EVENT_POWER_DISCONNECTED); } else { + powerMon->setState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); // within enter() the function getState() returns the state we came from @@ -205,6 +218,8 @@ static void powerIdle() static void powerExit() { + powerMon->setState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); @@ -216,6 +231,8 @@ static void powerExit() static void onEnter() { LOG_DEBUG("Enter state: ON\n"); + powerMon->setState(meshtastic_PowerMon_State_BT_On); + powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); } diff --git a/src/PowerMon.cpp b/src/PowerMon.cpp new file mode 100644 index 0000000000..3d28715e0c --- /dev/null +++ b/src/PowerMon.cpp @@ -0,0 +1,45 @@ +#include "PowerMon.h" +#include "NodeDB.h" + +// Use the 'live' config flag to figure out if we should be showing this message +static bool is_power_enabled(uint64_t m) +{ + return (m & config.power.powermon_enables) ? true : false; +} + +void PowerMon::setState(_meshtastic_PowerMon_State state, const char *reason) +{ +#ifdef USE_POWERMON + auto oldstates = states; + states |= state; + if (oldstates != states && is_power_enabled(state)) { + emitLog(reason); + } +#endif +} + +void PowerMon::clearState(_meshtastic_PowerMon_State state, const char *reason) +{ +#ifdef USE_POWERMON + auto oldstates = states; + states &= ~state; + if (oldstates != states && is_power_enabled(state)) { + emitLog(reason); + } +#endif +} + +void PowerMon::emitLog(const char *reason) +{ +#ifdef USE_POWERMON + // The nrf52 printf doesn't understand 64 bit ints, so if we ever reach that point this function will need to change. + LOG_INFO("S:PM:0x%08lx,%s\n", (uint32_t)states, reason); +#endif +} + +PowerMon *powerMon; + +void powerMonInit() +{ + powerMon = new PowerMon(); +} \ No newline at end of file diff --git a/src/PowerMon.h b/src/PowerMon.h new file mode 100644 index 0000000000..e9f5dbd59c --- /dev/null +++ b/src/PowerMon.h @@ -0,0 +1,34 @@ +#pragma once +#include "configuration.h" + +#include "meshtastic/powermon.pb.h" + +#ifndef MESHTASTIC_EXCLUDE_POWERMON +#define USE_POWERMON // FIXME turn this only for certain builds +#endif + +/** + * The singleton class for monitoring power consumption of device + * subsystems/modes. + * + * For more information see the PowerMon docs. + */ +class PowerMon +{ + uint64_t states = 0UL; + + public: + PowerMon() {} + + // Mark entry/exit of a power consuming state + void setState(_meshtastic_PowerMon_State state, const char *reason = ""); + void clearState(_meshtastic_PowerMon_State state, const char *reason = ""); + + private: + // Emit the coded log message + void emitLog(const char *reason); +}; + +extern PowerMon *powerMon; + +void powerMonInit(); \ No newline at end of file diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index e09e5fe30a..9c3dcdc987 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -3,6 +3,8 @@ #include "RTC.h" #include "concurrency/OSThread.h" #include "configuration.h" +#include "main.h" +#include "mesh/generated/meshtastic/mesh.pb.h" #include #include #include @@ -14,12 +16,7 @@ #include "platform/portduino/PortduinoGlue.h" #endif -/** - * A printer that doesn't go anywhere - */ -NoopPrint noopPrint; - -#if HAS_WIFI || HAS_ETHERNET +#if HAS_NETWORKING extern Syslog syslog; #endif void RedirectablePrint::rpInit() @@ -38,7 +35,7 @@ void RedirectablePrint::setDestination(Print *_dest) size_t RedirectablePrint::write(uint8_t c) { // Always send the characters to our segger JTAG debugger -#ifdef SEGGER_STDOUT_CH +#ifdef USE_SEGGER SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c); #endif @@ -49,7 +46,7 @@ size_t RedirectablePrint::write(uint8_t c) // serial port said (which could be zero) } -size_t RedirectablePrint::vprintf(const char *format, va_list arg) +size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_list arg) { va_list copy; static char printBuf[160]; @@ -65,25 +62,200 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg) len = sizeof(printBuf) - 1; printBuf[sizeof(printBuf) - 2] = '\n'; } - + for (size_t f = 0; f < len; f++) { + if (!std::isprint(static_cast(printBuf[f])) && printBuf[f] != '\n') + printBuf[f] = '#'; + } + if (logLevel != nullptr) { + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) + Print::write("\u001b[34m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) + Print::write("\u001b[32m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) + Print::write("\u001b[33m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) + Print::write("\u001b[31m", 6); + } len = Print::write(printBuf, len); + Print::write("\u001b[0m", 5); return len; } -size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) +void RedirectablePrint::log_to_serial(const char *logLevel, const char *format, va_list arg) +{ + size_t r = 0; + + // Cope with 0 len format strings, but look for new line terminator + bool hasNewline = *format && format[strlen(format) - 1] == '\n'; + + // If we are the first message on a report, include the header + if (!isContinuationMessage) { + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) + Print::write("\u001b[34m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) + Print::write("\u001b[32m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) + Print::write("\u001b[33m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) + Print::write("\u001b[31m", 6); + uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile + if (rtc_sec > 0) { + long hms = rtc_sec % SEC_PER_DAY; + // hms += tz.tz_dsttime * SEC_PER_HOUR; + // hms -= tz.tz_minuteswest * SEC_PER_MIN; + // mod `hms` to ensure in positive range of [0...SEC_PER_DAY) + hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; + + // Tear apart hms into h:m:s + int hour = hms / SEC_PER_HOUR; + int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; + int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN +#ifdef ARCH_PORTDUINO + ::printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); +#else + printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); +#endif + } else +#ifdef ARCH_PORTDUINO + ::printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); +#else + printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); +#endif + + auto thread = concurrency::OSThread::currentThread; + if (thread) { + print("["); + // printf("%p ", thread); + // assert(thread->ThreadName.length()); + print(thread->ThreadName); + print("] "); + } + } + r += vprintf(logLevel, format, arg); + + isContinuationMessage = !hasNewline; +} + +void RedirectablePrint::log_to_syslog(const char *logLevel, const char *format, va_list arg) +{ +#if HAS_NETWORKING && !defined(ARCH_PORTDUINO) + // if syslog is in use, collect the log messages and send them to syslog + if (syslog.isEnabled()) { + int ll = 0; + switch (logLevel[0]) { + case 'D': + ll = SYSLOG_DEBUG; + break; + case 'I': + ll = SYSLOG_INFO; + break; + case 'W': + ll = SYSLOG_WARN; + break; + case 'E': + ll = SYSLOG_ERR; + break; + case 'C': + ll = SYSLOG_CRIT; + break; + default: + ll = 0; + } + auto thread = concurrency::OSThread::currentThread; + if (thread) { + syslog.vlogf(ll, thread->ThreadName.c_str(), format, arg); + } else { + syslog.vlogf(ll, format, arg); + } + } +#endif +} + +void RedirectablePrint::log_to_ble(const char *logLevel, const char *format, va_list arg) +{ +#if !MESHTASTIC_EXCLUDE_BLUETOOTH + if (config.bluetooth.device_logging_enabled && !pauseBluetoothLogging) { + bool isBleConnected = false; +#ifdef ARCH_ESP32 + isBleConnected = nimbleBluetooth && nimbleBluetooth->isActive() && nimbleBluetooth->isConnected(); +#elif defined(ARCH_NRF52) + isBleConnected = nrf52Bluetooth != nullptr && nrf52Bluetooth->isConnected(); +#endif + if (isBleConnected) { + char *message; + size_t initialLen; + size_t len; + initialLen = strlen(format); + message = new char[initialLen + 1]; + len = vsnprintf(message, initialLen + 1, format, arg); + if (len > initialLen) { + delete[] message; + message = new char[len + 1]; + vsnprintf(message, len + 1, format, arg); + } + auto thread = concurrency::OSThread::currentThread; + meshtastic_LogRecord logRecord = meshtastic_LogRecord_init_zero; + logRecord.level = getLogLevel(logLevel); + strcpy(logRecord.message, message); + if (thread) + strcpy(logRecord.source, thread->ThreadName.c_str()); + logRecord.time = getValidTime(RTCQuality::RTCQualityDevice, true); + + uint8_t *buffer = new uint8_t[meshtastic_LogRecord_size]; + size_t size = pb_encode_to_bytes(buffer, meshtastic_LogRecord_size, meshtastic_LogRecord_fields, &logRecord); +#ifdef ARCH_ESP32 + nimbleBluetooth->sendLog(buffer, size); +#elif defined(ARCH_NRF52) + nrf52Bluetooth->sendLog(buffer, size); +#endif + delete[] message; + delete[] buffer; + } + } +#else + (void)logLevel; + (void)format; + (void)arg; +#endif +} + +meshtastic_LogRecord_Level RedirectablePrint::getLogLevel(const char *logLevel) +{ + meshtastic_LogRecord_Level ll = meshtastic_LogRecord_Level_UNSET; // default to unset + switch (logLevel[0]) { + case 'D': + ll = meshtastic_LogRecord_Level_DEBUG; + break; + case 'I': + ll = meshtastic_LogRecord_Level_INFO; + break; + case 'W': + ll = meshtastic_LogRecord_Level_WARNING; + break; + case 'E': + ll = meshtastic_LogRecord_Level_ERROR; + break; + case 'C': + ll = meshtastic_LogRecord_Level_CRITICAL; + break; + } + return ll; +} + +void RedirectablePrint::log(const char *logLevel, const char *format, ...) { #ifdef ARCH_PORTDUINO if (settingsMap[logoutputlevel] < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) - return 0; + return; else if (settingsMap[logoutputlevel] < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) - return 0; + return; else if (settingsMap[logoutputlevel] < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) - return 0; + return; #endif if (moduleConfig.serial.override_console_serial_port && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) { - return 0; + return; } - size_t r = 0; + #ifdef HAS_FREE_RTOS if (inDebugPrint != nullptr && xSemaphoreTake(inDebugPrint, portMAX_DELAY) == pdTRUE) { #else @@ -94,81 +266,11 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) va_list arg; va_start(arg, format); - // Cope with 0 len format strings, but look for new line terminator - bool hasNewline = *format && format[strlen(format) - 1] == '\n'; - - // If we are the first message on a report, include the header - if (!isContinuationMessage) { - uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile - if (rtc_sec > 0) { - long hms = rtc_sec % SEC_PER_DAY; - // hms += tz.tz_dsttime * SEC_PER_HOUR; - // hms -= tz.tz_minuteswest * SEC_PER_MIN; - // mod `hms` to ensure in positive range of [0...SEC_PER_DAY) - hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; - - // Tear apart hms into h:m:s - int hour = hms / SEC_PER_HOUR; - int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; - int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN -#ifdef ARCH_PORTDUINO - r += ::printf("%s | %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); -#else - r += printf("%s | %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); -#endif - } else -#ifdef ARCH_PORTDUINO - r += ::printf("%s | ??:??:?? %u ", logLevel, millis() / 1000); -#else - r += printf("%s | ??:??:?? %u ", logLevel, millis() / 1000); -#endif - - auto thread = concurrency::OSThread::currentThread; - if (thread) { - print("["); - // printf("%p ", thread); - // assert(thread->ThreadName.length()); - print(thread->ThreadName); - print("] "); - } - } - r += vprintf(format, arg); - -#if (HAS_WIFI || HAS_ETHERNET) && !defined(ARCH_PORTDUINO) - // if syslog is in use, collect the log messages and send them to syslog - if (syslog.isEnabled()) { - int ll = 0; - switch (logLevel[0]) { - case 'D': - ll = SYSLOG_DEBUG; - break; - case 'I': - ll = SYSLOG_INFO; - break; - case 'W': - ll = SYSLOG_WARN; - break; - case 'E': - ll = SYSLOG_ERR; - break; - case 'C': - ll = SYSLOG_CRIT; - break; - default: - ll = 0; - } - auto thread = concurrency::OSThread::currentThread; - if (thread) { - syslog.vlogf(ll, thread->ThreadName.c_str(), format, arg); - } else { - syslog.vlogf(ll, format, arg); - } - } -#endif + log_to_serial(logLevel, format, arg); + log_to_syslog(logLevel, format, arg); + log_to_ble(logLevel, format, arg); va_end(arg); - - isContinuationMessage = !hasNewline; #ifdef HAS_FREE_RTOS xSemaphoreGive(inDebugPrint); #else @@ -176,7 +278,7 @@ size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) #endif } - return r; + return; } void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len) diff --git a/src/RedirectablePrint.h b/src/RedirectablePrint.h index 31cc1b6ef7..23ae3c44de 100644 --- a/src/RedirectablePrint.h +++ b/src/RedirectablePrint.h @@ -1,6 +1,7 @@ #pragma once #include "../freertosinc.h" +#include "mesh/generated/meshtastic/mesh.pb.h" #include #include #include @@ -41,23 +42,21 @@ class RedirectablePrint : public Print * log message. Otherwise we assume more prints will come before the log message ends. This * allows you to call logDebug a few times to build up a single log message line if you wish. */ - size_t log(const char *logLevel, const char *format, ...) __attribute__((format(printf, 3, 4))); + void log(const char *logLevel, const char *format, ...) __attribute__((format(printf, 3, 4))); /** like printf but va_list based */ - size_t vprintf(const char *format, va_list arg); + size_t vprintf(const char *logLevel, const char *format, va_list arg); void hexDump(const char *logLevel, unsigned char *buf, uint16_t len); std::string mt_sprintf(const std::string fmt_str, ...); -}; -class NoopPrint : public Print -{ - public: - virtual size_t write(uint8_t c) { return 1; } -}; + protected: + /// Subclasses can override if they need to change how we format over the serial port + virtual void log_to_serial(const char *logLevel, const char *format, va_list arg); -/** - * A printer that doesn't go anywhere - */ -extern NoopPrint noopPrint; \ No newline at end of file + private: + void log_to_syslog(const char *logLevel, const char *format, va_list arg); + void log_to_ble(const char *logLevel, const char *format, va_list arg); + meshtastic_LogRecord_Level getLogLevel(const char *logLevel); +}; \ No newline at end of file diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index cf6375585c..9a9331e473 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -28,7 +28,7 @@ void consolePrintf(const char *format, ...) { va_list arg; va_start(arg, format); - console->vprintf(format, arg); + console->vprintf(nullptr, format, arg); va_end(arg); console->flush(); } @@ -38,7 +38,6 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con assert(!console); console = this; canWrite = false; // We don't send packets to our port until it has talked to us first - // setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks #ifdef RP2040_SLOW_CLOCK Port.setTX(SERIAL2_TX); @@ -85,13 +84,40 @@ bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len) { // only talk to the API once the configuration has been loaded and we're sure the serial port is not disabled. if (config.has_lora && config.device.serial_enabled) { - // Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets - if (!config.device.debug_log_enabled) - setDestination(&noopPrint); + // Switch to protobufs for log messages + usingProtobufs = true; canWrite = true; return StreamAPI::handleToRadio(buf, len); } else { return false; } +} + +void SerialConsole::log_to_serial(const char *logLevel, const char *format, va_list arg) +{ + if (usingProtobufs) { + meshtastic_LogRecord_Level ll = meshtastic_LogRecord_Level_UNSET; // default to unset + switch (logLevel[0]) { + case 'D': + ll = meshtastic_LogRecord_Level_DEBUG; + break; + case 'I': + ll = meshtastic_LogRecord_Level_INFO; + break; + case 'W': + ll = meshtastic_LogRecord_Level_WARNING; + break; + case 'E': + ll = meshtastic_LogRecord_Level_ERROR; + break; + case 'C': + ll = meshtastic_LogRecord_Level_CRITICAL; + break; + } + + auto thread = concurrency::OSThread::currentThread; + emitLogRecord(ll, thread ? thread->ThreadName.c_str() : "", format, arg); + } else + RedirectablePrint::log_to_serial(logLevel, format, arg); } \ No newline at end of file diff --git a/src/SerialConsole.h b/src/SerialConsole.h index f8891ba14f..f1e636c9de 100644 --- a/src/SerialConsole.h +++ b/src/SerialConsole.h @@ -8,6 +8,11 @@ */ class SerialConsole : public StreamAPI, public RedirectablePrint, private concurrency::OSThread { + /** + * If true we are talking to a smart host and all messages (including log messages) must be framed as protobufs. + */ + bool usingProtobufs = false; + public: SerialConsole(); @@ -31,10 +36,13 @@ class SerialConsole : public StreamAPI, public RedirectablePrint, private concur protected: /// Check the current underlying physical link to see if the client is currently connected virtual bool checkIsConnected() override; + + /// Possibly switch to protobufs if we see a valid protobuf message + virtual void log_to_serial(const char *logLevel, const char *format, va_list arg); }; // A simple wrapper to allow non class aware code write to the console void consolePrintf(const char *format, ...); void consoleInit(); -extern SerialConsole *console; +extern SerialConsole *console; \ No newline at end of file diff --git a/src/commands.h b/src/commands.h index 03ede5982e..f2b7830105 100644 --- a/src/commands.h +++ b/src/commands.h @@ -8,13 +8,11 @@ enum class Cmd { SET_ON, SET_OFF, ON_PRESS, - START_BLUETOOTH_PIN_SCREEN, + START_ALERT_FRAME, + STOP_ALERT_FRAME, START_FIRMWARE_UPDATE_SCREEN, - STOP_BLUETOOTH_PIN_SCREEN, STOP_BOOT_SCREEN, PRINT, - START_SHUTDOWN_SCREEN, - START_REBOOT_SCREEN, SHOW_PREV_FRAME, SHOW_NEXT_FRAME }; \ No newline at end of file diff --git a/src/configuration.h b/src/configuration.h index 3d10feeaaf..aad4ac4572 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -242,9 +242,6 @@ along with this program. If not, see . #define HAS_BLUETOOTH 0 #endif -#include "DebugConfiguration.h" -#include "RF95Configuration.h" - #ifndef HW_VENDOR #error HW_VENDOR must be defined #endif @@ -261,6 +258,7 @@ along with this program. If not, see . #define MESHTASTIC_EXCLUDE_GPS 1 #define MESHTASTIC_EXCLUDE_SCREEN 1 #define MESHTASTIC_EXCLUDE_MQTT 1 +#define MESHTASTIC_EXCLUDE_POWERMON 1 #endif // Turn off all optional modules @@ -281,6 +279,7 @@ along with this program. If not, see . #define MESHTASTIC_EXCLUDE_WAYPOINT 1 #define MESHTASTIC_EXCLUDE_INPUTBROKER 1 #define MESHTASTIC_EXCLUDE_SERIAL 1 +#define MESHTASTIC_EXCLUDE_POWERSTRESS 1 #endif // // Turn off wifi even if HW supports wifi (webserver relies on wifi and is also disabled) @@ -290,6 +289,9 @@ along with this program. If not, see . #define HAS_WIFI 0 #endif +// Allow code that needs internet to just check HAS_NETWORKING rather than HAS_WIFI || HAS_ETHERNET +#define HAS_NETWORKING (HAS_WIFI || HAS_ETHERNET) + // // Turn off Bluetooth #ifdef MESHTASTIC_EXCLUDE_BLUETOOTH #undef HAS_BLUETOOTH @@ -308,4 +310,7 @@ along with this program. If not, see . #ifdef MESHTASTIC_EXCLUDE_SCREEN #undef HAS_SCREEN #define HAS_SCREEN 0 -#endif \ No newline at end of file +#endif + +#include "DebugConfiguration.h" +#include "RF95Configuration.h" \ No newline at end of file diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 86408b8d2e..8738e2722d 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -314,7 +314,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) case SHT31_4x_ADDR: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2); - if (registerValue == 0x11a2) { + if (registerValue == 0x11a2 || registerValue == 0x11da) { type = SHT4X; LOG_INFO("SHT4X sensor found\n"); } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) { @@ -402,4 +402,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const size_t ScanI2CTwoWire::countDevices() const { return foundDevices.size(); -} \ No newline at end of file +} diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 40ee4ea032..fe70bcdcdd 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -3,6 +3,7 @@ #include "Default.h" #include "GPS.h" #include "NodeDB.h" +#include "PowerMon.h" #include "RTC.h" #include "main.h" // pmu_found @@ -784,6 +785,22 @@ GPS::~GPS() notifyGPSSleepObserver.observe(¬ifyGPSSleep); } +const char *GPS::powerStateToString() +{ + switch (powerState) { + case GPS_OFF: + return "OFF"; + case GPS_IDLE: + return "IDLE"; + case GPS_STANDBY: + return "STANDBY"; + case GPS_ACTIVE: + return "ACTIVE"; + default: + return "UNKNOWN"; + } +} + void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) { // Record the current powerState @@ -798,16 +815,19 @@ void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) else powerState = GPS_OFF; - LOG_DEBUG("GPS::powerState=%d\n", powerState); + LOG_DEBUG("GPS::powerState=%s\n", powerStateToString()); // If the next update is due *really soon*, don't actually power off or enter standby. Just wait it out. if (!on && powerState == GPS_IDLE) return; if (on) { + powerMon->setState(meshtastic_PowerMon_State_GPS_Active); clearBuffer(); // drop any old data waiting in the buffer before re-enabling if (en_gpio) digitalWrite(en_gpio, on ? GPS_EN_ACTIVE : !GPS_EN_ACTIVE); // turn this on if defined, every time + } else { + powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); } isInPowersave = !on; if (!standbyOnly && en_gpio != 0 && diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 91548ce2cf..7fa37cb7a4 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -289,6 +289,8 @@ class GPS : private concurrency::OSThread // delay counter to allow more sats before fixed position stops GPS thread uint8_t fixeddelayCtr = 0; + const char *powerStateToString(); + protected: GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN; }; diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 60168cffcf..f724ddd3d4 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -75,7 +75,6 @@ namespace graphics // A text message frame + debug frame + all the node infos FrameCallback *normalFrames; static uint32_t targetFramerate = IDLE_FRAMERATE; -static char btPIN[16] = "888888"; uint32_t logo_timeout = 5000; // 4 seconds for EACH logo @@ -108,15 +107,39 @@ GeoCoord geoCoord; static bool heartbeat = false; #endif -static uint16_t displayWidth, displayHeight; - -#define SCREEN_WIDTH displayWidth -#define SCREEN_HEIGHT displayHeight +// Quick access to screen dimensions from static drawing functions +// DEPRECATED. To-do: move static functions inside Screen class +#define SCREEN_WIDTH display->getWidth() +#define SCREEN_HEIGHT display->getHeight() #include "graphics/ScreenFonts.h" #define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2) +/// Check if the display can render a string (detect special chars; emoji) +static bool haveGlyphs(const char *str) +{ +#if defined(OLED_UA) || defined(OLED_RU) + // Don't want to make any assumptions about custom language support + return true; +#endif + + // Check each character with the lookup function for the OLED library + // We're not really meant to use this directly.. + bool have = true; + for (uint16_t i = 0; i < strlen(str); i++) { + uint8_t result = Screen::customFontTableLookup((uint8_t)str[i]); + // If font doesn't support a character, it is substituted for ¿ + if (result == 191 && (uint8_t)str[i] != 191) { + have = false; + break; + } + } + + LOG_DEBUG("haveGlyphs=%d\n", have); + return have; +} + /** * Draw the icon with extra info printed around the corners */ @@ -140,13 +163,15 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl if (upperMsg) display->drawString(x + 0, y + 0, upperMsg); - // Draw version in upper right - char buf[16]; - snprintf(buf, sizeof(buf), "%s", - xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long - display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf); + // Draw version and short name in upper right + char buf[25]; + snprintf(buf, sizeof(buf), "%s\n%s", xstr(APP_VERSION_SHORT), haveGlyphs(owner.short_name) ? owner.short_name : ""); + + display->setTextAlignment(TEXT_ALIGN_RIGHT); + display->drawString(x + SCREEN_WIDTH, y + 0, buf); screen->forceDisplay(); - // FIXME - draw serial # somewhere? + + display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code } static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) @@ -181,14 +206,15 @@ static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDi if (upperMsg) display->drawString(x + 0, y + 0, upperMsg); - // Draw version in upper right - char buf[16]; - snprintf(buf, sizeof(buf), "%s", - xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long - display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf); + // Draw version and shortname in upper right + char buf[25]; + snprintf(buf, sizeof(buf), "%s\n%s", xstr(APP_VERSION_SHORT), haveGlyphs(owner.short_name) ? owner.short_name : ""); + + display->setTextAlignment(TEXT_ALIGN_RIGHT); + display->drawString(x + SCREEN_WIDTH, y + 0, buf); screen->forceDisplay(); - // FIXME - draw serial # somewhere? + display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code } static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) @@ -198,7 +224,7 @@ static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i drawOEMIconScreen(region, display, state, x, y); } -static void drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *message) +void Screen::drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *message) { uint16_t x_offset = display->width() / 2; display->setTextAlignment(TEXT_ALIGN_CENTER); @@ -206,20 +232,6 @@ static void drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16 display->drawString(x_offset + x, 26 + y, message); } -static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -{ -#ifdef ARCH_ESP32 - if (wakeCause == ESP_SLEEP_WAKEUP_TIMER || wakeCause == ESP_SLEEP_WAKEUP_EXT1) { - drawFrameText(display, state, x, y, "Resuming..."); - } else -#endif - { - // Draw region in upper left - const char *region = myRegion ? myRegion->name : NULL; - drawIconScreen(region, display, state, x, y); - } -} - // Used on boot when a certificate is being created static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { @@ -277,40 +289,19 @@ static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state) } } -/// Check if the display can render a string (detect special chars; emoji) -static bool haveGlyphs(const char *str) -{ -#if defined(OLED_UA) || defined(OLED_RU) - // Don't want to make any assumptions about custom language support - return true; -#endif - - // Check each character with the lookup function for the OLED library - // We're not really meant to use this directly.. - bool have = true; - for (uint16_t i = 0; i < strlen(str); i++) { - uint8_t result = Screen::customFontTableLookup((uint8_t)str[i]); - // If font doesn't support a character, it is substituted for ¿ - if (result == 191 && (uint8_t)str[i] != 191) { - have = false; - break; - } - } - - LOG_DEBUG("haveGlyphs=%d\n", have); - return have; -} - #ifdef USE_EINK /// Used on eink displays while in deep sleep static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { + // Next frame should use full-refresh, and block while running, else device will sleep before async callback EINK_ADD_FRAMEFLAG(display, COSMETIC); EINK_ADD_FRAMEFLAG(display, BLOCKING); LOG_DEBUG("Drawing deep sleep screen\n"); - drawIconScreen("Sleeping...", display, state, x, y); + + // Display displayStr on the screen + drawIconScreen("Sleeping", display, state, x, y); } /// Used on eink displays when screen updates are paused @@ -375,7 +366,7 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int // in the array of "drawScreen" functions; however, // the passed-state doesn't quite reflect the "current" // screen, so we have to detect it. - if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == INCOMING) { + if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == TransitionRelationship_INCOMING) { // if we're transitioning from the end of the frame list back around to the first // frame, then we want this to be `0` module_frame = state->transitionFrameTarget; @@ -389,31 +380,6 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int pi.drawFrame(display, state, x, y); } -static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -{ - int x_offset = display->width() / 2; - int y_offset = display->height() <= 80 ? 0 : 32; - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->setFont(FONT_MEDIUM); - display->drawString(x_offset + x, y_offset + y, "Bluetooth"); - - display->setFont(FONT_SMALL); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5; - display->drawString(x_offset + x, y_offset + y, "Enter this code"); - - display->setFont(FONT_LARGE); - String displayPin(btPIN); - String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5; - display->drawString(x_offset + x, y_offset + y, pin); - - display->setFont(FONT_SMALL); - String deviceName = "Name: "; - deviceName.concat(getDeviceName()); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; - display->drawString(x_offset + x, y_offset + y, deviceName); -} - static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { display->setTextAlignment(TEXT_ALIGN_CENTER); @@ -1091,45 +1057,8 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state #endif } -/// Draw the last waypoint we received -static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -{ - static char tempBuf[237]; - - meshtastic_MeshPacket &mp = devicestate.rx_waypoint; - meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp)); - - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(FONT_SMALL); - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { - display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); - display->setColor(BLACK); - } - - uint32_t seconds = sinceReceived(&mp); - uint32_t minutes = seconds / 60; - uint32_t hours = minutes / 60; - uint32_t days = hours / 24; - - if (config.display.heading_bold) { - display->drawStringf(1 + x, 0 + y, tempBuf, "%s ago from %s", - screen->drawTimeDelta(days, hours, minutes, seconds).c_str(), - (node && node->has_user) ? node->user.short_name : "???"); - } - display->drawStringf(0 + x, 0 + y, tempBuf, "%s ago from %s", screen->drawTimeDelta(days, hours, minutes, seconds).c_str(), - (node && node->has_user) ? node->user.short_name : "???"); - - display->setColor(WHITE); - meshtastic_Waypoint scratch; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) { - snprintf(tempBuf, sizeof(tempBuf), "Received waypoint: %s", scratch.name); - display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf); - } -} - /// Draw a series of fields in a column, wrapping to multiple columns if needed -static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields) +void Screen::drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields) { // The coordinates define the left starting point of the text display->setTextAlignment(TEXT_ALIGN_LEFT); @@ -1309,56 +1238,13 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const } } #endif -namespace -{ - -/// A basic 2D point class for drawing -class Point -{ - public: - float x, y; - - Point(float _x, float _y) : x(_x), y(_y) {} - - /// Apply a rotation around zero (standard rotation matrix math) - void rotate(float radian) - { - float cos = cosf(radian), sin = sinf(radian); - float rx = x * cos + y * sin, ry = -x * sin + y * cos; - - x = rx; - y = ry; - } - - void translate(int16_t dx, int dy) - { - x += dx; - y += dy; - } - - void scale(float f) - { - // We use -f here to counter the flip that happens - // on the y axis when drawing and rotating on screen - x *= f; - y *= -f; - } -}; - -} // namespace - -static void drawLine(OLEDDisplay *d, const Point &p1, const Point &p2) -{ - d->drawLine(p1.x, p1.y, p2.x, p2.y); -} - /** * Given a recent lat/lon return a guess of the heading the user is walking on. * * We keep a series of "after you've gone 10 meters, what is your heading since * the last reference point?" */ -static float estimatedHeading(double lat, double lon) +float Screen::estimatedHeading(double lat, double lon) { static double oldLat, oldLon; static float b; @@ -1382,38 +1268,13 @@ static float estimatedHeading(double lat, double lon) return b; } -static uint16_t getCompassDiam(OLEDDisplay *display) -{ - uint16_t diam = 0; - uint16_t offset = 0; - - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) - offset = FONT_HEIGHT_SMALL; - - // get the smaller of the 2 dimensions and subtract 20 - if (display->getWidth() > (display->getHeight() - offset)) { - diam = display->getHeight() - offset; - // if 2/3 of the other size would be smaller, use that - if (diam > (display->getWidth() * 2 / 3)) { - diam = display->getWidth() * 2 / 3; - } - } else { - diam = display->getWidth(); - if (diam > ((display->getHeight() - offset) * 2 / 3)) { - diam = (display->getHeight() - offset) * 2 / 3; - } - } - - return diam - 20; -}; - /// We will skip one node - the one for us, so we just blindly loop over all /// nodes static size_t nodeIndex; static int8_t prevFrame = -1; // Draw the arrow pointing to a node's location -static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, float headingRadian) +void Screen::drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, uint16_t compassDiam, float headingRadian) { Point tip(0.0f, 0.5f), tail(0.0f, -0.5f); // pointing up initially float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f; @@ -1423,16 +1284,45 @@ static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t comp for (int i = 0; i < 4; i++) { arrowPoints[i]->rotate(headingRadian); - arrowPoints[i]->scale(getCompassDiam(display) * 0.6); + arrowPoints[i]->scale(compassDiam * 0.6); arrowPoints[i]->translate(compassX, compassY); } - drawLine(display, tip, tail); - drawLine(display, leftArrow, tip); - drawLine(display, rightArrow, tip); + display->drawLine(tip.x, tip.y, tail.x, tail.y); + display->drawLine(leftArrow.x, leftArrow.y, tip.x, tip.y); + display->drawLine(rightArrow.x, rightArrow.y, tip.x, tip.y); +} + +// Get a string representation of the time passed since something happened +void Screen::getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength) +{ + // Use an absolute timestamp in some cases. + // Particularly useful with E-Ink displays. Static UI, fewer refreshes. + uint8_t timestampHours, timestampMinutes; + int32_t daysAgo; + bool useTimestamp = deltaToTimestamp(agoSecs, ×tampHours, ×tampMinutes, &daysAgo); + + if (agoSecs < 120) // last 2 mins? + snprintf(timeStr, maxLength, "%u seconds ago", agoSecs); + // -- if suitable for timestamp -- + else if (useTimestamp && agoSecs < 15 * SECONDS_IN_MINUTE) // Last 15 minutes + snprintf(timeStr, maxLength, "%u minutes ago", agoSecs / SECONDS_IN_MINUTE); + else if (useTimestamp && daysAgo == 0) // Today + snprintf(timeStr, maxLength, "Last seen: %02u:%02u", (unsigned int)timestampHours, (unsigned int)timestampMinutes); + else if (useTimestamp && daysAgo == 1) // Yesterday + snprintf(timeStr, maxLength, "Seen yesterday"); + else if (useTimestamp && daysAgo > 1) // Last six months (capped by deltaToTimestamp method) + snprintf(timeStr, maxLength, "%li days ago", (long)daysAgo); + // -- if using time delta instead -- + else if (agoSecs < 120 * 60) // last 2 hrs + snprintf(timeStr, maxLength, "%u minutes ago", agoSecs / 60); + // Only show hours ago if it's been less than 6 months. Otherwise, we may have bad data. + else if ((agoSecs / 60 / 60) < (hours_in_month * 6)) + snprintf(timeStr, maxLength, "%u hours ago", agoSecs / 60 / 60); + else + snprintf(timeStr, maxLength, "unknown age"); } -// Draw north -static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading) +void Screen::drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading) { // If north is supposed to be at the top of the compass we want rotation to be +0 if (config.display.compass_north_top) @@ -1442,19 +1332,43 @@ static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t com Point N3(-0.04f, 0.55f), N4(0.04f, 0.55f); Point *rosePoints[] = {&N1, &N2, &N3, &N4}; + uint16_t compassDiam = Screen::getCompassDiam(SCREEN_WIDTH, SCREEN_HEIGHT); + for (int i = 0; i < 4; i++) { // North on compass will be negative of heading rosePoints[i]->rotate(-myHeading); - rosePoints[i]->scale(getCompassDiam(display)); + rosePoints[i]->scale(compassDiam); rosePoints[i]->translate(compassX, compassY); } - drawLine(display, N1, N3); - drawLine(display, N2, N4); - drawLine(display, N1, N4); + display->drawLine(N1.x, N1.y, N3.x, N3.y); + display->drawLine(N2.x, N2.y, N4.x, N4.y); + display->drawLine(N1.x, N1.y, N4.x, N4.y); } -/// Convert an integer GPS coords to a floating point -#define DegD(i) (i * 1e-7) +uint16_t Screen::getCompassDiam(uint32_t displayWidth, uint32_t displayHeight) +{ + uint16_t diam = 0; + uint16_t offset = 0; + + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) + offset = FONT_HEIGHT_SMALL; + + // get the smaller of the 2 dimensions and subtract 20 + if (displayWidth > (displayHeight - offset)) { + diam = displayHeight - offset; + // if 2/3 of the other size would be smaller, use that + if (diam > (displayWidth * 2 / 3)) { + diam = displayWidth * 2 / 3; + } + } else { + diam = displayWidth; + if (diam > ((displayHeight - offset) * 2 / 3)) { + diam = (displayHeight - offset) * 2 / 3; + } + } + + return diam - 20; +}; static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { @@ -1494,34 +1408,8 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ snprintf(signalStr, sizeof(signalStr), "Signal: %d%%", clamp((int)((node->snr + 10) * 5), 0, 100)); } - uint32_t agoSecs = sinceLastSeen(node); static char lastStr[20]; - - // Use an absolute timestamp in some cases. - // Particularly useful with E-Ink displays. Static UI, fewer refreshes. - uint8_t timestampHours, timestampMinutes; - int32_t daysAgo; - bool useTimestamp = deltaToTimestamp(agoSecs, ×tampHours, ×tampMinutes, &daysAgo); - - if (agoSecs < 120) // last 2 mins? - snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs); - // -- if suitable for timestamp -- - else if (useTimestamp && agoSecs < 15 * SECONDS_IN_MINUTE) // Last 15 minutes - snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / SECONDS_IN_MINUTE); - else if (useTimestamp && daysAgo == 0) // Today - snprintf(lastStr, sizeof(lastStr), "Last seen: %02u:%02u", (unsigned int)timestampHours, (unsigned int)timestampMinutes); - else if (useTimestamp && daysAgo == 1) // Yesterday - snprintf(lastStr, sizeof(lastStr), "Seen yesterday"); - else if (useTimestamp && daysAgo > 1) // Last six months (capped by deltaToTimestamp method) - snprintf(lastStr, sizeof(lastStr), "%li days ago", (long)daysAgo); - // -- if using time delta instead -- - else if (agoSecs < 120 * 60) // last 2 hrs - snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60); - // Only show hours ago if it's been less than 6 months. Otherwise, we may have bad data. - else if ((agoSecs / 60 / 60) < (hours_in_month * 6)) - snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60); - else - snprintf(lastStr, sizeof(lastStr), "unknown age"); + screen->getTimeAgoStr(sinceLastSeen(node), lastStr, sizeof(lastStr)); static char distStr[20]; if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) { @@ -1532,13 +1420,14 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); const char *fields[] = {username, lastStr, signalStr, distStr, NULL}; int16_t compassX = 0, compassY = 0; + uint16_t compassDiam = Screen::getCompassDiam(SCREEN_WIDTH, SCREEN_HEIGHT); // coordinates for the center of the compass/circle if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { - compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5; + compassX = x + SCREEN_WIDTH - compassDiam / 2 - 5; compassY = y + SCREEN_HEIGHT / 2; } else { - compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5; + compassX = x + SCREEN_WIDTH - compassDiam / 2 - 5; compassY = y + FONT_HEIGHT_SMALL + (SCREEN_HEIGHT - FONT_HEIGHT_SMALL) / 2; } bool hasNodeHeading = false; @@ -1549,8 +1438,8 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ if (screen->hasHeading()) myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians else - myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); - drawCompassNorth(display, compassX, compassY, myHeading); + myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); + screen->drawCompassNorth(display, compassX, compassY, myHeading); if (hasValidPosition(node)) { // display direction toward node @@ -1577,7 +1466,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ // If the top of the compass is not a static north we need adjust bearingToOther based on heading if (!config.display.compass_north_top) bearingToOther -= myHeading; - drawNodeHeading(display, compassX, compassY, bearingToOther); + screen->drawNodeHeading(display, compassX, compassY, compassDiam, bearingToOther); } } if (!hasNodeHeading) { @@ -1587,13 +1476,13 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ // hasValidPosition(node)); display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?"); } - display->drawCircle(compassX, compassY, getCompassDiam(display) / 2); + display->drawCircle(compassX, compassY, compassDiam / 2); if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { display->setColor(BLACK); } // Must be after distStr is populated - drawColumns(display, x, y, fields); + screen->drawColumns(display, x, y, fields); } Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry) @@ -1741,9 +1630,19 @@ void Screen::setup() // Add frames. EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); - static FrameCallback bootFrames[] = {drawBootScreen}; - static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]); - ui->setFrames(bootFrames, bootFrameCount); + alertFrames[0] = [this](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { +#ifdef ARCH_ESP32 + if (wakeCause == ESP_SLEEP_WAKEUP_TIMER || wakeCause == ESP_SLEEP_WAKEUP_EXT1) { + drawFrameText(display, state, x, y, "Resuming..."); + } else +#endif + { + // Draw region in upper left + const char *region = myRegion ? myRegion->name : NULL; + drawIconScreen(region, display, state, x, y); + } + }; + ui->setFrames(alertFrames, 1); // No overlays. ui->setOverlays(nullptr, 0); @@ -1916,13 +1815,22 @@ int32_t Screen::runOnce() case Cmd::SHOW_NEXT_FRAME: handleShowNextFrame(); break; - case Cmd::START_BLUETOOTH_PIN_SCREEN: - handleStartBluetoothPinScreen(cmd.bluetooth_pin); + case Cmd::START_ALERT_FRAME: { + showingBootScreen = false; // this should avoid the edge case where an alert triggers before the boot screen goes away + showingNormalScreen = false; + alertFrames[0] = alertFrame; +#ifdef USE_EINK + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Use fast-refresh for next frame, no skip please + EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update + handleSetOn(true); // Ensure power-on to receive deep-sleep screensaver (PowerFSM should handle?) +#endif + setFrameImmediateDraw(alertFrames); break; + } case Cmd::START_FIRMWARE_UPDATE_SCREEN: handleStartFirmwareUpdateScreen(); break; - case Cmd::STOP_BLUETOOTH_PIN_SCREEN: + case Cmd::STOP_ALERT_FRAME: case Cmd::STOP_BOOT_SCREEN: EINK_ADD_FRAMEFLAG(dispdev, COSMETIC); // E-Ink: Explicitly use full-refresh for next frame setFrames(); @@ -1931,12 +1839,6 @@ int32_t Screen::runOnce() handlePrint(cmd.print_text); free(cmd.print_text); break; - case Cmd::START_SHUTDOWN_SCREEN: - handleShutdownScreen(); - break; - case Cmd::START_REBOOT_SCREEN: - handleRebootScreen(); - break; default: LOG_ERROR("Invalid screen cmd\n"); } @@ -2133,10 +2035,6 @@ void Screen::setFrames() if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) { normalFrames[numframes++] = drawTextMessageFrame; } - // If we have a waypoint - show it next, unless it's a phone message and we aren't using any special modules - if (devicestate.has_rx_waypoint && shouldDrawMessage(&devicestate.rx_waypoint)) { - normalFrames[numframes++] = drawWaypointFrame; - } // then all the nodes // We only show a few nodes in our scrolling list - because meshes with many nodes would have too many screens @@ -2176,17 +2074,6 @@ void Screen::setFrames() setFastFramerate(); // Draw ASAP } -void Screen::handleStartBluetoothPinScreen(uint32_t pin) -{ - LOG_DEBUG("showing bluetooth screen\n"); - showingNormalScreen = false; - EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame - - static FrameCallback frames[] = {drawFrameBluetooth}; - snprintf(btPIN, sizeof(btPIN), "%06u", pin); - setFrameImmediateDraw(frames); -} - void Screen::setFrameImmediateDraw(FrameCallback *drawFrames) { ui->disableAllIndicators(); @@ -2194,41 +2081,6 @@ void Screen::setFrameImmediateDraw(FrameCallback *drawFrames) setFastFramerate(); } -void Screen::handleShutdownScreen() -{ - LOG_DEBUG("showing shutdown screen\n"); - showingNormalScreen = false; -#ifdef USE_EINK - EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Use fast-refresh for next frame, no skip please - EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update - handleSetOn(true); // Ensure power-on to receive deep-sleep screensaver (PowerFSM should handle?) -#endif - - auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { - drawFrameText(display, state, x, y, "Shutting down..."); - }; - static FrameCallback frames[] = {frame}; - - setFrameImmediateDraw(frames); -} - -void Screen::handleRebootScreen() -{ - LOG_DEBUG("showing reboot screen\n"); - showingNormalScreen = false; -#ifdef USE_EINK - EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Use fast-refresh for next frame, no skip please - EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update - handleSetOn(true); // Power-on to show rebooting screen (PowerFSM should handle?) -#endif - - auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { - drawFrameText(display, state, x, y, "Rebooting..."); - }; - static FrameCallback frames[] = {frame}; - setFrameImmediateDraw(frames); -} - void Screen::handleStartFirmwareUpdateScreen() { LOG_DEBUG("showing firmware screen\n"); @@ -2245,7 +2097,7 @@ void Screen::blink() uint8_t count = 10; dispdev->setBrightness(254); while (count > 0) { - dispdev->fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + dispdev->fillRect(0, 0, dispdev->getWidth(), dispdev->getHeight()); dispdev->display(); delay(50); dispdev->clear(); diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index f4d7197152..83c9a7a946 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -21,11 +21,13 @@ class Screen void print(const char *) {} void doDeepSleep() {} void forceDisplay(bool forceUiUpdate = false) {} - void startBluetoothPinScreen(uint32_t pin) {} - void stopBluetoothPinScreen() {} - void startRebootScreen() {} - void startShutdownScreen() {} void startFirmwareUpdateScreen() {} + void increaseBrightness() {} + void decreaseBrightness() {} + void setFunctionSymbal(std::string) {} + void removeFunctionSymbal(std::string) {} + void startAlert(const char *) {} + void endAlert() {} }; } // namespace graphics #else @@ -34,6 +36,8 @@ class Screen #include #include "../configuration.h" +#include "gps/GeoCoord.h" +#include "graphics/ScreenFonts.h" #ifdef USE_ST7567 #include @@ -82,6 +86,46 @@ class Screen #define SEGMENT_WIDTH 16 #define SEGMENT_HEIGHT 4 +/// Convert an integer GPS coords to a floating point +#define DegD(i) (i * 1e-7) + +namespace +{ +/// A basic 2D point class for drawing +class Point +{ + public: + float x, y; + + Point(float _x, float _y) : x(_x), y(_y) {} + + /// Apply a rotation around zero (standard rotation matrix math) + void rotate(float radian) + { + float cos = cosf(radian), sin = sinf(radian); + float rx = x * cos + y * sin, ry = -x * sin + y * cos; + + x = rx; + y = ry; + } + + void translate(int16_t dx, int dy) + { + x += dx; + y += dy; + } + + void scale(float f) + { + // We use -f here to counter the flip that happens + // on the y axis when drawing and rotating on screen + x *= f; + y *= -f; + } +}; + +} // namespace + namespace graphics { @@ -166,41 +210,56 @@ class Screen : public concurrency::OSThread void blink(); + void drawFrameText(OLEDDisplay *, OLEDDisplayUiState *, int16_t, int16_t, const char *); + + void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength); + + // Draw north + void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading); + + static uint16_t getCompassDiam(uint32_t displayWidth, uint32_t displayHeight); + + float estimatedHeading(double lat, double lon); + + void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, uint16_t compassDiam, float headingRadian); + + void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields); + /// Handle button press, trackball or swipe action) void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); } void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); } void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); } - /// Starts showing the Bluetooth PIN screen. - // - // Switches over to a static frame showing the Bluetooth pairing screen - // with the PIN. - void startBluetoothPinScreen(uint32_t pin) + // generic alert start + void startAlert(FrameCallback _alertFrame) { + alertFrame = _alertFrame; ScreenCmd cmd; - cmd.cmd = Cmd::START_BLUETOOTH_PIN_SCREEN; - cmd.bluetooth_pin = pin; + cmd.cmd = Cmd::START_ALERT_FRAME; enqueueCmd(cmd); } - void startFirmwareUpdateScreen() + void startAlert(const char *_alertMessage) { - ScreenCmd cmd; - cmd.cmd = Cmd::START_FIRMWARE_UPDATE_SCREEN; - enqueueCmd(cmd); + startAlert([_alertMessage](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { + uint16_t x_offset = display->width() / 2; + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(x_offset + x, 26 + y, _alertMessage); + }); } - void startShutdownScreen() + void endAlert() { ScreenCmd cmd; - cmd.cmd = Cmd::START_SHUTDOWN_SCREEN; + cmd.cmd = Cmd::STOP_ALERT_FRAME; enqueueCmd(cmd); } - void startRebootScreen() + void startFirmwareUpdateScreen() { ScreenCmd cmd; - cmd.cmd = Cmd::START_REBOOT_SCREEN; + cmd.cmd = Cmd::START_FIRMWARE_UPDATE_SCREEN; enqueueCmd(cmd); } @@ -222,9 +281,6 @@ class Screen : public concurrency::OSThread void setFunctionSymbal(std::string sym); void removeFunctionSymbal(std::string sym); - /// Stops showing the bluetooth PIN screen. - void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); } - /// Stops showing the boot screen. void stopBootScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BOOT_SCREEN}); } @@ -358,7 +414,13 @@ class Screen : public concurrency::OSThread bool isAUTOOled = false; + // Screen dimensions (for convenience) + // Defined during Screen::setup + uint16_t displayWidth = 0; + uint16_t displayHeight = 0; + private: + FrameCallback alertFrames[1]; struct ScreenCmd { Cmd cmd; union { @@ -384,11 +446,8 @@ class Screen : public concurrency::OSThread void handleOnPress(); void handleShowNextFrame(); void handleShowPrevFrame(); - void handleStartBluetoothPinScreen(uint32_t pin); void handlePrint(const char *text); void handleStartFirmwareUpdateScreen(); - void handleShutdownScreen(); - void handleRebootScreen(); /// Rebuilds our list of frames (screens) to default ones. void setFrames(); @@ -426,6 +485,9 @@ class Screen : public concurrency::OSThread bool digitalWatchFace = true; #endif + /// callback for current alert frame + FrameCallback alertFrame; + /// Queue of commands to execute in doTask. TypedQueue cmdQueue; /// Whether we are using a display @@ -452,4 +514,5 @@ class Screen : public concurrency::OSThread }; } // namespace graphics + #endif \ No newline at end of file diff --git a/src/graphics/ScreenFonts.h b/src/graphics/ScreenFonts.h index 4b34563f70..8a48d053e9 100644 --- a/src/graphics/ScreenFonts.h +++ b/src/graphics/ScreenFonts.h @@ -28,8 +28,8 @@ #define FONT_LARGE ArialMT_Plain_24 // Height: 28 #endif -#define fontHeight(font) ((font)[1] + 1) // height is position 1 +#define _fontHeight(font) ((font)[1] + 1) // height is position 1 -#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL) -#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM) -#define FONT_HEIGHT_LARGE fontHeight(FONT_LARGE) +#define FONT_HEIGHT_SMALL _fontHeight(FONT_SMALL) +#define FONT_HEIGHT_MEDIUM _fontHeight(FONT_MEDIUM) +#define FONT_HEIGHT_LARGE _fontHeight(FONT_LARGE) \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index ddb99568da..1e0d998e15 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" +#include "PowerMon.h" #include "ReliableRouter.h" #include "airtime.h" #include "buzz.h" @@ -48,7 +49,6 @@ NimbleBluetooth *nimbleBluetooth = nullptr; #ifdef ARCH_NRF52 #include "NRF52Bluetooth.h" NRF52Bluetooth *nrf52Bluetooth = nullptr; -; #endif #if HAS_WIFI @@ -155,6 +155,7 @@ bool isVibrating = false; bool eink_found = true; uint32_t serialSinceMsec; +bool pauseBluetoothLogging = false; bool pmu_found; @@ -173,7 +174,7 @@ const char *getDeviceName() static char name[20]; snprintf(name, sizeof(name), "%02x%02x", dmac[4], dmac[5]); // if the shortname exists and is NOT the new default of ab3c, use it for BLE name. - if ((owner.short_name != NULL) && (strcmp(owner.short_name, name) != 0)) { + if (strcmp(owner.short_name, name) != 0) { snprintf(name, sizeof(name), "%s_%02x%02x", owner.short_name, dmac[4], dmac[5]); } else { snprintf(name, sizeof(name), "Meshtastic_%02x%02x", dmac[4], dmac[5]); @@ -214,6 +215,14 @@ __attribute__((weak, noinline)) bool loopCanSleep() return true; } +/** + * Print info as a structured log message (for automated log processing) + */ +void printInfo() +{ + LOG_INFO("S:B:%d,%s\n", HW_VENDOR, optstr(APP_VERSION)); +} + void setup() { concurrency::hasBeenSetup = true; @@ -221,7 +230,7 @@ void setup() meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO; OLEDDISPLAY_GEOMETRY screen_geometry = GEOMETRY_128_64; -#ifdef SEGGER_STDOUT_CH +#ifdef USE_SEGGER auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM; #ifdef NRF52840_XXAA auto buflen = 4096; // this board has a fair amount of ram @@ -234,6 +243,7 @@ void setup() #ifdef DEBUG_PORT consoleInit(); // Set serial baud rate and init our mesh console #endif + powerMonInit(); serialSinceMsec = millis(); @@ -553,7 +563,7 @@ void setup() #endif // Hello - LOG_INFO("Meshtastic hwvendor=%d, swver=%s\n", HW_VENDOR, optstr(APP_VERSION)); + printInfo(); #ifdef ARCH_ESP32 esp32Setup(); @@ -930,7 +940,7 @@ void setup() nodeDB->saveToDisk(SEGMENT_CONFIG); if (!rIf->reconfigure()) { LOG_WARN("Reconfigure failed, rebooting\n"); - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); rebootAtMsec = millis() + 5000; } } diff --git a/src/main.h b/src/main.h index 2ef7edb3a9..ea2d80f94a 100644 --- a/src/main.h +++ b/src/main.h @@ -85,6 +85,8 @@ extern uint32_t serialSinceMsec; // This will suppress the current delay and instead try to run ASAP. extern bool runASAP; +extern bool pauseBluetoothLogging; + void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds(), enterDfuMode(); meshtastic_DeviceMetadata getDeviceMetadata(); diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index dd547a6f1a..0fdde52772 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -20,9 +20,8 @@ ErrorCode FloodingRouter::send(meshtastic_MeshPacket *p) bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { if (wasSeenRecently(p)) { // Note: this will also add a recent packet record - printPacket("Ignoring incoming msg, because we've already seen it", p); + printPacket("Ignoring incoming msg we've already seen", p); if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && - config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! Router::cancelSending(p->from, p->id); diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp index bffca0c448..fc059ec16d 100644 --- a/src/mesh/LR11x0Interface.cpp +++ b/src/mesh/LR11x0Interface.cpp @@ -184,6 +184,7 @@ template void LR11x0Interface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** @@ -223,7 +224,7 @@ template void LR11x0Interface::startReceive() 0); // only RX_DONE IRQ is needed, we'll check for PREAMBLE_DETECTED and HEADER_VALID in isActivelyReceiving assert(err == RADIOLIB_ERR_NONE); - isReceiving = true; + RadioLibInterface::startReceive(); // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 2cfb4843cd..9e2a5b1102 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -269,7 +269,7 @@ bool MeshService::trySendPosition(NodeNum dest, bool wantReplies) assert(node); if (hasValidPosition(node)) { -#if HAS_GPS +#if HAS_GPS && !MESHTASTIC_EXCLUDE_GPS if (positionModule) { LOG_INFO("Sending position ping to 0x%x, wantReplies=%d, channel=%d\n", dest, wantReplies, node->channel); positionModule->sendOurPosition(dest, wantReplies, node->channel); @@ -299,6 +299,7 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p) } else { LOG_WARN("ToPhone queue is full, dropping packet.\n"); releaseToPool(p); + fromNum++; // Make sure to notify observers in case they are reconnected so they can get the packets return; } } @@ -373,8 +374,8 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus) pos.time = getValidTime(RTCQualityFromNet); // In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB) - LOG_DEBUG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", pos.timestamp, pos.time, pos.latitude_i, - pos.longitude_i, pos.altitude); + LOG_DEBUG("onGPSChanged() pos@%x time=%u lat=%d lon=%d alt=%d\n", pos.timestamp, pos.time, pos.latitude_i, pos.longitude_i, + pos.altitude); // Update our current position in the local DB nodeDB->updatePosition(nodeDB->getNodeNum(), pos, RX_SRC_LOCAL); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index cf576e94fe..84872e4714 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -26,7 +26,7 @@ #include #ifdef ARCH_ESP32 -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "modules/esp32/StoreForwardModule.h" @@ -141,11 +141,6 @@ NodeDB::NodeDB() if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile))) saveWhat |= SEGMENT_CHANNELS; - if (!devicestate.node_remote_hardware_pins) { - meshtastic_NodeRemoteHardwarePin empty[12] = {meshtastic_RemoteHardwarePin_init_default}; - memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty)); - } - if (config.position.gps_enabled) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED; config.position.gps_enabled = 0; @@ -185,7 +180,7 @@ bool NodeDB::resetRadioConfig(bool factory_reset) if (didFactoryReset) { LOG_INFO("Rebooting due to factory reset"); - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); rebootAtMsec = millis() + (5 * 1000); } @@ -826,8 +821,8 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou if (src == RX_SRC_LOCAL) { // Local packet, fully authoritative - LOG_INFO("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.timestamp, p.time, p.latitude_i, - p.longitude_i, p.altitude); + LOG_INFO("updatePosition LOCAL pos@%x time=%u lat=%d lon=%d alt=%d\n", p.timestamp, p.time, p.latitude_i, p.longitude_i, + p.altitude); setLocalPosition(p); info->position = TypeConversions::ConvertToPositionLite(p); @@ -842,7 +837,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou // recorded based on the packet rxTime // // FIXME perhaps handle RX_SRC_USER separately? - LOG_INFO("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i); + LOG_INFO("updatePosition REMOTE node=0x%x time=%u lat=%d lon=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i); // First, back up fields that we want to protect from overwrite uint32_t tmp_time = info->position.time; diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index e9e36cc617..61bf90d4d3 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -155,8 +155,8 @@ class NodeDB localPosition.timestamp = position.timestamp > 0 ? position.timestamp : position.time; return; } - LOG_DEBUG("Setting local position: latitude=%i, longitude=%i, time=%u, timestamp=%u\n", position.latitude_i, - position.longitude_i, position.time, position.timestamp); + LOG_DEBUG("Setting local position: lat=%i lon=%i time=%u timestamp=%u\n", position.latitude_i, position.longitude_i, + position.time, position.timestamp); localPosition = position; } diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 26d0d9525a..0f69b21f9c 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -5,6 +5,7 @@ #include "Channels.h" #include "Default.h" +#include "FSCommon.h" #include "MeshService.h" #include "NodeDB.h" #include "PhoneAPI.h" @@ -46,6 +47,9 @@ void PhoneAPI::handleStartConfig() // even if we were already connected - restart our state machine state = STATE_SEND_MY_INFO; + pauseBluetoothLogging = true; + filesManifest = getFiles("/", 10); + LOG_DEBUG("Got %d files in manifest\n", filesManifest.size()); LOG_INFO("Starting API client config\n"); nodeInfoForPhone.num = 0; // Don't keep returning old nodeinfos @@ -148,6 +152,7 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) STATE_SEND_CONFIG, STATE_SEND_MODULE_CONFIG, STATE_SEND_OTHER_NODEINFOS, // states progress in this order as the device sends to the client + STATE_SEND_FILEMANIFEST, STATE_SEND_COMPLETE_ID, STATE_SEND_PACKETS // send packets or debug strings */ @@ -323,7 +328,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Advance when we have sent all of our ModuleConfig objects if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1)) { // Clients sending special nonce don't want to see other nodeinfos - state = config_nonce == SPECIAL_NONCE ? STATE_SEND_COMPLETE_ID : STATE_SEND_OTHER_NODEINFOS; + state = config_nonce == SPECIAL_NONCE ? STATE_SEND_FILEMANIFEST : STATE_SEND_OTHER_NODEINFOS; config_state = 0; } break; @@ -339,22 +344,36 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) nodeInfoForPhone.num = 0; // We just consumed a nodeinfo, will need a new one next time } else { LOG_INFO("Done sending nodeinfos\n"); - state = STATE_SEND_COMPLETE_ID; + state = STATE_SEND_FILEMANIFEST; // Go ahead and send that ID right now return getFromRadio(buf); } break; } + case STATE_SEND_FILEMANIFEST: { + LOG_INFO("getFromRadio=STATE_SEND_FILEMANIFEST\n"); + // last element + if (config_state == filesManifest.size()) { // also handles an empty filesManifest + config_state = 0; + filesManifest.clear(); + // Skip to complete packet + sendConfigComplete(); + } else { + fromRadioScratch.which_payload_variant = meshtastic_FromRadio_fileInfo_tag; + fromRadioScratch.fileInfo = filesManifest.at(config_state); + LOG_DEBUG("File: %s (%d) bytes\n", fromRadioScratch.fileInfo.file_name, fromRadioScratch.fileInfo.size_bytes); + config_state++; + } + break; + } + case STATE_SEND_COMPLETE_ID: - LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n"); - fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag; - fromRadioScratch.config_complete_id = config_nonce; - config_nonce = 0; - state = STATE_SEND_PACKETS; + sendConfigComplete(); break; case STATE_SEND_PACKETS: + pauseBluetoothLogging = false; // Do we have a message from the mesh or packet from the local device? LOG_INFO("getFromRadio=STATE_SEND_PACKETS\n"); if (queueStatusPacketForPhone) { @@ -388,7 +407,9 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Encapsulate as a FromRadio packet size_t numbytes = pb_encode_to_bytes(buf, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch); - LOG_DEBUG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes); + // VERY IMPORTANT to not print debug messages while writing to fromRadioScratch - because we use that same buffer + // for logging (when we are encapsulating with protobufs) + // LOG_DEBUG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes); return numbytes; } @@ -396,8 +417,20 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) return 0; } +void PhoneAPI::sendConfigComplete() +{ + LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n"); + fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag; + fromRadioScratch.config_complete_id = config_nonce; + config_nonce = 0; + state = STATE_SEND_PACKETS; + pauseBluetoothLogging = false; +} + void PhoneAPI::handleDisconnect() { + filesManifest.clear(); + pauseBluetoothLogging = false; LOG_INFO("PhoneAPI disconnect\n"); } @@ -439,6 +472,7 @@ bool PhoneAPI::available() case STATE_SEND_MODULECONFIG: case STATE_SEND_METADATA: case STATE_SEND_OWN_NODEINFO: + case STATE_SEND_FILEMANIFEST: case STATE_SEND_COMPLETE_ID: return true; @@ -453,7 +487,6 @@ bool PhoneAPI::available() } } return true; // Always say we have something, because we might need to advance our state machine - case STATE_SEND_PACKETS: { if (!queueStatusPacketForPhone) queueStatusPacketForPhone = service.getQueueStatusForPhone(); diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 49bf0e292b..3c3668300a 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -2,10 +2,20 @@ #include "Observer.h" #include "mesh-pb-constants.h" +#include #include +#include // Make sure that we never let our packets grow too large for one BLE packet #define MAX_TO_FROM_RADIO_SIZE 512 + +#if meshtastic_FromRadio_size > MAX_TO_FROM_RADIO_SIZE +#error "meshtastic_FromRadio_size is too large for our BLE packets" +#endif +#if meshtastic_ToRadio_size > MAX_TO_FROM_RADIO_SIZE +#error "meshtastic_ToRadio_size is too large for our BLE packets" +#endif + #define SPECIAL_NONCE 69420 /** @@ -29,6 +39,7 @@ class PhoneAPI STATE_SEND_CONFIG, // Replacement for the old Radioconfig STATE_SEND_MODULECONFIG, // Send Module specific config STATE_SEND_OTHER_NODEINFOS, // states progress in this order as the device sends to to the client + STATE_SEND_FILEMANIFEST, // Send file manifest STATE_SEND_COMPLETE_ID, STATE_SEND_PACKETS // send packets or debug strings }; @@ -65,6 +76,8 @@ class PhoneAPI uint32_t config_nonce = 0; uint32_t readIndex = 0; + std::vector filesManifest = {}; + void resetReadIndex() { readIndex = 0; } public: @@ -91,6 +104,8 @@ class PhoneAPI */ size_t getFromRadio(uint8_t *buf); + void sendConfigComplete(); + /** * Return true if we have data available to send to the phone */ @@ -98,8 +113,6 @@ class PhoneAPI bool isConnected() { return state != STATE_SEND_NOTHING; } - void setInitialState() { state = STATE_SEND_MY_INFO; } - protected: /// Our fromradio packet while it is being assembled meshtastic_FromRadio fromRadioScratch = {}; diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index c5356ad3bd..bd1ebdb0e6 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -25,7 +25,8 @@ typedef struct { } DACDB; // Interpolation function -DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val2) { +DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val2) +{ DACDB result; double fraction = (double)(dbm - dbm1) / (dbm2 - dbm1); result.dac = (uint8_t)(val1.dac + fraction * (val2.dac - val1.dac)); @@ -34,16 +35,17 @@ DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val } // Function to find the correct DAC and DB values based on dBm using interpolation -DACDB getDACandDB(uint8_t dbm) { +DACDB getDACandDB(uint8_t dbm) +{ // Predefined values static const struct { uint8_t dbm; DACDB values; } dbmToDACDB[] = { - {20, {168, 2}}, // 100mW - {24, {148, 6}}, // 250mW - {27, {128, 9}}, // 500mW - {30, {90, 12}} // 1000mW + {20, {168, 2}}, // 100mW + {24, {148, 6}}, // 250mW + {27, {128, 9}}, // 500mW + {30, {90, 12}} // 1000mW }; const int numValues = sizeof(dbmToDACDB) / sizeof(dbmToDACDB[0]); @@ -103,7 +105,7 @@ bool RF95Interface::init() if (power > RF95_MAX_POWER) // This chip has lower power limits than some power = RF95_MAX_POWER; - + limitPower(); iface = lora = new RadioLibRF95(&module); @@ -116,13 +118,13 @@ bool RF95Interface::init() // enable PA #ifdef RF95_PA_EN #if defined(RF95_PA_DAC_EN) - #ifdef RADIOMASTER_900_BANDIT_NANO - // Use calculated DAC value - dacWrite(RF95_PA_EN, powerDAC); - #else - // Use Value set in /*/variant.h - dacWrite(RF95_PA_EN, RF95_PA_LEVEL); - #endif +#ifdef RADIOMASTER_900_BANDIT_NANO + // Use calculated DAC value + dacWrite(RF95_PA_EN, powerDAC); +#else + // Use Value set in /*/variant.h + dacWrite(RF95_PA_EN, RF95_PA_LEVEL); +#endif #endif #endif @@ -254,6 +256,7 @@ void RF95Interface::setStandby() isReceiving = false; // If we were receiving, not any more disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** We override to turn on transmitter power as needed. diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 78228c077c..343b7f2008 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -261,7 +261,6 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr) uint8_t CWsize = map(snr, SNR_MIN, SNR_MAX, CWmin, CWmax); // LOG_DEBUG("rx_snr of %f so setting CWsize to:%d\n", snr, CWsize); if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || - config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT || config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { delay = random(0, 2 * CWsize) * slotTimeMsec; LOG_DEBUG("rx_snr found in packet. As a router, setting tx delay:%d\n", delay); @@ -522,7 +521,7 @@ void RadioInterface::applyModemConfig() LOG_INFO("Radio freq=%.3f, config.lora.frequency_offset=%.3f\n", freq, loraConfig.frequency_offset); LOG_INFO("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d\n", myRegion->name, channelName, loraConfig.modem_preset, channel_num, power); - LOG_INFO("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd, + LOG_INFO("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f MHz)\n", myRegion->freqStart, myRegion->freqEnd, myRegion->freqEnd - myRegion->freqStart); LOG_INFO("Radio myRegion->numChannels: %d x %.3fkHz\n", numChannels, bw); LOG_INFO("Radio channel_num: %d\n", channel_num + 1); diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index a4ceac9f12..f299ebff2c 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -1,6 +1,7 @@ #include "RadioLibInterface.h" #include "MeshTypes.h" #include "NodeDB.h" +#include "PowerMon.h" #include "SPILock.h" #include "configuration.h" #include "error.h" @@ -317,6 +318,7 @@ void RadioLibInterface::handleTransmitInterrupt() // ignore the transmit interrupt if (sendingPacket) completeSending(); + powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // But our transmitter is deffinitely off now } void RadioLibInterface::completeSending() @@ -412,6 +414,24 @@ void RadioLibInterface::handleReceiveInterrupt() } } +void RadioLibInterface::startReceive() +{ + isReceiving = true; + powerMon->setState(meshtastic_PowerMon_State_Lora_RXOn); +} + +void RadioLibInterface::configHardwareForSend() +{ + powerMon->setState(meshtastic_PowerMon_State_Lora_TXOn); +} + +void RadioLibInterface::setStandby() +{ + // neither sending nor receiving + powerMon->clearState(meshtastic_PowerMon_State_Lora_RXOn); + powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); +} + /** start an immediate transmit */ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp) { @@ -431,6 +451,7 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp) // This send failed, but make sure to 'complete' it properly completeSending(); + powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // Transmitter off now startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode) } diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 2c841a19ef..dd01d2037f 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -126,8 +126,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified * Start waiting to receive a message * * External functions can call this method to wake the device from sleep. + * Subclasses must override and call this base method */ - virtual void startReceive() = 0; + virtual void startReceive(); /** can we detect a LoRa preamble on the current channel? */ virtual bool isChannelActive() = 0; @@ -166,8 +167,9 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified meshtastic_QueueStatus getQueueStatus(); protected: - /** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */ - virtual void configHardwareForSend() {} + /** Do any hardware setup needed on entry into send configuration for the radio. + * Subclasses can customize, but must also call this base method */ + virtual void configHardwareForSend(); /** Could we send right now (i.e. either not actively receiving or transmitting)? */ virtual bool canSendImmediately(); @@ -186,5 +188,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified */ virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0; - virtual void setStandby() = 0; + /** + * Subclasses must override, implement and then call into this base class implementation + */ + virtual void setStandby(); }; \ No newline at end of file diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 3141d986bb..c8c18ae6d5 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -244,8 +244,10 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) // If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it) - assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag || - p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now + if (!(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag || + p->which_payload_variant == meshtastic_MeshPacket_decoded_tag)) { + return meshtastic_Routing_Error_BAD_REQUEST; + } // If the packet is not yet encrypted, do so now if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index afaa13b7f0..b564ba287e 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -231,6 +231,7 @@ template void SX126xInterface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** @@ -270,7 +271,7 @@ template void SX126xInterface::startReceive() LOG_ERROR("Radiolib error %d when attempting SX126X startReceiveDutyCycleAuto!\n", err); assert(err == RADIOLIB_ERR_NONE); - isReceiving = true; + RadioLibInterface::startReceive(); // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index 9e4fbfa772..fdb2b9a395 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -190,6 +190,7 @@ template void SX128xInterface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore + RadioLibInterface::setStandby(); } /** @@ -263,7 +264,7 @@ template void SX128xInterface::startReceive() LOG_ERROR("Radiolib error %d when attempting SX128X startReceive!\n", err); assert(err == RADIOLIB_ERR_NONE); - isReceiving = true; + RadioLibInterface::startReceive(); // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp index 4d04dffe48..9f59aa971c 100644 --- a/src/mesh/StreamAPI.cpp +++ b/src/mesh/StreamAPI.cpp @@ -1,5 +1,6 @@ #include "StreamAPI.h" #include "PowerFSM.h" +#include "RTC.h" #include "configuration.h" #define START1 0x94 @@ -96,7 +97,6 @@ void StreamAPI::writeStream() void StreamAPI::emitTxBuffer(size_t len) { if (len != 0) { - // LOG_DEBUG("emit tx %d\n", len); txBuf[0] = START1; txBuf[1] = START2; txBuf[2] = (len >> 8) & 0xff; @@ -119,6 +119,25 @@ void StreamAPI::emitRebooted() emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch)); } +void StreamAPI::emitLogRecord(meshtastic_LogRecord_Level level, const char *src, const char *format, va_list arg) +{ + // In case we send a FromRadio packet + memset(&fromRadioScratch, 0, sizeof(fromRadioScratch)); + fromRadioScratch.which_payload_variant = meshtastic_FromRadio_log_record_tag; + fromRadioScratch.log_record.level = level; + + uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); + fromRadioScratch.log_record.time = rtc_sec; + strncpy(fromRadioScratch.log_record.source, src, sizeof(fromRadioScratch.log_record.source) - 1); + + auto num_printed = + vsnprintf(fromRadioScratch.log_record.message, sizeof(fromRadioScratch.log_record.message) - 1, format, arg); + if (num_printed > 0 && fromRadioScratch.log_record.message[num_printed - 1] == + '\n') // Strip any ending newline, because we have records for framing instead. + fromRadioScratch.log_record.message[num_printed - 1] = '\0'; + emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch)); +} + /// Hookable to find out when connection changes void StreamAPI::onConnectionChanged(bool connected) { @@ -131,4 +150,4 @@ void StreamAPI::onConnectionChanged(bool connected) // received a packet in a while powerFSM.trigger(EVENT_SERIAL_DISCONNECTED); } -} +} \ No newline at end of file diff --git a/src/mesh/StreamAPI.h b/src/mesh/StreamAPI.h index 3196e96f8b..45cbb231c7 100644 --- a/src/mesh/StreamAPI.h +++ b/src/mesh/StreamAPI.h @@ -82,4 +82,7 @@ class StreamAPI : public PhoneAPI /// Subclasses can use this scratch buffer if they wish uint8_t txBuf[MAX_STREAM_BUF_SIZE] = {0}; -}; + + /// Low level function to emit a protobuf encapsulated log record + void emitLogRecord(meshtastic_LogRecord_Level level, const char *src, const char *format, va_list arg); +}; \ No newline at end of file diff --git a/src/mesh/eth/ethClient.cpp b/src/mesh/eth/ethClient.cpp index 5373f243e6..9f3bb8ab7f 100644 --- a/src/mesh/eth/ethClient.cpp +++ b/src/mesh/eth/ethClient.cpp @@ -12,6 +12,8 @@ #include #include +#if HAS_NETWORKING + #ifndef DISABLE_NTP #include @@ -183,3 +185,5 @@ bool isEthernetAvailable() return true; } } + +#endif \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 5a78f13668..e3037c910d 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -22,7 +22,6 @@ typedef enum _meshtastic_Config_DeviceConfig_Role { The wifi radio and the oled screen will be put to sleep. This mode may still potentially have higher power usage due to it's preference in message rebroadcasting on the mesh. */ meshtastic_Config_DeviceConfig_Role_ROUTER = 2, - /* Description: Combination of both ROUTER and CLIENT. Not for mobile devices. */ meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT = 3, /* Description: Infrastructure node for extending network coverage by relaying messages with minimal overhead. Not visible in Nodes list. Technical Details: Mesh packets will simply be rebroadcasted over this node. Nodes configured with this role will not originate NodeInfo, Position, Telemetry @@ -372,6 +371,9 @@ typedef struct _meshtastic_Config_PowerConfig { uint32_t min_wake_secs; /* I2C address of INA_2XX to use for reading device battery voltage */ uint8_t device_battery_ina_address; + /* If non-zero, we want powermon log outputs. With the particular (bitfield) sources enabled. + Note: we picked an ID of 32 so that lower more efficient IDs can be used for more frequently used options. */ + uint64_t powermon_enables; } meshtastic_Config_PowerConfig; typedef struct _meshtastic_Config_NetworkConfig_IpV4Config { @@ -612,7 +614,7 @@ extern "C" { #define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}} #define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} #define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} -#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} @@ -621,7 +623,7 @@ extern "C" { #define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}} #define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} #define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} -#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} @@ -662,6 +664,7 @@ extern "C" { #define meshtastic_Config_PowerConfig_ls_secs_tag 7 #define meshtastic_Config_PowerConfig_min_wake_secs_tag 8 #define meshtastic_Config_PowerConfig_device_battery_ina_address_tag 9 +#define meshtastic_Config_PowerConfig_powermon_enables_tag 32 #define meshtastic_Config_NetworkConfig_IpV4Config_ip_tag 1 #define meshtastic_Config_NetworkConfig_IpV4Config_gateway_tag 2 #define meshtastic_Config_NetworkConfig_IpV4Config_subnet_tag 3 @@ -773,7 +776,8 @@ X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \ X(a, STATIC, SINGULAR, UINT32, sds_secs, 6) \ X(a, STATIC, SINGULAR, UINT32, ls_secs, 7) \ X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 8) \ -X(a, STATIC, SINGULAR, UINT32, device_battery_ina_address, 9) +X(a, STATIC, SINGULAR, UINT32, device_battery_ina_address, 9) \ +X(a, STATIC, SINGULAR, UINT64, powermon_enables, 32) #define meshtastic_Config_PowerConfig_CALLBACK NULL #define meshtastic_Config_PowerConfig_DEFAULT NULL @@ -871,7 +875,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 196 #define meshtastic_Config_PositionConfig_size 62 -#define meshtastic_Config_PowerConfig_size 40 +#define meshtastic_Config_PowerConfig_size 52 #define meshtastic_Config_size 199 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index 5e291ee947..fc7bea53a4 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -8,7 +8,6 @@ #include "meshtastic/channel.pb.h" #include "meshtastic/localonly.pb.h" #include "meshtastic/mesh.pb.h" -#include "meshtastic/module_config.pb.h" #include "meshtastic/telemetry.pb.h" #if PB_PROTO_HEADER_VERSION != 40 @@ -308,7 +307,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size #define meshtastic_ChannelFile_size 718 #define meshtastic_NodeInfoLite_size 166 -#define meshtastic_OEMStore_size 3372 +#define meshtastic_OEMStore_size 3384 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 96a9976f03..c1d2a4ae3e 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -181,7 +181,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size -#define meshtastic_LocalConfig_size 541 +#define meshtastic_LocalConfig_size 553 #define meshtastic_LocalModuleConfig_size 685 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/mesh.pb.cpp b/src/mesh/generated/meshtastic/mesh.pb.cpp index 46d59d6094..3fa81e1312 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.cpp +++ b/src/mesh/generated/meshtastic/mesh.pb.cpp @@ -36,7 +36,7 @@ PB_BIND(meshtastic_NodeInfo, meshtastic_NodeInfo, AUTO) PB_BIND(meshtastic_MyNodeInfo, meshtastic_MyNodeInfo, AUTO) -PB_BIND(meshtastic_LogRecord, meshtastic_LogRecord, AUTO) +PB_BIND(meshtastic_LogRecord, meshtastic_LogRecord, 2) PB_BIND(meshtastic_QueueStatus, meshtastic_QueueStatus, AUTO) @@ -45,6 +45,9 @@ PB_BIND(meshtastic_QueueStatus, meshtastic_QueueStatus, AUTO) PB_BIND(meshtastic_FromRadio, meshtastic_FromRadio, 2) +PB_BIND(meshtastic_FileInfo, meshtastic_FileInfo, AUTO) + + PB_BIND(meshtastic_ToRadio, meshtastic_ToRadio, 2) diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 0641158155..dbe9281ec0 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -167,6 +167,15 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO = 64, /* Heltec Capsule Sensor V3 with ESP32-S3 CPU, Portable LoRa device that can replace GNSS modules or sensors */ meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3 = 65, + /* Heltec Vision Master T190 with ESP32-S3 CPU, and a 1.90 inch TFT display */ + meshtastic_HardwareModel_HELTEC_VISION_MASTER_T190 = 66, + /* Heltec Vision Master E213 with ESP32-S3 CPU, and a 2.13 inch E-Ink display */ + meshtastic_HardwareModel_HELTEC_VISION_MASTER_E213 = 67, + /* Heltec Vision Master E290 with ESP32-S3 CPU, and a 2.9 inch E-Ink display */ + meshtastic_HardwareModel_HELTEC_VISION_MASTER_E290 = 68, + /* Heltec Mesh Node T114 board with nRF52840 CPU, and a 1.14 inch TFT display, Ultimate low-power design, + specifically adapted for the Meshtatic project */ + meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 = 69, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ @@ -691,11 +700,11 @@ typedef struct _meshtastic_MyNodeInfo { and then extend as needed by emitting multiple records. */ typedef struct _meshtastic_LogRecord { /* Log levels, chosen to match python logging conventions. */ - char message[64]; + char message[384]; /* Seconds since 1970 - or 0 for unknown/unset */ uint32_t time; /* Usually based on thread name - if known */ - char source[8]; + char source[32]; /* Not yet set */ meshtastic_LogRecord_Level level; } meshtastic_LogRecord; @@ -711,6 +720,14 @@ typedef struct _meshtastic_QueueStatus { uint32_t mesh_packet_id; } meshtastic_QueueStatus; +/* Individual File info for the device */ +typedef struct _meshtastic_FileInfo { + /* The fully qualified path of the file */ + char file_name[228]; + /* The size of the file in bytes */ + uint32_t size_bytes; +} meshtastic_FileInfo; + typedef PB_BYTES_ARRAY_T(237) meshtastic_Compressed_data_t; /* Compressed message payload */ typedef struct _meshtastic_Compressed { @@ -815,6 +832,8 @@ typedef struct _meshtastic_FromRadio { meshtastic_DeviceMetadata metadata; /* MQTT Client Proxy Message (device sending to client / phone for publishing to MQTT) */ meshtastic_MqttClientProxyMessage mqttClientProxyMessage; + /* File system manifest messages */ + meshtastic_FileInfo fileInfo; }; } meshtastic_FromRadio; @@ -958,6 +977,7 @@ extern "C" { + #define meshtastic_Compressed_portnum_ENUMTYPE meshtastic_PortNum @@ -985,6 +1005,7 @@ extern "C" { #define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_default {0, 0, 0, 0} #define meshtastic_FromRadio_init_default {0, 0, {meshtastic_MeshPacket_init_default}} +#define meshtastic_FileInfo_init_default {"", 0} #define meshtastic_ToRadio_init_default {0, {meshtastic_MeshPacket_init_default}} #define meshtastic_Compressed_init_default {_meshtastic_PortNum_MIN, {0, {0}}} #define meshtastic_NeighborInfo_init_default {0, 0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}} @@ -1008,6 +1029,7 @@ extern "C" { #define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_zero {0, 0, 0, 0} #define meshtastic_FromRadio_init_zero {0, 0, {meshtastic_MeshPacket_init_zero}} +#define meshtastic_FileInfo_init_zero {"", 0} #define meshtastic_ToRadio_init_zero {0, {meshtastic_MeshPacket_init_zero}} #define meshtastic_Compressed_init_zero {_meshtastic_PortNum_MIN, {0, {0}}} #define meshtastic_NeighborInfo_init_zero {0, 0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}} @@ -1110,6 +1132,8 @@ extern "C" { #define meshtastic_QueueStatus_free_tag 2 #define meshtastic_QueueStatus_maxlen_tag 3 #define meshtastic_QueueStatus_mesh_packet_id_tag 4 +#define meshtastic_FileInfo_file_name_tag 1 +#define meshtastic_FileInfo_size_bytes_tag 2 #define meshtastic_Compressed_portnum_tag 1 #define meshtastic_Compressed_data_tag 2 #define meshtastic_Neighbor_node_id_tag 1 @@ -1144,6 +1168,7 @@ extern "C" { #define meshtastic_FromRadio_xmodemPacket_tag 12 #define meshtastic_FromRadio_metadata_tag 13 #define meshtastic_FromRadio_mqttClientProxyMessage_tag 14 +#define meshtastic_FromRadio_fileInfo_tag 15 #define meshtastic_ToRadio_packet_tag 1 #define meshtastic_ToRadio_want_config_id_tag 3 #define meshtastic_ToRadio_disconnect_tag 4 @@ -1321,7 +1346,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,queueStatus,queueStatus), 11) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 12) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,metadata,metadata), 13) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 14) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 14) \ +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,fileInfo,fileInfo), 15) #define meshtastic_FromRadio_CALLBACK NULL #define meshtastic_FromRadio_DEFAULT NULL #define meshtastic_FromRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket @@ -1335,6 +1361,13 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttC #define meshtastic_FromRadio_payload_variant_xmodemPacket_MSGTYPE meshtastic_XModem #define meshtastic_FromRadio_payload_variant_metadata_MSGTYPE meshtastic_DeviceMetadata #define meshtastic_FromRadio_payload_variant_mqttClientProxyMessage_MSGTYPE meshtastic_MqttClientProxyMessage +#define meshtastic_FromRadio_payload_variant_fileInfo_MSGTYPE meshtastic_FileInfo + +#define meshtastic_FileInfo_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, file_name, 1) \ +X(a, STATIC, SINGULAR, UINT32, size_bytes, 2) +#define meshtastic_FileInfo_CALLBACK NULL +#define meshtastic_FileInfo_DEFAULT NULL #define meshtastic_ToRadio_FIELDLIST(X, a) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \ @@ -1434,6 +1467,7 @@ extern const pb_msgdesc_t meshtastic_MyNodeInfo_msg; extern const pb_msgdesc_t meshtastic_LogRecord_msg; extern const pb_msgdesc_t meshtastic_QueueStatus_msg; extern const pb_msgdesc_t meshtastic_FromRadio_msg; +extern const pb_msgdesc_t meshtastic_FileInfo_msg; extern const pb_msgdesc_t meshtastic_ToRadio_msg; extern const pb_msgdesc_t meshtastic_Compressed_msg; extern const pb_msgdesc_t meshtastic_NeighborInfo_msg; @@ -1459,6 +1493,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_LogRecord_fields &meshtastic_LogRecord_msg #define meshtastic_QueueStatus_fields &meshtastic_QueueStatus_msg #define meshtastic_FromRadio_fields &meshtastic_FromRadio_msg +#define meshtastic_FileInfo_fields &meshtastic_FileInfo_msg #define meshtastic_ToRadio_fields &meshtastic_ToRadio_msg #define meshtastic_Compressed_fields &meshtastic_Compressed_msg #define meshtastic_NeighborInfo_fields &meshtastic_NeighborInfo_msg @@ -1478,9 +1513,10 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_Compressed_size 243 #define meshtastic_Data_size 270 #define meshtastic_DeviceMetadata_size 46 +#define meshtastic_FileInfo_size 236 #define meshtastic_FromRadio_size 510 #define meshtastic_Heartbeat_size 0 -#define meshtastic_LogRecord_size 81 +#define meshtastic_LogRecord_size 426 #define meshtastic_MeshPacket_size 326 #define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 18 diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index 233e8d6534..6cc82352ab 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -124,6 +124,8 @@ typedef enum _meshtastic_PortNum { meshtastic_PortNum_ATAK_PLUGIN = 72, /* Provides unencrypted information about a node for consumption by a map via MQTT */ meshtastic_PortNum_MAP_REPORT_APP = 73, + /* PowerStress based monitoring support (for automated power consumption testing) */ + meshtastic_PortNum_POWERSTRESS_APP = 74, /* Private applications should use portnums >= 256. To simplify initial development and testing you can use "PRIVATE_APP" in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */ diff --git a/src/mesh/generated/meshtastic/powermon.pb.cpp b/src/mesh/generated/meshtastic/powermon.pb.cpp new file mode 100644 index 0000000000..ce41ea0217 --- /dev/null +++ b/src/mesh/generated/meshtastic/powermon.pb.cpp @@ -0,0 +1,17 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.8 */ + +#include "meshtastic/powermon.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(meshtastic_PowerMon, meshtastic_PowerMon, AUTO) + + +PB_BIND(meshtastic_PowerStressMessage, meshtastic_PowerStressMessage, AUTO) + + + + + diff --git a/src/mesh/generated/meshtastic/powermon.pb.h b/src/mesh/generated/meshtastic/powermon.pb.h new file mode 100644 index 0000000000..7de0618e9b --- /dev/null +++ b/src/mesh/generated/meshtastic/powermon.pb.h @@ -0,0 +1,138 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.8 */ + +#ifndef PB_MESHTASTIC_MESHTASTIC_POWERMON_PB_H_INCLUDED +#define PB_MESHTASTIC_MESHTASTIC_POWERMON_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +/* Any significant power changing event in meshtastic should be tagged with a powermon state transition. +If you are making new meshtastic features feel free to add new entries at the end of this definition. */ +typedef enum _meshtastic_PowerMon_State { + meshtastic_PowerMon_State_None = 0, + meshtastic_PowerMon_State_CPU_DeepSleep = 1, + meshtastic_PowerMon_State_CPU_LightSleep = 2, + /* The external Vext1 power is on. Many boards have auxillary power rails that the CPU turns on only +occasionally. In cases where that rail has multiple devices on it we usually want to have logging on +the state of that rail as an independent record. +For instance on the Heltec Tracker 1.1 board, this rail is the power source for the GPS and screen. + +The log messages will be short and complete (see PowerMon.Event in the protobufs for details). +something like "S:PM:C,0x00001234,REASON" where the hex number is the bitmask of all current states. +(We use a bitmask for states so that if a log message gets lost it won't be fatal) */ + meshtastic_PowerMon_State_Vext1_On = 4, + meshtastic_PowerMon_State_Lora_RXOn = 8, + meshtastic_PowerMon_State_Lora_TXOn = 16, + meshtastic_PowerMon_State_Lora_RXActive = 32, + meshtastic_PowerMon_State_BT_On = 64, + meshtastic_PowerMon_State_LED_On = 128, + meshtastic_PowerMon_State_Screen_On = 256, + meshtastic_PowerMon_State_Screen_Drawing = 512, + meshtastic_PowerMon_State_Wifi_On = 1024, + /* GPS is actively trying to find our location +See GPSPowerState for more details */ + meshtastic_PowerMon_State_GPS_Active = 2048 +} meshtastic_PowerMon_State; + +/* What operation would we like the UUT to perform. +note: senders should probably set want_response in their request packets, so that they can know when the state +machine has started processing their request */ +typedef enum _meshtastic_PowerStressMessage_Opcode { + /* Unset/unused */ + meshtastic_PowerStressMessage_Opcode_UNSET = 0, + meshtastic_PowerStressMessage_Opcode_PRINT_INFO = 1, /* Print board version slog and send an ack that we are alive and ready to process commands */ + meshtastic_PowerStressMessage_Opcode_FORCE_QUIET = 2, /* Try to turn off all automatic processing of packets, screen, sleeping, etc (to make it easier to measure in isolation) */ + meshtastic_PowerStressMessage_Opcode_END_QUIET = 3, /* Stop powerstress processing - probably by just rebooting the board */ + meshtastic_PowerStressMessage_Opcode_SCREEN_ON = 16, /* Turn the screen on */ + meshtastic_PowerStressMessage_Opcode_SCREEN_OFF = 17, /* Turn the screen off */ + meshtastic_PowerStressMessage_Opcode_CPU_IDLE = 32, /* Let the CPU run but we assume mostly idling for num_seconds */ + meshtastic_PowerStressMessage_Opcode_CPU_DEEPSLEEP = 33, /* Force deep sleep for FIXME seconds */ + meshtastic_PowerStressMessage_Opcode_CPU_FULLON = 34, /* Spin the CPU as fast as possible for num_seconds */ + meshtastic_PowerStressMessage_Opcode_LED_ON = 48, /* Turn the LED on for num_seconds (and leave it on - for baseline power measurement purposes) */ + meshtastic_PowerStressMessage_Opcode_LED_OFF = 49, /* Force the LED off for num_seconds */ + meshtastic_PowerStressMessage_Opcode_LORA_OFF = 64, /* Completely turn off the LORA radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_LORA_TX = 65, /* Send Lora packets for num_seconds */ + meshtastic_PowerStressMessage_Opcode_LORA_RX = 66, /* Receive Lora packets for num_seconds (node will be mostly just listening, unless an external agent is helping stress this by sending packets on the current channel) */ + meshtastic_PowerStressMessage_Opcode_BT_OFF = 80, /* Turn off the BT radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_BT_ON = 81, /* Turn on the BT radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_WIFI_OFF = 96, /* Turn off the WIFI radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_WIFI_ON = 97, /* Turn on the WIFI radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_GPS_OFF = 112, /* Turn off the GPS radio for num_seconds */ + meshtastic_PowerStressMessage_Opcode_GPS_ON = 113 /* Turn on the GPS radio for num_seconds */ +} meshtastic_PowerStressMessage_Opcode; + +/* Struct definitions */ +/* Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs). +But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) */ +typedef struct _meshtastic_PowerMon { + char dummy_field; +} meshtastic_PowerMon; + +/* PowerStress testing support via the C++ PowerStress module */ +typedef struct _meshtastic_PowerStressMessage { + /* What type of HardwareMessage is this? */ + meshtastic_PowerStressMessage_Opcode cmd; + float num_seconds; +} meshtastic_PowerStressMessage; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Helper constants for enums */ +#define _meshtastic_PowerMon_State_MIN meshtastic_PowerMon_State_None +#define _meshtastic_PowerMon_State_MAX meshtastic_PowerMon_State_GPS_Active +#define _meshtastic_PowerMon_State_ARRAYSIZE ((meshtastic_PowerMon_State)(meshtastic_PowerMon_State_GPS_Active+1)) + +#define _meshtastic_PowerStressMessage_Opcode_MIN meshtastic_PowerStressMessage_Opcode_UNSET +#define _meshtastic_PowerStressMessage_Opcode_MAX meshtastic_PowerStressMessage_Opcode_GPS_ON +#define _meshtastic_PowerStressMessage_Opcode_ARRAYSIZE ((meshtastic_PowerStressMessage_Opcode)(meshtastic_PowerStressMessage_Opcode_GPS_ON+1)) + + +#define meshtastic_PowerStressMessage_cmd_ENUMTYPE meshtastic_PowerStressMessage_Opcode + + +/* Initializer values for message structs */ +#define meshtastic_PowerMon_init_default {0} +#define meshtastic_PowerStressMessage_init_default {_meshtastic_PowerStressMessage_Opcode_MIN, 0} +#define meshtastic_PowerMon_init_zero {0} +#define meshtastic_PowerStressMessage_init_zero {_meshtastic_PowerStressMessage_Opcode_MIN, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define meshtastic_PowerStressMessage_cmd_tag 1 +#define meshtastic_PowerStressMessage_num_seconds_tag 2 + +/* Struct field encoding specification for nanopb */ +#define meshtastic_PowerMon_FIELDLIST(X, a) \ + +#define meshtastic_PowerMon_CALLBACK NULL +#define meshtastic_PowerMon_DEFAULT NULL + +#define meshtastic_PowerStressMessage_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, cmd, 1) \ +X(a, STATIC, SINGULAR, FLOAT, num_seconds, 2) +#define meshtastic_PowerStressMessage_CALLBACK NULL +#define meshtastic_PowerStressMessage_DEFAULT NULL + +extern const pb_msgdesc_t meshtastic_PowerMon_msg; +extern const pb_msgdesc_t meshtastic_PowerStressMessage_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define meshtastic_PowerMon_fields &meshtastic_PowerMon_msg +#define meshtastic_PowerStressMessage_fields &meshtastic_PowerStressMessage_msg + +/* Maximum encoded size of messages (where known) */ +#define MESHTASTIC_MESHTASTIC_POWERMON_PB_H_MAX_SIZE meshtastic_PowerStressMessage_size +#define meshtastic_PowerMon_size 0 +#define meshtastic_PowerStressMessage_size 7 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 7f9df058dd..b309484e23 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -6,7 +6,7 @@ #include "main.h" #include "mesh/http/ContentHelper.h" #include "mesh/http/WebServer.h" -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "mqtt/JSON.h" diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index ffb16bd3e5..e733d18011 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -1,5 +1,5 @@ #include "configuration.h" -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "NodeDB.h" #include "RTC.h" #include "concurrency/Periodic.h" diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 0915864623..e24c62712d 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -137,7 +137,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta #if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH if (BleOta::getOtaAppVersion().isEmpty()) { LOG_INFO("No OTA firmware available, scheduling regular reboot in %d seconds\n", s); - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); } else { screen->startFirmwareUpdateScreen(); BleOta::switchToOtaApp(); @@ -145,7 +145,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta } #else LOG_INFO("Not on ESP32, scheduling regular reboot in %d seconds\n", s); - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); #endif rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000); break; @@ -232,9 +232,9 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta #if !MESHTASTIC_EXCLUDE_GPS if (gps != nullptr) gps->enable(); -#endif // Send our new fixed position to the mesh for good measure positionModule->sendOurPosition(); +#endif } break; } @@ -299,8 +299,8 @@ void AdminModule::handleGetModuleConfigResponse(const meshtastic_MeshPacket &mp, { // Skip if it's disabled or no pins are exposed if (!r->get_module_config_response.payload_variant.remote_hardware.enabled || - !r->get_module_config_response.payload_variant.remote_hardware.available_pins) { - LOG_DEBUG("Remote hardware module disabled or no vailable_pins. Skipping...\n"); + r->get_module_config_response.payload_variant.remote_hardware.available_pins_count == 0) { + LOG_DEBUG("Remote hardware module disabled or no available_pins. Skipping...\n"); return; } for (uint8_t i = 0; i < devicestate.node_remote_hardware_pins_count; i++) { @@ -388,6 +388,10 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) LOG_DEBUG("Tried to set node_info_broadcast_secs too low, setting to %d\n", min_node_info_broadcast_secs); config.device.node_info_broadcast_secs = min_node_info_broadcast_secs; } + // Router Client is deprecated; Set it to client + if (c.payload_variant.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT) { + config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT; + } break; case meshtastic_Config_position_tag: LOG_INFO("Setting config: Position\n"); @@ -811,7 +815,7 @@ void AdminModule::handleGetChannel(const meshtastic_MeshPacket &req, uint32_t ch void AdminModule::reboot(int32_t seconds) { LOG_INFO("Rebooting in %d seconds\n", seconds); - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); rebootAtMsec = (seconds < 0) ? 0 : (millis() + seconds * 1000); } diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h index 32b32c253a..6ecc888294 100644 --- a/src/modules/AdminModule.h +++ b/src/modules/AdminModule.h @@ -1,6 +1,6 @@ #pragma once #include "ProtobufModule.h" -#if HAS_WIFI && !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index f513e045f4..be414dce13 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -597,14 +597,14 @@ int32_t CannedMessageModule::runOnce() // handle fn+s for shutdown case 0x9b: if (screen) - screen->startShutdownScreen(); + screen->startAlert("Shutting down..."); shutdownAtMsec = millis() + DEFAULT_SHUTDOWN_SECONDS * 1000; runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; break; // and fn+r for reboot case 0x90: if (screen) - screen->startRebootScreen(); + screen->startAlert("Rebooting..."); rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000; runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; break; diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index ba1f5c11ea..300afc2460 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -27,6 +27,9 @@ #if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE #include "modules/RemoteHardwareModule.h" #endif +#if !MESHTASTIC_EXCLUDE_POWERSTRESS +#include "modules/PowerStressModule.h" +#endif #include "modules/RoutingModule.h" #include "modules/TextMessageModule.h" #if !MESHTASTIC_EXCLUDE_TRACEROUTE @@ -115,6 +118,9 @@ void setupModules() #if !MESHTASTIC_EXCLUDE_REMOTEHARDWARE new RemoteHardwareModule(); +#endif +#if !MESHTASTIC_EXCLUDE_POWERSTRESS + new PowerStressModule(); #endif // Example: Put your module here // new ReplyModule(); diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 49f2b808b9..61616841b3 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -73,7 +73,7 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes } // Log packet size and data fields - LOG_DEBUG("POSITION node=%08x l=%d latI=%d lonI=%d msl=%d hae=%d geo=%d pdop=%d hdop=%d vdop=%d siv=%d fxq=%d fxt=%d pts=%d " + LOG_DEBUG("POSITION node=%08x l=%d lat=%d lon=%d msl=%d hae=%d geo=%d pdop=%d hdop=%d vdop=%d siv=%d fxq=%d fxt=%d pts=%d " "time=%d\n", getFrom(&mp), mp.decoded.payload.size, p.latitude_i, p.longitude_i, p.altitude, p.altitude_hae, p.altitude_geoidal_separation, p.PDOP, p.HDOP, p.VDOP, p.sats_in_view, p.fix_quality, p.fix_type, p.timestamp, @@ -219,7 +219,7 @@ meshtastic_MeshPacket *PositionModule::allocReply() LOG_INFO("Providing time to mesh %u\n", p.time); } - LOG_INFO("Position reply: time=%i, latI=%i, lonI=%i\n", p.time, p.latitude_i, p.longitude_i); + LOG_INFO("Position reply: time=%i lat=%i lon=%i\n", p.time, p.latitude_i, p.longitude_i); // TAK Tracker devices should send their position in a TAK packet over the ATAK port if (config.device.role == meshtastic_Config_DeviceConfig_Role_TAK_TRACKER) diff --git a/src/modules/PowerStressModule.cpp b/src/modules/PowerStressModule.cpp new file mode 100644 index 0000000000..c86017ae28 --- /dev/null +++ b/src/modules/PowerStressModule.cpp @@ -0,0 +1,77 @@ +#include "PowerStressModule.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include "main.h" + +extern void printInfo(); + +PowerStressModule::PowerStressModule() + : ProtobufModule("powerstress", meshtastic_PortNum_POWERSTRESS_APP, &meshtastic_PowerStressMessage_msg), + concurrency::OSThread("PowerStressModule") +{ +} + +bool PowerStressModule::handleReceivedProtobuf(const meshtastic_MeshPacket &req, meshtastic_PowerStressMessage *pptr) +{ + // We only respond to messages if powermon debugging is already on + if (config.power.powermon_enables) { + auto p = *pptr; + LOG_INFO("Received PowerStress cmd=%d\n", p.cmd); + + // Some commands we can handle immediately, anything else gets deferred to be handled by our thread + switch (p.cmd) { + case meshtastic_PowerStressMessage_Opcode_UNSET: + LOG_ERROR("PowerStress operation unset\n"); + break; + + case meshtastic_PowerStressMessage_Opcode_PRINT_INFO: + printInfo(); + break; + + default: + if (currentMessage.cmd != meshtastic_PowerStressMessage_Opcode_UNSET) + LOG_ERROR("PowerStress operation %d already in progress! Can't start new command\n", currentMessage.cmd); + else + currentMessage = p; // copy for use by thread (the message provided to us will be getting freed) + break; + } + } + return true; +} + +int32_t PowerStressModule::runOnce() +{ + + if (!config.power.powermon_enables) { + // Powermon not enabled - stop using CPU/stop this thread + return disable(); + } + + int32_t sleep_msec = 10; // when not active check for new messages every 10ms + + auto &p = currentMessage; + + if (isRunningCommand) { + // Done with the previous command - our sleep must have finished + p.cmd = meshtastic_PowerStressMessage_Opcode_UNSET; + p.num_seconds = 0; + } else { + sleep_msec = (int32_t)(p.num_seconds * 1000); + isRunningCommand = !!sleep_msec; // if the command wants us to sleep, make sure to mark that we have something running + + switch (p.cmd) { + case meshtastic_PowerStressMessage_Opcode_UNSET: // No need to start a new command + break; + case meshtastic_PowerStressMessage_Opcode_LED_ON: + break; + default: + LOG_ERROR("PowerStress operation %d not yet implemented!\n", p.cmd); + sleep_msec = 0; // Don't do whatever sleep was requested... + break; + } + } + return sleep_msec; +} \ No newline at end of file diff --git a/src/modules/PowerStressModule.h b/src/modules/PowerStressModule.h new file mode 100644 index 0000000000..2d449f690c --- /dev/null +++ b/src/modules/PowerStressModule.h @@ -0,0 +1,38 @@ +#pragma once +#include "ProtobufModule.h" +#include "concurrency/OSThread.h" +#include "mesh/generated/meshtastic/powermon.pb.h" + +/** + * A module that provides easy low-level remote access to device hardware. + */ +class PowerStressModule : public ProtobufModule, private concurrency::OSThread +{ + meshtastic_PowerStressMessage currentMessage = meshtastic_PowerStressMessage_init_default; + bool isRunningCommand = false; + + public: + /** Constructor + * name is for debugging output + */ + PowerStressModule(); + + protected: + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_PowerStressMessage *p) override; + + /** + * Periodically read the gpios we have been asked to WATCH, if they have changed, + * broadcast a message with the change information. + * + * The method that will be called each time our thread gets a chance to run + * + * Returns desired period for next invocation (or RUN_SAME for no change) + */ + virtual int32_t runOnce() override; +}; + +extern PowerStressModule powerStressModule; \ No newline at end of file diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index 4f5fbcd131..ba043feabf 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -85,53 +85,90 @@ bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPack return false; // Let others look at this message also if they want } -bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +bool AirQualityTelemetryModule::getAirQualityTelemetry(meshtastic_Telemetry *m) { if (!aqi.read(&data)) { LOG_WARN("Skipping send measurements. Could not read AQIn\n"); return false; } - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; - m.time = getTime(); - m.which_variant = meshtastic_Telemetry_air_quality_metrics_tag; - m.variant.air_quality_metrics.pm10_standard = data.pm10_standard; - m.variant.air_quality_metrics.pm25_standard = data.pm25_standard; - m.variant.air_quality_metrics.pm100_standard = data.pm100_standard; + m->time = getTime(); + m->which_variant = meshtastic_Telemetry_air_quality_metrics_tag; + m->variant.air_quality_metrics.pm10_standard = data.pm10_standard; + m->variant.air_quality_metrics.pm25_standard = data.pm25_standard; + m->variant.air_quality_metrics.pm100_standard = data.pm100_standard; - m.variant.air_quality_metrics.pm10_environmental = data.pm10_env; - m.variant.air_quality_metrics.pm25_environmental = data.pm25_env; - m.variant.air_quality_metrics.pm100_environmental = data.pm100_env; + m->variant.air_quality_metrics.pm10_environmental = data.pm10_env; + m->variant.air_quality_metrics.pm25_environmental = data.pm25_env; + m->variant.air_quality_metrics.pm100_environmental = data.pm100_env; LOG_INFO("(Sending): PM1.0(Standard)=%i, PM2.5(Standard)=%i, PM10.0(Standard)=%i\n", - m.variant.air_quality_metrics.pm10_standard, m.variant.air_quality_metrics.pm25_standard, - m.variant.air_quality_metrics.pm100_standard); + m->variant.air_quality_metrics.pm10_standard, m->variant.air_quality_metrics.pm25_standard, + m->variant.air_quality_metrics.pm100_standard); LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i\n", - m.variant.air_quality_metrics.pm10_environmental, m.variant.air_quality_metrics.pm25_environmental, - m.variant.air_quality_metrics.pm100_environmental); - - meshtastic_MeshPacket *p = allocDataProtobuf(m); - p->to = dest; - p->decoded.want_response = false; - if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) - p->priority = meshtastic_MeshPacket_Priority_RELIABLE; - else - p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; - - // release previous packet before occupying a new spot - if (lastMeasurementPacket != nullptr) - packetPool.release(lastMeasurementPacket); - - lastMeasurementPacket = packetPool.allocCopy(*p); - if (phoneOnly) { - LOG_INFO("Sending packet to phone\n"); - service.sendToPhone(p); - } else { - LOG_INFO("Sending packet to mesh\n"); - service.sendToMesh(p, RX_SRC_LOCAL, true); - } + m->variant.air_quality_metrics.pm10_environmental, m->variant.air_quality_metrics.pm25_environmental, + m->variant.air_quality_metrics.pm100_environmental); + return true; } +meshtastic_MeshPacket *AirQualityTelemetryModule::allocReply() +{ + if (currentRequest) { + auto req = *currentRequest; + const auto &p = req.decoded; + meshtastic_Telemetry scratch; + meshtastic_Telemetry *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { + decoded = &scratch; + } else { + LOG_ERROR("Error decoding AirQualityTelemetry module!\n"); + return NULL; + } + // Check for a request for air quality metrics + if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) { + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getAirQualityTelemetry(&m)) { + LOG_INFO("Air quality telemetry replying to request\n"); + return allocDataProtobuf(m); + } else { + return NULL; + } + } + } + return NULL; +} + +bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +{ + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getAirQualityTelemetry(&m)) { + meshtastic_MeshPacket *p = allocDataProtobuf(m); + p->to = dest; + p->decoded.want_response = false; + if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) + p->priority = meshtastic_MeshPacket_Priority_RELIABLE; + else + p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; + + // release previous packet before occupying a new spot + if (lastMeasurementPacket != nullptr) + packetPool.release(lastMeasurementPacket); + + lastMeasurementPacket = packetPool.allocCopy(*p); + if (phoneOnly) { + LOG_INFO("Sending packet to phone\n"); + service.sendToPhone(p); + } else { + LOG_INFO("Sending packet to mesh\n"); + service.sendToMesh(p, RX_SRC_LOCAL, true); + } + return true; + } + + return false; +} + #endif \ No newline at end of file diff --git a/src/modules/Telemetry/AirQualityTelemetry.h b/src/modules/Telemetry/AirQualityTelemetry.h index eb0355001e..9d09078b11 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.h +++ b/src/modules/Telemetry/AirQualityTelemetry.h @@ -26,6 +26,11 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override; virtual int32_t runOnce() override; + /** Called to get current Air Quality data + @return true if it contains valid data + */ + bool getAirQualityTelemetry(meshtastic_Telemetry *m); + virtual meshtastic_MeshPacket *allocReply() override; /** * Send our Telemetry into the mesh */ diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index b64e8d1130..9cc4bf6ea5 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -52,14 +52,27 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket & meshtastic_MeshPacket *DeviceTelemetryModule::allocReply() { - if (ignoreRequest) { - return NULL; - } - - LOG_INFO("Device telemetry replying to request\n"); + if (currentRequest) { + auto req = *currentRequest; + const auto &p = req.decoded; + meshtastic_Telemetry scratch; + meshtastic_Telemetry *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { + decoded = &scratch; + } else { + LOG_ERROR("Error decoding DeviceTelemetry module!\n"); + return NULL; + } + // Check for a request for device metrics + if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) { + LOG_INFO("Device telemetry replying to request\n"); - meshtastic_Telemetry telemetry = getDeviceTelemetry(); - return allocDataProtobuf(telemetry); + meshtastic_Telemetry telemetry = getDeviceTelemetry(); + return allocDataProtobuf(telemetry); + } + } + return NULL; } meshtastic_Telemetry DeviceTelemetryModule::getDeviceTelemetry() @@ -104,4 +117,4 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) service.sendToMesh(p, RX_SRC_LOCAL, true); } return true; -} +} \ No newline at end of file diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index b1149799b5..dcaf000777 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -198,7 +198,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt if (lastMeasurementPacket == nullptr) { // If there's no valid packet, display "Environment" display->drawString(x, y, "Environment"); - display->drawString(x, y += fontHeight(FONT_SMALL), "No measurement"); + display->drawString(x, y += _fontHeight(FONT_SMALL), "No measurement"); return; } @@ -223,31 +223,31 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt } // Continue with the remaining details - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Temp/Hum: " + last_temp + " / " + String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%"); if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0) { - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA"); } if (lastMeasurement.variant.environment_metrics.voltage != 0) { - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Volt/Cur: " + String(lastMeasurement.variant.environment_metrics.voltage, 0) + "V / " + String(lastMeasurement.variant.environment_metrics.current, 0) + "mA"); } if (lastMeasurement.variant.environment_metrics.iaq != 0) { - display->drawString(x, y += fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq)); + display->drawString(x, y += _fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq)); } if (lastMeasurement.variant.environment_metrics.distance != 0) - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Water Level: " + String(lastMeasurement.variant.environment_metrics.distance, 0) + "mm"); if (lastMeasurement.variant.environment_metrics.weight != 0) - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg"); } @@ -280,102 +280,138 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac return false; // Let others look at this message also if they want } -bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m) { - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; bool valid = true; bool hasSensor = false; - m.time = getTime(); - m.which_variant = meshtastic_Telemetry_environment_metrics_tag; + m->time = getTime(); + m->which_variant = meshtastic_Telemetry_environment_metrics_tag; #ifdef T1000X_SENSOR_EN // add by WayenWeng valid = valid && t1000xSensor.getMetrics(&m); hasSensor = true; #else if (dfRobotLarkSensor.hasSensor()) { - valid = valid && dfRobotLarkSensor.getMetrics(&m); + valid = valid && dfRobotLarkSensor.getMetrics(m); hasSensor = true; } if (sht31Sensor.hasSensor()) { - valid = valid && sht31Sensor.getMetrics(&m); + valid = valid && sht31Sensor.getMetrics(m); + hasSensor = true; + } + if (sht4xSensor.hasSensor()) { + valid = valid && sht4xSensor.getMetrics(m); hasSensor = true; } if (lps22hbSensor.hasSensor()) { - valid = valid && lps22hbSensor.getMetrics(&m); + valid = valid && lps22hbSensor.getMetrics(m); hasSensor = true; } if (shtc3Sensor.hasSensor()) { - valid = valid && shtc3Sensor.getMetrics(&m); + valid = valid && shtc3Sensor.getMetrics(m); hasSensor = true; } if (bmp085Sensor.hasSensor()) { - valid = valid && bmp085Sensor.getMetrics(&m); + valid = valid && bmp085Sensor.getMetrics(m); hasSensor = true; } if (bmp280Sensor.hasSensor()) { - valid = valid && bmp280Sensor.getMetrics(&m); + valid = valid && bmp280Sensor.getMetrics(m); hasSensor = true; } if (bme280Sensor.hasSensor()) { - valid = valid && bme280Sensor.getMetrics(&m); + valid = valid && bme280Sensor.getMetrics(m); hasSensor = true; } if (bme680Sensor.hasSensor()) { - valid = valid && bme680Sensor.getMetrics(&m); + valid = valid && bme680Sensor.getMetrics(m); hasSensor = true; } if (mcp9808Sensor.hasSensor()) { - valid = valid && mcp9808Sensor.getMetrics(&m); + valid = valid && mcp9808Sensor.getMetrics(m); hasSensor = true; } if (ina219Sensor.hasSensor()) { - valid = valid && ina219Sensor.getMetrics(&m); + valid = valid && ina219Sensor.getMetrics(m); hasSensor = true; } if (ina260Sensor.hasSensor()) { - valid = valid && ina260Sensor.getMetrics(&m); + valid = valid && ina260Sensor.getMetrics(m); hasSensor = true; } if (veml7700Sensor.hasSensor()) { - valid = valid && veml7700Sensor.getMetrics(&m); + valid = valid && veml7700Sensor.getMetrics(m); hasSensor = true; } if (tsl2591Sensor.hasSensor()) { - valid = valid && tsl2591Sensor.getMetrics(&m); + valid = valid && tsl2591Sensor.getMetrics(m); hasSensor = true; } if (opt3001Sensor.hasSensor()) { - valid = valid && opt3001Sensor.getMetrics(&m); + valid = valid && opt3001Sensor.getMetrics(m); hasSensor = true; } if (mlx90632Sensor.hasSensor()) { - valid = valid && mlx90632Sensor.getMetrics(&m); + valid = valid && mlx90632Sensor.getMetrics(m); hasSensor = true; } if (rcwl9620Sensor.hasSensor()) { - valid = valid && rcwl9620Sensor.getMetrics(&m); + valid = valid && rcwl9620Sensor.getMetrics(m); hasSensor = true; } if (nau7802Sensor.hasSensor()) { - valid = valid && nau7802Sensor.getMetrics(&m); + valid = valid && nau7802Sensor.getMetrics(m); hasSensor = true; } if (aht10Sensor.hasSensor()) { if (!bmp280Sensor.hasSensor()) { - valid = valid && aht10Sensor.getMetrics(&m); + valid = valid && aht10Sensor.getMetrics(m); hasSensor = true; } else { // prefer bmp280 temp if both sensors are present, fetch only humidity meshtastic_Telemetry m_ahtx = meshtastic_Telemetry_init_zero; LOG_INFO("AHTX0+BMP280 module detected: using temp from BMP280 and humy from AHTX0\n"); aht10Sensor.getMetrics(&m_ahtx); - m.variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity; + m->variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity; } } #endif - valid = valid && hasSensor; - if (valid) { + return valid && hasSensor; +} + +meshtastic_MeshPacket *EnvironmentTelemetryModule::allocReply() +{ + if (currentRequest) { + auto req = *currentRequest; + const auto &p = req.decoded; + meshtastic_Telemetry scratch; + meshtastic_Telemetry *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { + decoded = &scratch; + } else { + LOG_ERROR("Error decoding EnvironmentTelemetry module!\n"); + return NULL; + } + // Check for a request for environment metrics + if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) { + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getEnvironmentTelemetry(&m)) { + LOG_INFO("Environment telemetry replying to request\n"); + return allocDataProtobuf(m); + } else { + return NULL; + } + } + } + return NULL; +} + +bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +{ + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getEnvironmentTelemetry(&m)) { LOG_INFO("(Sending): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f\n", m.variant.environment_metrics.barometric_pressure, m.variant.environment_metrics.current, m.variant.environment_metrics.gas_resistance, m.variant.environment_metrics.relative_humidity, @@ -413,8 +449,9 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) setIntervalFromNow(5000); } } + return true; } - return valid; + return false; } AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule(const meshtastic_MeshPacket &mp, @@ -515,4 +552,4 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule return result; } -#endif \ No newline at end of file +#endif diff --git a/src/modules/Telemetry/EnvironmentTelemetry.h b/src/modules/Telemetry/EnvironmentTelemetry.h index ca150347e7..ced617c2fc 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.h +++ b/src/modules/Telemetry/EnvironmentTelemetry.h @@ -32,6 +32,11 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override; virtual int32_t runOnce() override; + /** Called to get current Environment telemetry data + @return true if it contains valid data + */ + bool getEnvironmentTelemetry(meshtastic_Telemetry *m); + virtual meshtastic_MeshPacket *allocReply() override; /** * Send our Telemetry into the mesh */ diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index 826de8a4ab..fb5aee375b 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -108,7 +108,7 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s display->drawString(x, y, "Power Telemetry"); if (lastMeasurementPacket == nullptr) { display->setFont(FONT_SMALL); - display->drawString(x, y += fontHeight(FONT_MEDIUM), "No measurement"); + display->drawString(x, y += _fontHeight(FONT_MEDIUM), "No measurement"); return; } @@ -120,22 +120,22 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s auto &p = lastMeasurementPacket->decoded; if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &lastMeasurement)) { display->setFont(FONT_SMALL); - display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error"); + display->drawString(x, y += _fontHeight(FONT_MEDIUM), "Measurement Error"); LOG_ERROR("Unable to decode last packet"); return; } display->setFont(FONT_SMALL); String last_temp = String(lastMeasurement.variant.environment_metrics.temperature, 0) + "°C"; - display->drawString(x, y += fontHeight(FONT_MEDIUM) - 2, "From: " + String(lastSender) + "(" + String(agoSecs) + "s)"); + display->drawString(x, y += _fontHeight(FONT_MEDIUM) - 2, "From: " + String(lastSender) + "(" + String(agoSecs) + "s)"); if (lastMeasurement.variant.power_metrics.ch1_voltage != 0) { - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Ch 1 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch1_voltage, 0) + "V / " + String(lastMeasurement.variant.power_metrics.ch1_current, 0) + "mA"); - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Ch 2 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch2_voltage, 0) + "V / " + String(lastMeasurement.variant.power_metrics.ch2_current, 0) + "mA"); - display->drawString(x, y += fontHeight(FONT_SMALL), + display->drawString(x, y += _fontHeight(FONT_SMALL), "Ch 3 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch3_voltage, 0) + "V / " + String(lastMeasurement.variant.power_metrics.ch3_current, 0) + "mA"); } @@ -163,29 +163,63 @@ bool PowerTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &m return false; // Let others look at this message also if they want } -bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +bool PowerTelemetryModule::getPowerTelemetry(meshtastic_Telemetry *m) { - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; bool valid = false; - m.time = getTime(); - m.which_variant = meshtastic_Telemetry_power_metrics_tag; - - m.variant.power_metrics.ch1_voltage = 0; - m.variant.power_metrics.ch1_current = 0; - m.variant.power_metrics.ch2_voltage = 0; - m.variant.power_metrics.ch2_current = 0; - m.variant.power_metrics.ch3_voltage = 0; - m.variant.power_metrics.ch3_current = 0; + m->time = getTime(); + m->which_variant = meshtastic_Telemetry_power_metrics_tag; + + m->variant.power_metrics.ch1_voltage = 0; + m->variant.power_metrics.ch1_current = 0; + m->variant.power_metrics.ch2_voltage = 0; + m->variant.power_metrics.ch2_current = 0; + m->variant.power_metrics.ch3_voltage = 0; + m->variant.power_metrics.ch3_current = 0; #if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) if (ina219Sensor.hasSensor()) - valid = ina219Sensor.getMetrics(&m); + valid = ina219Sensor.getMetrics(m); if (ina260Sensor.hasSensor()) - valid = ina260Sensor.getMetrics(&m); + valid = ina260Sensor.getMetrics(m); if (ina3221Sensor.hasSensor()) - valid = ina3221Sensor.getMetrics(&m); + valid = ina3221Sensor.getMetrics(m); #endif - if (valid) { + return valid; +} + +meshtastic_MeshPacket *PowerTelemetryModule::allocReply() +{ + if (currentRequest) { + auto req = *currentRequest; + const auto &p = req.decoded; + meshtastic_Telemetry scratch; + meshtastic_Telemetry *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { + decoded = &scratch; + } else { + LOG_ERROR("Error decoding PowerTelemetry module!\n"); + return NULL; + } + // Check for a request for power metrics + if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) { + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getPowerTelemetry(&m)) { + LOG_INFO("Power telemetry replying to request\n"); + return allocDataProtobuf(m); + } else { + return NULL; + } + } + } + + return NULL; +} + +bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) +{ + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + if (getPowerTelemetry(&m)) { LOG_INFO("(Sending): ch1_voltage=%f, ch1_current=%f, ch2_voltage=%f, ch2_current=%f, " "ch3_voltage=%f, ch3_current=%f\n", m.variant.power_metrics.ch1_voltage, m.variant.power_metrics.ch1_current, m.variant.power_metrics.ch2_voltage, @@ -218,8 +252,9 @@ bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) setIntervalFromNow(5000); } } + return true; } - return valid; + return false; } #endif \ No newline at end of file diff --git a/src/modules/Telemetry/PowerTelemetry.h b/src/modules/Telemetry/PowerTelemetry.h index 3d6b686f22..1b68847dba 100644 --- a/src/modules/Telemetry/PowerTelemetry.h +++ b/src/modules/Telemetry/PowerTelemetry.h @@ -33,6 +33,11 @@ class PowerTelemetryModule : private concurrency::OSThread, public ProtobufModul */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override; virtual int32_t runOnce() override; + /** Called to get current Power telemetry data + @return true if it contains valid data + */ + bool getPowerTelemetry(meshtastic_Telemetry *m); + virtual meshtastic_MeshPacket *allocReply() override; /** * Send our Telemetry into the mesh */ diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp index ea2cb4ea8c..edd29682e0 100644 --- a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp +++ b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp @@ -16,8 +16,7 @@ int32_t INA3221Sensor::runOnce() return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; } if (!status) { - ina3221.setAddr(INA3221_ADDR42_SDA); // i2c address 0x42 - ina3221.begin(); + ina3221.begin(nodeTelemetrySensorsMap[sensorType].second); ina3221.setShuntRes(100, 100, 100); // 0.1 Ohm shunt resistors status = true; } else { diff --git a/src/modules/WaypointModule.cpp b/src/modules/WaypointModule.cpp index 83485c8eee..d5b7d29ee5 100644 --- a/src/modules/WaypointModule.cpp +++ b/src/modules/WaypointModule.cpp @@ -2,6 +2,11 @@ #include "NodeDB.h" #include "PowerFSM.h" #include "configuration.h" +#if HAS_SCREEN +#include "gps/RTC.h" +#include "graphics/Screen.h" +#include "main.h" +#endif WaypointModule *waypointModule; @@ -11,14 +16,155 @@ ProcessMessage WaypointModule::handleReceived(const meshtastic_MeshPacket &mp) auto &p = mp.decoded; LOG_INFO("Received waypoint msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes); #endif - + UIFrameEvent e = {true, true}; // We only store/display messages destined for us. // Keep a copy of the most recent text message. devicestate.rx_waypoint = mp; devicestate.has_rx_waypoint = true; powerFSM.trigger(EVENT_RECEIVED_MSG); - notifyObservers(&mp); + notifyObservers(&e); return ProcessMessage::CONTINUE; // Let others look at this message also if they want } + +#if HAS_SCREEN +bool WaypointModule::shouldDraw() +{ +#if !MESHTASTIC_EXCLUDE_WAYPOINT + // If no waypoint to show + if (!devicestate.has_rx_waypoint) + return false; + + // Decode the message, to find the expiration time (is waypoint still valid) + // This handles "deletion" as well as expiration + meshtastic_Waypoint wp; + memset(&wp, 0, sizeof(wp)); + if (pb_decode_from_bytes(devicestate.rx_waypoint.decoded.payload.bytes, devicestate.rx_waypoint.decoded.payload.size, + &meshtastic_Waypoint_msg, &wp)) { + // Valid waypoint + if (wp.expire > getTime()) + return devicestate.has_rx_waypoint = true; + + // Expired, or deleted + else + return devicestate.has_rx_waypoint = false; + } + + // If decoding failed + LOG_ERROR("Failed to decode waypoint\n"); + devicestate.has_rx_waypoint = false; + return false; +#else + return false; +#endif +} + +/// Draw the last waypoint we received +void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + // Prepare to draw + display->setFont(FONT_SMALL); + display->setTextAlignment(TEXT_ALIGN_LEFT); + + // Handle inverted display + // Unsure of expected behavior: for now, copy drawNodeInfo + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) + display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); + + // Decode the waypoint + meshtastic_MeshPacket &mp = devicestate.rx_waypoint; + meshtastic_Waypoint wp; + memset(&wp, 0, sizeof(wp)); + if (!pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &wp)) { + // This *should* be caught by shouldDrawWaypoint, but we'll short-circuit here just in case + display->drawStringMaxWidth(0 + x, 0 + y, x + display->getWidth(), "Couldn't decode waypoint"); + devicestate.has_rx_waypoint = false; + return; + } + + // Get timestamp info. Will pass as a field to drawColumns + static char lastStr[20]; + screen->getTimeAgoStr(sinceReceived(&mp), lastStr, sizeof(lastStr)); + + // Will contain distance information, passed as a field to drawColumns + static char distStr[20]; + + // Get our node, to use our own position + meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); + + // Text fields to draw (left of compass) + // Last element must be NULL. This signals the end of the char*[] to drawColumns + const char *fields[] = {"Waypoint", lastStr, wp.name, distStr, NULL}; + + // Dimensions / co-ordinates for the compass/circle + int16_t compassX = 0, compassY = 0; + uint16_t compassDiam = graphics::Screen::getCompassDiam(display->getWidth(), display->getHeight()); + + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { + compassX = x + display->getWidth() - compassDiam / 2 - 5; + compassY = y + display->getHeight() / 2; + } else { + compassX = x + display->getWidth() - compassDiam / 2 - 5; + compassY = y + FONT_HEIGHT_SMALL + (display->getHeight() - FONT_HEIGHT_SMALL) / 2; + } + + // If our node has a position: + if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) { + const meshtastic_PositionLite &op = ourNode->position; + float myHeading; + if (screen->hasHeading()) + myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians + else + myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); + screen->drawCompassNorth(display, compassX, compassY, myHeading); + + // Distance to Waypoint + float d = GeoCoord::latLongToMeter(DegD(wp.latitude_i), DegD(wp.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i)); + if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) { + if (d < (2 * MILES_TO_FEET)) + snprintf(distStr, sizeof(distStr), "%.0f ft", d * METERS_TO_FEET); + else + snprintf(distStr, sizeof(distStr), "%.1f mi", d * METERS_TO_FEET / MILES_TO_FEET); + } else { + if (d < 2000) + snprintf(distStr, sizeof(distStr), "%.0f m", d); + else + snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000); + } + + // Compass bearing to waypoint + float bearingToOther = + GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(wp.latitude_i), DegD(wp.longitude_i)); + // If the top of the compass is a static north then bearingToOther can be drawn on the compass directly + // If the top of the compass is not a static north we need adjust bearingToOther based on heading + if (!config.display.compass_north_top) + bearingToOther -= myHeading; + screen->drawNodeHeading(display, compassX, compassY, compassDiam, bearingToOther); + } + + // If our node doesn't have position + else { + // ? in the compass + display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?"); + + // ? in the distance field + if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) + strncpy(distStr, "? mi", sizeof(distStr)); + else + strncpy(distStr, "? km", sizeof(distStr)); + } + + // Undo color-inversion, if set prior to drawing header + // Unsure of expected behavior? For now: copy drawNodeInfo + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { + display->setColor(BLACK); + } + + // Draw compass circle + display->drawCircle(compassX, compassY, compassDiam / 2); + + // Must be after distStr is populated + screen->drawColumns(display, x, y, fields); +} +#endif \ No newline at end of file diff --git a/src/modules/WaypointModule.h b/src/modules/WaypointModule.h index ddbabf4deb..4c9c7b86b0 100644 --- a/src/modules/WaypointModule.h +++ b/src/modules/WaypointModule.h @@ -5,21 +5,29 @@ /** * Waypoint message handling for meshtastic */ -class WaypointModule : public SinglePortModule, public Observable +class WaypointModule : public SinglePortModule, public Observable { public: /** Constructor * name is for debugging output */ WaypointModule() : SinglePortModule("waypoint", meshtastic_PortNum_WAYPOINT_APP) {} - +#if HAS_SCREEN + bool shouldDraw(); +#endif protected: /** Called to handle a particular incoming message @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it */ + + virtual Observable *getUIFrameObservable() override { return this; } +#if HAS_SCREEN + virtual bool wantUIFrame() override { return this->shouldDraw(); } + virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override; +#endif virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override; }; -extern WaypointModule *waypointModule; +extern WaypointModule *waypointModule; \ No newline at end of file diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index e6712871d0..0bae515dfa 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -66,10 +66,6 @@ bool PaxcounterModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, m meshtastic_MeshPacket *PaxcounterModule::allocReply() { - if (ignoreRequest) { - return NULL; - } - meshtastic_Paxcount pl = meshtastic_Paxcount_init_default; pl.wifi = count_from_libpax.wifi_count; pl.ble = count_from_libpax.ble_count; @@ -131,4 +127,4 @@ void PaxcounterModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state } #endif // HAS_SCREEN -#endif +#endif \ No newline at end of file diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp index 12cddc5202..dc8650ad0b 100644 --- a/src/modules/esp32/StoreForwardModule.cpp +++ b/src/modules/esp32/StoreForwardModule.cpp @@ -319,8 +319,8 @@ ProcessMessage StoreForwardModule::handleReceived(const meshtastic_MeshPacket &m #ifdef ARCH_ESP32 if (moduleConfig.store_forward.enabled) { - // The router node should not be sending messages as a client. Unless he is a ROUTER_CLIENT - if ((getFrom(&mp) != nodeDB->getNodeNum()) || (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT)) { + // The router node should not be sending messages as a client + if ((getFrom(&mp) != nodeDB->getNodeNum())) { if ((mp.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) && is_server) { auto &p = mp.decoded; diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 9f9ac5c243..a64720c78c 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -14,7 +14,7 @@ #endif #include "mesh/generated/meshtastic/remote_hardware.pb.h" #include "sleep.h" -#if HAS_WIFI && !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #include #endif @@ -175,7 +175,7 @@ void mqttInit() new MQTT(); } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE) #else MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) @@ -206,7 +206,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) moduleConfig.mqtt.map_report_settings.publish_interval_secs, default_map_publish_interval_secs); } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING if (!moduleConfig.mqtt.proxy_to_client_enabled) pubSub.setCallback(mqttCallback); #endif @@ -226,7 +226,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) bool MQTT::isConnectedDirectly() { -#ifdef HAS_NETWORKING +#if HAS_NETWORKING return pubSub.connected(); #else return false; @@ -244,7 +244,7 @@ bool MQTT::publish(const char *topic, const char *payload, bool retained) service.sendMqttMessageToClientProxy(msg); return true; } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING else if (isConnectedDirectly()) { return pubSub.publish(topic, payload, retained); } @@ -264,7 +264,7 @@ bool MQTT::publish(const char *topic, const uint8_t *payload, size_t length, boo service.sendMqttMessageToClientProxy(msg); return true; } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING else if (isConnectedDirectly()) { return pubSub.publish(topic, payload, length, retained); } @@ -284,7 +284,7 @@ void MQTT::reconnect() publishStatus(); return; // Don't try to connect directly to the server } -#ifdef HAS_NETWORKING +#if HAS_NETWORKING // Defaults int serverPort = 1883; const char *serverAddr = default_mqtt_address; @@ -357,7 +357,7 @@ void MQTT::reconnect() void MQTT::sendSubscriptions() { -#ifdef HAS_NETWORKING +#if HAS_NETWORKING size_t numChan = channels.getNumChannels(); for (size_t i = 0; i < numChan; i++) { const auto &ch = channels.getByIndex(i); @@ -396,7 +396,7 @@ bool MQTT::wantsLink() const int32_t MQTT::runOnce() { -#ifdef HAS_NETWORKING +#if HAS_NETWORKING if (!moduleConfig.mqtt.enabled || !(moduleConfig.mqtt.map_reporting_enabled || channels.anyMqttEnabled())) return disable(); @@ -482,7 +482,12 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket & auto &ch = channels.getByIndex(chIndex); - if (&mp_decoded.decoded && strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0 && + if (mp_decoded.which_payload_variant != meshtastic_MeshPacket_decoded_tag) { + LOG_CRIT("MQTT::onSend(): mp_decoded isn't actually decoded\n"); + return; + } + + if (strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0 && (mp_decoded.decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP || mp_decoded.decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP)) { LOG_DEBUG("MQTT onSend - Ignoring range test or detection sensor message on public mqtt\n"); diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index f2eb6b1204..1ebba4afe9 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -8,17 +8,15 @@ #include "mqtt/JSON.h" #if HAS_WIFI #include -#define HAS_NETWORKING 1 #if !defined(ARCH_PORTDUINO) #include #endif #endif #if HAS_ETHERNET #include -#define HAS_NETWORKING 1 #endif -#ifdef HAS_NETWORKING +#if HAS_NETWORKING #include #endif @@ -43,7 +41,7 @@ class MQTT : private concurrency::OSThread #endif public: -#ifdef HAS_NETWORKING +#if HAS_NETWORKING PubSubClient pubSub; #endif MQTT(); diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 68aa9b4653..d959553a4b 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -12,6 +12,7 @@ NimBLECharacteristic *fromNumCharacteristic; NimBLECharacteristic *BatteryCharacteristic; +NimBLECharacteristic *logRadioCharacteristic; NimBLEServer *bleServer; static bool passkeyShowing; @@ -58,7 +59,6 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks { virtual void onRead(NimBLECharacteristic *pCharacteristic) { - LOG_INFO("From Radio onread\n"); uint8_t fromRadioBytes[meshtastic_FromRadio_size]; size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); @@ -82,7 +82,33 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks LOG_INFO("*** Enter passkey %d on the peer side ***\n", passkey); powerFSM.trigger(EVENT_BLUETOOTH_PAIR); - screen->startBluetoothPinScreen(passkey); +#if HAS_SCREEN + screen->startAlert([passkey](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { + char btPIN[16] = "888888"; + snprintf(btPIN, sizeof(btPIN), "%06u", passkey); + int x_offset = display->width() / 2; + int y_offset = display->height() <= 80 ? 0 : 32; + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(x_offset + x, y_offset + y, "Bluetooth"); + + display->setFont(FONT_SMALL); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5; + display->drawString(x_offset + x, y_offset + y, "Enter this code"); + + display->setFont(FONT_LARGE); + String displayPin(btPIN); + String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5; + display->drawString(x_offset + x, y_offset + y, pin); + + display->setFont(FONT_SMALL); + String deviceName = "Name: "; + deviceName.concat(getDeviceName()); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; + display->drawString(x_offset + x, y_offset + y, deviceName); + }); +#endif passkeyShowing = true; return passkey; @@ -94,7 +120,7 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks if (passkeyShowing) { passkeyShowing = false; - screen->stopBluetoothPinScreen(); + screen->endAlert(); } } @@ -180,6 +206,8 @@ void NimbleBluetooth::setupService() ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE); FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ); fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ); + logRadioCharacteristic = + bleService->createCharacteristic(LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ, 512U); } else { ToRadioCharacteristic = bleService->createCharacteristic( TORADIO_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_AUTHEN | NIMBLE_PROPERTY::WRITE_ENC); @@ -188,6 +216,9 @@ void NimbleBluetooth::setupService() fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC); + logRadioCharacteristic = bleService->createCharacteristic( + LOGRADIO_UUID, + NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC, 512U); } bluetoothPhoneAPI = new BluetoothPhoneAPI(); @@ -236,6 +267,14 @@ void NimbleBluetooth::clearBonds() NimBLEDevice::deleteAllBonds(); } +void NimbleBluetooth::sendLog(const uint8_t *logMessage, size_t length) +{ + if (!bleServer || !isConnected() || length > 512) { + return; + } + logRadioCharacteristic->notify(logMessage, length, true); +} + void clearNVS() { NimBLEDevice::deleteAllBonds(); diff --git a/src/nimble/NimbleBluetooth.h b/src/nimble/NimbleBluetooth.h index d1e347830a..45602e0887 100644 --- a/src/nimble/NimbleBluetooth.h +++ b/src/nimble/NimbleBluetooth.h @@ -11,6 +11,7 @@ class NimbleBluetooth : BluetoothApi bool isActive(); bool isConnected(); int getRssi(); + void sendLog(const uint8_t *logMessage, size_t length); private: void setupService(); diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index 1dd7a389af..aa51e810a8 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -8,7 +8,7 @@ #include "nimble/NimbleBluetooth.h" #endif -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif @@ -24,23 +24,22 @@ #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !MESHTASTIC_EXCLUDE_BLUETOOTH void setBluetoothEnable(bool enable) { -#ifndef MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI if (!isWifiAvailable() && config.bluetooth.enabled == true) +#else + if (config.bluetooth.enabled == true) #endif -#ifdef MESHTASTIC_EXCLUDE_WIFI - if (config.bluetooth.enabled == true) -#endif - { - if (!nimbleBluetooth) { - nimbleBluetooth = new NimbleBluetooth(); - } - if (enable && !nimbleBluetooth->isActive()) { - nimbleBluetooth->setup(); - } - // For ESP32, no way to recover from bluetooth shutdown without reboot - // BLE advertising automatically stops when MCU enters light-sleep(?) - // For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse + { + if (!nimbleBluetooth) { + nimbleBluetooth = new NimbleBluetooth(); } + if (enable && !nimbleBluetooth->isActive()) { + nimbleBluetooth->setup(); + } + // For ESP32, no way to recover from bluetooth shutdown without reboot + // BLE advertising automatically stops when MCU enters light-sleep(?) + // For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse + } } #else void setBluetoothEnable(bool enable) {} diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 8b817f51b4..455219d2b3 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -8,11 +8,11 @@ #include "mesh/mesh-pb-constants.h" #include #include - static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16)); static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16)); static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16)); static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16)); +static BLECharacteristic logRadio = BLECharacteristic(BLEUuid(LOGRADIO_UUID_16)); static BLEDis bledis; // DIS (Device Information Service) helper class instance static BLEBas blebas; // BAS (Battery Service) helper class instance @@ -52,16 +52,14 @@ static BluetoothPhoneAPI *bluetoothPhoneAPI; void onConnect(uint16_t conn_handle) { + // Get the reference to current connection BLEConnection *connection = Bluefruit.Connection(conn_handle); connectionHandle = conn_handle; - char central_name[32] = {0}; connection->getPeerName(central_name, sizeof(central_name)); - LOG_INFO("BLE Connected to %s\n", central_name); } - /** * Callback invoked when a connection is dropped * @param conn_handle connection where this event happens @@ -72,37 +70,36 @@ void onDisconnect(uint16_t conn_handle, uint8_t reason) // FIXME - we currently assume only one active connection LOG_INFO("BLE Disconnected, reason = 0x%x\n", reason); } - void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value) { // Display the raw request packet LOG_INFO("CCCD Updated: %u\n", cccd_value); - // Check the characteristic this CCCD update is associated with in case // this handler is used for multiple CCCD records. - if (chr->uuid == fromNum.uuid) { - if (chr->notifyEnabled(conn_hdl)) { - LOG_INFO("fromNum 'Notify' enabled\n"); + + // According to the GATT spec: cccd value = 0x0001 means notifications are enabled + // and cccd value = 0x0002 means indications are enabled + + if (chr->uuid == fromNum.uuid || chr->uuid == logRadio.uuid) { + auto result = cccd_value == 2 ? chr->indicateEnabled(conn_hdl) : chr->notifyEnabled(conn_hdl); + if (result) { + LOG_INFO("Notify/Indicate enabled\n"); } else { - LOG_INFO("fromNum 'Notify' disabled\n"); + LOG_INFO("Notify/Indicate disabled\n"); } } } - void startAdv(void) { // Advertising packet Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); - // IncludeService UUID // Bluefruit.ScanResponse.addService(meshBleService); Bluefruit.ScanResponse.addTxPower(); Bluefruit.ScanResponse.addName(); - // Include Name // Bluefruit.Advertising.addName(); Bluefruit.Advertising.addService(meshBleService); - /* Start Advertising * - Enable auto advertising if disconnected * - Interval: fast mode = 20 ms, slow mode = 152.5 ms @@ -117,7 +114,6 @@ void startAdv(void) Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X } - // Just ack that the caller is allowed to read static void authorizeRead(uint16_t conn_hdl) { @@ -125,7 +121,6 @@ static void authorizeRead(uint16_t conn_hdl) reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply); } - /** * client is starting read, pull the bytes from our API class */ @@ -134,7 +129,6 @@ void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e if (request->offset == 0) { // If the read is long, we will get multiple authorize invocations - we only populate data on the first size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); - // Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue // or make empty if the queue is empty fromRadio.write(fromRadioBytes, numBytes); @@ -143,37 +137,22 @@ void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e } authorizeRead(conn_hdl); } - void onToRadioWrite(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len) { LOG_INFO("toRadioWriteCb data %p, len %u\n", data, len); - bluetoothPhoneAPI->handleToRadio(data, len); } -/** - * client is starting read, pull the bytes from our API class - */ -void onFromNumAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) -{ - LOG_INFO("fromNumAuthorizeCb\n"); - - authorizeRead(conn_hdl); -} - void setupMeshService(void) { bluetoothPhoneAPI = new BluetoothPhoneAPI(); - meshBleService.begin(); - // Note: You must call .begin() on the BLEService before calling .begin() on // any characteristic(s) within that service definition.. Calling .begin() on // a BLECharacteristic will cause it to be added to the last BLEService that // was 'begin()'ed! auto secMode = config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN ? SECMODE_OPEN : SECMODE_ENC_NO_MITM; - fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ); fromNum.setPermission(secMode, SECMODE_NO_ACCESS); // FIXME, secure this!!! fromNum.setFixedLen( @@ -203,10 +182,15 @@ void setupMeshService(void) // We don't call this callback via the adafruit queue, because we can safely run in the BLE context toRadio.setWriteCallback(onToRadioWrite, false); toRadio.begin(); -} + logRadio.setProperties(CHR_PROPS_INDICATE | CHR_PROPS_NOTIFY | CHR_PROPS_READ); + logRadio.setPermission(secMode, SECMODE_NO_ACCESS); + logRadio.setMaxLen(512); + logRadio.setCccdWriteCallback(onCccd); + logRadio.write32(0); + logRadio.begin(); +} static uint32_t configuredPasskey; - void NRF52Bluetooth::shutdown() { // Shutdown bluetooth for minimum power draw @@ -216,29 +200,23 @@ void NRF52Bluetooth::shutdown() } Bluefruit.Advertising.stop(); } - void NRF52Bluetooth::startDisabled() { // Setup Bluetooth nrf52Bluetooth->setup(); - // Shutdown bluetooth for minimum power draw Bluefruit.Advertising.stop(); Bluefruit.setTxPower(-40); // Minimum power - LOG_INFO("Disabling NRF52 Bluetooth. (Workaround: tx power min, advertising stopped)\n"); } - bool NRF52Bluetooth::isConnected() { return Bluefruit.connected(connectionHandle); } - int NRF52Bluetooth::getRssi() { return 0; // FIXME figure out where to source this } - void NRF52Bluetooth::setup() { // Initialise the Bluefruit module @@ -246,12 +224,10 @@ void NRF52Bluetooth::setup() Bluefruit.autoConnLed(false); Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); Bluefruit.begin(); - // Clear existing data. Bluefruit.Advertising.stop(); Bluefruit.Advertising.clearData(); Bluefruit.ScanResponse.clearData(); - if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) { configuredPasskey = config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN ? config.bluetooth.fixed_pin @@ -270,7 +246,6 @@ void NRF52Bluetooth::setup() } // Set the advertised device name (keep it short!) Bluefruit.setName(getDeviceName()); - // Set the connect/disconnect callback handlers Bluefruit.Periph.setConnectCallback(onConnect); Bluefruit.Periph.setDisconnectCallback(onDisconnect); @@ -287,24 +262,19 @@ void NRF52Bluetooth::setup() bledis.setModel(optstr(HW_VERSION)); bledis.setFirmwareRev(optstr(APP_VERSION)); bledis.begin(); - // Start the BLE Battery Service and set it to 100% LOG_INFO("Configuring the Battery Service\n"); blebas.begin(); blebas.write(0); // Unknown battery level for now - // Setup the Heart Rate Monitor service using // BLEService and BLECharacteristic classes LOG_INFO("Configuring the Mesh bluetooth service\n"); setupMeshService(); - // Setup the advertising packet(s) LOG_INFO("Setting up the advertising payload(s)\n"); startAdv(); - LOG_INFO("Advertising\n"); } - void NRF52Bluetooth::resumeAdvertising() { Bluefruit.Advertising.restartOnDisconnect(true); @@ -312,34 +282,52 @@ void NRF52Bluetooth::resumeAdvertising() Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.start(0); } - /// Given a level between 0-100, update the BLE attribute void updateBatteryLevel(uint8_t level) { blebas.write(level); } - void NRF52Bluetooth::clearBonds() { LOG_INFO("Clearing bluetooth bonds!\n"); bond_print_list(BLE_GAP_ROLE_PERIPH); bond_print_list(BLE_GAP_ROLE_CENTRAL); - Bluefruit.Periph.clearBonds(); Bluefruit.Central.clearBonds(); } - void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle) { LOG_INFO("BLE connection secured\n"); } - bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) { LOG_INFO("BLE pairing process started with passkey %.3s %.3s\n", passkey, passkey + 3); powerFSM.trigger(EVENT_BLUETOOTH_PAIR); - screen->startBluetoothPinScreen(configuredPasskey); - + screen->startAlert([](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { + char btPIN[16] = "888888"; + snprintf(btPIN, sizeof(btPIN), "%06u", configuredPasskey); + int x_offset = display->width() / 2; + int y_offset = display->height() <= 80 ? 0 : 32; + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(x_offset + x, y_offset + y, "Bluetooth"); + + display->setFont(FONT_SMALL); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5; + display->drawString(x_offset + x, y_offset + y, "Enter this code"); + + display->setFont(FONT_LARGE); + String displayPin(btPIN); + String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5; + display->drawString(x_offset + x, y_offset + y, pin); + + display->setFont(FONT_SMALL); + String deviceName = "Name: "; + deviceName.concat(getDeviceName()); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; + display->drawString(x_offset + x, y_offset + y, deviceName); + }); if (match_request) { uint32_t start_time = millis(); while (millis() < start_time + 30000) { @@ -350,13 +338,21 @@ bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passke LOG_INFO("BLE passkey pairing: match_request=%i\n", match_request); return true; } - void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_status) { if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) LOG_INFO("BLE pairing success\n"); else LOG_INFO("BLE pairing failed\n"); + screen->endAlert(); +} - screen->stopBluetoothPinScreen(); -} \ No newline at end of file +void NRF52Bluetooth::sendLog(const uint8_t *logMessage, size_t length) +{ + if (!isConnected() || length > 512) + return; + if (logRadio.indicateEnabled()) + logRadio.indicate(logMessage, (uint16_t)length); + else + logRadio.notify(logMessage, (uint16_t)length); +} diff --git a/src/platform/nrf52/NRF52Bluetooth.h b/src/platform/nrf52/NRF52Bluetooth.h index 450af47f91..2229163f81 100644 --- a/src/platform/nrf52/NRF52Bluetooth.h +++ b/src/platform/nrf52/NRF52Bluetooth.h @@ -13,10 +13,10 @@ class NRF52Bluetooth : BluetoothApi void clearBonds(); bool isConnected(); int getRssi(); + void sendLog(const uint8_t *logMessage, size_t length); private: static void onConnectionSecured(uint16_t conn_handle); - void convertToUint8(uint8_t target[4], uint32_t source); static bool onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request); static void onPairingCompleted(uint16_t conn_handle, uint8_t auth_status); }; \ No newline at end of file diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 1f2c6867d5..b79f28f139 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -63,7 +63,8 @@ static void initBrownout() // We don't bother with setting up brownout if soft device is disabled - because during production we always use softdevice } -static const bool useSoftDevice = true; // Set to false for easier debugging +// This is a public global so that the debugger can set it to false automatically from our gdbinit +bool useSoftDevice = true; // Set to false for easier debugging #if !MESHTASTIC_EXCLUDE_BLUETOOTH void setBluetoothEnable(bool enable) @@ -149,13 +150,43 @@ void nrf52Loop() checkSDEvents(); } +#ifdef USE_SEMIHOSTING +#include + +/** + * Note: this variable is in BSS and therfore false by default. But the gdbinit + * file will be installing a temporary breakpoint that changes wantSemihost to true. + */ +bool wantSemihost; + +/** + * Turn on semihosting if the ICE debugger wants it. + */ +void nrf52InitSemiHosting() +{ + if (wantSemihost) { + static SemihostingStream semiStream; + // We must dynamically alloc because the constructor does semihost operations which + // would crash any load not talking to a debugger + semiStream.open(); + semiStream.println("Semihosting starts!"); + // Redirect our serial output to instead go via the ICE port + console->setDestination(&semiStream); + } +} +#endif + void nrf52Setup() { - auto why = NRF_POWER->RESETREAS; + uint32_t why = NRF_POWER->RESETREAS; // per // https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpower.html LOG_DEBUG("Reset reason: 0x%x\n", why); +#ifdef USE_SEMIHOSTING + nrf52InitSemiHosting(); +#endif + // Per // https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/monitor-mode-debugging-with-j-link-and-gdbeclipse // This is the recommended setting for Monitor Mode Debugging diff --git a/src/shutdown.h b/src/shutdown.h index 54fb3071b7..3f191eea88 100644 --- a/src/shutdown.h +++ b/src/shutdown.h @@ -38,7 +38,7 @@ void powerCommandsCheck() #if defined(ARCH_ESP32) || defined(ARCH_NRF52) if (shutdownAtMsec) { - screen->startShutdownScreen(); + screen->startAlert("Shutting down..."); } #endif diff --git a/src/sleep.cpp b/src/sleep.cpp index 55e70e7b87..04963b8a2e 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -8,6 +8,7 @@ #include "MeshRadio.h" #include "MeshService.h" #include "NodeDB.h" +#include "PowerMon.h" #include "detect/LoRaRadioType.h" #include "error.h" #include "main.h" @@ -17,7 +18,7 @@ #ifdef ARCH_ESP32 #include "esp32/pm.h" #include "esp_pm.h" -#if !MESHTASTIC_EXCLUDE_WIFI +#if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "rom/rtc.h" @@ -56,20 +57,20 @@ RTC_DATA_ATTR int bootCount = 0; */ void setCPUFast(bool on) { -#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI +#if defined(ARCH_ESP32) && HAS_WIFI if (isWifiAvailable()) { /* * * There's a newly introduced bug in the espressif framework where WiFi is - * unstable when the frequency is less than 240mhz. + * unstable when the frequency is less than 240MHz. * * This mostly impacts WiFi AP mode but we'll bump the frequency for * all WiFi use cases. * (Added: Dec 23, 2021 by Jm Casler) */ #ifndef CONFIG_IDF_TARGET_ESP32C3 - LOG_DEBUG("Setting CPU to 240mhz because WiFi is in use.\n"); + LOG_DEBUG("Setting CPU to 240MHz because WiFi is in use.\n"); setCpuFrequencyMhz(240); #endif return; @@ -85,6 +86,11 @@ void setCPUFast(bool on) void setLed(bool ledOn) { + if (ledOn) + powerMon->setState(meshtastic_PowerMon_State_LED_On); + else + powerMon->clearState(meshtastic_PowerMon_State_LED_On); + #ifdef LED_PIN // toggle the led so we can get some rough sense of how often loop is pausing digitalWrite(LED_PIN, ledOn ^ LED_INVERTED); diff --git a/variants/heltec_wireless_paper/pins_arduino.h b/variants/heltec_wireless_paper/pins_arduino.h index 9e1d8a9a01..2bb44161ab 100644 --- a/variants/heltec_wireless_paper/pins_arduino.h +++ b/variants/heltec_wireless_paper/pins_arduino.h @@ -3,11 +3,7 @@ #include -#define WIFI_Kit_32 true -#define DISPLAY_HEIGHT 64 -#define DISPLAY_WIDTH 128 - -static const uint8_t LED_BUILTIN = 35; +static const uint8_t LED_BUILTIN = 18; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN @@ -65,6 +61,6 @@ static const uint8_t LED = 18; static const uint8_t RST_LoRa = 12; static const uint8_t BUSY_LoRa = 13; -static const uint8_t DIO0 = 14; +static const uint8_t DIO1 = 14; #endif /* Pins_Arduino_h */ diff --git a/variants/heltec_wireless_paper/variant.h b/variants/heltec_wireless_paper/variant.h index 29b8bbbd14..c41d6d9dfe 100644 --- a/variants/heltec_wireless_paper/variant.h +++ b/variants/heltec_wireless_paper/variant.h @@ -1,14 +1,12 @@ #define LED_PIN 18 +#define BUTTON_PIN 0 -// Enable bus for external periherals +// I2C #define I2C_SDA SDA #define I2C_SCL SCL +// Display (E-Ink) #define USE_EINK - -/* - * eink display pins - */ #define PIN_EINK_CS 4 #define PIN_EINK_BUSY 7 #define PIN_EINK_DC 5 @@ -16,32 +14,28 @@ #define PIN_EINK_SCLK 3 #define PIN_EINK_MOSI 2 -/* - * SPI interfaces - */ +// SPI #define SPI_INTERFACES_COUNT 2 +#define PIN_SPI_MISO 10 // MISO +#define PIN_SPI_MOSI 11 // MOSI +#define PIN_SPI_SCK 9 // SCK -#define PIN_SPI_MISO 10 // MISO P0.17 -#define PIN_SPI_MOSI 11 // MOSI P0.15 -#define PIN_SPI_SCK 9 // SCK P0.13 - -#define VEXT_ENABLE 45 // active low, powers the oled display and the lora antenna boost -#define BUTTON_PIN 0 - +// Power +#define VEXT_ENABLE 45 // Active low, powers the E-Ink display #define ADC_CTRL 19 #define BATTERY_PIN 20 #define ADC_CHANNEL ADC2_GPIO20_CHANNEL #define ADC_MULTIPLIER 2 // Voltage divider is roughly 1:1 #define BAT_MEASURE_ADC_UNIT 2 // Use ADC2 -#define ADC_ATTENUATION ADC_ATTEN_DB_11 // Voltage divider output is quite high +#define ADC_ATTENUATION ADC_ATTEN_DB_12 // Voltage divider output is quite high +// LoRa #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module #define LORA_RESET 12 #define LORA_DIO1 14 // SX1262 IRQ #define LORA_DIO2 13 // SX1262 BUSY -#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled #define LORA_SCK 9 #define LORA_MISO 11 diff --git a/variants/heltec_wireless_paper_v1/pins_arduino.h b/variants/heltec_wireless_paper_v1/pins_arduino.h index 9e1d8a9a01..2bb44161ab 100644 --- a/variants/heltec_wireless_paper_v1/pins_arduino.h +++ b/variants/heltec_wireless_paper_v1/pins_arduino.h @@ -3,11 +3,7 @@ #include -#define WIFI_Kit_32 true -#define DISPLAY_HEIGHT 64 -#define DISPLAY_WIDTH 128 - -static const uint8_t LED_BUILTIN = 35; +static const uint8_t LED_BUILTIN = 18; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN @@ -65,6 +61,6 @@ static const uint8_t LED = 18; static const uint8_t RST_LoRa = 12; static const uint8_t BUSY_LoRa = 13; -static const uint8_t DIO0 = 14; +static const uint8_t DIO1 = 14; #endif /* Pins_Arduino_h */ diff --git a/variants/heltec_wireless_paper_v1/variant.h b/variants/heltec_wireless_paper_v1/variant.h index 29b8bbbd14..c41d6d9dfe 100644 --- a/variants/heltec_wireless_paper_v1/variant.h +++ b/variants/heltec_wireless_paper_v1/variant.h @@ -1,14 +1,12 @@ #define LED_PIN 18 +#define BUTTON_PIN 0 -// Enable bus for external periherals +// I2C #define I2C_SDA SDA #define I2C_SCL SCL +// Display (E-Ink) #define USE_EINK - -/* - * eink display pins - */ #define PIN_EINK_CS 4 #define PIN_EINK_BUSY 7 #define PIN_EINK_DC 5 @@ -16,32 +14,28 @@ #define PIN_EINK_SCLK 3 #define PIN_EINK_MOSI 2 -/* - * SPI interfaces - */ +// SPI #define SPI_INTERFACES_COUNT 2 +#define PIN_SPI_MISO 10 // MISO +#define PIN_SPI_MOSI 11 // MOSI +#define PIN_SPI_SCK 9 // SCK -#define PIN_SPI_MISO 10 // MISO P0.17 -#define PIN_SPI_MOSI 11 // MOSI P0.15 -#define PIN_SPI_SCK 9 // SCK P0.13 - -#define VEXT_ENABLE 45 // active low, powers the oled display and the lora antenna boost -#define BUTTON_PIN 0 - +// Power +#define VEXT_ENABLE 45 // Active low, powers the E-Ink display #define ADC_CTRL 19 #define BATTERY_PIN 20 #define ADC_CHANNEL ADC2_GPIO20_CHANNEL #define ADC_MULTIPLIER 2 // Voltage divider is roughly 1:1 #define BAT_MEASURE_ADC_UNIT 2 // Use ADC2 -#define ADC_ATTENUATION ADC_ATTEN_DB_11 // Voltage divider output is quite high +#define ADC_ATTENUATION ADC_ATTEN_DB_12 // Voltage divider output is quite high +// LoRa #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module #define LORA_RESET 12 #define LORA_DIO1 14 // SX1262 IRQ #define LORA_DIO2 13 // SX1262 BUSY -#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled #define LORA_SCK 9 #define LORA_MISO 11 diff --git a/variants/heltec_wireless_tracker/platformio.ini b/variants/heltec_wireless_tracker/platformio.ini index 3259d563c3..c7ecce8eab 100644 --- a/variants/heltec_wireless_tracker/platformio.ini +++ b/variants/heltec_wireless_tracker/platformio.ini @@ -1,7 +1,7 @@ [env:heltec-wireless-tracker] extends = esp32s3_base board = heltec_wireless_tracker -upload_protocol = esp-builtin +upload_protocol = esptool build_flags = ${esp32s3_base.build_flags} -I variants/heltec_wireless_tracker @@ -11,4 +11,4 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} - lovyan03/LovyanGFX@^1.1.8 \ No newline at end of file + lovyan03/LovyanGFX@^1.1.8 diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index ef3e5a6458..6a67b00835 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -20,6 +20,7 @@ lib_deps = debug_tool = jlink + ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds ;upload_protocol = jlink @@ -27,26 +28,93 @@ debug_tool = jlink ; Allows programming and debug via the RAK NanoDAP as the default debugger tool for the RAK4631 (it is only $10!) ; programming time is about the same as the bootloader version. ; For information on this see the meshtastic developers documentation for "Development on the NRF52" -[env:rak4631_dap] +[env:rak4631_dbg] extends = env:rak4631 board_level = extra -; pyocd pack --i nrf52840 + +; if the builtin version of openocd has a buggy version of semihosting, so use the external version +; platform_packages = platformio/tool-openocd@^3.1200.0 + +build_flags = + ${env:rak4631.build_flags} + -D USE_SEMIHOSTING + +lib_deps = + ${env:rak4631.lib_deps} + https://github.com/geeksville/Armduino-Semihosting.git#35b538fdf208c3530c1434cd099a08e486672ee4 + +; NOTE: the pyocd support for semihosting is buggy. So I switched to using the builtin platformio support for the stlink adapter which worked much better. +; However the built in openocd version in platformio has buggy support for TCP to semihosting. +; +; So I'm now trying the external openocd - but the openocd scripts for nrf52.cfg assume you are using a DAP adapter not an STLINK adapter. +; In theory I could change those scripts. But for now I'm trying going back to a DAP adapter but with the external openocd. + +upload_protocol = stlink ; eventually use platformio/tool-pyocd@^2.3600.0 instad -upload_protocol = custom -upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE +;upload_protocol = custom +;upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE + +; We want the initial breakpoint at setup() instead of main(). Also we want to enable semihosting at that point so instead of +; debug_init_break = tbreak setup +; we just turn off the platformio tbreak and do it in .gdbinit (where we have more flexibility for scripting) +; also we use a permanent breakpoint so it gets reused each time we restart the debugging session? +debug_init_break = tbreak setup + +; Note: add "monitor arm semihosting_redirect tcp 4444 all" if you want the stdout from the device to go to that port number instead +; (for use by meshtastic command line) +; monitor arm semihosting disable +; monitor debug_level 3 +; +; IMPORTANT: fileio must be disabled before using port 5555 - openocd ver 0.12 has a bug where if enabled it never properly parses the special :tt name +; for stdio access. +; monitor arm semihosting_redirect tcp 5555 stdio + +; Also note: it is _impossible_ to do non blocking reads on the semihost console port (an oversight when ARM specified the semihost API). +; So we'll neve be able to general purpose bi-directional communication with the device over semihosting. +debug_extra_cmds = + echo Running .gdbinit script + monitor arm semihosting enable + monitor arm semihosting_fileio enable + monitor arm semihosting_redirect disable + commands 1 + echo Breakpoint at setup() has semihosting console, connect to it with "telnet localhost 5555" + set wantSemihost = true + set useSoftDevice = false + end + ; Only reprogram the board if the code has changed debug_load_mode = modified ;debug_load_mode = manual -debug_tool = custom +debug_tool = stlink +;debug_tool = custom +; debug_server = +; openocd +; -f +; /usr/local/share/openocd/scripts/interface/stlink.cfg +; -f +; /usr/local/share/openocd/scripts/target/nrf52.cfg +; $PLATFORMIO_CORE_DIR/packages/tool-openocd/openocd/scripts/interface/cmsis-dap.cfg + +; Allows programming and debug via the RAK NanoDAP as the default debugger tool for the RAK4631 (it is only $10!) +; programming time is about the same as the bootloader version. +; For information on this see the meshtastic developers documentation for "Development on the NRF52" ; We manually pass in the elf file so that pyocd can reverse engineer FreeRTOS data (running threads, etc...) -debug_server = - pyocd - gdbserver - -t - nrf52840 - --elf - ${platformio.build_dir}/${this.__env__}/firmware.elf +;debug_server = +; pyocd +; gdbserver +; -j +; ${platformio.workspace_dir}/.. +; -t +; nrf52840 +; --semihosting +; --elf +; ${platformio.build_dir}/${this.__env__}/firmware.elf + +; If you want to debug the semihosting support you can turn on extra logging in pyocd with +; -L +; pyocd.debug.semihost.trace=debug + ; The following is not needed because it automatically tries do this ;debug_server_ready_pattern = -.*GDB server started on port \d+.* ;debug_port = localhost:3333 \ No newline at end of file diff --git a/variants/tlora_t3s3_v1/platformio.ini b/variants/tlora_t3s3_v1/platformio.ini index 002b2f224a..0a57972803 100644 --- a/variants/tlora_t3s3_v1/platformio.ini +++ b/variants/tlora_t3s3_v1/platformio.ini @@ -2,7 +2,7 @@ extends = esp32s3_base board = tlora-t3s3-v1 board_check = true -upload_protocol = esp-builtin +upload_protocol = esptool build_flags = ${esp32_base.build_flags} -D TLORA_T3S3_V1 -I variants/tlora_t3s3_v1 diff --git a/variants/wio-sdk-wm1110/nrf52840_s140_v7.ld b/variants/wio-sdk-wm1110/nrf52840_s140_v7.ld new file mode 100644 index 0000000000..6aaeb4034f --- /dev/null +++ b/variants/wio-sdk-wm1110/nrf52840_s140_v7.ld @@ -0,0 +1,38 @@ +/* Linker script to configure memory regions. */ + +SEARCH_DIR(.) +GROUP(-lgcc -lc -lnosys) + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xED000 - 0x27000 + + /* SRAM required by Softdevice depend on + * - Attribute Table Size (Number of Services and Characteristics) + * - Vendor UUID count + * - Max ATT MTU + * - Concurrent connection peripheral + central + secure links + * - Event Len, HVN queue, Write CMD queue + */ + RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x20040000 - 0x20006000 +} + +SECTIONS +{ + . = ALIGN(4); + .svc_data : + { + PROVIDE(__start_svc_data = .); + KEEP(*(.svc_data)) + PROVIDE(__stop_svc_data = .); + } > RAM + + .fs_data : + { + PROVIDE(__start_fs_data = .); + KEEP(*(.fs_data)) + PROVIDE(__stop_fs_data = .); + } > RAM +} INSERT AFTER .data; + +INCLUDE "nrf52_common.ld" diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini index cd3a76d02f..4410eff112 100644 --- a/variants/wio-sdk-wm1110/platformio.ini +++ b/variants/wio-sdk-wm1110/platformio.ini @@ -10,10 +10,24 @@ board_level = extra build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld +board_build.ldscript = variants/wio-sdk-wm1110/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-sdk-wm1110> lib_deps = ${nrf52840_base.lib_deps} debug_tool = jlink +;debug_tool = stlink +;debug_speed = 4000 +; No need to reflash if the binary hasn't changed +debug_load_mode = modified ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) upload_protocol = jlink +;upload_protocol = stlink +; we prefer to stop in setup() because we are an 'ardiuno' app +debug_init_break = tbreak setup + +; we need to turn off BLE/soft device if we are debugging otherwise it will watchdog reset us. +debug_extra_cmds = + echo Running .gdbinit script + commands 1 + set useSoftDevice = false + end diff --git a/variants/wio-sdk-wm1110/softdevice/ble.h b/variants/wio-sdk-wm1110/softdevice/ble.h new file mode 100644 index 0000000000..177b436ad8 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble.h @@ -0,0 +1,652 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON BLE SoftDevice Common + @{ + @defgroup ble_api Events, type definitions and API calls + @{ + + @brief Module independent events, type definitions and API calls for the BLE SoftDevice. + + */ + +#ifndef BLE_H__ +#define BLE_H__ + +#include "ble_err.h" +#include "ble_gap.h" +#include "ble_gatt.h" +#include "ble_gattc.h" +#include "ble_gatts.h" +#include "ble_l2cap.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_COMMON_ENUMERATIONS Enumerations + * @{ */ + +/** + * @brief Common API SVC numbers. + */ +enum BLE_COMMON_SVCS { + SD_BLE_ENABLE = BLE_SVC_BASE, /**< Enable and initialize the BLE stack */ + SD_BLE_EVT_GET, /**< Get an event from the pending events queue. */ + SD_BLE_UUID_VS_ADD, /**< Add a Vendor Specific base UUID. */ + SD_BLE_UUID_DECODE, /**< Decode UUID bytes. */ + SD_BLE_UUID_ENCODE, /**< Encode UUID bytes. */ + SD_BLE_VERSION_GET, /**< Get the local version information (company ID, Link Layer Version, Link Layer Subversion). */ + SD_BLE_USER_MEM_REPLY, /**< User Memory Reply. */ + SD_BLE_OPT_SET, /**< Set a BLE option. */ + SD_BLE_OPT_GET, /**< Get a BLE option. */ + SD_BLE_CFG_SET, /**< Add a configuration to the BLE stack. */ + SD_BLE_UUID_VS_REMOVE, /**< Remove a Vendor Specific base UUID. */ +}; + +/** + * @brief BLE Module Independent Event IDs. + */ +enum BLE_COMMON_EVTS { + BLE_EVT_USER_MEM_REQUEST = BLE_EVT_BASE + 0, /**< User Memory request. See @ref ble_evt_user_mem_request_t + \n Reply with @ref sd_ble_user_mem_reply. */ + BLE_EVT_USER_MEM_RELEASE = BLE_EVT_BASE + 1, /**< User Memory release. See @ref ble_evt_user_mem_release_t */ +}; + +/**@brief BLE Connection Configuration IDs. + * + * IDs that uniquely identify a connection configuration. + */ +enum BLE_CONN_CFGS { + BLE_CONN_CFG_GAP = BLE_CONN_CFG_BASE + 0, /**< BLE GAP specific connection configuration. */ + BLE_CONN_CFG_GATTC = BLE_CONN_CFG_BASE + 1, /**< BLE GATTC specific connection configuration. */ + BLE_CONN_CFG_GATTS = BLE_CONN_CFG_BASE + 2, /**< BLE GATTS specific connection configuration. */ + BLE_CONN_CFG_GATT = BLE_CONN_CFG_BASE + 3, /**< BLE GATT specific connection configuration. */ + BLE_CONN_CFG_L2CAP = BLE_CONN_CFG_BASE + 4, /**< BLE L2CAP specific connection configuration. */ +}; + +/**@brief BLE Common Configuration IDs. + * + * IDs that uniquely identify a common configuration. + */ +enum BLE_COMMON_CFGS { + BLE_COMMON_CFG_VS_UUID = BLE_CFG_BASE, /**< Vendor specific base UUID configuration */ +}; + +/**@brief Common Option IDs. + * IDs that uniquely identify a common option. + */ +enum BLE_COMMON_OPTS { + BLE_COMMON_OPT_PA_LNA = BLE_OPT_BASE + 0, /**< PA and LNA options */ + BLE_COMMON_OPT_CONN_EVT_EXT = BLE_OPT_BASE + 1, /**< Extended connection events option */ + BLE_COMMON_OPT_EXTENDED_RC_CAL = BLE_OPT_BASE + 2, /**< Extended RC calibration option */ +}; + +/** @} */ + +/** @addtogroup BLE_COMMON_DEFINES Defines + * @{ */ + +/** @brief Required pointer alignment for BLE Events. + */ +#define BLE_EVT_PTR_ALIGNMENT 4 + +/** @brief Leaves the maximum of the two arguments. + */ +#define BLE_MAX(a, b) ((a) < (b) ? (b) : (a)) + +/** @brief Maximum possible length for BLE Events. + * @note The highest value used for @ref ble_gatt_conn_cfg_t::att_mtu in any connection configuration shall be used as a + * parameter. If that value has not been configured for any connections then @ref BLE_GATT_ATT_MTU_DEFAULT must be used instead. + */ +#define BLE_EVT_LEN_MAX(ATT_MTU) \ + (offsetof(ble_evt_t, evt.gattc_evt.params.prim_srvc_disc_rsp.services) + ((ATT_MTU)-1) / 4 * sizeof(ble_gattc_service_t)) + +/** @defgroup BLE_USER_MEM_TYPES User Memory Types + * @{ */ +#define BLE_USER_MEM_TYPE_INVALID 0x00 /**< Invalid User Memory Types. */ +#define BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES 0x01 /**< User Memory for GATTS queued writes. */ +/** @} */ + +/** @defgroup BLE_UUID_VS_COUNTS Vendor Specific base UUID counts + * @{ + */ +#define BLE_UUID_VS_COUNT_DEFAULT 10 /**< Default VS UUID count. */ +#define BLE_UUID_VS_COUNT_MAX 254 /**< Maximum VS UUID count. */ +/** @} */ + +/** @defgroup BLE_COMMON_CFG_DEFAULTS Configuration defaults. + * @{ + */ +#define BLE_CONN_CFG_TAG_DEFAULT 0 /**< Default configuration tag, SoftDevice default connection configuration. */ + +/** @} */ + +/** @} */ + +/** @addtogroup BLE_COMMON_STRUCTURES Structures + * @{ */ + +/**@brief User Memory Block. */ +typedef struct { + uint8_t *p_mem; /**< Pointer to the start of the user memory block. */ + uint16_t len; /**< Length in bytes of the user memory block. */ +} ble_user_mem_block_t; + +/**@brief Event structure for @ref BLE_EVT_USER_MEM_REQUEST. */ +typedef struct { + uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ +} ble_evt_user_mem_request_t; + +/**@brief Event structure for @ref BLE_EVT_USER_MEM_RELEASE. */ +typedef struct { + uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ + ble_user_mem_block_t mem_block; /**< User memory block */ +} ble_evt_user_mem_release_t; + +/**@brief Event structure for events not associated with a specific function module. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which this event occurred. */ + union { + ble_evt_user_mem_request_t user_mem_request; /**< User Memory Request Event Parameters. */ + ble_evt_user_mem_release_t user_mem_release; /**< User Memory Release Event Parameters. */ + } params; /**< Event parameter union. */ +} ble_common_evt_t; + +/**@brief BLE Event header. */ +typedef struct { + uint16_t evt_id; /**< Value from a BLE__EVT series. */ + uint16_t evt_len; /**< Length in octets including this header. */ +} ble_evt_hdr_t; + +/**@brief Common BLE Event type, wrapping the module specific event reports. */ +typedef struct { + ble_evt_hdr_t header; /**< Event header. */ + union { + ble_common_evt_t common_evt; /**< Common Event, evt_id in BLE_EVT_* series. */ + ble_gap_evt_t gap_evt; /**< GAP originated event, evt_id in BLE_GAP_EVT_* series. */ + ble_gattc_evt_t gattc_evt; /**< GATT client originated event, evt_id in BLE_GATTC_EVT* series. */ + ble_gatts_evt_t gatts_evt; /**< GATT server originated event, evt_id in BLE_GATTS_EVT* series. */ + ble_l2cap_evt_t l2cap_evt; /**< L2CAP originated event, evt_id in BLE_L2CAP_EVT* series. */ + } evt; /**< Event union. */ +} ble_evt_t; + +/** + * @brief Version Information. + */ +typedef struct { + uint8_t version_number; /**< Link Layer Version number. See + https://www.bluetooth.org/en-us/specification/assigned-numbers/link-layer for assigned values. */ + uint16_t company_id; /**< Company ID, Nordic Semiconductor's company ID is 89 (0x0059) + (https://www.bluetooth.org/apps/content/Default.aspx?doc_id=49708). */ + uint16_t + subversion_number; /**< Link Layer Sub Version number, corresponds to the SoftDevice Config ID or Firmware ID (FWID). */ +} ble_version_t; + +/** + * @brief Configuration parameters for the PA and LNA. + */ +typedef struct { + uint8_t enable : 1; /**< Enable toggling for this amplifier */ + uint8_t active_high : 1; /**< Set the pin to be active high */ + uint8_t gpio_pin : 6; /**< The GPIO pin to toggle for this amplifier */ +} ble_pa_lna_cfg_t; + +/** + * @brief PA & LNA GPIO toggle configuration + * + * This option configures the SoftDevice to toggle pins when the radio is active for use with a power amplifier and/or + * a low noise amplifier. + * + * Toggling the pins is achieved by using two PPI channels and a GPIOTE channel. The hardware channel IDs are provided + * by the application and should be regarded as reserved as long as any PA/LNA toggling is enabled. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * @note Setting this option while the radio is in use (i.e. any of the roles are active) may have undefined consequences + * and must be avoided by the application. + */ +typedef struct { + ble_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */ + ble_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */ + + uint8_t ppi_ch_id_set; /**< PPI channel used for radio pin setting */ + uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */ + uint8_t gpiote_ch_id; /**< GPIOTE channel used for radio pin toggling */ +} ble_common_opt_pa_lna_t; + +/** + * @brief Configuration of extended BLE connection events. + * + * When enabled the SoftDevice will dynamically extend the connection event when possible. + * + * The connection event length is controlled by the connection configuration as set by @ref ble_gap_conn_cfg_t::event_length. + * The connection event can be extended if there is time to send another packet pair before the start of the next connection + * interval, and if there are no conflicts with other BLE roles requesting radio time. + * + * @note @ref sd_ble_opt_get is not supported for this option. + */ +typedef struct { + uint8_t enable : 1; /**< Enable extended BLE connection events, disabled by default. */ +} ble_common_opt_conn_evt_ext_t; + +/** + * @brief Enable/disable extended RC calibration. + * + * If extended RC calibration is enabled and the internal RC oscillator (@ref NRF_CLOCK_LF_SRC_RC) is used as the SoftDevice + * LFCLK source, the SoftDevice as a peripheral will by default try to increase the receive window if two consecutive packets + * are not received. If it turns out that the packets were not received due to clock drift, the RC calibration is started. + * This calibration comes in addition to the periodic calibration that is configured by @ref sd_softdevice_enable(). When + * using only peripheral connections, the periodic calibration can therefore be configured with a much longer interval as the + * peripheral will be able to detect and adjust automatically to clock drift, and calibrate on demand. + * + * If extended RC calibration is disabled and the internal RC oscillator is used as the SoftDevice LFCLK source, the + * RC oscillator is calibrated periodically as configured by @ref sd_softdevice_enable(). + * + * @note @ref sd_ble_opt_get is not supported for this option. + */ +typedef struct { + uint8_t enable : 1; /**< Enable extended RC calibration, enabled by default. */ +} ble_common_opt_extended_rc_cal_t; + +/**@brief Option structure for common options. */ +typedef union { + ble_common_opt_pa_lna_t pa_lna; /**< Parameters for controlling PA and LNA pin toggling. */ + ble_common_opt_conn_evt_ext_t conn_evt_ext; /**< Parameters for enabling extended connection events. */ + ble_common_opt_extended_rc_cal_t extended_rc_cal; /**< Parameters for enabling extended RC calibration. */ +} ble_common_opt_t; + +/**@brief Common BLE Option type, wrapping the module specific options. */ +typedef union { + ble_common_opt_t common_opt; /**< COMMON options, opt_id in @ref BLE_COMMON_OPTS series. */ + ble_gap_opt_t gap_opt; /**< GAP option, opt_id in @ref BLE_GAP_OPTS series. */ + ble_gattc_opt_t gattc_opt; /**< GATTC option, opt_id in @ref BLE_GATTC_OPTS series. */ +} ble_opt_t; + +/**@brief BLE connection configuration type, wrapping the module specific configurations, set with + * @ref sd_ble_cfg_set. + * + * @note Connection configurations don't have to be set. + * In the case that no configurations has been set, or fewer connection configurations has been set than enabled connections, + * the default connection configuration will be automatically added for the remaining connections. + * When creating connections with the default configuration, @ref BLE_CONN_CFG_TAG_DEFAULT should be used in + * place of @ref ble_conn_cfg_t::conn_cfg_tag. + * + * @sa sd_ble_gap_adv_start() + * @sa sd_ble_gap_connect() + * + * @mscs + * @mmsc{@ref BLE_CONN_CFG} + * @endmscs + + */ +typedef struct { + uint8_t conn_cfg_tag; /**< The application chosen tag it can use with the + @ref sd_ble_gap_adv_start() and @ref sd_ble_gap_connect() calls + to select this configuration when creating a connection. + Must be different for all connection configurations added and not @ref BLE_CONN_CFG_TAG_DEFAULT. */ + union { + ble_gap_conn_cfg_t gap_conn_cfg; /**< GAP connection configuration, cfg_id is @ref BLE_CONN_CFG_GAP. */ + ble_gattc_conn_cfg_t gattc_conn_cfg; /**< GATTC connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTC. */ + ble_gatts_conn_cfg_t gatts_conn_cfg; /**< GATTS connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTS. */ + ble_gatt_conn_cfg_t gatt_conn_cfg; /**< GATT connection configuration, cfg_id is @ref BLE_CONN_CFG_GATT. */ + ble_l2cap_conn_cfg_t l2cap_conn_cfg; /**< L2CAP connection configuration, cfg_id is @ref BLE_CONN_CFG_L2CAP. */ + } params; /**< Connection configuration union. */ +} ble_conn_cfg_t; + +/** + * @brief Configuration of Vendor Specific base UUIDs, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_PARAM Too many UUIDs configured. + */ +typedef struct { + uint8_t vs_uuid_count; /**< Number of 128-bit Vendor Specific base UUID bases to allocate memory for. + Default value is @ref BLE_UUID_VS_COUNT_DEFAULT. Maximum value is + @ref BLE_UUID_VS_COUNT_MAX. */ +} ble_common_cfg_vs_uuid_t; + +/**@brief Common BLE Configuration type, wrapping the common configurations. */ +typedef union { + ble_common_cfg_vs_uuid_t vs_uuid_cfg; /**< Vendor Specific base UUID configuration, cfg_id is @ref BLE_COMMON_CFG_VS_UUID. */ +} ble_common_cfg_t; + +/**@brief BLE Configuration type, wrapping the module specific configurations. */ +typedef union { + ble_conn_cfg_t conn_cfg; /**< Connection specific configurations, cfg_id in @ref BLE_CONN_CFGS series. */ + ble_common_cfg_t common_cfg; /**< Global common configurations, cfg_id in @ref BLE_COMMON_CFGS series. */ + ble_gap_cfg_t gap_cfg; /**< Global GAP configurations, cfg_id in @ref BLE_GAP_CFGS series. */ + ble_gatts_cfg_t gatts_cfg; /**< Global GATTS configuration, cfg_id in @ref BLE_GATTS_CFGS series. */ +} ble_cfg_t; + +/** @} */ + +/** @addtogroup BLE_COMMON_FUNCTIONS Functions + * @{ */ + +/**@brief Enable the BLE stack + * + * @param[in, out] p_app_ram_base Pointer to a variable containing the start address of the + * application RAM region (APP_RAM_BASE). On return, this will + * contain the minimum start address of the application RAM region + * required by the SoftDevice for this configuration. + * @warning After this call, the SoftDevice may generate several events. The list of events provided + * below require the application to initiate a SoftDevice API call. The corresponding API call + * is referenced in the event documentation. + * If the application fails to do so, the BLE connection may timeout, or the SoftDevice may stop + * communicating with the peer device. + * - @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST + * - @ref BLE_GAP_EVT_SEC_INFO_REQUEST + * - @ref BLE_GAP_EVT_SEC_REQUEST + * - @ref BLE_GAP_EVT_AUTH_KEY_REQUEST + * - @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST + * - @ref BLE_EVT_USER_MEM_REQUEST + * - @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST + * + * @note The memory requirement for a specific configuration will not increase between SoftDevices + * with the same major version number. + * + * @note At runtime the IC's RAM is split into 2 regions: The SoftDevice RAM region is located + * between 0x20000000 and APP_RAM_BASE-1 and the application's RAM region is located between + * APP_RAM_BASE and the start of the call stack. + * + * @details This call initializes the BLE stack, no BLE related function other than @ref + * sd_ble_cfg_set can be called before this one. + * + * @mscs + * @mmsc{@ref BLE_COMMON_ENABLE} + * @endmscs + * + * @retval ::NRF_SUCCESS The BLE stack has been initialized successfully. + * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized and cannot be reinitialized. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_NO_MEM One or more of the following is true: + * - The amount of memory assigned to the SoftDevice by *p_app_ram_base is not + * large enough to fit this configuration's memory requirement. Check *p_app_ram_base + * and set the start address of the application RAM region accordingly. + * - Dynamic part of the SoftDevice RAM region is larger then 64 kB which + * is currently not supported. + * @retval ::NRF_ERROR_RESOURCES The total number of L2CAP Channels configured using @ref sd_ble_cfg_set is too large. + */ +SVCALL(SD_BLE_ENABLE, uint32_t, sd_ble_enable(uint32_t *p_app_ram_base)); + +/**@brief Add configurations for the BLE stack + * + * @param[in] cfg_id Config ID, see @ref BLE_CONN_CFGS, @ref BLE_COMMON_CFGS, @ref + * BLE_GAP_CFGS or @ref BLE_GATTS_CFGS. + * @param[in] p_cfg Pointer to a ble_cfg_t structure containing the configuration value. + * @param[in] app_ram_base The start address of the application RAM region (APP_RAM_BASE). + * See @ref sd_ble_enable for details about APP_RAM_BASE. + * + * @note The memory requirement for a specific configuration will not increase between SoftDevices + * with the same major version number. + * + * @note If a configuration is set more than once, the last one set is the one that takes effect on + * @ref sd_ble_enable. + * + * @note Any part of the BLE stack that is NOT configured with @ref sd_ble_cfg_set will have default + * configuration. + * + * @note @ref sd_ble_cfg_set may be called at any time when the SoftDevice is enabled (see @ref + * sd_softdevice_enable) while the BLE part of the SoftDevice is not enabled (see @ref + * sd_ble_enable). + * + * @note Error codes for the configurations are described in the configuration structs. + * + * @mscs + * @mmsc{@ref BLE_COMMON_ENABLE} + * @endmscs + * + * @retval ::NRF_SUCCESS The configuration has been added successfully. + * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid cfg_id supplied. + * @retval ::NRF_ERROR_NO_MEM The amount of memory assigned to the SoftDevice by app_ram_base is not + * large enough to fit this configuration's memory requirement. + */ +SVCALL(SD_BLE_CFG_SET, uint32_t, sd_ble_cfg_set(uint32_t cfg_id, ble_cfg_t const *p_cfg, uint32_t app_ram_base)); + +/**@brief Get an event from the pending events queue. + * + * @param[out] p_dest Pointer to buffer to be filled in with an event, or NULL to retrieve the event length. + * This buffer must be aligned to the extend defined by @ref BLE_EVT_PTR_ALIGNMENT. + * The buffer should be interpreted as a @ref ble_evt_t struct. + * @param[in, out] p_len Pointer the length of the buffer, on return it is filled with the event length. + * + * @details This call allows the application to pull a BLE event from the BLE stack. The application is signaled that + * an event is available from the BLE stack by the triggering of the SD_EVT_IRQn interrupt. + * The application is free to choose whether to call this function from thread mode (main context) or directly from the + * Interrupt Service Routine that maps to SD_EVT_IRQn. In any case however, and because the BLE stack runs at a higher + * priority than the application, this function should be called in a loop (until @ref NRF_ERROR_NOT_FOUND is returned) + * every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the BLE stack. Failure to do so + * could potentially leave events in the internal queue without the application being aware of this fact. + * + * Sizing the p_dest buffer is equally important, since the application needs to provide all the memory necessary for the event to + * be copied into application memory. If the buffer provided is not large enough to fit the entire contents of the event, + * @ref NRF_ERROR_DATA_SIZE will be returned and the application can then call again with a larger buffer size. + * The maximum possible event length is defined by @ref BLE_EVT_LEN_MAX. The application may also "peek" the event length + * by providing p_dest as a NULL pointer and inspecting the value of *p_len upon return: + * + * \code + * uint16_t len; + * errcode = sd_ble_evt_get(NULL, &len); + * \endcode + * + * @mscs + * @mmsc{@ref BLE_COMMON_IRQ_EVT_MSC} + * @mmsc{@ref BLE_COMMON_THREAD_EVT_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Event pulled and stored into the supplied buffer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_NOT_FOUND No events ready to be pulled. + * @retval ::NRF_ERROR_DATA_SIZE Event ready but could not fit into the supplied buffer. + */ +SVCALL(SD_BLE_EVT_GET, uint32_t, sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len)); + +/**@brief Add a Vendor Specific base UUID. + * + * @details This call enables the application to add a Vendor Specific base UUID to the BLE stack's table, for later + * use with all other modules and APIs. This then allows the application to use the shorter, 24-bit @ref ble_uuid_t + * format when dealing with both 16-bit and 128-bit UUIDs without having to check for lengths and having split code + * paths. This is accomplished by extending the grouping mechanism that the Bluetooth SIG standard base UUID uses + * for all other 128-bit UUIDs. The type field in the @ref ble_uuid_t structure is an index (relative to + * @ref BLE_UUID_TYPE_VENDOR_BEGIN) to the table populated by multiple calls to this function, and the UUID field + * in the same structure contains the 2 bytes at indexes 12 and 13. The number of possible 128-bit UUIDs available to + * the application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536, + * although restricted to modifying bytes 12 and 13 for each of the entries in the supplied array. + * + * @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by + * the 16-bit uuid field in @ref ble_uuid_t. + * + * @note If a UUID is already present in the BLE stack's internal table, the corresponding index will be returned in + * p_uuid_type along with an @ref NRF_SUCCESS error code. + * + * @param[in] p_vs_uuid Pointer to a 16-octet (128-bit) little endian Vendor Specific base UUID disregarding + * bytes 12 and 13. + * @param[out] p_uuid_type Pointer to a uint8_t where the type field in @ref ble_uuid_t corresponding to this UUID will be + * stored. + * + * @retval ::NRF_SUCCESS Successfully added the Vendor Specific base UUID. + * @retval ::NRF_ERROR_INVALID_ADDR If p_vs_uuid or p_uuid_type is NULL or invalid. + * @retval ::NRF_ERROR_NO_MEM If there are no more free slots for VS UUIDs. + */ +SVCALL(SD_BLE_UUID_VS_ADD, uint32_t, sd_ble_uuid_vs_add(ble_uuid128_t const *p_vs_uuid, uint8_t *p_uuid_type)); + +/**@brief Remove a Vendor Specific base UUID. + * + * @details This call removes a Vendor Specific base UUID. This function allows + * the application to reuse memory allocated for Vendor Specific base UUIDs. + * + * @note Currently this function can only be called with a p_uuid_type set to @ref BLE_UUID_TYPE_UNKNOWN or the last added UUID + * type. + * + * @param[inout] p_uuid_type Pointer to a uint8_t where its value matches the UUID type in @ref ble_uuid_t::type to be removed. + * If the type is set to @ref BLE_UUID_TYPE_UNKNOWN, or the pointer is NULL, the last Vendor Specific + * base UUID will be removed. If the function returns successfully, the UUID type that was removed will + * be written back to @p p_uuid_type. If function returns with a failure, it contains the last type that + * is in use by the ATT Server. + * + * @retval ::NRF_SUCCESS Successfully removed the Vendor Specific base UUID. + * @retval ::NRF_ERROR_INVALID_ADDR If p_uuid_type is invalid. + * @retval ::NRF_ERROR_INVALID_PARAM If p_uuid_type points to a non-valid UUID type. + * @retval ::NRF_ERROR_FORBIDDEN If the Vendor Specific base UUID is in use by the ATT Server. + */ +SVCALL(SD_BLE_UUID_VS_REMOVE, uint32_t, sd_ble_uuid_vs_remove(uint8_t *p_uuid_type)); + +/** @brief Decode little endian raw UUID bytes (16-bit or 128-bit) into a 24 bit @ref ble_uuid_t structure. + * + * @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared + * to the corresponding ones in each entry of the table of Vendor Specific base UUIDs + * to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index + * relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type. + * + * @note If the UUID length supplied is 2, then the type set by this call will always be @ref BLE_UUID_TYPE_BLE. + * + * @param[in] uuid_le_len Length in bytes of the buffer pointed to by p_uuid_le (must be 2 or 16 bytes). + * @param[in] p_uuid_le Pointer pointing to little endian raw UUID bytes. + * @param[out] p_uuid Pointer to a @ref ble_uuid_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Successfully decoded into the @ref ble_uuid_t structure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid UUID length. + * @retval ::NRF_ERROR_NOT_FOUND For a 128-bit UUID, no match in the populated table of UUIDs. + */ +SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uint8_t const *p_uuid_le, ble_uuid_t *p_uuid)); + +/** @brief Encode a @ref ble_uuid_t structure into little endian raw UUID bytes (16-bit or 128-bit). + * + * @note The pointer to the destination buffer p_uuid_le may be NULL, in which case only the validity and size of p_uuid is + * computed. + * + * @param[in] p_uuid Pointer to a @ref ble_uuid_t structure that will be encoded into bytes. + * @param[out] p_uuid_le_len Pointer to a uint8_t that will be filled with the encoded length (2 or 16 bytes). + * @param[out] p_uuid_le Pointer to a buffer where the little endian raw UUID bytes (2 or 16) will be stored. + * + * @retval ::NRF_SUCCESS Successfully encoded into the buffer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid UUID type. + */ +SVCALL(SD_BLE_UUID_ENCODE, uint32_t, sd_ble_uuid_encode(ble_uuid_t const *p_uuid, uint8_t *p_uuid_le_len, uint8_t *p_uuid_le)); + +/**@brief Get Version Information. + * + * @details This call allows the application to get the BLE stack version information. + * + * @param[out] p_version Pointer to a ble_version_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Version information stored successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy (typically doing a locally-initiated disconnection procedure). + */ +SVCALL(SD_BLE_VERSION_GET, uint32_t, sd_ble_version_get(ble_version_t *p_version)); + +/**@brief Provide a user memory block. + * + * @note This call can only be used as a response to a @ref BLE_EVT_USER_MEM_REQUEST event issued to the application. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_block Pointer to a user memory block structure or NULL if memory is managed by the application. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully queued a response to the peer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid user memory block length supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection state or no user memory request pending. + */ +SVCALL(SD_BLE_USER_MEM_REPLY, uint32_t, sd_ble_user_mem_reply(uint16_t conn_handle, ble_user_mem_block_t const *p_block)); + +/**@brief Set a BLE option. + * + * @details This call allows the application to set the value of an option. + * + * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS, @ref BLE_GAP_OPTS, and @ref BLE_GATTC_OPTS. + * @param[in] p_opt Pointer to a @ref ble_opt_t structure containing the option value. + * + * @retval ::NRF_SUCCESS Option set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Unable to set the parameter at this time. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. + */ +SVCALL(SD_BLE_OPT_SET, uint32_t, sd_ble_opt_set(uint32_t opt_id, ble_opt_t const *p_opt)); + +/**@brief Get a BLE option. + * + * @details This call allows the application to retrieve the value of an option. + * + * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS and @ref BLE_GAP_OPTS. + * @param[out] p_opt Pointer to a ble_opt_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Option retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Unable to retrieve the parameter at this time. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. + * @retval ::NRF_ERROR_NOT_SUPPORTED This option is not supported. + * + */ +SVCALL(SD_BLE_OPT_GET, uint32_t, sd_ble_opt_get(uint32_t opt_id, ble_opt_t *p_opt)); + +/** @} */ +#ifdef __cplusplus +} +#endif +#endif /* BLE_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_err.h b/variants/wio-sdk-wm1110/softdevice/ble_err.h new file mode 100644 index 0000000000..d20f6d1416 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_err.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @addtogroup nrf_error + @{ + @ingroup BLE_COMMON + @} + + @defgroup ble_err General error codes + @{ + + @brief General error code definitions for the BLE API. + + @ingroup BLE_COMMON +*/ +#ifndef NRF_BLE_ERR_H__ +#define NRF_BLE_ERR_H__ + +#include "nrf_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* @defgroup BLE_ERRORS Error Codes + * @{ */ +#define BLE_ERROR_NOT_ENABLED (NRF_ERROR_STK_BASE_NUM + 0x001) /**< @ref sd_ble_enable has not been called. */ +#define BLE_ERROR_INVALID_CONN_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x002) /**< Invalid connection handle. */ +#define BLE_ERROR_INVALID_ATTR_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x003) /**< Invalid attribute handle. */ +#define BLE_ERROR_INVALID_ADV_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x004) /**< Invalid advertising handle. */ +#define BLE_ERROR_INVALID_ROLE (NRF_ERROR_STK_BASE_NUM + 0x005) /**< Invalid role. */ +#define BLE_ERROR_BLOCKED_BY_OTHER_LINKS \ + (NRF_ERROR_STK_BASE_NUM + 0x006) /**< The attempt to change link settings failed due to the scheduling of other links. */ +/** @} */ + +/** @defgroup BLE_ERROR_SUBRANGES Module specific error code subranges + * @brief Assignment of subranges for module specific error codes. + * @note For specific error codes, see ble_.h or ble_error_.h. + * @{ */ +#define NRF_L2CAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x100) /**< L2CAP specific errors. */ +#define NRF_GAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x200) /**< GAP specific errors. */ +#define NRF_GATTC_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x300) /**< GATT client specific errors. */ +#define NRF_GATTS_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x400) /**< GATT server specific errors. */ +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif + +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gap.h b/variants/wio-sdk-wm1110/softdevice/ble_gap.h new file mode 100644 index 0000000000..8ebdfa82b0 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_gap.h @@ -0,0 +1,2895 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GAP Generic Access Profile (GAP) + @{ + @brief Definitions and prototypes for the GAP interface. + */ + +#ifndef BLE_GAP_H__ +#define BLE_GAP_H__ + +#include "ble_err.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup BLE_GAP_ENUMERATIONS Enumerations + * @{ */ + +/**@brief GAP API SVC numbers. + */ +enum BLE_GAP_SVCS { + SD_BLE_GAP_ADDR_SET = BLE_GAP_SVC_BASE, /**< Set own Bluetooth Address. */ + SD_BLE_GAP_ADDR_GET = BLE_GAP_SVC_BASE + 1, /**< Get own Bluetooth Address. */ + SD_BLE_GAP_WHITELIST_SET = BLE_GAP_SVC_BASE + 2, /**< Set active whitelist. */ + SD_BLE_GAP_DEVICE_IDENTITIES_SET = BLE_GAP_SVC_BASE + 3, /**< Set device identity list. */ + SD_BLE_GAP_PRIVACY_SET = BLE_GAP_SVC_BASE + 4, /**< Set Privacy settings*/ + SD_BLE_GAP_PRIVACY_GET = BLE_GAP_SVC_BASE + 5, /**< Get Privacy settings*/ + SD_BLE_GAP_ADV_SET_CONFIGURE = BLE_GAP_SVC_BASE + 6, /**< Configure an advertising set. */ + SD_BLE_GAP_ADV_START = BLE_GAP_SVC_BASE + 7, /**< Start Advertising. */ + SD_BLE_GAP_ADV_STOP = BLE_GAP_SVC_BASE + 8, /**< Stop Advertising. */ + SD_BLE_GAP_CONN_PARAM_UPDATE = BLE_GAP_SVC_BASE + 9, /**< Connection Parameter Update. */ + SD_BLE_GAP_DISCONNECT = BLE_GAP_SVC_BASE + 10, /**< Disconnect. */ + SD_BLE_GAP_TX_POWER_SET = BLE_GAP_SVC_BASE + 11, /**< Set TX Power. */ + SD_BLE_GAP_APPEARANCE_SET = BLE_GAP_SVC_BASE + 12, /**< Set Appearance. */ + SD_BLE_GAP_APPEARANCE_GET = BLE_GAP_SVC_BASE + 13, /**< Get Appearance. */ + SD_BLE_GAP_PPCP_SET = BLE_GAP_SVC_BASE + 14, /**< Set PPCP. */ + SD_BLE_GAP_PPCP_GET = BLE_GAP_SVC_BASE + 15, /**< Get PPCP. */ + SD_BLE_GAP_DEVICE_NAME_SET = BLE_GAP_SVC_BASE + 16, /**< Set Device Name. */ + SD_BLE_GAP_DEVICE_NAME_GET = BLE_GAP_SVC_BASE + 17, /**< Get Device Name. */ + SD_BLE_GAP_AUTHENTICATE = BLE_GAP_SVC_BASE + 18, /**< Initiate Pairing/Bonding. */ + SD_BLE_GAP_SEC_PARAMS_REPLY = BLE_GAP_SVC_BASE + 19, /**< Reply with Security Parameters. */ + SD_BLE_GAP_AUTH_KEY_REPLY = BLE_GAP_SVC_BASE + 20, /**< Reply with an authentication key. */ + SD_BLE_GAP_LESC_DHKEY_REPLY = BLE_GAP_SVC_BASE + 21, /**< Reply with an LE Secure Connections DHKey. */ + SD_BLE_GAP_KEYPRESS_NOTIFY = BLE_GAP_SVC_BASE + 22, /**< Notify of a keypress during an authentication procedure. */ + SD_BLE_GAP_LESC_OOB_DATA_GET = BLE_GAP_SVC_BASE + 23, /**< Get the local LE Secure Connections OOB data. */ + SD_BLE_GAP_LESC_OOB_DATA_SET = BLE_GAP_SVC_BASE + 24, /**< Set the remote LE Secure Connections OOB data. */ + SD_BLE_GAP_ENCRYPT = BLE_GAP_SVC_BASE + 25, /**< Initiate encryption procedure. */ + SD_BLE_GAP_SEC_INFO_REPLY = BLE_GAP_SVC_BASE + 26, /**< Reply with Security Information. */ + SD_BLE_GAP_CONN_SEC_GET = BLE_GAP_SVC_BASE + 27, /**< Obtain connection security level. */ + SD_BLE_GAP_RSSI_START = BLE_GAP_SVC_BASE + 28, /**< Start reporting of changes in RSSI. */ + SD_BLE_GAP_RSSI_STOP = BLE_GAP_SVC_BASE + 29, /**< Stop reporting of changes in RSSI. */ + SD_BLE_GAP_SCAN_START = BLE_GAP_SVC_BASE + 30, /**< Start Scanning. */ + SD_BLE_GAP_SCAN_STOP = BLE_GAP_SVC_BASE + 31, /**< Stop Scanning. */ + SD_BLE_GAP_CONNECT = BLE_GAP_SVC_BASE + 32, /**< Connect. */ + SD_BLE_GAP_CONNECT_CANCEL = BLE_GAP_SVC_BASE + 33, /**< Cancel ongoing connection procedure. */ + SD_BLE_GAP_RSSI_GET = BLE_GAP_SVC_BASE + 34, /**< Get the last RSSI sample. */ + SD_BLE_GAP_PHY_UPDATE = BLE_GAP_SVC_BASE + 35, /**< Initiate or respond to a PHY Update Procedure. */ + SD_BLE_GAP_DATA_LENGTH_UPDATE = BLE_GAP_SVC_BASE + 36, /**< Initiate or respond to a Data Length Update Procedure. */ + SD_BLE_GAP_QOS_CHANNEL_SURVEY_START = BLE_GAP_SVC_BASE + 37, /**< Start Quality of Service (QoS) channel survey module. */ + SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP = BLE_GAP_SVC_BASE + 38, /**< Stop Quality of Service (QoS) channel survey module. */ + SD_BLE_GAP_ADV_ADDR_GET = BLE_GAP_SVC_BASE + 39, /**< Get the Address used on air while Advertising. */ + SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET = BLE_GAP_SVC_BASE + 40, /**< Get the next connection event counter. */ + SD_BLE_GAP_CONN_EVT_TRIGGER_START = BLE_GAP_SVC_BASE + 41, /** Start triggering a given task on connection event start. */ + SD_BLE_GAP_CONN_EVT_TRIGGER_STOP = + BLE_GAP_SVC_BASE + 42, /** Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. */ +}; + +/**@brief GAP Event IDs. + * IDs that uniquely identify an event coming from the stack to the application. + */ +enum BLE_GAP_EVTS { + BLE_GAP_EVT_CONNECTED = + BLE_GAP_EVT_BASE, /**< Connected to peer. \n See @ref ble_gap_evt_connected_t */ + BLE_GAP_EVT_DISCONNECTED = + BLE_GAP_EVT_BASE + 1, /**< Disconnected from peer. \n See @ref ble_gap_evt_disconnected_t. */ + BLE_GAP_EVT_CONN_PARAM_UPDATE = + BLE_GAP_EVT_BASE + 2, /**< Connection Parameters updated. \n See @ref ble_gap_evt_conn_param_update_t. */ + BLE_GAP_EVT_SEC_PARAMS_REQUEST = + BLE_GAP_EVT_BASE + 3, /**< Request to provide security parameters. \n Reply with @ref sd_ble_gap_sec_params_reply. + \n See @ref ble_gap_evt_sec_params_request_t. */ + BLE_GAP_EVT_SEC_INFO_REQUEST = + BLE_GAP_EVT_BASE + 4, /**< Request to provide security information. \n Reply with @ref sd_ble_gap_sec_info_reply. + \n See @ref ble_gap_evt_sec_info_request_t. */ + BLE_GAP_EVT_PASSKEY_DISPLAY = + BLE_GAP_EVT_BASE + 5, /**< Request to display a passkey to the user. \n In LESC Numeric Comparison, reply with @ref + sd_ble_gap_auth_key_reply. \n See @ref ble_gap_evt_passkey_display_t. */ + BLE_GAP_EVT_KEY_PRESSED = + BLE_GAP_EVT_BASE + 6, /**< Notification of a keypress on the remote device.\n See @ref ble_gap_evt_key_pressed_t */ + BLE_GAP_EVT_AUTH_KEY_REQUEST = + BLE_GAP_EVT_BASE + 7, /**< Request to provide an authentication key. \n Reply with @ref sd_ble_gap_auth_key_reply. + \n See @ref ble_gap_evt_auth_key_request_t. */ + BLE_GAP_EVT_LESC_DHKEY_REQUEST = + BLE_GAP_EVT_BASE + 8, /**< Request to calculate an LE Secure Connections DHKey. \n Reply with @ref + sd_ble_gap_lesc_dhkey_reply. \n See @ref ble_gap_evt_lesc_dhkey_request_t */ + BLE_GAP_EVT_AUTH_STATUS = + BLE_GAP_EVT_BASE + 9, /**< Authentication procedure completed with status. \n See @ref ble_gap_evt_auth_status_t. */ + BLE_GAP_EVT_CONN_SEC_UPDATE = + BLE_GAP_EVT_BASE + 10, /**< Connection security updated. \n See @ref ble_gap_evt_conn_sec_update_t. */ + BLE_GAP_EVT_TIMEOUT = + BLE_GAP_EVT_BASE + 11, /**< Timeout expired. \n See @ref ble_gap_evt_timeout_t. */ + BLE_GAP_EVT_RSSI_CHANGED = + BLE_GAP_EVT_BASE + 12, /**< RSSI report. \n See @ref ble_gap_evt_rssi_changed_t. */ + BLE_GAP_EVT_ADV_REPORT = + BLE_GAP_EVT_BASE + 13, /**< Advertising report. \n See @ref ble_gap_evt_adv_report_t. */ + BLE_GAP_EVT_SEC_REQUEST = + BLE_GAP_EVT_BASE + 14, /**< Security Request. \n Reply with @ref sd_ble_gap_authenticate +\n or with @ref sd_ble_gap_encrypt if required security information is available +. \n See @ref ble_gap_evt_sec_request_t. */ + BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 15, /**< Connection Parameter Update Request. \n Reply with @ref + sd_ble_gap_conn_param_update. \n See @ref ble_gap_evt_conn_param_update_request_t. */ + BLE_GAP_EVT_SCAN_REQ_REPORT = + BLE_GAP_EVT_BASE + 16, /**< Scan request report. \n See @ref ble_gap_evt_scan_req_report_t. */ + BLE_GAP_EVT_PHY_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 17, /**< PHY Update Request. \n Reply with @ref sd_ble_gap_phy_update. \n + See @ref ble_gap_evt_phy_update_request_t. */ + BLE_GAP_EVT_PHY_UPDATE = + BLE_GAP_EVT_BASE + 18, /**< PHY Update Procedure is complete. \n See @ref ble_gap_evt_phy_update_t. */ + BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 19, /**< Data Length Update Request. \n Reply with @ref + sd_ble_gap_data_length_update. \n See @ref ble_gap_evt_data_length_update_request_t. */ + BLE_GAP_EVT_DATA_LENGTH_UPDATE = + BLE_GAP_EVT_BASE + + 20, /**< LL Data Channel PDU payload length updated. \n See @ref ble_gap_evt_data_length_update_t. */ + BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT = + BLE_GAP_EVT_BASE + + 21, /**< Channel survey report. \n See @ref ble_gap_evt_qos_channel_survey_report_t. */ + BLE_GAP_EVT_ADV_SET_TERMINATED = + BLE_GAP_EVT_BASE + + 22, /**< Advertising set terminated. \n See @ref ble_gap_evt_adv_set_terminated_t. */ +}; + +/**@brief GAP Option IDs. + * IDs that uniquely identify a GAP option. + */ +enum BLE_GAP_OPTS { + BLE_GAP_OPT_CH_MAP = BLE_GAP_OPT_BASE, /**< Channel Map. @ref ble_gap_opt_ch_map_t */ + BLE_GAP_OPT_LOCAL_CONN_LATENCY = BLE_GAP_OPT_BASE + 1, /**< Local connection latency. @ref ble_gap_opt_local_conn_latency_t */ + BLE_GAP_OPT_PASSKEY = BLE_GAP_OPT_BASE + 2, /**< Set passkey. @ref ble_gap_opt_passkey_t */ + BLE_GAP_OPT_COMPAT_MODE_1 = BLE_GAP_OPT_BASE + 3, /**< Compatibility mode. @ref ble_gap_opt_compat_mode_1_t */ + BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT = + BLE_GAP_OPT_BASE + 4, /**< Set Authenticated payload timeout. @ref ble_gap_opt_auth_payload_timeout_t */ + BLE_GAP_OPT_SLAVE_LATENCY_DISABLE = + BLE_GAP_OPT_BASE + 5, /**< Disable slave latency. @ref ble_gap_opt_slave_latency_disable_t */ +}; + +/**@brief GAP Configuration IDs. + * + * IDs that uniquely identify a GAP configuration. + */ +enum BLE_GAP_CFGS { + BLE_GAP_CFG_ROLE_COUNT = BLE_GAP_CFG_BASE, /**< Role count configuration. */ + BLE_GAP_CFG_DEVICE_NAME = BLE_GAP_CFG_BASE + 1, /**< Device name configuration. */ + BLE_GAP_CFG_PPCP_INCL_CONFIG = BLE_GAP_CFG_BASE + 2, /**< Peripheral Preferred Connection Parameters characteristic + inclusion configuration. */ + BLE_GAP_CFG_CAR_INCL_CONFIG = BLE_GAP_CFG_BASE + 3, /**< Central Address Resolution characteristic + inclusion configuration. */ +}; + +/**@brief GAP TX Power roles. + */ +enum BLE_GAP_TX_POWER_ROLES { + BLE_GAP_TX_POWER_ROLE_ADV = 1, /**< Advertiser role. */ + BLE_GAP_TX_POWER_ROLE_SCAN_INIT = 2, /**< Scanner and initiator role. */ + BLE_GAP_TX_POWER_ROLE_CONN = 3, /**< Connection role. */ +}; + +/** @} */ + +/**@addtogroup BLE_GAP_DEFINES Defines + * @{ */ + +/**@defgroup BLE_ERRORS_GAP SVC return values specific to GAP + * @{ */ +#define BLE_ERROR_GAP_UUID_LIST_MISMATCH \ + (NRF_GAP_ERR_BASE + 0x000) /**< UUID list does not contain an integral number of UUIDs. */ +#define BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST \ + (NRF_GAP_ERR_BASE + 0x001) /**< Use of Whitelist not permitted with discoverable advertising. */ +#define BLE_ERROR_GAP_INVALID_BLE_ADDR \ + (NRF_GAP_ERR_BASE + 0x002) /**< The upper two bits of the address do not correspond to the specified address type. */ +#define BLE_ERROR_GAP_WHITELIST_IN_USE \ + (NRF_GAP_ERR_BASE + 0x003) /**< Attempt to modify the whitelist while already in use by another operation. */ +#define BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE \ + (NRF_GAP_ERR_BASE + 0x004) /**< Attempt to modify the device identity list while already in use by another operation. */ +#define BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE \ + (NRF_GAP_ERR_BASE + 0x005) /**< The device identity list contains entries with duplicate identity addresses. */ +/**@} */ + +/**@defgroup BLE_GAP_ROLES GAP Roles + * @{ */ +#define BLE_GAP_ROLE_INVALID 0x0 /**< Invalid Role. */ +#define BLE_GAP_ROLE_PERIPH 0x1 /**< Peripheral Role. */ +#define BLE_GAP_ROLE_CENTRAL 0x2 /**< Central Role. */ +/**@} */ + +/**@defgroup BLE_GAP_TIMEOUT_SOURCES GAP Timeout sources + * @{ */ +#define BLE_GAP_TIMEOUT_SRC_SCAN 0x01 /**< Scanning timeout. */ +#define BLE_GAP_TIMEOUT_SRC_CONN 0x02 /**< Connection timeout. */ +#define BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD 0x03 /**< Authenticated payload timeout. */ +/**@} */ + +/**@defgroup BLE_GAP_ADDR_TYPES GAP Address types + * @{ */ +#define BLE_GAP_ADDR_TYPE_PUBLIC 0x00 /**< Public (identity) address.*/ +#define BLE_GAP_ADDR_TYPE_RANDOM_STATIC 0x01 /**< Random static (identity) address. */ +#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE 0x02 /**< Random private resolvable address. */ +#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE 0x03 /**< Random private non-resolvable address. */ +#define BLE_GAP_ADDR_TYPE_ANONYMOUS \ + 0x7F /**< An advertiser may advertise without its address. \ + This type of advertising is called anonymous. */ +/**@} */ + +/**@brief The default interval in seconds at which a private address is refreshed. */ +#define BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S (900) /* 15 minutes. */ +/**@brief The maximum interval in seconds at which a private address can be refreshed. */ +#define BLE_GAP_MAX_PRIVATE_ADDR_CYCLE_INTERVAL_S (41400) /* 11 hours 30 minutes. */ + +/** @brief BLE address length. */ +#define BLE_GAP_ADDR_LEN (6) + +/**@defgroup BLE_GAP_PRIVACY_MODES Privacy modes + * @{ */ +#define BLE_GAP_PRIVACY_MODE_OFF 0x00 /**< Device will send and accept its identity address for its own address. */ +#define BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY 0x01 /**< Device will send and accept only private addresses for its own address. */ +#define BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY \ + 0x02 /**< Device will send and accept only private addresses for its own address, \ + and will not accept a peer using identity address as sender address when \ + the peer IRK is exchanged, non-zero and added to the identity list. */ +/**@} */ + +/** @brief Invalid power level. */ +#define BLE_GAP_POWER_LEVEL_INVALID 127 + +/** @brief Advertising set handle not set. */ +#define BLE_GAP_ADV_SET_HANDLE_NOT_SET (0xFF) + +/** @brief The default number of advertising sets. */ +#define BLE_GAP_ADV_SET_COUNT_DEFAULT (1) + +/** @brief The maximum number of advertising sets supported by this SoftDevice. */ +#define BLE_GAP_ADV_SET_COUNT_MAX (1) + +/**@defgroup BLE_GAP_ADV_SET_DATA_SIZES Advertising data sizes. + * @{ */ +#define BLE_GAP_ADV_SET_DATA_SIZE_MAX \ + (31) /**< Maximum data length for an advertising set. \ + If more advertising data is required, use extended advertising instead. */ +#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED \ + (255) /**< Maximum supported data length for an extended advertising set. */ + +#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED \ + (238) /**< Maximum supported data length for an extended connectable advertising set. */ +/**@}. */ + +/** @brief Set ID not available in advertising report. */ +#define BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE 0xFF + +/**@defgroup BLE_GAP_EVT_ADV_SET_TERMINATED_REASON GAP Advertising Set Terminated reasons + * @{ */ +#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT 0x01 /**< Timeout value reached. */ +#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED 0x02 /**< @ref ble_gap_adv_params_t::max_adv_evts was reached. */ +/**@} */ + +/**@defgroup BLE_GAP_AD_TYPE_DEFINITIONS GAP Advertising and Scan Response Data format + * @note Found at https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm + * @{ */ +#define BLE_GAP_AD_TYPE_FLAGS 0x01 /**< Flags for discoverability. */ +#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 /**< Partial list of 16 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 /**< Complete list of 16 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 /**< Partial list of 32 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 /**< Complete list of 32 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 /**< Partial list of 128 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 /**< Complete list of 128 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 /**< Short local device name. */ +#define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 /**< Complete local device name. */ +#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A /**< Transmit power level. */ +#define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D /**< Class of device. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E /**< Simple Pairing Hash C. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F /**< Simple Pairing Randomizer R. */ +#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 /**< Security Manager TK Value. */ +#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 /**< Security Manager Out Of Band Flags. */ +#define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 /**< Slave Connection Interval Range. */ +#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 /**< List of 16-bit Service Solicitation UUIDs. */ +#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 /**< List of 128-bit Service Solicitation UUIDs. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 /**< Service Data - 16-bit UUID. */ +#define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 /**< Public Target Address. */ +#define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 /**< Random Target Address. */ +#define BLE_GAP_AD_TYPE_APPEARANCE 0x19 /**< Appearance. */ +#define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A /**< Advertising Interval. */ +#define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B /**< LE Bluetooth Device Address. */ +#define BLE_GAP_AD_TYPE_LE_ROLE 0x1C /**< LE Role. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D /**< Simple Pairing Hash C-256. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E /**< Simple Pairing Randomizer R-256. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 /**< Service Data - 32-bit UUID. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 /**< Service Data - 128-bit UUID. */ +#define BLE_GAP_AD_TYPE_LESC_CONFIRMATION_VALUE 0x22 /**< LE Secure Connections Confirmation Value */ +#define BLE_GAP_AD_TYPE_LESC_RANDOM_VALUE 0x23 /**< LE Secure Connections Random Value */ +#define BLE_GAP_AD_TYPE_URI 0x24 /**< URI */ +#define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D /**< 3D Information Data. */ +#define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF /**< Manufacturer Specific Data. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_FLAGS GAP Advertisement Flags + * @{ */ +#define BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE (0x01) /**< LE Limited Discoverable Mode. */ +#define BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) /**< LE General Discoverable Mode. */ +#define BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) /**< BR/EDR not supported. */ +#define BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER (0x08) /**< Simultaneous LE and BR/EDR, Controller. */ +#define BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST (0x10) /**< Simultaneous LE and BR/EDR, Host. */ +#define BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE \ + (BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE | \ + BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE Limited Discoverable Mode, BR/EDR not supported. */ +#define BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE \ + (BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | \ + BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE General Discoverable Mode, BR/EDR not supported. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_INTERVALS GAP Advertising interval max and min + * @{ */ +#define BLE_GAP_ADV_INTERVAL_MIN 0x000020 /**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */ +#define BLE_GAP_ADV_INTERVAL_MAX 0x004000 /**< Maximum Advertising interval in 625 us units, i.e. 10.24 s. */ + /**@} */ + +/**@defgroup BLE_GAP_SCAN_INTERVALS GAP Scan interval max and min + * @{ */ +#define BLE_GAP_SCAN_INTERVAL_MIN 0x0004 /**< Minimum Scan interval in 625 us units, i.e. 2.5 ms. */ +#define BLE_GAP_SCAN_INTERVAL_MAX 0xFFFF /**< Maximum Scan interval in 625 us units, i.e. 40,959.375 s. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_WINDOW GAP Scan window max and min + * @{ */ +#define BLE_GAP_SCAN_WINDOW_MIN 0x0004 /**< Minimum Scan window in 625 us units, i.e. 2.5 ms. */ +#define BLE_GAP_SCAN_WINDOW_MAX 0xFFFF /**< Maximum Scan window in 625 us units, i.e. 40,959.375 s. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_TIMEOUT GAP Scan timeout max and min + * @{ */ +#define BLE_GAP_SCAN_TIMEOUT_MIN 0x0001 /**< Minimum Scan timeout in 10 ms units, i.e 10 ms. */ +#define BLE_GAP_SCAN_TIMEOUT_UNLIMITED 0x0000 /**< Continue to scan forever. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_BUFFER_SIZE GAP Minimum scanner buffer size + * + * Scan buffers are used for storing advertising data received from an advertiser. + * If ble_gap_scan_params_t::extended is set to 0, @ref BLE_GAP_SCAN_BUFFER_MIN is the minimum scan buffer length. + * else the minimum scan buffer size is @ref BLE_GAP_SCAN_BUFFER_EXTENDED_MIN. + * @{ */ +#define BLE_GAP_SCAN_BUFFER_MIN \ + (31) /**< Minimum data length for an \ + advertising set. */ +#define BLE_GAP_SCAN_BUFFER_MAX \ + (31) /**< Maximum data length for an \ + advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MIN \ + (255) /**< Minimum data length for an \ + extended advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX \ + (1650) /**< Maximum data length for an \ + extended advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED \ + (255) /**< Maximum supported data length for \ + an extended advertising set. */ +/** @} */ + +/**@defgroup BLE_GAP_ADV_TYPES GAP Advertising types + * + * Advertising types defined in Bluetooth Core Specification v5.0, Vol 6, Part B, Section 4.4.2. + * + * The maximum advertising data length is defined by @ref BLE_GAP_ADV_SET_DATA_SIZE_MAX. + * The maximum supported data length for an extended advertiser is defined by + * @ref BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED + * Note that some of the advertising types do not support advertising data. Non-scannable types do not support + * scan response data. + * + * @{ */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x01 /**< Connectable and scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE \ + 0x02 /**< Connectable non-scannable directed advertising \ + events. Advertising interval is less that 3.75 ms. \ + Use this type for fast reconnections. \ + @note Advertising data is not supported. */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x03 /**< Connectable non-scannable directed advertising \ + events. \ + @note Advertising data is not supported. */ +#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x04 /**< Non-connectable scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x05 /**< Non-connectable non-scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x06 /**< Connectable non-scannable undirected advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x07 /**< Connectable non-scannable directed advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x08 /**< Non-connectable scannable undirected advertising \ + events using extended advertising PDUs. \ + @note Only scan response data is supported. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED \ + 0x09 /**< Non-connectable scannable directed advertising \ + events using extended advertising PDUs. \ + @note Only scan response data is supported. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x0A /**< Non-connectable non-scannable undirected advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x0B /**< Non-connectable non-scannable directed advertising \ + events using extended advertising PDUs. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_FILTER_POLICIES GAP Advertising filter policies + * @{ */ +#define BLE_GAP_ADV_FP_ANY 0x00 /**< Allow scan requests and connect requests from any device. */ +#define BLE_GAP_ADV_FP_FILTER_SCANREQ 0x01 /**< Filter scan requests with whitelist. */ +#define BLE_GAP_ADV_FP_FILTER_CONNREQ 0x02 /**< Filter connect requests with whitelist. */ +#define BLE_GAP_ADV_FP_FILTER_BOTH 0x03 /**< Filter both scan and connect requests with whitelist. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_DATA_STATUS GAP Advertising data status + * @{ */ +#define BLE_GAP_ADV_DATA_STATUS_COMPLETE 0x00 /**< All data in the advertising event have been received. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA \ + 0x01 /**< More data to be received. \ + @note This value will only be used if \ + @ref ble_gap_scan_params_t::report_incomplete_evts and \ + @ref ble_gap_adv_report_type_t::extended_pdu are set to true. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED \ + 0x02 /**< Incomplete data. Buffer size insufficient to receive more. \ + @note This value will only be used if \ + @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MISSED \ + 0x03 /**< Failed to receive the remaining data. \ + @note This value will only be used if \ + @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ +/**@} */ + +/**@defgroup BLE_GAP_SCAN_FILTER_POLICIES GAP Scanner filter policies + * @{ */ +#define BLE_GAP_SCAN_FP_ACCEPT_ALL \ + 0x00 /**< Accept all advertising packets except directed advertising packets \ + not addressed to this device. */ +#define BLE_GAP_SCAN_FP_WHITELIST \ + 0x01 /**< Accept advertising packets from devices in the whitelist except directed \ + packets not addressed to this device. */ +#define BLE_GAP_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED \ + 0x02 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL. \ + In addition, accept directed advertising packets, where the advertiser's \ + address is a resolvable private address that cannot be resolved. */ +#define BLE_GAP_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED \ + 0x03 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST. \ + In addition, accept directed advertising packets, where the advertiser's \ + address is a resolvable private address that cannot be resolved. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_TIMEOUT_VALUES GAP Advertising timeout values in 10 ms units + * @{ */ +#define BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX \ + (128) /**< Maximum high duty advertising time in 10 ms units. Corresponds to 1.28 s. \ + */ +#define BLE_GAP_ADV_TIMEOUT_LIMITED_MAX \ + (18000) /**< Maximum advertising time in 10 ms units corresponding to TGAP(lim_adv_timeout) = 180 s in limited discoverable \ + mode. */ +#define BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED \ + (0) /**< Unlimited advertising in general discoverable mode. \ + For high duty cycle advertising, this corresponds to @ref BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX. */ +/**@} */ + +/**@defgroup BLE_GAP_DISC_MODES GAP Discovery modes + * @{ */ +#define BLE_GAP_DISC_MODE_NOT_DISCOVERABLE 0x00 /**< Not discoverable discovery Mode. */ +#define BLE_GAP_DISC_MODE_LIMITED 0x01 /**< Limited Discovery Mode. */ +#define BLE_GAP_DISC_MODE_GENERAL 0x02 /**< General Discovery Mode. */ +/**@} */ + +/**@defgroup BLE_GAP_IO_CAPS GAP IO Capabilities + * @{ */ +#define BLE_GAP_IO_CAPS_DISPLAY_ONLY 0x00 /**< Display Only. */ +#define BLE_GAP_IO_CAPS_DISPLAY_YESNO 0x01 /**< Display and Yes/No entry. */ +#define BLE_GAP_IO_CAPS_KEYBOARD_ONLY 0x02 /**< Keyboard Only. */ +#define BLE_GAP_IO_CAPS_NONE 0x03 /**< No I/O capabilities. */ +#define BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY 0x04 /**< Keyboard and Display. */ +/**@} */ + +/**@defgroup BLE_GAP_AUTH_KEY_TYPES GAP Authentication Key Types + * @{ */ +#define BLE_GAP_AUTH_KEY_TYPE_NONE 0x00 /**< No key (may be used to reject). */ +#define BLE_GAP_AUTH_KEY_TYPE_PASSKEY 0x01 /**< 6-digit Passkey. */ +#define BLE_GAP_AUTH_KEY_TYPE_OOB 0x02 /**< Out Of Band data. */ +/**@} */ + +/**@defgroup BLE_GAP_KP_NOT_TYPES GAP Keypress Notification Types + * @{ */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_START 0x00 /**< Passkey entry started. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_IN 0x01 /**< Passkey digit entered. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_OUT 0x02 /**< Passkey digit erased. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_CLEAR 0x03 /**< Passkey cleared. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_END 0x04 /**< Passkey entry completed. */ +/**@} */ + +/**@defgroup BLE_GAP_SEC_STATUS GAP Security status + * @{ */ +#define BLE_GAP_SEC_STATUS_SUCCESS 0x00 /**< Procedure completed with success. */ +#define BLE_GAP_SEC_STATUS_TIMEOUT 0x01 /**< Procedure timed out. */ +#define BLE_GAP_SEC_STATUS_PDU_INVALID 0x02 /**< Invalid PDU received. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE1_BEGIN 0x03 /**< Reserved for Future Use range #1 begin. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE1_END 0x80 /**< Reserved for Future Use range #1 end. */ +#define BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED 0x81 /**< Passkey entry failed (user canceled or other). */ +#define BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE 0x82 /**< Out of Band Key not available. */ +#define BLE_GAP_SEC_STATUS_AUTH_REQ 0x83 /**< Authentication requirements not met. */ +#define BLE_GAP_SEC_STATUS_CONFIRM_VALUE 0x84 /**< Confirm value failed. */ +#define BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP 0x85 /**< Pairing not supported. */ +#define BLE_GAP_SEC_STATUS_ENC_KEY_SIZE 0x86 /**< Encryption key size. */ +#define BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED 0x87 /**< Unsupported SMP command. */ +#define BLE_GAP_SEC_STATUS_UNSPECIFIED 0x88 /**< Unspecified reason. */ +#define BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS 0x89 /**< Too little time elapsed since last attempt. */ +#define BLE_GAP_SEC_STATUS_INVALID_PARAMS 0x8A /**< Invalid parameters. */ +#define BLE_GAP_SEC_STATUS_DHKEY_FAILURE 0x8B /**< DHKey check failure. */ +#define BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE 0x8C /**< Numeric Comparison failure. */ +#define BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG 0x8D /**< BR/EDR pairing in progress. */ +#define BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED 0x8E /**< BR/EDR Link Key cannot be used for LE keys. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE2_BEGIN 0x8F /**< Reserved for Future Use range #2 begin. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE2_END 0xFF /**< Reserved for Future Use range #2 end. */ +/**@} */ + +/**@defgroup BLE_GAP_SEC_STATUS_SOURCES GAP Security status sources + * @{ */ +#define BLE_GAP_SEC_STATUS_SOURCE_LOCAL 0x00 /**< Local failure. */ +#define BLE_GAP_SEC_STATUS_SOURCE_REMOTE 0x01 /**< Remote failure. */ +/**@} */ + +/**@defgroup BLE_GAP_CP_LIMITS GAP Connection Parameters Limits + * @{ */ +#define BLE_GAP_CP_MIN_CONN_INTVL_NONE 0xFFFF /**< No new minimum connection interval specified in connect parameters. */ +#define BLE_GAP_CP_MIN_CONN_INTVL_MIN \ + 0x0006 /**< Lowest minimum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ +#define BLE_GAP_CP_MIN_CONN_INTVL_MAX \ + 0x0C80 /**< Highest minimum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ + */ +#define BLE_GAP_CP_MAX_CONN_INTVL_NONE 0xFFFF /**< No new maximum connection interval specified in connect parameters. */ +#define BLE_GAP_CP_MAX_CONN_INTVL_MIN \ + 0x0006 /**< Lowest maximum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ +#define BLE_GAP_CP_MAX_CONN_INTVL_MAX \ + 0x0C80 /**< Highest maximum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ + */ +#define BLE_GAP_CP_SLAVE_LATENCY_MAX 0x01F3 /**< Highest slave latency permitted, in connection events. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_NONE 0xFFFF /**< No new supervision timeout specified in connect parameters. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN 0x000A /**< Lowest supervision timeout permitted, in units of 10 ms, i.e. 100 ms. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX 0x0C80 /**< Highest supervision timeout permitted, in units of 10 ms, i.e. 32 s. */ +/**@} */ + +/**@defgroup BLE_GAP_DEVNAME GAP device name defines. + * @{ */ +#define BLE_GAP_DEVNAME_DEFAULT "nRF5x" /**< Default device name value. */ +#define BLE_GAP_DEVNAME_DEFAULT_LEN 31 /**< Default number of octets in device name. */ +#define BLE_GAP_DEVNAME_MAX_LEN 248 /**< Maximum number of octets in device name. */ +/**@} */ + +/**@brief Disable RSSI events for connections */ +#define BLE_GAP_RSSI_THRESHOLD_INVALID 0xFF + +/**@defgroup BLE_GAP_PHYS GAP PHYs + * @{ */ +#define BLE_GAP_PHY_AUTO 0x00 /**< Automatic PHY selection. Refer @ref sd_ble_gap_phy_update for more information.*/ +#define BLE_GAP_PHY_1MBPS 0x01 /**< 1 Mbps PHY. */ +#define BLE_GAP_PHY_2MBPS 0x02 /**< 2 Mbps PHY. */ +#define BLE_GAP_PHY_CODED 0x04 /**< Coded PHY. */ +#define BLE_GAP_PHY_NOT_SET 0xFF /**< PHY is not configured. */ + +/**@brief Supported PHYs in connections, for scanning, and for advertising. */ +#define BLE_GAP_PHYS_SUPPORTED (BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_CODED) /**< All PHYs are supported. */ + +/**@} */ + +/**@defgroup BLE_GAP_CONN_SEC_MODE_SET_MACROS GAP attribute security requirement setters + * + * See @ref ble_gap_conn_sec_mode_t. + * @{ */ +/**@brief Set sec_mode pointed to by ptr to have no access rights.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(ptr) \ + do { \ + (ptr)->sm = 0; \ + (ptr)->lv = 0; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require no protection, open link.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_OPEN(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 1; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require encryption, but no MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 2; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require encryption and MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 3; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require LESC encryption and MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 4; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require signing or encryption, no MITM protection needed.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(ptr) \ + do { \ + (ptr)->sm = 2; \ + (ptr)->lv = 1; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require signing or encryption with MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 2; \ + (ptr)->lv = 2; \ + } while (0) +/**@} */ + +/**@brief GAP Security Random Number Length. */ +#define BLE_GAP_SEC_RAND_LEN 8 + +/**@brief GAP Security Key Length. */ +#define BLE_GAP_SEC_KEY_LEN 16 + +/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key Length. */ +#define BLE_GAP_LESC_P256_PK_LEN 64 + +/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman DHKey Length. */ +#define BLE_GAP_LESC_DHKEY_LEN 32 + +/**@brief GAP Passkey Length. */ +#define BLE_GAP_PASSKEY_LEN 6 + +/**@brief Maximum amount of addresses in the whitelist. */ +#define BLE_GAP_WHITELIST_ADDR_MAX_COUNT (8) + +/**@brief Maximum amount of identities in the device identities list. */ +#define BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT (8) + +/**@brief Default connection count for a configuration. */ +#define BLE_GAP_CONN_COUNT_DEFAULT (1) + +/**@defgroup BLE_GAP_EVENT_LENGTH GAP event length defines. + * @{ */ +#define BLE_GAP_EVENT_LENGTH_MIN (2) /**< Minimum event length, in 1.25 ms units. */ +#define BLE_GAP_EVENT_LENGTH_CODED_PHY_MIN (6) /**< The shortest event length in 1.25 ms units supporting LE Coded PHY. */ +#define BLE_GAP_EVENT_LENGTH_DEFAULT (3) /**< Default event length, in 1.25 ms units. */ +/**@} */ + +/**@defgroup BLE_GAP_ROLE_COUNT GAP concurrent connection count defines. + * @{ */ +#define BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT (1) /**< Default maximum number of connections concurrently acting as peripherals. */ +#define BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT (3) /**< Default maximum number of connections concurrently acting as centrals. */ +#define BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT \ + (1) /**< Default number of SMP instances shared between all connections acting as centrals. */ +#define BLE_GAP_ROLE_COUNT_COMBINED_MAX \ + (20) /**< Maximum supported number of concurrent connections in the peripheral and central roles combined. */ + +/**@} */ + +/**@brief Automatic data length parameter. */ +#define BLE_GAP_DATA_LENGTH_AUTO 0 + +/**@defgroup BLE_GAP_AUTH_PAYLOAD_TIMEOUT Authenticated payload timeout defines. + * @{ */ +#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX (48000) /**< Maximum authenticated payload timeout in 10 ms units, i.e. 8 minutes. */ +#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MIN (1) /**< Minimum authenticated payload timeout in 10 ms units, i.e. 10 ms. */ +/**@} */ + +/**@defgroup GAP_SEC_MODES GAP Security Modes + * @{ */ +#define BLE_GAP_SEC_MODE 0x00 /**< No key (may be used to reject). */ +/**@} */ + +/**@brief The total number of channels in Bluetooth Low Energy. */ +#define BLE_GAP_CHANNEL_COUNT (40) + +/**@defgroup BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS Quality of Service (QoS) Channel survey interval defines + * @{ */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS (0) /**< Continuous channel survey. */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MIN_US (7500) /**< Minimum channel survey interval in microseconds (7.5 ms). */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MAX_US (4000000) /**< Maximum channel survey interval in microseconds (4 s). */ + /**@} */ + +/** @} */ + +/** @defgroup BLE_GAP_CHAR_INCL_CONFIG GAP Characteristic inclusion configurations + * @{ + */ +#define BLE_GAP_CHAR_INCL_CONFIG_INCLUDE (0) /**< Include the characteristic in the Attribute Table */ +#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITH_SPACE \ + (1) /**< Do not include the characteristic in the Attribute table. \ + The SoftDevice will reserve the attribute handles \ + which are otherwise used for this characteristic. \ + By reserving the attribute handles it will be possible \ + to upgrade the SoftDevice without changing handle of the \ + Service Changed characteristic. */ +#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITHOUT_SPACE \ + (2) /**< Do not include the characteristic in the Attribute table. \ + The SoftDevice will not reserve the attribute handles \ + which are otherwise used for this characteristic. */ +/**@} */ + +/** @defgroup BLE_GAP_CHAR_INCL_CONFIG_DEFAULTS Characteristic inclusion default values + * @{ */ +#define BLE_GAP_PPCP_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ +#define BLE_GAP_CAR_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ +/**@} */ + +/** @defgroup BLE_GAP_SLAVE_LATENCY Slave latency configuration options + * @{ */ +#define BLE_GAP_SLAVE_LATENCY_ENABLE \ + (0) /**< Slave latency is enabled. When slave latency is enabled, \ + the slave will wake up every time it has data to send, \ + and/or every slave latency number of connection events. */ +#define BLE_GAP_SLAVE_LATENCY_DISABLE \ + (1) /**< Disable slave latency. The slave will wake up every connection event \ + regardless of the requested slave latency. \ + This option consumes the most power. */ +#define BLE_GAP_SLAVE_LATENCY_WAIT_FOR_ACK \ + (2) /**< The slave will wake up every connection event if it has not received \ + an ACK from the master for at least slave latency events. This \ + configuration may increase the power consumption in environments \ + with a lot of radio activity. */ +/**@} */ + +/**@addtogroup BLE_GAP_STRUCTURES Structures + * @{ */ + +/**@brief Advertising event properties. */ +typedef struct { + uint8_t type; /**< Advertising type. See @ref BLE_GAP_ADV_TYPES. */ + uint8_t anonymous : 1; /**< Omit advertiser's address from all PDUs. + @note Anonymous advertising is only available for + @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED and + @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED. */ + uint8_t include_tx_power : 1; /**< This feature is not supported on this SoftDevice. */ +} ble_gap_adv_properties_t; + +/**@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 Advertising Auxiliary Pointer. */ +typedef struct { + uint16_t aux_offset; /**< Time offset from the beginning of advertising packet to the auxiliary packet in 100 us units. */ + uint8_t aux_phy; /**< Indicates the PHY on which the auxiliary advertising packet is sent. See @ref BLE_GAP_PHYS. */ +} ble_gap_aux_pointer_t; + +/**@brief Bluetooth Low Energy address. */ +typedef struct { + uint8_t + addr_id_peer : 1; /**< Only valid for peer addresses. + This bit is set by the SoftDevice to indicate whether the address has been resolved from + a Resolvable Private Address (when the peer is using privacy). + If set to 1, @ref addr and @ref addr_type refer to the identity address of the resolved address. + + This bit is ignored when a variable of type @ref ble_gap_addr_t is used as input to API functions. + */ + uint8_t addr_type : 7; /**< See @ref BLE_GAP_ADDR_TYPES. */ + uint8_t addr[BLE_GAP_ADDR_LEN]; /**< 48-bit address, LSB format. + @ref addr is not used if @ref addr_type is @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. */ +} ble_gap_addr_t; + +/**@brief GAP connection parameters. + * + * @note When ble_conn_params_t is received in an event, both min_conn_interval and + * max_conn_interval will be equal to the connection interval set by the central. + * + * @note If both conn_sup_timeout and max_conn_interval are specified, then the following constraint applies: + * conn_sup_timeout * 4 > (1 + slave_latency) * max_conn_interval + * that corresponds to the following Bluetooth Spec requirement: + * The Supervision_Timeout in milliseconds shall be larger than + * (1 + Conn_Latency) * Conn_Interval_Max * 2, where Conn_Interval_Max is given in milliseconds. + */ +typedef struct { + uint16_t min_conn_interval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t max_conn_interval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t slave_latency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t conn_sup_timeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ +} ble_gap_conn_params_t; + +/**@brief GAP connection security modes. + * + * Security Mode 0 Level 0: No access permissions at all (this level is not defined by the Bluetooth Core specification).\n + * Security Mode 1 Level 1: No security is needed (aka open link).\n + * Security Mode 1 Level 2: Encrypted link required, MITM protection not necessary.\n + * Security Mode 1 Level 3: MITM protected encrypted link required.\n + * Security Mode 1 Level 4: LESC MITM protected encrypted link using a 128-bit strength encryption key required.\n + * Security Mode 2 Level 1: Signing or encryption required, MITM protection not necessary.\n + * Security Mode 2 Level 2: MITM protected signing required, unless link is MITM protected encrypted.\n + */ +typedef struct { + uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ + uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */ + +} ble_gap_conn_sec_mode_t; + +/**@brief GAP connection security status.*/ +typedef struct { + ble_gap_conn_sec_mode_t sec_mode; /**< Currently active security mode for this connection.*/ + uint8_t + encr_key_size; /**< Length of currently active encryption key, 7 to 16 octets (only applicable for bonding procedures). */ +} ble_gap_conn_sec_t; + +/**@brief Identity Resolving Key. */ +typedef struct { + uint8_t irk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing IRK. */ +} ble_gap_irk_t; + +/**@brief Channel mask (40 bits). + * Every channel is represented with a bit positioned as per channel index defined in Bluetooth Core Specification v5.0, + * Vol 6, Part B, Section 1.4.1. The LSB contained in array element 0 represents channel index 0, and bit 39 represents + * channel index 39. If a bit is set to 1, the channel is not used. + */ +typedef uint8_t ble_gap_ch_mask_t[5]; + +/**@brief GAP advertising parameters. */ +typedef struct { + ble_gap_adv_properties_t properties; /**< The properties of the advertising events. */ + ble_gap_addr_t const *p_peer_addr; /**< Address of a known peer. + @note ble_gap_addr_t::addr_type cannot be + @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. + - When privacy is enabled and the local device uses + @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE addresses, + the device identity list is searched for a matching entry. If + the local IRK for that device identity is set, the local IRK + for that device will be used to generate the advertiser address + field in the advertising packet. + - If @ref ble_gap_adv_properties_t::type is directed, this must be + set to the targeted scanner or initiator. If the peer address is + in the device identity list, the peer IRK for that device will be + used to generate @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE + target addresses used in the advertising event PDUs. */ + uint32_t interval; /**< Advertising interval in 625 us units. @sa BLE_GAP_ADV_INTERVALS. + @note If @ref ble_gap_adv_properties_t::type is set to + @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE + advertising, this parameter is ignored. */ + uint16_t duration; /**< Advertising duration in 10 ms units. When timeout is reached, + an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. + @sa BLE_GAP_ADV_TIMEOUT_VALUES. + @note The SoftDevice will always complete at least one advertising + event even if the duration is set too low. */ + uint8_t max_adv_evts; /**< Maximum advertising events that shall be sent prior to disabling + advertising. Setting the value to 0 disables the limitation. When + the count of advertising events specified by this parameter + (if not 0) is reached, advertising will be automatically stopped + and an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised + @note If @ref ble_gap_adv_properties_t::type is set to + @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE, + this parameter is ignored. */ + ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. + At least one of the primary channels, that is channel index 37-39, must be used. + Masking away secondary advertising channels is not supported. */ + uint8_t filter_policy; /**< Filter Policy. @sa BLE_GAP_ADV_FILTER_POLICIES. */ + uint8_t primary_phy; /**< Indicates the PHY on which the primary advertising channel packets + are transmitted. If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS + will be used. + Valid values are @ref BLE_GAP_PHY_1MBPS and @ref BLE_GAP_PHY_CODED. + @note The primary_phy shall indicate @ref BLE_GAP_PHY_1MBPS if + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t secondary_phy; /**< Indicates the PHY on which the secondary advertising channel packets + are transmitted. + If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS will be used. + Valid values are + @ref BLE_GAP_PHY_1MBPS, @ref BLE_GAP_PHY_2MBPS, and @ref BLE_GAP_PHY_CODED. + If @ref ble_gap_adv_properties_t::type is an extended advertising type + and connectable, this is the PHY that will be used to establish a + connection and send AUX_ADV_IND packets on. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t set_id : 4; /**< The advertising set identifier distinguishes this advertising set from other + advertising sets transmitted by this and other devices. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t scan_req_notification : 1; /**< Enable scan request notifications for this advertising set. When a + scan request is received and the scanner address is allowed + by the filter policy, @ref BLE_GAP_EVT_SCAN_REQ_REPORT is raised. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is a non-scannable + advertising type. */ +} ble_gap_adv_params_t; + +/**@brief GAP advertising data buffers. + * + * The application must provide the buffers for advertisement. The memory shall reside in application RAM, and + * shall never be modified while advertising. The data shall be kept alive until either: + * - @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. + * - @ref BLE_GAP_EVT_CONNECTED is raised with @ref ble_gap_evt_connected_t::adv_handle set to the corresponding + * advertising handle. + * - Advertising is stopped. + * - Advertising data is changed. + * To update advertising data while advertising, provide new buffers to @ref sd_ble_gap_adv_set_configure. */ +typedef struct { + ble_data_t adv_data; /**< Advertising data. + @note + Advertising data can only be specified for a @ref ble_gap_adv_properties_t::type + that is allowed to contain advertising data. */ + ble_data_t scan_rsp_data; /**< Scan response data. + @note + Scan response data can only be specified for a @ref ble_gap_adv_properties_t::type + that is scannable. */ +} ble_gap_adv_data_t; + +/**@brief GAP scanning parameters. */ +typedef struct { + uint8_t extended : 1; /**< If 1, the scanner will accept extended advertising packets. + If set to 0, the scanner will not receive advertising packets + on secondary advertising channels, and will not be able + to receive long advertising PDUs. */ + uint8_t report_incomplete_evts : 1; /**< If 1, events of type @ref ble_gap_evt_adv_report_t may have + @ref ble_gap_adv_report_type_t::status set to + @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. + This parameter is ignored when used with @ref sd_ble_gap_connect + @note This may be used to abort receiving more packets from an extended + advertising event, and is only available for extended + scanning, see @ref sd_ble_gap_scan_start. + @note This feature is not supported by this SoftDevice. */ + uint8_t active : 1; /**< If 1, perform active scanning by sending scan requests. + This parameter is ignored when used with @ref sd_ble_gap_connect. */ + uint8_t filter_policy : 2; /**< Scanning filter policy. @sa BLE_GAP_SCAN_FILTER_POLICIES. + @note Only @ref BLE_GAP_SCAN_FP_ACCEPT_ALL and + @ref BLE_GAP_SCAN_FP_WHITELIST are valid when used with + @ref sd_ble_gap_connect */ + uint8_t scan_phys; /**< Bitfield of PHYs to scan on. If set to @ref BLE_GAP_PHY_AUTO, + scan_phys will default to @ref BLE_GAP_PHY_1MBPS. + - If @ref ble_gap_scan_params_t::extended is set to 0, the only + supported PHY is @ref BLE_GAP_PHY_1MBPS. + - When used with @ref sd_ble_gap_scan_start, + the bitfield indicates the PHYs the scanner will use for scanning + on primary advertising channels. The scanner will accept + @ref BLE_GAP_PHYS_SUPPORTED as secondary advertising channel PHYs. + - When used with @ref sd_ble_gap_connect, the bitfield indicates + the PHYs the initiator will use for scanning on primary advertising + channels. The initiator will accept connections initiated on either + of the @ref BLE_GAP_PHYS_SUPPORTED PHYs. + If scan_phys contains @ref BLE_GAP_PHY_1MBPS and/or @ref BLE_GAP_PHY_2MBPS, + the primary scan PHY is @ref BLE_GAP_PHY_1MBPS. + If scan_phys also contains @ref BLE_GAP_PHY_CODED, the primary scan + PHY will also contain @ref BLE_GAP_PHY_CODED. If the only scan PHY is + @ref BLE_GAP_PHY_CODED, the primary scan PHY is + @ref BLE_GAP_PHY_CODED only. */ + uint16_t interval; /**< Scan interval in 625 us units. @sa BLE_GAP_SCAN_INTERVALS. */ + uint16_t window; /**< Scan window in 625 us units. @sa BLE_GAP_SCAN_WINDOW. + If scan_phys contains both @ref BLE_GAP_PHY_1MBPS and + @ref BLE_GAP_PHY_CODED interval shall be larger than or + equal to twice the scan window. */ + uint16_t timeout; /**< Scan timeout in 10 ms units. @sa BLE_GAP_SCAN_TIMEOUT. */ + ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. + At least one of the primary channels, that is channel index 37-39, must be + set to 0. + Masking away secondary channels is not supported. */ +} ble_gap_scan_params_t; + +/**@brief Privacy. + * + * The privacy feature provides a way for the device to avoid being tracked over a period of time. + * The privacy feature, when enabled, hides the local device identity and replaces it with a private address + * that is automatically refreshed at a specified interval. + * + * If a device still wants to be recognized by other peers, it needs to share it's Identity Resolving Key (IRK). + * With this key, a device can generate a random private address that can only be recognized by peers in possession of that + * key, and devices can establish connections without revealing their real identities. + * + * Both network privacy (@ref BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY) and device privacy (@ref + * BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY) are supported. + * + * @note If the device IRK is updated, the new IRK becomes the one to be distributed in all + * bonding procedures performed after @ref sd_ble_gap_privacy_set returns. + * The IRK distributed during bonding procedure is the device IRK that is active when @ref sd_ble_gap_sec_params_reply is + * called. + */ +typedef struct { + uint8_t privacy_mode; /**< Privacy mode, see @ref BLE_GAP_PRIVACY_MODES. Default is @ref BLE_GAP_PRIVACY_MODE_OFF. */ + uint8_t private_addr_type; /**< The private address type must be either @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE or + @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE. */ + uint16_t private_addr_cycle_s; /**< Private address cycle interval in seconds. Providing an address cycle value of 0 will use + the default value defined by @ref BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S. */ + ble_gap_irk_t + *p_device_irk; /**< When used as input, pointer to IRK structure that will be used as the default IRK. If NULL, the device + default IRK will be used. When used as output, pointer to IRK structure where the current default IRK + will be written to. If NULL, this argument is ignored. By default, the default IRK is used to generate + random private resolvable addresses for the local device unless instructed otherwise. */ +} ble_gap_privacy_params_t; + +/**@brief PHY preferences for TX and RX + * @note tx_phys and rx_phys are bit fields. Multiple bits can be set in them to indicate multiple preferred PHYs for each + * direction. + * @code + * p_gap_phys->tx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; + * p_gap_phys->rx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; + * @endcode + * + */ +typedef struct { + uint8_t tx_phys; /**< Preferred transmit PHYs, see @ref BLE_GAP_PHYS. */ + uint8_t rx_phys; /**< Preferred receive PHYs, see @ref BLE_GAP_PHYS. */ +} ble_gap_phys_t; + +/** @brief Keys that can be exchanged during a bonding procedure. */ +typedef struct { + uint8_t enc : 1; /**< Long Term Key and Master Identification. */ + uint8_t id : 1; /**< Identity Resolving Key and Identity Address Information. */ + uint8_t sign : 1; /**< Connection Signature Resolving Key. */ + uint8_t link : 1; /**< Derive the Link Key from the LTK. */ +} ble_gap_sec_kdist_t; + +/**@brief GAP security parameters. */ +typedef struct { + uint8_t bond : 1; /**< Perform bonding. */ + uint8_t mitm : 1; /**< Enable Man In The Middle protection. */ + uint8_t lesc : 1; /**< Enable LE Secure Connection pairing. */ + uint8_t keypress : 1; /**< Enable generation of keypress notifications. */ + uint8_t io_caps : 3; /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */ + uint8_t oob : 1; /**< The OOB data flag. + - In LE legacy pairing, this flag is set if a device has out of band authentication data. + The OOB method is used if both of the devices have out of band authentication data. + - In LE Secure Connections pairing, this flag is set if a device has the peer device's out of band + authentication data. The OOB method is used if at least one device has the peer device's OOB data + available. */ + uint8_t + min_key_size; /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */ + uint8_t max_key_size; /**< Maximum encryption key size in octets between min_key_size and 16. */ + ble_gap_sec_kdist_t kdist_own; /**< Key distribution bitmap: keys that the local device will distribute. */ + ble_gap_sec_kdist_t kdist_peer; /**< Key distribution bitmap: keys that the remote device will distribute. */ +} ble_gap_sec_params_t; + +/**@brief GAP Encryption Information. */ +typedef struct { + uint8_t ltk[BLE_GAP_SEC_KEY_LEN]; /**< Long Term Key. */ + uint8_t lesc : 1; /**< Key generated using LE Secure Connections. */ + uint8_t auth : 1; /**< Authenticated Key. */ + uint8_t ltk_len : 6; /**< LTK length in octets. */ +} ble_gap_enc_info_t; + +/**@brief GAP Master Identification. */ +typedef struct { + uint16_t ediv; /**< Encrypted Diversifier. */ + uint8_t rand[BLE_GAP_SEC_RAND_LEN]; /**< Random Number. */ +} ble_gap_master_id_t; + +/**@brief GAP Signing Information. */ +typedef struct { + uint8_t csrk[BLE_GAP_SEC_KEY_LEN]; /**< Connection Signature Resolving Key. */ +} ble_gap_sign_info_t; + +/**@brief GAP LE Secure Connections P-256 Public Key. */ +typedef struct { + uint8_t pk[BLE_GAP_LESC_P256_PK_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key. Stored in the + standard SMP protocol format: {X,Y} both in little-endian. */ +} ble_gap_lesc_p256_pk_t; + +/**@brief GAP LE Secure Connections DHKey. */ +typedef struct { + uint8_t key[BLE_GAP_LESC_DHKEY_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman Key. Stored in little-endian. */ +} ble_gap_lesc_dhkey_t; + +/**@brief GAP LE Secure Connections OOB data. */ +typedef struct { + ble_gap_addr_t addr; /**< Bluetooth address of the device. */ + uint8_t r[BLE_GAP_SEC_KEY_LEN]; /**< Random Number. */ + uint8_t c[BLE_GAP_SEC_KEY_LEN]; /**< Confirm Value. */ +} ble_gap_lesc_oob_data_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONNECTED. */ +typedef struct { + ble_gap_addr_t + peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref + ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ + uint8_t role; /**< BLE role for this connection, see @ref BLE_GAP_ROLES */ + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ + uint8_t adv_handle; /**< Advertising handle in which advertising has ended. + This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ + ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated + advertising set. The advertising buffers provided in + @ref sd_ble_gap_adv_set_configure are now released. + This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ +} ble_gap_evt_connected_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DISCONNECTED. */ +typedef struct { + uint8_t reason; /**< HCI error code, see @ref BLE_HCI_STATUS_CODES. */ +} ble_gap_evt_disconnected_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE. */ +typedef struct { + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ +} ble_gap_evt_conn_param_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST. */ +typedef struct { + ble_gap_phys_t peer_preferred_phys; /**< The PHYs the peer prefers to use. */ +} ble_gap_evt_phy_update_request_t; + +/**@brief Event Structure for @ref BLE_GAP_EVT_PHY_UPDATE. */ +typedef struct { + uint8_t status; /**< Status of the procedure, see @ref BLE_HCI_STATUS_CODES.*/ + uint8_t tx_phy; /**< TX PHY for this connection, see @ref BLE_GAP_PHYS. */ + uint8_t rx_phy; /**< RX PHY for this connection, see @ref BLE_GAP_PHYS. */ +} ble_gap_evt_phy_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. */ +typedef struct { + ble_gap_sec_params_t peer_params; /**< Initiator Security Parameters. */ +} ble_gap_evt_sec_params_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_INFO_REQUEST. */ +typedef struct { + ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. */ + ble_gap_master_id_t master_id; /**< Master Identification for LTK lookup. */ + uint8_t enc_info : 1; /**< If 1, Encryption Information required. */ + uint8_t id_info : 1; /**< If 1, Identity Information required. */ + uint8_t sign_info : 1; /**< If 1, Signing Information required. */ +} ble_gap_evt_sec_info_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_PASSKEY_DISPLAY. */ +typedef struct { + uint8_t passkey[BLE_GAP_PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */ + uint8_t match_request : 1; /**< If 1 requires the application to report the match using @ref sd_ble_gap_auth_key_reply + with either @ref BLE_GAP_AUTH_KEY_TYPE_NONE if there is no match or + @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY if there is a match. */ +} ble_gap_evt_passkey_display_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_KEY_PRESSED. */ +typedef struct { + uint8_t kp_not; /**< Keypress notification type, see @ref BLE_GAP_KP_NOT_TYPES. */ +} ble_gap_evt_key_pressed_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_KEY_REQUEST. */ +typedef struct { + uint8_t key_type; /**< See @ref BLE_GAP_AUTH_KEY_TYPES. */ +} ble_gap_evt_auth_key_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST. */ +typedef struct { + ble_gap_lesc_p256_pk_t + *p_pk_peer; /**< LE Secure Connections remote P-256 Public Key. This will point to the application-supplied memory + inside the keyset during the call to @ref sd_ble_gap_sec_params_reply. */ + uint8_t oobd_req : 1; /**< LESC OOB data required. A call to @ref sd_ble_gap_lesc_oob_data_set is required to complete the + procedure. */ +} ble_gap_evt_lesc_dhkey_request_t; + +/**@brief Security levels supported. + * @note See Bluetooth Specification Version 4.2 Volume 3, Part C, Chapter 10, Section 10.2.1. + */ +typedef struct { + uint8_t lv1 : 1; /**< If 1: Level 1 is supported. */ + uint8_t lv2 : 1; /**< If 1: Level 2 is supported. */ + uint8_t lv3 : 1; /**< If 1: Level 3 is supported. */ + uint8_t lv4 : 1; /**< If 1: Level 4 is supported. */ +} ble_gap_sec_levels_t; + +/**@brief Encryption Key. */ +typedef struct { + ble_gap_enc_info_t enc_info; /**< Encryption Information. */ + ble_gap_master_id_t master_id; /**< Master Identification. */ +} ble_gap_enc_key_t; + +/**@brief Identity Key. */ +typedef struct { + ble_gap_irk_t id_info; /**< Identity Resolving Key. */ + ble_gap_addr_t id_addr_info; /**< Identity Address. */ +} ble_gap_id_key_t; + +/**@brief Security Keys. */ +typedef struct { + ble_gap_enc_key_t *p_enc_key; /**< Encryption Key, or NULL. */ + ble_gap_id_key_t *p_id_key; /**< Identity Key, or NULL. */ + ble_gap_sign_info_t *p_sign_key; /**< Signing Key, or NULL. */ + ble_gap_lesc_p256_pk_t *p_pk; /**< LE Secure Connections P-256 Public Key. When in debug mode the application must use the + value defined in the Core Bluetooth Specification v4.2 Vol.3, Part H, Section 2.3.5.6.1 */ +} ble_gap_sec_keys_t; + +/**@brief Security key set for both local and peer keys. */ +typedef struct { + ble_gap_sec_keys_t keys_own; /**< Keys distributed by the local device. For LE Secure Connections the encryption key will be + generated locally and will always be stored if bonding. */ + ble_gap_sec_keys_t + keys_peer; /**< Keys distributed by the remote device. For LE Secure Connections, p_enc_key must always be NULL. */ +} ble_gap_sec_keyset_t; + +/**@brief Data Length Update Procedure parameters. */ +typedef struct { + uint16_t max_tx_octets; /**< Maximum number of payload octets that a Controller supports for transmission of a single Link + Layer Data Channel PDU. */ + uint16_t max_rx_octets; /**< Maximum number of payload octets that a Controller supports for reception of a single Link Layer + Data Channel PDU. */ + uint16_t max_tx_time_us; /**< Maximum time, in microseconds, that a Controller supports for transmission of a single Link + Layer Data Channel PDU. */ + uint16_t max_rx_time_us; /**< Maximum time, in microseconds, that a Controller supports for reception of a single Link Layer + Data Channel PDU. */ +} ble_gap_data_length_params_t; + +/**@brief Data Length Update Procedure local limitation. */ +typedef struct { + uint16_t tx_payload_limited_octets; /**< If > 0, the requested TX packet length is too long by this many octets. */ + uint16_t rx_payload_limited_octets; /**< If > 0, the requested RX packet length is too long by this many octets. */ + uint16_t tx_rx_time_limited_us; /**< If > 0, the requested combination of TX and RX packet lengths is too long by this many + microseconds. */ +} ble_gap_data_length_limitation_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_STATUS. */ +typedef struct { + uint8_t auth_status; /**< Authentication status, see @ref BLE_GAP_SEC_STATUS. */ + uint8_t error_src : 2; /**< On error, source that caused the failure, see @ref BLE_GAP_SEC_STATUS_SOURCES. */ + uint8_t bonded : 1; /**< Procedure resulted in a bond. */ + uint8_t lesc : 1; /**< Procedure resulted in a LE Secure Connection. */ + ble_gap_sec_levels_t sm1_levels; /**< Levels supported in Security Mode 1. */ + ble_gap_sec_levels_t sm2_levels; /**< Levels supported in Security Mode 2. */ + ble_gap_sec_kdist_t kdist_own; /**< Bitmap stating which keys were exchanged (distributed) by the local device. If bonding + with LE Secure Connections, the enc bit will be always set. */ + ble_gap_sec_kdist_t kdist_peer; /**< Bitmap stating which keys were exchanged (distributed) by the remote device. If bonding + with LE Secure Connections, the enc bit will never be set. */ +} ble_gap_evt_auth_status_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_SEC_UPDATE. */ +typedef struct { + ble_gap_conn_sec_t conn_sec; /**< Connection security level. */ +} ble_gap_evt_conn_sec_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Source of timeout event, see @ref BLE_GAP_TIMEOUT_SOURCES. */ + union { + ble_data_t adv_report_buffer; /**< If source is set to @ref BLE_GAP_TIMEOUT_SRC_SCAN, the released + scan buffer is contained in this field. */ + } params; /**< Event Parameters. */ +} ble_gap_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_RSSI_CHANGED. */ +typedef struct { + int8_t rssi; /**< Received Signal Strength Indication in dBm. + @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature + measurement. */ + uint8_t ch_index; /**< Data Channel Index on which the Signal Strength is measured (0-36). */ +} ble_gap_evt_rssi_changed_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_ADV_SET_TERMINATED */ +typedef struct { + uint8_t reason; /**< Reason for why the advertising set terminated. See + @ref BLE_GAP_EVT_ADV_SET_TERMINATED_REASON. */ + uint8_t adv_handle; /**< Advertising handle in which advertising has ended. */ + uint8_t num_completed_adv_events; /**< If @ref ble_gap_adv_params_t::max_adv_evts was not set to 0, + this field indicates the number of completed advertising events. */ + ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated + advertising set. The advertising buffers provided in + @ref sd_ble_gap_adv_set_configure are now released. */ +} ble_gap_evt_adv_set_terminated_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; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_REQUEST. */ +typedef struct { + uint8_t bond : 1; /**< Perform bonding. */ + uint8_t mitm : 1; /**< Man In The Middle protection requested. */ + uint8_t lesc : 1; /**< LE Secure Connections requested. */ + uint8_t keypress : 1; /**< Generation of keypress notifications requested. */ +} ble_gap_evt_sec_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST. */ +typedef struct { + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ +} ble_gap_evt_conn_param_update_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SCAN_REQ_REPORT. */ +typedef struct { + uint8_t adv_handle; /**< Advertising handle for the advertising set which received the Scan Request */ + int8_t rssi; /**< Received Signal Strength Indication in dBm. + @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature + measurement. */ + ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref + ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ +} ble_gap_evt_scan_req_report_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST. */ +typedef struct { + ble_gap_data_length_params_t peer_params; /**< Peer data length parameters. */ +} ble_gap_evt_data_length_update_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE. + * + * @note This event may also be raised after a PHY Update procedure. + */ +typedef struct { + ble_gap_data_length_params_t effective_params; /**< The effective data length parameters. */ +} ble_gap_evt_data_length_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT. */ +typedef struct { + int8_t + channel_energy[BLE_GAP_CHANNEL_COUNT]; /**< The measured energy on the Bluetooth Low Energy + channels, in dBm, indexed by Channel Index. + If no measurement is available for the given channel, channel_energy is set to + @ref BLE_GAP_POWER_LEVEL_INVALID. */ +} ble_gap_evt_qos_channel_survey_report_t; + +/**@brief GAP event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which event occurred. */ + union /**< union alternative identified by evt_id in enclosing struct. */ + { + ble_gap_evt_connected_t connected; /**< Connected Event Parameters. */ + ble_gap_evt_disconnected_t disconnected; /**< Disconnected Event Parameters. */ + ble_gap_evt_conn_param_update_t conn_param_update; /**< Connection Parameter Update Parameters. */ + ble_gap_evt_sec_params_request_t sec_params_request; /**< Security Parameters Request Event Parameters. */ + ble_gap_evt_sec_info_request_t sec_info_request; /**< Security Information Request Event Parameters. */ + ble_gap_evt_passkey_display_t passkey_display; /**< Passkey Display Event Parameters. */ + ble_gap_evt_key_pressed_t key_pressed; /**< Key Pressed Event Parameters. */ + ble_gap_evt_auth_key_request_t auth_key_request; /**< Authentication Key Request Event Parameters. */ + ble_gap_evt_lesc_dhkey_request_t lesc_dhkey_request; /**< LE Secure Connections DHKey calculation request. */ + ble_gap_evt_auth_status_t auth_status; /**< Authentication Status Event Parameters. */ + ble_gap_evt_conn_sec_update_t conn_sec_update; /**< Connection Security Update Event Parameters. */ + ble_gap_evt_timeout_t timeout; /**< Timeout Event Parameters. */ + ble_gap_evt_rssi_changed_t rssi_changed; /**< RSSI Event Parameters. */ + ble_gap_evt_adv_report_t adv_report; /**< Advertising Report Event Parameters. */ + ble_gap_evt_adv_set_terminated_t adv_set_terminated; /**< Advertising Set Terminated Event Parameters. */ + ble_gap_evt_sec_request_t sec_request; /**< Security Request Event Parameters. */ + ble_gap_evt_conn_param_update_request_t conn_param_update_request; /**< Connection Parameter Update Parameters. */ + ble_gap_evt_scan_req_report_t scan_req_report; /**< Scan Request Report Parameters. */ + ble_gap_evt_phy_update_request_t phy_update_request; /**< PHY Update Request Event Parameters. */ + ble_gap_evt_phy_update_t phy_update; /**< PHY Update Parameters. */ + ble_gap_evt_data_length_update_request_t data_length_update_request; /**< Data Length Update Request Event Parameters. */ + ble_gap_evt_data_length_update_t data_length_update; /**< Data Length Update Event Parameters. */ + ble_gap_evt_qos_channel_survey_report_t + qos_channel_survey_report; /**< Quality of Service (QoS) Channel Survey Report Parameters. */ + } params; /**< Event Parameters. */ +} ble_gap_evt_t; + +/** + * @brief BLE GAP connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_CONN_COUNT The connection count for the connection configurations is zero. + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - The sum of conn_count for all connection configurations combined exceeds UINT8_MAX. + * - The event length is smaller than @ref BLE_GAP_EVENT_LENGTH_MIN. + */ +typedef struct { + uint8_t conn_count; /**< The number of concurrent connections the application can create with this configuration. + The default and minimum value is @ref BLE_GAP_CONN_COUNT_DEFAULT. */ + uint16_t event_length; /**< The time set aside for this connection on every connection interval in 1.25 ms units. + The default value is @ref BLE_GAP_EVENT_LENGTH_DEFAULT, the minimum value is @ref + BLE_GAP_EVENT_LENGTH_MIN. The event length and the connection interval are the primary parameters + for setting the throughput of a connection. + See the SoftDevice Specification for details on throughput. */ +} ble_gap_conn_cfg_t; + +/** + * @brief Configuration of maximum concurrent connections in the different connected roles, set with + * @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_CONN_COUNT The sum of periph_role_count and central_role_count is too + * large. The maximum supported sum of concurrent connections is + * @ref BLE_GAP_ROLE_COUNT_COMBINED_MAX. + * @retval ::NRF_ERROR_INVALID_PARAM central_sec_count is larger than central_role_count. + * @retval ::NRF_ERROR_RESOURCES The adv_set_count is too large. The maximum + * supported advertising handles is + * @ref BLE_GAP_ADV_SET_COUNT_MAX. + */ +typedef struct { + uint8_t adv_set_count; /**< Maximum number of advertising sets. Default value is @ref BLE_GAP_ADV_SET_COUNT_DEFAULT. */ + uint8_t periph_role_count; /**< Maximum number of connections concurrently acting as a peripheral. Default value is @ref + BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT. */ + uint8_t central_role_count; /**< Maximum number of connections concurrently acting as a central. Default value is @ref + BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT. */ + uint8_t central_sec_count; /**< Number of SMP instances shared between all connections acting as a central. Default value is + @ref BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT. */ + uint8_t qos_channel_survey_role_available : 1; /**< If set, the Quality of Service (QoS) channel survey module is available to + the application using @ref sd_ble_gap_qos_channel_survey_start. */ +} ble_gap_cfg_role_count_t; + +/** + * @brief Device name and its properties, set with @ref sd_ble_cfg_set. + * + * @note If the device name is not configured, the default device name will be + * @ref BLE_GAP_DEVNAME_DEFAULT, the maximum device name length will be + * @ref BLE_GAP_DEVNAME_DEFAULT_LEN, vloc will be set to @ref BLE_GATTS_VLOC_STACK and the device name + * will have no write access. + * + * @note If @ref max_len is more than @ref BLE_GAP_DEVNAME_DEFAULT_LEN and vloc is set to @ref BLE_GATTS_VLOC_STACK, + * the attribute table size must be increased to have room for the longer device name (see + * @ref sd_ble_cfg_set and @ref ble_gatts_cfg_attr_tab_size_t). + * + * @note If vloc is @ref BLE_GATTS_VLOC_STACK : + * - p_value must point to non-volatile memory (flash) or be NULL. + * - If p_value is NULL, the device name will initially be empty. + * + * @note If vloc is @ref BLE_GATTS_VLOC_USER : + * - p_value cannot be NULL. + * - If the device name is writable, p_value must point to volatile memory (RAM). + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - Invalid device name location (vloc). + * - Invalid device name security mode. + * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: + * - The device name length is invalid (must be between 0 and @ref BLE_GAP_DEVNAME_MAX_LEN). + * - The device name length is too long for the given Attribute Table. + * @retval ::NRF_ERROR_NOT_SUPPORTED Device name security mode is not supported. + */ +typedef struct { + ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ + uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ + uint8_t *p_value; /**< Pointer to where the value (device name) is stored or will be stored. */ + uint16_t current_len; /**< Current length in bytes of the memory pointed to by p_value.*/ + uint16_t max_len; /**< Maximum length in bytes of the memory pointed to by p_value.*/ +} ble_gap_cfg_device_name_t; + +/**@brief Peripheral Preferred Connection Parameters include configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t include_cfg; /**< Inclusion configuration of the Peripheral Preferred Connection Parameters characteristic. + See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_PPCP_INCL_CONFIG_DEFAULT. */ +} ble_gap_cfg_ppcp_incl_cfg_t; + +/**@brief Central Address Resolution include configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t include_cfg; /**< Inclusion configuration of the Central Address Resolution characteristic. + See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_CAR_INCL_CONFIG_DEFAULT. */ +} ble_gap_cfg_car_incl_cfg_t; + +/**@brief Configuration structure for GAP configurations. */ +typedef union { + ble_gap_cfg_role_count_t role_count_cfg; /**< Role count configuration, cfg_id is @ref BLE_GAP_CFG_ROLE_COUNT. */ + ble_gap_cfg_device_name_t device_name_cfg; /**< Device name configuration, cfg_id is @ref BLE_GAP_CFG_DEVICE_NAME. */ + ble_gap_cfg_ppcp_incl_cfg_t ppcp_include_cfg; /**< Peripheral Preferred Connection Parameters characteristic include + configuration, cfg_id is @ref BLE_GAP_CFG_PPCP_INCL_CONFIG. */ + ble_gap_cfg_car_incl_cfg_t car_include_cfg; /**< Central Address Resolution characteristic include configuration, + cfg_id is @ref BLE_GAP_CFG_CAR_INCL_CONFIG. */ +} ble_gap_cfg_t; + +/**@brief Channel Map option. + * + * @details Used with @ref sd_ble_opt_get to get the current channel map + * or @ref sd_ble_opt_set to set a new channel map. When setting the + * channel map, it applies to all current and future connections. When getting the + * current channel map, it applies to a single connection and the connection handle + * must be supplied. + * + * @note Setting the channel map may take some time, depending on connection parameters. + * The time taken may be different for each connection and the get operation will + * return the previous channel map until the new one has taken effect. + * + * @note After setting the channel map, by spec it can not be set again until at least 1 s has passed. + * See Bluetooth Specification Version 4.1 Volume 2, Part E, Section 7.3.46. + * + * @retval ::NRF_SUCCESS Get or set successful. + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - Less then two bits in @ref ch_map are set. + * - Bits for primary advertising channels (37-39) are set. + * @retval ::NRF_ERROR_BUSY Channel map was set again before enough time had passed. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied for get. + * + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle (only applicable for get) */ + uint8_t ch_map[5]; /**< Channel Map (37-bit). */ +} ble_gap_opt_ch_map_t; + +/**@brief Local connection latency option. + * + * @details Local connection latency is a feature which enables the slave to improve + * current consumption by ignoring the slave latency set by the peer. The + * local connection latency can only be set to a multiple of the slave latency, + * and cannot be longer than half of the supervision timeout. + * + * @details Used with @ref sd_ble_opt_set to set the local connection latency. The + * @ref sd_ble_opt_get is not supported for this option, but the actual + * local connection latency (unless set to NULL) is set as a return parameter + * when setting the option. + * + * @note The latency set will be truncated down to the closest slave latency event + * multiple, or the nearest multiple before half of the supervision timeout. + * + * @note The local connection latency is disabled by default, and needs to be enabled for new + * connections and whenever the connection is updated. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint16_t requested_latency; /**< Requested local connection latency. */ + uint16_t *p_actual_latency; /**< Pointer to storage for the actual local connection latency (can be set to NULL to skip return + value). */ +} ble_gap_opt_local_conn_latency_t; + +/**@brief Disable slave latency + * + * @details Used with @ref sd_ble_opt_set to temporarily disable slave latency of a peripheral connection + * (see @ref ble_gap_conn_params_t::slave_latency). And to re-enable it again. When disabled, the + * peripheral will ignore the slave_latency set by the central. + * + * @note Shall only be called on peripheral links. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint8_t disable; /**< For allowed values see @ref BLE_GAP_SLAVE_LATENCY */ +} ble_gap_opt_slave_latency_disable_t; + +/**@brief Passkey Option. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} + * @endmscs + * + * @details Structure containing the passkey to be used during pairing. This can be used with @ref + * sd_ble_opt_set to make the SoftDevice use a preprogrammed passkey for authentication + * instead of generating a random one. + * + * @note Repeated pairing attempts using the same preprogrammed passkey makes pairing vulnerable to MITM attacks. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * + */ +typedef struct { + uint8_t const *p_passkey; /**< Pointer to 6-digit ASCII string (digit 0..9 only, no NULL termination) passkey to be used + during pairing. If this is NULL, the SoftDevice will generate a random passkey if required.*/ +} ble_gap_opt_passkey_t; + +/**@brief Compatibility mode 1 option. + * + * @details This can be used with @ref sd_ble_opt_set to enable and disable + * compatibility mode 1. Compatibility mode 1 is disabled by default. + * + * @note Compatibility mode 1 enables interoperability with devices that do not support a value of + * 0 for the WinOffset parameter in the Link Layer CONNECT_IND packet. This applies to a + * limited set of legacy peripheral devices from another vendor. Enabling this compatibility + * mode will only have an effect if the local device will act as a central device and + * initiate a connection to a peripheral device. In that case it may lead to the connection + * creation taking up to one connection interval longer to complete for all connections. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_INVALID_STATE When connection creation is ongoing while mode 1 is set. + */ +typedef struct { + uint8_t enable : 1; /**< Enable compatibility mode 1.*/ +} ble_gap_opt_compat_mode_1_t; + +/**@brief Authenticated payload timeout option. + * + * @details This can be used with @ref sd_ble_opt_set to change the Authenticated payload timeout to a value other + * than the default of @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX. + * + * @note The authenticated payload timeout event ::BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD will be generated + * if auth_payload_timeout time has elapsed without receiving a packet with a valid MIC on an encrypted + * link. + * + * @note The LE ping procedure will be initiated before the timer expires to give the peer a chance + * to reset the timer. In addition the stack will try to prioritize running of LE ping over other + * activities to increase chances of finishing LE ping before timer expires. To avoid side-effects + * on other activities, it is recommended to use high timeout values. + * Recommended timeout > 2*(connInterval * (6 + connSlaveLatency)). + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. auth_payload_timeout was outside of allowed range. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint16_t auth_payload_timeout; /**< Requested timeout in 10 ms unit, see @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT. */ +} ble_gap_opt_auth_payload_timeout_t; + +/**@brief Option structure for GAP options. */ +typedef union { + ble_gap_opt_ch_map_t ch_map; /**< Parameters for the Channel Map option. */ + ble_gap_opt_local_conn_latency_t local_conn_latency; /**< Parameters for the Local connection latency option */ + ble_gap_opt_passkey_t passkey; /**< Parameters for the Passkey option.*/ + ble_gap_opt_compat_mode_1_t compat_mode_1; /**< Parameters for the compatibility mode 1 option.*/ + ble_gap_opt_auth_payload_timeout_t auth_payload_timeout; /**< Parameters for the authenticated payload timeout option.*/ + ble_gap_opt_slave_latency_disable_t slave_latency_disable; /**< Parameters for the Disable slave latency option */ +} ble_gap_opt_t; + +/**@brief Connection event triggering parameters. */ +typedef struct { + uint8_t ppi_ch_id; /**< PPI channel to use. This channel should be regarded as reserved until + connection event PPI task triggering is stopped. + The PPI channel ID can not be one of the PPI channels reserved by + the SoftDevice. See @ref NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK. */ + uint32_t task_endpoint; /**< Task Endpoint to trigger. */ + uint16_t conn_evt_counter_start; /**< The connection event on which the task triggering should start. */ + uint16_t period_in_events; /**< Trigger period. Valid range is [1, 32767]. + If the device is in slave role and slave latency is enabled, + this parameter should be set to a multiple of (slave latency + 1) + to ensure low power operation. */ +} ble_gap_conn_event_trigger_t; +/**@} */ + +/**@addtogroup BLE_GAP_FUNCTIONS Functions + * @{ */ + +/**@brief Set the local Bluetooth identity address. + * + * The local Bluetooth identity address is the address that identifies this device to other peers. + * The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. + * + * @note The identity address cannot be changed while advertising, scanning or creating a connection. + * + * @note This address will be distributed to the peer during bonding. + * If the address changes, the address stored in the peer device will not be valid and the ability to + * reconnect using the old address will be lost. + * + * @note By default the SoftDevice will set an address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC upon being + * enabled. The address is a random number populated during the IC manufacturing process and remains unchanged + * for the lifetime of each IC. + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @endmscs + * + * @param[in] p_addr Pointer to address structure. + * + * @retval ::NRF_SUCCESS Address successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_STATE The identity address cannot be changed while advertising, + * scanning or creating a connection. + */ +SVCALL(SD_BLE_GAP_ADDR_SET, uint32_t, sd_ble_gap_addr_set(ble_gap_addr_t const *p_addr)); + +/**@brief Get local Bluetooth identity address. + * + * @note This will always return the identity address irrespective of the privacy settings, + * i.e. the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. + * + * @param[out] p_addr Pointer to address structure to be filled in. + * + * @retval ::NRF_SUCCESS Address successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + */ +SVCALL(SD_BLE_GAP_ADDR_GET, uint32_t, sd_ble_gap_addr_get(ble_gap_addr_t *p_addr)); + +/**@brief Get the Bluetooth device address used by the advertiser. + * + * @note This function will return the local Bluetooth address used in advertising PDUs. When + * using privacy, the SoftDevice will generate a new private address every + * @ref ble_gap_privacy_params_t::private_addr_cycle_s configured using + * @ref sd_ble_gap_privacy_set. Hence depending on when the application calls this API, the + * address returned may not be the latest address that is used in the advertising PDUs. + * + * @param[in] adv_handle The advertising handle to get the address from. + * @param[out] p_addr Pointer to address structure to be filled in. + * + * @retval ::NRF_SUCCESS Address successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. + * @retval ::NRF_ERROR_INVALID_STATE The advertising set is currently not advertising. + */ +SVCALL(SD_BLE_GAP_ADV_ADDR_GET, uint32_t, sd_ble_gap_adv_addr_get(uint8_t adv_handle, ble_gap_addr_t *p_addr)); + +/**@brief Set the active whitelist in the SoftDevice. + * + * @note Only one whitelist can be used at a time and the whitelist is shared between the BLE roles. + * The whitelist cannot be set if a BLE role is using the whitelist. + * + * @note If an address is resolved using the information in the device identity list, then the whitelist + * filter policy applies to the peer identity address and not the resolvable address sent on air. + * + * @mscs + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} + * @endmscs + * + * @param[in] pp_wl_addrs Pointer to a whitelist of peer addresses, if NULL the whitelist will be cleared. + * @param[in] len Length of the whitelist, maximum @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT. + * + * @retval ::NRF_SUCCESS The whitelist is successfully set/cleared. + * @retval ::NRF_ERROR_INVALID_ADDR The whitelist (or one of its entries) provided is invalid. + * @retval ::BLE_ERROR_GAP_WHITELIST_IN_USE The whitelist is in use by a BLE role and cannot be set or cleared. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_DATA_SIZE The given whitelist size is invalid (zero or too large); this can only return when + * pp_wl_addrs is not NULL. + */ +SVCALL(SD_BLE_GAP_WHITELIST_SET, uint32_t, sd_ble_gap_whitelist_set(ble_gap_addr_t const *const *pp_wl_addrs, uint8_t len)); + +/**@brief Set device identity list. + * + * @note Only one device identity list can be used at a time and the list is shared between the BLE roles. + * The device identity list cannot be set if a BLE role is using the list. + * + * @param[in] pp_id_keys Pointer to an array of peer identity addresses and peer IRKs, if NULL the device identity list will + * be cleared. + * @param[in] pp_local_irks Pointer to an array of local IRKs. Each entry in the array maps to the entry in pp_id_keys at the + * same index. To fill in the list with the currently set device IRK for all peers, set to NULL. + * @param[in] len Length of the device identity list, maximum @ref BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT. + * + * @mscs + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS The device identity list successfully set/cleared. + * @retval ::NRF_ERROR_INVALID_ADDR The device identity list (or one of its entries) provided is invalid. + * This code may be returned if the local IRK list also has an invalid entry. + * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE The device identity list is in use and cannot be set or cleared. + * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE The device identity list contains multiple entries with the same identity + * address. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_DATA_SIZE The given device identity list size invalid (zero or too large); this can + * only return when pp_id_keys is not NULL. + */ +SVCALL(SD_BLE_GAP_DEVICE_IDENTITIES_SET, uint32_t, + sd_ble_gap_device_identities_set(ble_gap_id_key_t const *const *pp_id_keys, ble_gap_irk_t const *const *pp_local_irks, + uint8_t len)); + +/**@brief Set privacy settings. + * + * @note Privacy settings cannot be changed while advertising, scanning or creating a connection. + * + * @param[in] p_privacy_params Privacy settings. + * + * @mscs + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_INVALID_ADDR The pointer to privacy settings is NULL or invalid. + * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. + * @retval ::NRF_ERROR_INVALID_PARAM Out of range parameters are provided. + * @retval ::NRF_ERROR_NOT_SUPPORTED The SoftDevice does not support privacy if the Central Address Resolution + characteristic is not configured to be included and the SoftDevice is configured + to support central roles. + See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + * @retval ::NRF_ERROR_INVALID_STATE Privacy settings cannot be changed while advertising, scanning + * or creating a connection. + */ +SVCALL(SD_BLE_GAP_PRIVACY_SET, uint32_t, sd_ble_gap_privacy_set(ble_gap_privacy_params_t const *p_privacy_params)); + +/**@brief Get privacy settings. + * + * @note ::ble_gap_privacy_params_t::p_device_irk must be initialized to NULL or a valid address before this function is called. + * If it is initialized to a valid address, the address pointed to will contain the current device IRK on return. + * + * @param[in,out] p_privacy_params Privacy settings. + * + * @retval ::NRF_SUCCESS Privacy settings read. + * @retval ::NRF_ERROR_INVALID_ADDR The pointer given for returning the privacy settings may be NULL or invalid. + * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. + */ +SVCALL(SD_BLE_GAP_PRIVACY_GET, uint32_t, sd_ble_gap_privacy_get(ble_gap_privacy_params_t *p_privacy_params)); + +/**@brief Configure an advertising set. Set, clear or update advertising and scan response data. + * + * @note The format of the advertising data will be checked by this call to ensure interoperability. + * Limitations imposed by this API call to the data provided include having a flags data type in the scan response data and + * duplicating the local name in the advertising data and scan response data. + * + * @note In order to update advertising data while advertising, new advertising buffers must be provided. + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in,out] p_adv_handle Provide a pointer to a handle containing @ref + * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising set. On success, a new handle is then returned through the + * pointer. Provide a pointer to an existing advertising handle to configure an existing advertising set. + * @param[in] p_adv_data Advertising data. If set to NULL, no advertising data will be used. See + * @ref ble_gap_adv_data_t. + * @param[in] p_adv_params Advertising parameters. When this function is used to update advertising + * data while advertising, this parameter must be NULL. See @ref ble_gap_adv_params_t. + * + * @retval ::NRF_SUCCESS Advertising set successfully configured. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: + * - Invalid advertising data configuration specified. See @ref + * ble_gap_adv_data_t. + * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. + * - Use of whitelist requested but whitelist has not been set, + * see @ref sd_ble_gap_whitelist_set. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR ble_gap_adv_params_t::p_peer_addr is invalid. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - It is invalid to provide non-NULL advertising set parameters while + * advertising. + * - It is invalid to provide the same data buffers while advertising. To + * update advertising data, provide new advertising buffers. + * @retval ::BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST Discoverable mode and whitelist incompatible. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. Use @ref + * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_FLAGS Invalid combination of advertising flags supplied. + * @retval ::NRF_ERROR_INVALID_DATA Invalid data type(s) supplied. Check the advertising data format + * specification given in Bluetooth Specification Version 5.0, Volume 3, Part C, Chapter 11. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid data length(s) supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported data length or advertising parameter configuration. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to configure a new advertising handle. Update an + * existing advertising handle instead. + * @retval ::BLE_ERROR_GAP_UUID_LIST_MISMATCH Invalid UUID list supplied. + */ +SVCALL(SD_BLE_GAP_ADV_SET_CONFIGURE, uint32_t, + sd_ble_gap_adv_set_configure(uint8_t *p_adv_handle, ble_gap_adv_data_t const *p_adv_data, + ble_gap_adv_params_t const *p_adv_params)); + +/**@brief Start advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). + * + * @note Only one advertiser may be active at any time. + * + * @note If privacy is enabled, the advertiser's private address will be refreshed when this function is called. + * See @ref sd_ble_gap_privacy_set(). + * + * @events + * @event{@ref BLE_GAP_EVT_CONNECTED, Generated after connection has been established through connectable advertising.} + * @event{@ref BLE_GAP_EVT_ADV_SET_TERMINATED, Advertising set has terminated.} + * @event{@ref BLE_GAP_EVT_SCAN_REQ_REPORT, A scan request was received.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] adv_handle Advertising handle to advertise on, received from @ref sd_ble_gap_adv_set_configure. + * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or + * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. For non-connectable + * advertising, this is ignored. + * + * @retval ::NRF_SUCCESS The BLE stack has started advertising. + * @retval ::NRF_ERROR_INVALID_STATE adv_handle is not configured or already advertising. + * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration + * tag has been reached; connectable advertiser cannot be started. + * To increase the number of available connections, + * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. Configure a new adveriting handle with @ref + sd_ble_gap_adv_set_configure. + * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: + * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. + * - Use of whitelist requested but whitelist has not been set, see @ref + sd_ble_gap_whitelist_set. + * @retval ::NRF_ERROR_RESOURCES Either: + * - adv_handle is configured with connectable advertising, but the event_length parameter + * associated with conn_cfg_tag is too small to be able to establish a connection on + * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. + * - Not enough BLE role slots available. + Stop one or more currently active roles (Central, Peripheral, Broadcaster or Observer) + and try again. + * - p_adv_params is configured with connectable advertising, but the event_length + parameter + * associated with conn_cfg_tag is too small to be able to establish a connection on + * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. + */ +SVCALL(SD_BLE_GAP_ADV_START, uint32_t, sd_ble_gap_adv_start(uint8_t adv_handle, uint8_t conn_cfg_tag)); + +/**@brief Stop advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] adv_handle The advertising handle that should stop advertising. + * + * @retval ::NRF_SUCCESS The BLE stack has stopped advertising. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Invalid advertising handle. + * @retval ::NRF_ERROR_INVALID_STATE The advertising handle is not advertising. + */ +SVCALL(SD_BLE_GAP_ADV_STOP, uint32_t, sd_ble_gap_adv_stop(uint8_t adv_handle)); + +/**@brief Update connection parameters. + * + * @details In the central role this will initiate a Link Layer connection parameter update procedure, + * otherwise in the peripheral role, this will send the corresponding L2CAP request and wait for + * the central to perform the procedure. In both cases, and regardless of success or failure, the application + * will be informed of the result with a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE event. + * + * @details This function can be used as a central both to reply to a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST or to start the + * procedure unrequested. + * + * @events + * @event{@ref BLE_GAP_EVT_CONN_PARAM_UPDATE, Result of the connection parameter update procedure.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CPU_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CPU_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CPU_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_conn_params Pointer to desired connection parameters. If NULL is provided on a peripheral role, + * the parameters in the PPCP characteristic of the GAP service will be used instead. + * If NULL is provided on a central role and in response to a @ref + * BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST, the peripheral request will be rejected + * + * @retval ::NRF_SUCCESS The Connection Update procedure has been started successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. + * @retval ::NRF_ERROR_BUSY Procedure already in progress, wait for pending procedures to complete and retry. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GAP_CONN_PARAM_UPDATE, uint32_t, + sd_ble_gap_conn_param_update(uint16_t conn_handle, ble_gap_conn_params_t const *p_conn_params)); + +/**@brief Disconnect (GAP Link Termination). + * + * @details This call initiates the disconnection procedure, and its completion will be communicated to the application + * with a @ref BLE_GAP_EVT_DISCONNECTED event. + * + * @events + * @event{@ref BLE_GAP_EVT_DISCONNECTED, Generated when disconnection procedure is complete.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CONN_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] hci_status_code HCI status code, see @ref BLE_HCI_STATUS_CODES (accepted values are @ref + * BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION and @ref BLE_HCI_CONN_INTERVAL_UNACCEPTABLE). + * + * @retval ::NRF_SUCCESS The disconnection procedure has been started successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. + */ +SVCALL(SD_BLE_GAP_DISCONNECT, uint32_t, sd_ble_gap_disconnect(uint16_t conn_handle, uint8_t hci_status_code)); + +/**@brief Set the radio's transmit power. + * + * @param[in] role The role to set the transmit power for, see @ref BLE_GAP_TX_POWER_ROLES for + * possible roles. + * @param[in] handle The handle parameter is interpreted depending on role: + * - If role is @ref BLE_GAP_TX_POWER_ROLE_CONN, this value is the specific connection handle. + * - If role is @ref BLE_GAP_TX_POWER_ROLE_ADV, the advertising set identified with the advertising handle, + * will use the specified transmit power, and include it in the advertising packet headers if + * @ref ble_gap_adv_properties_t::include_tx_power set. + * - For all other roles handle is ignored. + * @param[in] tx_power Radio transmit power in dBm (see note for accepted values). + * + * @note Supported tx_power values: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm and +4dBm. + * In addition, on some chips following values are supported: +2dBm, +5dBm, +6dBm, +7dBm and +8dBm. + * Setting these values on a chip that does not support them will result in undefined behaviour. + * @note The initiator will have the same transmit power as the scanner. + * @note When a connection is created it will inherit the transmit power from the initiator or + * advertiser leading to the connection. + * + * @retval ::NRF_SUCCESS Successfully changed the transmit power. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_TX_POWER_SET, uint32_t, sd_ble_gap_tx_power_set(uint8_t role, uint16_t handle, int8_t tx_power)); + +/**@brief Set GAP Appearance value. + * + * @param[in] appearance Appearance (16-bit), see @ref BLE_APPEARANCES. + * + * @retval ::NRF_SUCCESS Appearance value set successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + */ +SVCALL(SD_BLE_GAP_APPEARANCE_SET, uint32_t, sd_ble_gap_appearance_set(uint16_t appearance)); + +/**@brief Get GAP Appearance value. + * + * @param[out] p_appearance Pointer to appearance (16-bit) to be filled in, see @ref BLE_APPEARANCES. + * + * @retval ::NRF_SUCCESS Appearance value retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GAP_APPEARANCE_GET, uint32_t, sd_ble_gap_appearance_get(uint16_t *p_appearance)); + +/**@brief Set GAP Peripheral Preferred Connection Parameters. + * + * @param[in] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure with the desired parameters. + * + * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, + see @ref ble_gap_cfg_ppcp_incl_cfg_t. + */ +SVCALL(SD_BLE_GAP_PPCP_SET, uint32_t, sd_ble_gap_ppcp_set(ble_gap_conn_params_t const *p_conn_params)); + +/**@brief Get GAP Peripheral Preferred Connection Parameters. + * + * @param[out] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure where the parameters will be stored. + * + * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, + see @ref ble_gap_cfg_ppcp_incl_cfg_t. + */ +SVCALL(SD_BLE_GAP_PPCP_GET, uint32_t, sd_ble_gap_ppcp_get(ble_gap_conn_params_t *p_conn_params)); + +/**@brief Set GAP device name. + * + * @note If the device name is located in application flash memory (see @ref ble_gap_cfg_device_name_t), + * it cannot be changed. Then @ref NRF_ERROR_FORBIDDEN will be returned. + * + * @param[in] p_write_perm Write permissions for the Device Name characteristic, see @ref ble_gap_conn_sec_mode_t. + * @param[in] p_dev_name Pointer to a UTF-8 encoded, non NULL-terminated string. + * @param[in] len Length of the UTF-8, non NULL-terminated string pointed to by p_dev_name in octets (must be smaller or + * equal than @ref BLE_GAP_DEVNAME_MAX_LEN). + * + * @retval ::NRF_SUCCESS GAP device name and permissions set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_FORBIDDEN Device name is not writable. + */ +SVCALL(SD_BLE_GAP_DEVICE_NAME_SET, uint32_t, + sd_ble_gap_device_name_set(ble_gap_conn_sec_mode_t const *p_write_perm, uint8_t const *p_dev_name, uint16_t len)); + +/**@brief Get GAP device name. + * + * @note If the device name is longer than the size of the supplied buffer, + * p_len will return the complete device name length, + * and not the number of bytes actually returned in p_dev_name. + * The application may use this information to allocate a suitable buffer size. + * + * @param[out] p_dev_name Pointer to an empty buffer where the UTF-8 non NULL-terminated string will be placed. Set to + * NULL to obtain the complete device name length. + * @param[in,out] p_len Length of the buffer pointed by p_dev_name, complete device name length on output. + * + * @retval ::NRF_SUCCESS GAP device name retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + */ +SVCALL(SD_BLE_GAP_DEVICE_NAME_GET, uint32_t, sd_ble_gap_device_name_get(uint8_t *p_dev_name, uint16_t *p_len)); + +/**@brief Initiate the GAP Authentication procedure. + * + * @details In the central role, this function will send an SMP Pairing Request (or an SMP Pairing Failed if rejected), + * otherwise in the peripheral role, an SMP Security Request will be sent. + * + * @events + * @event{Depending on the security parameters set and the packet exchanges with the peer\, the following events may be + * generated:} + * @event{@ref BLE_GAP_EVT_SEC_PARAMS_REQUEST} + * @event{@ref BLE_GAP_EVT_SEC_INFO_REQUEST} + * @event{@ref BLE_GAP_EVT_PASSKEY_DISPLAY} + * @event{@ref BLE_GAP_EVT_KEY_PRESSED} + * @event{@ref BLE_GAP_EVT_AUTH_KEY_REQUEST} + * @event{@ref BLE_GAP_EVT_LESC_DHKEY_REQUEST} + * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE} + * @event{@ref BLE_GAP_EVT_AUTH_STATUS} + * @event{@ref BLE_GAP_EVT_TIMEOUT} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_SEC_REQ_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_sec_params Pointer to the @ref ble_gap_sec_params_t structure with the security parameters to be used during the + * pairing or bonding procedure. In the peripheral role, only the bond, mitm, lesc and keypress fields of this structure are used. + * In the central role, this pointer may be NULL to reject a Security Request. + * + * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - No link has been established. + * - An encryption is already executing or queued. + * @retval ::NRF_ERROR_NO_MEM The maximum number of authentication procedures that can run in parallel for the given role is + * reached. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. + * Distribution of own Identity Information is only supported if the Central + * Address Resolution characteristic is configured to be included or + * the Softdevice is configured to support peripheral roles only. + * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + * @retval ::NRF_ERROR_TIMEOUT A SMP timeout has occurred, and further SMP operations on this link is prohibited. + */ +SVCALL(SD_BLE_GAP_AUTHENTICATE, uint32_t, + sd_ble_gap_authenticate(uint16_t conn_handle, ble_gap_sec_params_t const *p_sec_params)); + +/**@brief Reply with GAP security parameters. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST, calling it at other times will result in + * an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_CONFIRM_FAIL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_KS_TOO_SMALL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_APP_ERROR_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_REMOTE_PAIRING_FAIL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_TIMEOUT_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] sec_status Security status, see @ref BLE_GAP_SEC_STATUS. + * @param[in] p_sec_params Pointer to a @ref ble_gap_sec_params_t security parameters structure. In the central role this must be + * set to NULL, as the parameters have already been provided during a previous call to @ref sd_ble_gap_authenticate. + * @param[in,out] p_sec_keyset Pointer to a @ref ble_gap_sec_keyset_t security keyset structure. Any keys generated and/or + * distributed as a result of the ongoing security procedure will be stored into the memory referenced by the pointers inside this + * structure. The keys will be stored and available to the application upon reception of a @ref BLE_GAP_EVT_AUTH_STATUS event. + * Note that the SoftDevice expects the application to provide memory for storing the + * peer's keys. So it must be ensured that the relevant pointers inside this structure are not NULL. The + * pointers to the local key can, however, be NULL, in which case, the local key data will not be available to the application + * upon reception of the + * @ref BLE_GAP_EVT_AUTH_STATUS event. + * + * @retval ::NRF_SUCCESS Successfully accepted security parameter from the application. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Security parameters has not been requested. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. + * Distribution of own Identity Information is only supported if the Central + * Address Resolution characteristic is configured to be included or + * the Softdevice is configured to support peripheral roles only. + * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + */ +SVCALL(SD_BLE_GAP_SEC_PARAMS_REPLY, uint32_t, + sd_ble_gap_sec_params_reply(uint16_t conn_handle, uint8_t sec_status, ble_gap_sec_params_t const *p_sec_params, + ble_gap_sec_keyset_t const *p_sec_keyset)); + +/**@brief Reply with an authentication key. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_AUTH_KEY_REQUEST or a @ref BLE_GAP_EVT_PASSKEY_DISPLAY, + * calling it at other times will result in an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] key_type See @ref BLE_GAP_AUTH_KEY_TYPES. + * @param[in] p_key If key type is @ref BLE_GAP_AUTH_KEY_TYPE_NONE, then NULL. + * If key type is @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY, then a 6-byte ASCII string (digit 0..9 only, no NULL + * termination) or NULL when confirming LE Secure Connections Numeric Comparison. If key type is @ref BLE_GAP_AUTH_KEY_TYPE_OOB, + * then a 16-byte OOB key value in little-endian format. + * + * @retval ::NRF_SUCCESS Authentication key successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Authentication key has not been requested. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_AUTH_KEY_REPLY, uint32_t, + sd_ble_gap_auth_key_reply(uint16_t conn_handle, uint8_t key_type, uint8_t const *p_key)); + +/**@brief Reply with an LE Secure connections DHKey. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST, calling it at other times will result in + * an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_dhkey LE Secure Connections DHKey. + * + * @retval ::NRF_SUCCESS DHKey successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - The peer is not authenticated. + * - The application has not pulled a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_DHKEY_REPLY, uint32_t, + sd_ble_gap_lesc_dhkey_reply(uint16_t conn_handle, ble_gap_lesc_dhkey_t const *p_dhkey)); + +/**@brief Notify the peer of a local keypress. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] kp_not See @ref BLE_GAP_KP_NOT_TYPES. + * + * @retval ::NRF_SUCCESS Keypress notification successfully queued for transmission. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Authentication key not requested. + * - Passkey has not been entered. + * - Keypresses have not been enabled by both peers. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy. Retry at later time. + */ +SVCALL(SD_BLE_GAP_KEYPRESS_NOTIFY, uint32_t, sd_ble_gap_keypress_notify(uint16_t conn_handle, uint8_t kp_not)); + +/**@brief Generate a set of OOB data to send to a peer out of band. + * + * @note The @ref ble_gap_addr_t included in the OOB data returned will be the currently active one (or, if a connection has + * already been established, the one used during connection setup). The application may manually overwrite it with an updated + * value. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. Can be @ref BLE_CONN_HANDLE_INVALID if a BLE connection has not been established yet. + * @param[in] p_pk_own LE Secure Connections local P-256 Public Key. + * @param[out] p_oobd_own The OOB data to be sent out of band to a peer. + * + * @retval ::NRF_SUCCESS OOB data successfully generated. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_OOB_DATA_GET, uint32_t, + sd_ble_gap_lesc_oob_data_get(uint16_t conn_handle, ble_gap_lesc_p256_pk_t const *p_pk_own, + ble_gap_lesc_oob_data_t *p_oobd_own)); + +/**@brief Provide the OOB data sent/received out of band. + * + * @note An authentication procedure with OOB selected as an algorithm must be in progress when calling this function. + * @note A @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event with the oobd_req set to 1 must have been received prior to calling this + * function. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_oobd_own The OOB data sent out of band to a peer or NULL if the peer has not received OOB data. + * Must correspond to @ref ble_gap_sec_params_t::oob flag in @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. + * @param[in] p_oobd_peer The OOB data received out of band from a peer or NULL if none received. + * Must correspond to @ref ble_gap_sec_params_t::oob flag + * in @ref sd_ble_gap_authenticate in the central role or + * in @ref sd_ble_gap_sec_params_reply in the peripheral role. + * + * @retval ::NRF_SUCCESS OOB data accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Authentication key not requested + * - Not expecting LESC OOB data + * - Have not actually exchanged passkeys. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_OOB_DATA_SET, uint32_t, + sd_ble_gap_lesc_oob_data_set(uint16_t conn_handle, ble_gap_lesc_oob_data_t const *p_oobd_own, + ble_gap_lesc_oob_data_t const *p_oobd_peer)); + +/**@brief Initiate GAP Encryption procedure. + * + * @details In the central role, this function will initiate the encryption procedure using the encryption information provided. + * + * @events + * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE, The connection security has been updated.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_master_id Pointer to a @ref ble_gap_master_id_t master identification structure. + * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. + * + * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::BLE_ERROR_INVALID_ROLE Operation is not supported in the Peripheral role. + * @retval ::NRF_ERROR_BUSY Procedure already in progress or not allowed at this time, wait for pending procedures to complete and + * retry. + */ +SVCALL(SD_BLE_GAP_ENCRYPT, uint32_t, + sd_ble_gap_encrypt(uint16_t conn_handle, ble_gap_master_id_t const *p_master_id, ble_gap_enc_info_t const *p_enc_info)); + +/**@brief Reply with GAP security information. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_INFO_REQUEST, calling it at other times will result in + * @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * @note Data signing is not yet supported, and p_sign_info must therefore be NULL. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_ENC_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. May be NULL to signal none is + * available. + * @param[in] p_id_info Pointer to a @ref ble_gap_irk_t identity information structure. May be NULL to signal none is available. + * @param[in] p_sign_info Pointer to a @ref ble_gap_sign_info_t signing information structure. May be NULL to signal none is + * available. + * + * @retval ::NRF_SUCCESS Successfully accepted security information. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - No link has been established. + * - No @ref BLE_GAP_EVT_SEC_INFO_REQUEST pending. + * - Encryption information provided by the app without being requested. See @ref + * ble_gap_evt_sec_info_request_t::enc_info. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_SEC_INFO_REPLY, uint32_t, + sd_ble_gap_sec_info_reply(uint16_t conn_handle, ble_gap_enc_info_t const *p_enc_info, ble_gap_irk_t const *p_id_info, + ble_gap_sign_info_t const *p_sign_info)); + +/**@brief Get the current connection security. + * + * @param[in] conn_handle Connection handle. + * @param[out] p_conn_sec Pointer to a @ref ble_gap_conn_sec_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Current connection security successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_CONN_SEC_GET, uint32_t, sd_ble_gap_conn_sec_get(uint16_t conn_handle, ble_gap_conn_sec_t *p_conn_sec)); + +/**@brief Start reporting the received signal strength to the application. + * + * A new event is reported whenever the RSSI value changes, until @ref sd_ble_gap_rssi_stop is called. + * + * @events + * @event{@ref BLE_GAP_EVT_RSSI_CHANGED, New RSSI data available. How often the event is generated is + * dependent on the settings of the threshold_dbm + * and skip_count input parameters.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] threshold_dbm Minimum change in dBm before triggering the @ref BLE_GAP_EVT_RSSI_CHANGED event. Events are + * disabled if threshold_dbm equals @ref BLE_GAP_RSSI_THRESHOLD_INVALID. + * @param[in] skip_count Number of RSSI samples with a change of threshold_dbm or more before sending a new @ref + * BLE_GAP_EVT_RSSI_CHANGED event. + * + * @retval ::NRF_SUCCESS Successfully activated RSSI reporting. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is already ongoing. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_RSSI_START, uint32_t, sd_ble_gap_rssi_start(uint16_t conn_handle, uint8_t threshold_dbm, uint8_t skip_count)); + +/**@brief Stop reporting the received signal strength. + * + * @note An RSSI change detected before the call but not yet received by the application + * may be reported after @ref sd_ble_gap_rssi_stop has been called. + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * + * @retval ::NRF_SUCCESS Successfully deactivated RSSI reporting. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_RSSI_STOP, uint32_t, sd_ble_gap_rssi_stop(uint16_t conn_handle)); + +/**@brief Get the received signal strength for the last connection event. + * + * @ref sd_ble_gap_rssi_start must be called to start reporting RSSI before using this function. @ref NRF_ERROR_NOT_FOUND + * will be returned until RSSI was sampled for the first time after calling @ref sd_ble_gap_rssi_start. + * @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature measurement. + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[out] p_rssi Pointer to the location where the RSSI measurement shall be stored. + * @param[out] p_ch_index Pointer to the location where Channel Index for the RSSI measurement shall be stored. + * + * @retval ::NRF_SUCCESS Successfully read the RSSI. + * @retval ::NRF_ERROR_NOT_FOUND No sample is available. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. + */ +SVCALL(SD_BLE_GAP_RSSI_GET, uint32_t, sd_ble_gap_rssi_get(uint16_t conn_handle, int8_t *p_rssi, uint8_t *p_ch_index)); + +/**@brief Start or continue scanning (GAP Discovery procedure, Observer Procedure). + * + * @note A call to this function will require the application to keep the memory pointed by + * p_adv_report_buffer alive until the buffer is released. The buffer is released when the scanner is stopped + * or when this function is called with another buffer. + * + * @note The scanner will automatically stop in the following cases: + * - @ref sd_ble_gap_scan_stop is called. + * - @ref sd_ble_gap_connect is called. + * - A @ref BLE_GAP_EVT_TIMEOUT with source set to @ref BLE_GAP_TIMEOUT_SRC_SCAN is received. + * - When a @ref BLE_GAP_EVT_ADV_REPORT event is received and @ref ble_gap_adv_report_type_t::status is not set to + * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. In this case scanning is only paused to let the application + * access received data. The application must call this function to continue scanning, or call @ref + * sd_ble_gap_scan_stop to stop scanning. + * + * @note If a @ref BLE_GAP_EVT_ADV_REPORT event is received with @ref ble_gap_adv_report_type_t::status set to + * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the scanner will continue scanning, and the application will + * receive more reports from this advertising event. The following reports will include the old and new received data. + * + * @events + * @event{@ref BLE_GAP_EVT_ADV_REPORT, An advertising or scan response packet has been received.} + * @event{@ref BLE_GAP_EVT_TIMEOUT, Scanner has timed out.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_SCAN_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] p_scan_params Pointer to scan parameters structure. When this function is used to continue + * scanning, this parameter must be NULL. + * @param[in] p_adv_report_buffer Pointer to buffer used to store incoming advertising data. + * The memory pointed to should be kept alive until the scanning is stopped. + * See @ref BLE_GAP_SCAN_BUFFER_SIZE for minimum and maximum buffer size. + * If the scanner receives advertising data larger than can be stored in the buffer, + * a @ref BLE_GAP_EVT_ADV_REPORT will be raised with @ref ble_gap_adv_report_type_t::status + * set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED. + * + * @retval ::NRF_SUCCESS Successfully initiated scanning procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Scanning is already ongoing and p_scan_params was not NULL + * - Scanning is not running and p_scan_params was NULL. + * - The scanner has timed out when this function is called to continue scanning. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. See @ref ble_gap_scan_params_t. + * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported parameters supplied. See @ref ble_gap_scan_params_t. + * @retval ::NRF_ERROR_INVALID_LENGTH The provided buffer length is invalid. See @ref BLE_GAP_SCAN_BUFFER_MIN. + * @retval ::NRF_ERROR_RESOURCES Not enough BLE role slots available. + * Stop one or more currently active roles (Central, Peripheral or Broadcaster) and try again + */ +SVCALL(SD_BLE_GAP_SCAN_START, uint32_t, + sd_ble_gap_scan_start(ble_gap_scan_params_t const *p_scan_params, ble_data_t const *p_adv_report_buffer)); + +/**@brief Stop scanning (GAP Discovery procedure, Observer Procedure). + * + * @note The buffer provided in @ref sd_ble_gap_scan_start is released. + * + * @mscs + * @mmsc{@ref BLE_GAP_SCAN_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully stopped scanning procedure. + * @retval ::NRF_ERROR_INVALID_STATE Not in the scanning state. + */ +SVCALL(SD_BLE_GAP_SCAN_STOP, uint32_t, sd_ble_gap_scan_stop(void)); + +/**@brief Create a connection (GAP Link Establishment). + * + * @note If a scanning procedure is currently in progress it will be automatically stopped when calling this function. + * The scanning procedure will be stopped even if the function returns an error. + * + * @events + * @event{@ref BLE_GAP_EVT_CONNECTED, A connection was established.} + * @event{@ref BLE_GAP_EVT_TIMEOUT, Failed to establish a connection.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} + * @endmscs + * + * @param[in] p_peer_addr Pointer to peer identity address. If @ref ble_gap_scan_params_t::filter_policy is set to use + * whitelist, then p_peer_addr is ignored. + * @param[in] p_scan_params Pointer to scan parameters structure. + * @param[in] p_conn_params Pointer to desired connection parameters. + * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or + * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. + * + * @retval ::NRF_SUCCESS Successfully initiated connection procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid parameter(s) pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * - Invalid parameter(s) in p_scan_params or p_conn_params. + * - Use of whitelist requested but whitelist has not been set, see @ref + * sd_ble_gap_whitelist_set. + * - Peer address was not present in the device identity list, see @ref + * sd_ble_gap_device_identities_set. + * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. + * @retval ::NRF_ERROR_INVALID_STATE The SoftDevice is in an invalid state to perform this operation. This may be due to an + * existing locally initiated connect procedure, which must complete before initiating again. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid Peer address. + * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration tag has been reached. + * To increase the number of available connections, + * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. + * @retval ::NRF_ERROR_RESOURCES Either: + * - Not enough BLE role slots available. + * Stop one or more currently active roles (Central, Peripheral or Observer) and try again. + * - The event_length parameter associated with conn_cfg_tag is too small to be able to + * establish a connection on the selected @ref ble_gap_scan_params_t::scan_phys. + * Use @ref sd_ble_cfg_set to increase the event length. + */ +SVCALL(SD_BLE_GAP_CONNECT, uint32_t, + sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params, + ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag)); + +/**@brief Cancel a connection establishment. + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully canceled an ongoing connection procedure. + * @retval ::NRF_ERROR_INVALID_STATE No locally initiated connect procedure started or connection + * completed occurred. + */ +SVCALL(SD_BLE_GAP_CONNECT_CANCEL, uint32_t, sd_ble_gap_connect_cancel(void)); + +/**@brief Initiate or respond to a PHY Update Procedure + * + * @details This function is used to initiate or respond to a PHY Update Procedure. It will always + * generate a @ref BLE_GAP_EVT_PHY_UPDATE event if successfully executed. + * If this function is used to initiate a PHY Update procedure and the only option + * provided in @ref ble_gap_phys_t::tx_phys and @ref ble_gap_phys_t::rx_phys is the + * currently active PHYs in the respective directions, the SoftDevice will generate a + * @ref BLE_GAP_EVT_PHY_UPDATE with the current PHYs set and will not initiate the + * procedure in the Link Layer. + * + * If @ref ble_gap_phys_t::tx_phys or @ref ble_gap_phys_t::rx_phys is @ref BLE_GAP_PHY_AUTO, + * then the stack will select PHYs based on the peer's PHY preferences and the local link + * configuration. The PHY Update procedure will for this case result in a PHY combination + * that respects the time constraints configured with @ref sd_ble_cfg_set and the current + * link layer data length. + * + * When acting as a central, the SoftDevice will select the fastest common PHY in each direction. + * + * If the peer does not support the PHY Update Procedure, then the resulting + * @ref BLE_GAP_EVT_PHY_UPDATE event will have a status set to + * @ref BLE_HCI_UNSUPPORTED_REMOTE_FEATURE. + * + * If the PHY Update procedure was rejected by the peer due to a procedure collision, the status + * will be @ref BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION or + * @ref BLE_HCI_DIFFERENT_TRANSACTION_COLLISION. + * If the peer responds to the PHY Update procedure with invalid parameters, the status + * will be @ref BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS. + * If the PHY Update procedure was rejected by the peer for a different reason, the status will + * contain the reason as specified by the peer. + * + * @events + * @event{@ref BLE_GAP_EVT_PHY_UPDATE, Result of the PHY Update Procedure.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_PHY_UPDATE} + * @mmsc{@ref BLE_GAP_PERIPHERAL_PHY_UPDATE} + * @endmscs + * + * @param[in] conn_handle Connection handle to indicate the connection for which the PHY Update is requested. + * @param[in] p_gap_phys Pointer to PHY structure. + * + * @retval ::NRF_SUCCESS Successfully requested a PHY Update. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the combination of + * @ref ble_gap_phys_t::tx_phys, @ref ble_gap_phys_t::rx_phys, and @ref + * ble_gap_data_length_params_t. The connection event length is configured with @ref BLE_CONN_CFG_GAP using @ref sd_ble_cfg_set. + * @retval ::NRF_ERROR_BUSY Procedure is already in progress or not allowed at this time. Process pending events and wait for the + * pending procedure to complete and retry. + * + */ +SVCALL(SD_BLE_GAP_PHY_UPDATE, uint32_t, sd_ble_gap_phy_update(uint16_t conn_handle, ble_gap_phys_t const *p_gap_phys)); + +/**@brief Initiate or respond to a Data Length Update Procedure. + * + * @note If the application uses @ref BLE_GAP_DATA_LENGTH_AUTO for one or more members of + * p_dl_params, the SoftDevice will choose the highest value supported in current + * configuration and connection parameters. + * @note If the link PHY is Coded, the SoftDevice will ensure that the MaxTxTime and/or MaxRxTime + * used in the Data Length Update procedure is at least 2704 us. Otherwise, MaxTxTime and + * MaxRxTime will be limited to maximum 2120 us. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_dl_params Pointer to local parameters to be used in Data Length Update + * Procedure. Set any member to @ref BLE_GAP_DATA_LENGTH_AUTO to let + * the SoftDevice automatically decide the value for that member. + * Set to NULL to use automatic values for all members. + * @param[out] p_dl_limitation Pointer to limitation to be written when local device does not + * have enough resources or does not support the requested Data Length + * Update parameters. Ignored if NULL. + * + * @mscs + * @mmsc{@ref BLE_GAP_DATA_LENGTH_UPDATE_PROCEDURE_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully set Data Length Extension initiation/response parameters. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The requested parameters are not supported by the SoftDevice. Inspect + * p_dl_limitation to see which parameter is not supported. + * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the requested + * parameters. Use @ref sd_ble_cfg_set with @ref BLE_CONN_CFG_GAP to increase the connection event length. Inspect p_dl_limitation + * to see where the limitation is. + * @retval ::NRF_ERROR_BUSY Peer has already initiated a Data Length Update Procedure. Process the + * pending @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event to respond. + */ +SVCALL(SD_BLE_GAP_DATA_LENGTH_UPDATE, uint32_t, + sd_ble_gap_data_length_update(uint16_t conn_handle, ble_gap_data_length_params_t const *p_dl_params, + ble_gap_data_length_limitation_t *p_dl_limitation)); + +/**@brief Start the Quality of Service (QoS) channel survey module. + * + * @details The channel survey module provides measurements of the energy levels on + * the Bluetooth Low Energy channels. When the module is enabled, @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT + * events will periodically report the measured energy levels for each channel. + * + * @note The measurements are scheduled with lower priority than other Bluetooth Low Energy roles, + * Radio Timeslot API events and Flash API events. + * + * @note The channel survey module will attempt to do measurements so that the average interval + * between measurements will be interval_us. However due to the channel survey module + * having the lowest priority of all roles and modules, this may not be possible. In that + * case fewer than expected channel survey reports may be given. + * + * @note In order to use the channel survey module, @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available + * must be set. This is done using @ref sd_ble_cfg_set. + * + * @param[in] interval_us Requested average interval for the measurements and reports. See + * @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS for valid ranges. If set + * to @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS, the channel + * survey role will be scheduled at every available opportunity. + * + * @retval ::NRF_SUCCESS The module is successfully started. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. interval_us is out of the + * allowed range. + * @retval ::NRF_ERROR_INVALID_STATE Trying to start the module when already running. + * @retval ::NRF_ERROR_RESOURCES The channel survey module is not available to the application. + * Set @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available using + * @ref sd_ble_cfg_set. + */ +SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_START, uint32_t, sd_ble_gap_qos_channel_survey_start(uint32_t interval_us)); + +/**@brief Stop the Quality of Service (QoS) channel survey module. + * + * @note The SoftDevice may generate one @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT event after this + * function is called. + * + * @retval ::NRF_SUCCESS The module is successfully stopped. + * @retval ::NRF_ERROR_INVALID_STATE Trying to stop the module when it is not running. + */ +SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP, uint32_t, sd_ble_gap_qos_channel_survey_stop(void)); + +/**@brief Obtain the next connection event counter value. + * + * @details The connection event counter is initialized to zero on the first connection event. The value is incremented + * by one for each connection event. For more information see Bluetooth Core Specification v5.0, Vol 6, Part B, + * Section 4.5.1. + * + * @note The connection event counter obtained through this API will be outdated if this API is called + * at the same time as the connection event counter is incremented. + * + * @note This API will always return the last connection event counter + 1. + * The actual connection event may be multiple connection events later if: + * - Slave latency is enabled and there is no data to transmit or receive. + * - Another role is scheduled with a higher priority at the same time as the next connection event. + * + * @param[in] conn_handle Connection handle. + * @param[out] p_counter Pointer to the variable where the next connection event counter will be written. + * + * @retval ::NRF_SUCCESS The connection event counter was successfully retrieved. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET, uint32_t, + sd_ble_gap_next_conn_evt_counter_get(uint16_t conn_handle, uint16_t *p_counter)); + +/**@brief Start triggering a given task on connection event start. + * + * @details When enabled, this feature will trigger a PPI task at the start of connection events. + * The application can configure the SoftDevice to trigger every N connection events starting from + * a given connection event counter. See also @ref ble_gap_conn_event_trigger_t. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_params Connection event trigger parameters. + * + * @retval ::NRF_SUCCESS Success. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. See @ref ble_gap_conn_event_trigger_t. + * @retval ::NRF_ERROR_INVALID_STATE Either: + * - Trying to start connection event triggering when it is already ongoing. + * - @ref ble_gap_conn_event_trigger_t::conn_evt_counter_start is in the past. + * Use @ref sd_ble_gap_next_conn_evt_counter_get to find a new value + to be used as ble_gap_conn_event_trigger_t::conn_evt_counter_start. + */ +SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_START, uint32_t, + sd_ble_gap_conn_evt_trigger_start(uint16_t conn_handle, ble_gap_conn_event_trigger_t const *p_params)); + +/**@brief Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. + * + * @param[in] conn_handle Connection handle. + * + * @retval ::NRF_SUCCESS Success. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE Trying to stop connection event triggering when it is not enabled. + */ +SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_STOP, uint32_t, sd_ble_gap_conn_evt_trigger_stop(uint16_t conn_handle)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GAP_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gatt.h b/variants/wio-sdk-wm1110/softdevice/ble_gatt.h new file mode 100644 index 0000000000..df0d728fc8 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_gatt.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATT Generic Attribute Profile (GATT) Common + @{ + @brief Common definitions and prototypes for the GATT interfaces. + */ + +#ifndef BLE_GATT_H__ +#define BLE_GATT_H__ + +#include "ble_err.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATT_DEFINES Defines + * @{ */ + +/** @brief Default ATT MTU, in bytes. */ +#define BLE_GATT_ATT_MTU_DEFAULT 23 + +/**@brief Invalid Attribute Handle. */ +#define BLE_GATT_HANDLE_INVALID 0x0000 + +/**@brief First Attribute Handle. */ +#define BLE_GATT_HANDLE_START 0x0001 + +/**@brief Last Attribute Handle. */ +#define BLE_GATT_HANDLE_END 0xFFFF + +/** @defgroup BLE_GATT_TIMEOUT_SOURCES GATT Timeout sources + * @{ */ +#define BLE_GATT_TIMEOUT_SRC_PROTOCOL 0x00 /**< ATT Protocol timeout. */ +/** @} */ + +/** @defgroup BLE_GATT_WRITE_OPS GATT Write operations + * @{ */ +#define BLE_GATT_OP_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATT_OP_WRITE_REQ 0x01 /**< Write Request. */ +#define BLE_GATT_OP_WRITE_CMD 0x02 /**< Write Command. */ +#define BLE_GATT_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ +#define BLE_GATT_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ +#define BLE_GATT_OP_EXEC_WRITE_REQ 0x05 /**< Execute Write Request. */ +/** @} */ + +/** @defgroup BLE_GATT_EXEC_WRITE_FLAGS GATT Execute Write flags + * @{ */ +#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL 0x00 /**< Cancel prepared write. */ +#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE 0x01 /**< Execute prepared write. */ +/** @} */ + +/** @defgroup BLE_GATT_HVX_TYPES GATT Handle Value operations + * @{ */ +#define BLE_GATT_HVX_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATT_HVX_NOTIFICATION 0x01 /**< Handle Value Notification. */ +#define BLE_GATT_HVX_INDICATION 0x02 /**< Handle Value Indication. */ +/** @} */ + +/** @defgroup BLE_GATT_STATUS_CODES GATT Status Codes + * @{ */ +#define BLE_GATT_STATUS_SUCCESS 0x0000 /**< Success. */ +#define BLE_GATT_STATUS_UNKNOWN 0x0001 /**< Unknown or not applicable status. */ +#define BLE_GATT_STATUS_ATTERR_INVALID 0x0100 /**< ATT Error: Invalid Error Code. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_HANDLE 0x0101 /**< ATT Error: Invalid Attribute Handle. */ +#define BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED 0x0102 /**< ATT Error: Read not permitted. */ +#define BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED 0x0103 /**< ATT Error: Write not permitted. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_PDU 0x0104 /**< ATT Error: Used in ATT as Invalid PDU. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION 0x0105 /**< ATT Error: Authenticated link required. */ +#define BLE_GATT_STATUS_ATTERR_REQUEST_NOT_SUPPORTED 0x0106 /**< ATT Error: Used in ATT as Request Not Supported. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_OFFSET 0x0107 /**< ATT Error: Offset specified was past the end of the attribute. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION 0x0108 /**< ATT Error: Used in ATT as Insufficient Authorization. */ +#define BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL 0x0109 /**< ATT Error: Used in ATT as Prepare Queue Full. */ +#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND 0x010A /**< ATT Error: Used in ATT as Attribute not found. */ +#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_LONG \ + 0x010B /**< ATT Error: Attribute cannot be read or written using read/write blob requests. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_ENC_KEY_SIZE 0x010C /**< ATT Error: Encryption key size used is insufficient. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH 0x010D /**< ATT Error: Invalid value size. */ +#define BLE_GATT_STATUS_ATTERR_UNLIKELY_ERROR 0x010E /**< ATT Error: Very unlikely error. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION 0x010F /**< ATT Error: Encrypted link required. */ +#define BLE_GATT_STATUS_ATTERR_UNSUPPORTED_GROUP_TYPE \ + 0x0110 /**< ATT Error: Attribute type is not a supported grouping attribute. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_RESOURCES 0x0111 /**< ATT Error: Insufficient resources. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_BEGIN 0x0112 /**< ATT Error: Reserved for Future Use range #1 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_END 0x017F /**< ATT Error: Reserved for Future Use range #1 end. */ +#define BLE_GATT_STATUS_ATTERR_APP_BEGIN 0x0180 /**< ATT Error: Application range begin. */ +#define BLE_GATT_STATUS_ATTERR_APP_END 0x019F /**< ATT Error: Application range end. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_BEGIN 0x01A0 /**< ATT Error: Reserved for Future Use range #2 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_END 0x01DF /**< ATT Error: Reserved for Future Use range #2 end. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_BEGIN 0x01E0 /**< ATT Error: Reserved for Future Use range #3 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_END 0x01FC /**< ATT Error: Reserved for Future Use range #3 end. */ +#define BLE_GATT_STATUS_ATTERR_CPS_WRITE_REQ_REJECTED \ + 0x01FC /**< ATT Common Profile and Service Error: Write request rejected. \ + */ +#define BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR \ + 0x01FD /**< ATT Common Profile and Service Error: Client Characteristic Configuration Descriptor improperly configured. */ +#define BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG \ + 0x01FE /**< ATT Common Profile and Service Error: Procedure Already in Progress. */ +#define BLE_GATT_STATUS_ATTERR_CPS_OUT_OF_RANGE 0x01FF /**< ATT Common Profile and Service Error: Out Of Range. */ +/** @} */ + +/** @defgroup BLE_GATT_CPF_FORMATS Characteristic Presentation Formats + * @note Found at + * http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml + * @{ */ +#define BLE_GATT_CPF_FORMAT_RFU 0x00 /**< Reserved For Future Use. */ +#define BLE_GATT_CPF_FORMAT_BOOLEAN 0x01 /**< Boolean. */ +#define BLE_GATT_CPF_FORMAT_2BIT 0x02 /**< Unsigned 2-bit integer. */ +#define BLE_GATT_CPF_FORMAT_NIBBLE 0x03 /**< Unsigned 4-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT8 0x04 /**< Unsigned 8-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT12 0x05 /**< Unsigned 12-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT16 0x06 /**< Unsigned 16-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT24 0x07 /**< Unsigned 24-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT32 0x08 /**< Unsigned 32-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT48 0x09 /**< Unsigned 48-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT64 0x0A /**< Unsigned 64-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT128 0x0B /**< Unsigned 128-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT8 0x0C /**< Signed 2-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT12 0x0D /**< Signed 12-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT16 0x0E /**< Signed 16-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT24 0x0F /**< Signed 24-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT32 0x10 /**< Signed 32-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT48 0x11 /**< Signed 48-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT64 0x12 /**< Signed 64-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT128 0x13 /**< Signed 128-bit integer. */ +#define BLE_GATT_CPF_FORMAT_FLOAT32 0x14 /**< IEEE-754 32-bit floating point. */ +#define BLE_GATT_CPF_FORMAT_FLOAT64 0x15 /**< IEEE-754 64-bit floating point. */ +#define BLE_GATT_CPF_FORMAT_SFLOAT 0x16 /**< IEEE-11073 16-bit SFLOAT. */ +#define BLE_GATT_CPF_FORMAT_FLOAT 0x17 /**< IEEE-11073 32-bit FLOAT. */ +#define BLE_GATT_CPF_FORMAT_DUINT16 0x18 /**< IEEE-20601 format. */ +#define BLE_GATT_CPF_FORMAT_UTF8S 0x19 /**< UTF-8 string. */ +#define BLE_GATT_CPF_FORMAT_UTF16S 0x1A /**< UTF-16 string. */ +#define BLE_GATT_CPF_FORMAT_STRUCT 0x1B /**< Opaque Structure. */ +/** @} */ + +/** @defgroup BLE_GATT_CPF_NAMESPACES GATT Bluetooth Namespaces + * @{ + */ +#define BLE_GATT_CPF_NAMESPACE_BTSIG 0x01 /**< Bluetooth SIG defined Namespace. */ +#define BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN 0x0000 /**< Namespace Description Unknown. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATT_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATT connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_PARAM att_mtu is smaller than @ref BLE_GATT_ATT_MTU_DEFAULT. + */ +typedef struct { + uint16_t att_mtu; /**< Maximum size of ATT packet the SoftDevice can send or receive. + The default and minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + @mscs + @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} + @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} + @endmscs + */ +} ble_gatt_conn_cfg_t; + +/**@brief GATT Characteristic Properties. */ +typedef struct { + /* Standard properties */ + uint8_t broadcast : 1; /**< Broadcasting of the value permitted. */ + uint8_t read : 1; /**< Reading the value permitted. */ + uint8_t write_wo_resp : 1; /**< Writing the value with Write Command permitted. */ + uint8_t write : 1; /**< Writing the value with Write Request permitted. */ + uint8_t notify : 1; /**< Notification of the value permitted. */ + uint8_t indicate : 1; /**< Indications of the value permitted. */ + uint8_t auth_signed_wr : 1; /**< Writing the value with Signed Write Command permitted. */ +} ble_gatt_char_props_t; + +/**@brief GATT Characteristic Extended Properties. */ +typedef struct { + /* Extended properties */ + uint8_t reliable_wr : 1; /**< Writing the value with Queued Write operations permitted. */ + uint8_t wr_aux : 1; /**< Writing the Characteristic User Description descriptor permitted. */ +} ble_gatt_char_ext_props_t; + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GATT_H__ + +/** @} */ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gattc.h b/variants/wio-sdk-wm1110/softdevice/ble_gattc.h new file mode 100644 index 0000000000..f1df1782ca --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_gattc.h @@ -0,0 +1,764 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATTC Generic Attribute Profile (GATT) Client + @{ + @brief Definitions and prototypes for the GATT Client interface. + */ + +#ifndef BLE_GATTC_H__ +#define BLE_GATTC_H__ + +#include "ble_err.h" +#include "ble_gatt.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATTC_ENUMERATIONS Enumerations + * @{ */ + +/**@brief GATTC API SVC numbers. */ +enum BLE_GATTC_SVCS { + SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER = BLE_GATTC_SVC_BASE, /**< Primary Service Discovery. */ + SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, /**< Relationship Discovery. */ + SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, /**< Characteristic Discovery. */ + SD_BLE_GATTC_DESCRIPTORS_DISCOVER, /**< Characteristic Descriptor Discovery. */ + SD_BLE_GATTC_ATTR_INFO_DISCOVER, /**< Attribute Information Discovery. */ + SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, /**< Read Characteristic Value by UUID. */ + SD_BLE_GATTC_READ, /**< Generic read. */ + SD_BLE_GATTC_CHAR_VALUES_READ, /**< Read multiple Characteristic Values. */ + SD_BLE_GATTC_WRITE, /**< Generic write. */ + SD_BLE_GATTC_HV_CONFIRM, /**< Handle Value Confirmation. */ + SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. */ +}; + +/** + * @brief GATT Client Event IDs. + */ +enum BLE_GATTC_EVTS { + BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP = BLE_GATTC_EVT_BASE, /**< Primary Service Discovery Response event. \n See @ref + ble_gattc_evt_prim_srvc_disc_rsp_t. */ + BLE_GATTC_EVT_REL_DISC_RSP, /**< Relationship Discovery Response event. \n See @ref ble_gattc_evt_rel_disc_rsp_t. + */ + BLE_GATTC_EVT_CHAR_DISC_RSP, /**< Characteristic Discovery Response event. \n See @ref + ble_gattc_evt_char_disc_rsp_t. */ + BLE_GATTC_EVT_DESC_DISC_RSP, /**< Descriptor Discovery Response event. \n See @ref + ble_gattc_evt_desc_disc_rsp_t. */ + BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, /**< Attribute Information Response event. \n See @ref + ble_gattc_evt_attr_info_disc_rsp_t. */ + BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP, /**< Read By UUID Response event. \n See @ref + ble_gattc_evt_char_val_by_uuid_read_rsp_t. */ + BLE_GATTC_EVT_READ_RSP, /**< Read Response event. \n See @ref ble_gattc_evt_read_rsp_t. */ + BLE_GATTC_EVT_CHAR_VALS_READ_RSP, /**< Read multiple Response event. \n See @ref + ble_gattc_evt_char_vals_read_rsp_t. */ + BLE_GATTC_EVT_WRITE_RSP, /**< Write Response event. \n See @ref ble_gattc_evt_write_rsp_t. */ + BLE_GATTC_EVT_HVX, /**< Handle Value Notification or Indication event. \n Confirm indication with @ref + sd_ble_gattc_hv_confirm. \n See @ref ble_gattc_evt_hvx_t. */ + BLE_GATTC_EVT_EXCHANGE_MTU_RSP, /**< Exchange MTU Response event. \n See @ref + ble_gattc_evt_exchange_mtu_rsp_t. */ + BLE_GATTC_EVT_TIMEOUT, /**< Timeout event. \n See @ref ble_gattc_evt_timeout_t. */ + BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE /**< Write without Response transmission complete. \n See @ref + ble_gattc_evt_write_cmd_tx_complete_t. */ +}; + +/**@brief GATTC Option IDs. + * IDs that uniquely identify a GATTC option. + */ +enum BLE_GATTC_OPTS { + BLE_GATTC_OPT_UUID_DISC = BLE_GATTC_OPT_BASE, /**< UUID discovery. @ref ble_gattc_opt_uuid_disc_t */ +}; + +/** @} */ + +/** @addtogroup BLE_GATTC_DEFINES Defines + * @{ */ + +/** @defgroup BLE_ERRORS_GATTC SVC return values specific to GATTC + * @{ */ +#define BLE_ERROR_GATTC_PROC_NOT_PERMITTED (NRF_GATTC_ERR_BASE + 0x000) /**< Procedure not Permitted. */ +/** @} */ + +/** @defgroup BLE_GATTC_ATTR_INFO_FORMAT Attribute Information Formats + * @{ */ +#define BLE_GATTC_ATTR_INFO_FORMAT_16BIT 1 /**< 16-bit Attribute Information Format. */ +#define BLE_GATTC_ATTR_INFO_FORMAT_128BIT 2 /**< 128-bit Attribute Information Format. */ +/** @} */ + +/** @defgroup BLE_GATTC_DEFAULTS GATT Client defaults + * @{ */ +#define BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT \ + 1 /**< Default number of Write without Response that can be queued for transmission. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATTC_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATTC connection configuration parameters, set with @ref sd_ble_cfg_set. + */ +typedef struct { + uint8_t write_cmd_tx_queue_size; /**< The guaranteed minimum number of Write without Response that can be queued for + transmission. The default value is @ref BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT */ +} ble_gattc_conn_cfg_t; + +/**@brief Operation Handle Range. */ +typedef struct { + uint16_t start_handle; /**< Start Handle. */ + uint16_t end_handle; /**< End Handle. */ +} ble_gattc_handle_range_t; + +/**@brief GATT service. */ +typedef struct { + ble_uuid_t uuid; /**< Service UUID. */ + ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */ +} ble_gattc_service_t; + +/**@brief GATT include. */ +typedef struct { + uint16_t handle; /**< Include Handle. */ + ble_gattc_service_t included_srvc; /**< Handle of the included service. */ +} ble_gattc_include_t; + +/**@brief GATT characteristic. */ +typedef struct { + ble_uuid_t uuid; /**< Characteristic UUID. */ + ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ + uint8_t char_ext_props : 1; /**< Extended properties present. */ + uint16_t handle_decl; /**< Handle of the Characteristic Declaration. */ + uint16_t handle_value; /**< Handle of the Characteristic Value. */ +} ble_gattc_char_t; + +/**@brief GATT descriptor. */ +typedef struct { + uint16_t handle; /**< Descriptor Handle. */ + ble_uuid_t uuid; /**< Descriptor UUID. */ +} ble_gattc_desc_t; + +/**@brief Write Parameters. */ +typedef struct { + uint8_t write_op; /**< Write Operation to be performed, see @ref BLE_GATT_WRITE_OPS. */ + uint8_t flags; /**< Flags, see @ref BLE_GATT_EXEC_WRITE_FLAGS. */ + uint16_t handle; /**< Handle to the attribute to be written. */ + uint16_t offset; /**< Offset in bytes. @note For WRITE_CMD and WRITE_REQ, offset must be 0. */ + uint16_t len; /**< Length of data in bytes. */ + uint8_t const *p_value; /**< Pointer to the value data. */ +} ble_gattc_write_params_t; + +/**@brief Attribute Information for 16-bit Attribute UUID. */ +typedef struct { + uint16_t handle; /**< Attribute handle. */ + ble_uuid_t uuid; /**< 16-bit Attribute UUID. */ +} ble_gattc_attr_info16_t; + +/**@brief Attribute Information for 128-bit Attribute UUID. */ +typedef struct { + uint16_t handle; /**< Attribute handle. */ + ble_uuid128_t uuid; /**< 128-bit Attribute UUID. */ +} ble_gattc_attr_info128_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Service count. */ + ble_gattc_service_t services[1]; /**< Service data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use + event structures with variable length array members. */ +} ble_gattc_evt_prim_srvc_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_REL_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Include count. */ + ble_gattc_include_t includes[1]; /**< Include data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use + event structures with variable length array members. */ +} ble_gattc_evt_rel_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Characteristic count. */ + ble_gattc_char_t chars[1]; /**< Characteristic data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event + structures with variable length array members. */ +} ble_gattc_evt_char_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_DESC_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Descriptor count. */ + ble_gattc_desc_t descs[1]; /**< Descriptor data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event + structures with variable length array members. */ +} ble_gattc_evt_desc_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Attribute count. */ + uint8_t format; /**< Attribute information format, see @ref BLE_GATTC_ATTR_INFO_FORMAT. */ + union { + ble_gattc_attr_info16_t attr_info16[1]; /**< Attribute information for 16-bit Attribute UUID. + @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on + how to use event structures with variable length array members. */ + ble_gattc_attr_info128_t attr_info128[1]; /**< Attribute information for 128-bit Attribute UUID. + @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on + how to use event structures with variable length array members. */ + } info; /**< Attribute information union. */ +} ble_gattc_evt_attr_info_disc_rsp_t; + +/**@brief GATT read by UUID handle value pair. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint8_t *p_value; /**< Pointer to the Attribute Value, length is available in @ref + ble_gattc_evt_char_val_by_uuid_read_rsp_t::value_len. */ +} ble_gattc_handle_value_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP. */ +typedef struct { + uint16_t count; /**< Handle-Value Pair Count. */ + uint16_t value_len; /**< Length of the value in Handle-Value(s) list. */ + uint8_t handle_value[1]; /**< Handle-Value(s) list. To iterate through the list use @ref + sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter. + @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with + variable length array members. */ +} ble_gattc_evt_char_val_by_uuid_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_READ_RSP. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint16_t offset; /**< Offset of the attribute data. */ + uint16_t len; /**< Attribute data length. */ + uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP. */ +typedef struct { + uint16_t len; /**< Concatenated Attribute values length. */ + uint8_t values[1]; /**< Attribute values. @note This is a variable length array. The size of 1 indicated is only a placeholder + for compilation. See @ref sd_ble_evt_get for more information on how to use event structures with + variable length array members. */ +} ble_gattc_evt_char_vals_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_RSP. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint8_t write_op; /**< Type of write operation, see @ref BLE_GATT_WRITE_OPS. */ + uint16_t offset; /**< Data offset. */ + uint16_t len; /**< Data length. */ + uint8_t data[1]; /**< Data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_write_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_HVX. */ +typedef struct { + uint16_t handle; /**< Handle to which the HVx operation applies. */ + uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ + uint16_t len; /**< Attribute data length. */ + uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_hvx_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. */ +typedef struct { + uint16_t server_rx_mtu; /**< Server RX MTU size. */ +} ble_gattc_evt_exchange_mtu_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ +} ble_gattc_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE. */ +typedef struct { + uint8_t count; /**< Number of write without response transmissions completed. */ +} ble_gattc_evt_write_cmd_tx_complete_t; + +/**@brief GATTC event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which event occurred. */ + uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ + uint16_t + error_handle; /**< In case of error: The handle causing the error. In all other cases @ref BLE_GATT_HANDLE_INVALID. */ + union { + ble_gattc_evt_prim_srvc_disc_rsp_t prim_srvc_disc_rsp; /**< Primary Service Discovery Response Event Parameters. */ + ble_gattc_evt_rel_disc_rsp_t rel_disc_rsp; /**< Relationship Discovery Response Event Parameters. */ + ble_gattc_evt_char_disc_rsp_t char_disc_rsp; /**< Characteristic Discovery Response Event Parameters. */ + ble_gattc_evt_desc_disc_rsp_t desc_disc_rsp; /**< Descriptor Discovery Response Event Parameters. */ + ble_gattc_evt_char_val_by_uuid_read_rsp_t + char_val_by_uuid_read_rsp; /**< Characteristic Value Read by UUID Response Event Parameters. */ + ble_gattc_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. */ + ble_gattc_evt_char_vals_read_rsp_t char_vals_read_rsp; /**< Characteristic Values Read Response Event Parameters. */ + ble_gattc_evt_write_rsp_t write_rsp; /**< Write Response Event Parameters. */ + ble_gattc_evt_hvx_t hvx; /**< Handle Value Notification/Indication Event Parameters. */ + ble_gattc_evt_exchange_mtu_rsp_t exchange_mtu_rsp; /**< Exchange MTU Response Event Parameters. */ + ble_gattc_evt_timeout_t timeout; /**< Timeout Event Parameters. */ + ble_gattc_evt_attr_info_disc_rsp_t attr_info_disc_rsp; /**< Attribute Information Discovery Event Parameters. */ + ble_gattc_evt_write_cmd_tx_complete_t + write_cmd_tx_complete; /**< Write without Response transmission complete Event Parameters. */ + } params; /**< Event Parameters. @note Only valid if @ref gatt_status == @ref BLE_GATT_STATUS_SUCCESS. */ +} ble_gattc_evt_t; + +/**@brief UUID discovery option. + * + * @details Used with @ref sd_ble_opt_set to enable and disable automatic insertion of discovered 128-bit UUIDs to the + * Vendor Specific UUID table. Disabled by default. + * - When disabled, if a procedure initiated by + * @ref sd_ble_gattc_primary_services_discover, + * @ref sd_ble_gattc_relationships_discover, + * @ref sd_ble_gattc_characteristics_discover, + * @ref sd_ble_gattc_descriptors_discover + * finds a 128-bit UUID which was not added by @ref sd_ble_uuid_vs_add, @ref ble_uuid_t::type will be set + * to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. + * - When enabled, all found 128-bit UUIDs will be automatically added. The application can use + * @ref sd_ble_uuid_encode to retrieve the 128-bit UUID from @ref ble_uuid_t received in the corresponding + * event. If the total number of Vendor Specific UUIDs exceeds the table capacity, @ref ble_uuid_t::type will + * be set to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. + * See also @ref ble_common_cfg_vs_uuid_t, @ref sd_ble_uuid_vs_remove. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * + * @retval ::NRF_SUCCESS Set successfully. + * + */ +typedef struct { + uint8_t auto_add_vs_enable : 1; /**< Set to 1 to enable (or 0 to disable) automatic insertion of discovered 128-bit UUIDs. */ +} ble_gattc_opt_uuid_disc_t; + +/**@brief Option structure for GATTC options. */ +typedef union { + ble_gattc_opt_uuid_disc_t uuid_disc; /**< Parameters for the UUID discovery option. */ +} ble_gattc_opt_t; + +/** @} */ + +/** @addtogroup BLE_GATTC_FUNCTIONS Functions + * @{ */ + +/**@brief Initiate or continue a GATT Primary Service Discovery procedure. + * + * @details This function initiates or resumes a Primary Service discovery procedure, starting from the supplied handle. + * If the last service has not been reached, this function must be called again with an updated start handle value to + * continue the search. See also @ref ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_PRIM_SRVC_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] start_handle Handle to start searching from. + * @param[in] p_srvc_uuid Pointer to the service UUID to be found. If it is NULL, all primary services will be returned. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Primary Service Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER, uint32_t, + sd_ble_gattc_primary_services_discover(uint16_t conn_handle, uint16_t start_handle, ble_uuid_t const *p_srvc_uuid)); + +/**@brief Initiate or continue a GATT Relationship Discovery procedure. + * + * @details This function initiates or resumes the Find Included Services sub-procedure. If the last included service has not been + * reached, this must be called again with an updated handle range to continue the search. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_REL_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_REL_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Relationship Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, uint32_t, + sd_ble_gattc_relationships_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Characteristic Discovery procedure. + * + * @details This function initiates or resumes a Characteristic discovery procedure. If the last Characteristic has not been + * reached, this must be called again with an updated handle range to continue the discovery. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_CHAR_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Characteristic Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, uint32_t, + sd_ble_gattc_characteristics_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Characteristic Descriptor Discovery procedure. + * + * @details This function initiates or resumes a Characteristic Descriptor discovery procedure. If the last Descriptor has not + * been reached, this must be called again with an updated handle range to continue the discovery. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_DESC_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_DESC_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Characteristic to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Descriptor Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t, + sd_ble_gattc_descriptors_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Read using Characteristic UUID procedure. + * + * @details This function initiates or resumes a Read using Characteristic UUID procedure. If the last Characteristic has not been + * reached, this must be called again with an updated handle range to continue the discovery. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_READ_UUID_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_uuid Pointer to a Characteristic value UUID to read. + * @param[in] p_handle_range A pointer to the range of handles to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Read using Characteristic UUID procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, uint32_t, + sd_ble_gattc_char_value_by_uuid_read(uint16_t conn_handle, ble_uuid_t const *p_uuid, + ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Read (Long) Characteristic or Descriptor procedure. + * + * @details This function initiates or resumes a GATT Read (Long) Characteristic or Descriptor procedure. If the Characteristic or + * Descriptor to be read is longer than ATT_MTU - 1, this function must be called multiple times with appropriate offset to read + * the complete value. + * + * @events + * @event{@ref BLE_GATTC_EVT_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_VALUE_READ_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] handle The handle of the attribute to be read. + * @param[in] offset Offset into the attribute value to be read. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Read (Long) procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_READ, uint32_t, sd_ble_gattc_read(uint16_t conn_handle, uint16_t handle, uint16_t offset)); + +/**@brief Initiate a GATT Read Multiple Characteristic Values procedure. + * + * @details This function initiates a GATT Read Multiple Characteristic Values procedure. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_READ_MULT_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handles A pointer to the handle(s) of the attribute(s) to be read. + * @param[in] handle_count The number of handles in p_handles. + * + * @retval ::NRF_SUCCESS Successfully started the Read Multiple Characteristic Values procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t, + sd_ble_gattc_char_values_read(uint16_t conn_handle, uint16_t const *p_handles, uint16_t handle_count)); + +/**@brief Perform a Write (Characteristic Value or Descriptor, with or without response, signed or not, long or reliable) + * procedure. + * + * @details This function can perform all write procedures described in GATT. + * + * @note Only one write with response procedure can be ongoing per connection at a time. + * If the application tries to write with response while another write with response procedure is ongoing, + * the function call will return @ref NRF_ERROR_BUSY. + * A @ref BLE_GATTC_EVT_WRITE_RSP event will be issued as soon as the write response arrives from the peer. + * + * @note The number of Write without Response that can be queued is configured by @ref + * ble_gattc_conn_cfg_t::write_cmd_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. + * A @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event will be issued as soon as the transmission of the write without + * response is complete. + * + * @note The application can keep track of the available queue element count for writes without responses by following the + * procedure below: + * - Store initial queue element count in a variable. + * - Decrement the variable, which stores the currently available queue element count, by one when a call to this + * function returns @ref NRF_SUCCESS. + * - Increment the variable, which stores the current available queue element count, by the count variable in @ref + * BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event. + * + * @events + * @event{@ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE, Write without response transmission complete.} + * @event{@ref BLE_GATTC_EVT_WRITE_RSP, Write response received from the peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_VALUE_WRITE_WITHOUT_RESP_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_WRITE_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_LONG_WRITE_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_RELIABLE_WRITE_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_write_params A pointer to a write parameters structure. + * + * @retval ::NRF_SUCCESS Successfully started the Write procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_BUSY For write with response, procedure already in progress. Wait for a @ref BLE_GATTC_EVT_WRITE_RSP event + * and retry. + * @retval ::NRF_ERROR_RESOURCES Too many writes without responses queued. + * Wait for a @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event and retry. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_WRITE, uint32_t, sd_ble_gattc_write(uint16_t conn_handle, ble_gattc_write_params_t const *p_write_params)); + +/**@brief Send a Handle Value Confirmation to the GATT Server. + * + * @mscs + * @mmsc{@ref BLE_GATTC_HVI_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] handle The handle of the attribute in the indication. + * + * @retval ::NRF_SUCCESS Successfully queued the Handle Value Confirmation for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no Indication pending to be confirmed. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_HV_CONFIRM, uint32_t, sd_ble_gattc_hv_confirm(uint16_t conn_handle, uint16_t handle)); + +/**@brief Discovers information about a range of attributes on a GATT server. + * + * @events + * @event{@ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, Generated when information about a range of attributes has been received.} + * @endevents + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range The range of handles to request information about. + * + * @retval ::NRF_SUCCESS Successfully started an attribute information discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t, + sd_ble_gattc_attr_info_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Start an ATT_MTU exchange by sending an Exchange MTU Request to the server. + * + * @details The SoftDevice sets ATT_MTU to the minimum of: + * - The Client RX MTU value, and + * - The Server RX MTU value from @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. + * + * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. + * + * @events + * @event{@ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] client_rx_mtu Client RX MTU size. + * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration + used for this connection. + * - The value must be equal to Server RX MTU size given in @ref sd_ble_gatts_exchange_mtu_reply + * if an ATT_MTU exchange has already been performed in the other direction. + * + * @retval ::NRF_SUCCESS Successfully sent request to the server. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state or an ATT_MTU exchange was already requested once. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid Client RX MTU size supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, uint32_t, + sd_ble_gattc_exchange_mtu_request(uint16_t conn_handle, uint16_t client_rx_mtu)); + +/**@brief Iterate through Handle-Value(s) list in @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. + * + * @param[in] p_gattc_evt Pointer to event buffer containing @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. + * @note If the buffer contains different event, behavior is undefined. + * @param[in,out] p_iter Iterator, points to @ref ble_gattc_handle_value_t structure that will be filled in with + * the next Handle-Value pair in each iteration. If the function returns other than + * @ref NRF_SUCCESS, it will not be changed. + * - To start iteration, initialize the structure to zero. + * - To continue, pass the value from previous iteration. + * + * \code + * ble_gattc_handle_value_t iter; + * memset(&iter, 0, sizeof(ble_gattc_handle_value_t)); + * while (sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(&ble_evt.evt.gattc_evt, &iter) == NRF_SUCCESS) + * { + * app_handle = iter.handle; + * memcpy(app_value, iter.p_value, ble_evt.evt.gattc_evt.params.char_val_by_uuid_read_rsp.value_len); + * } + * \endcode + * + * @retval ::NRF_SUCCESS Successfully retrieved the next Handle-Value pair. + * @retval ::NRF_ERROR_NOT_FOUND No more Handle-Value pairs available in the list. + */ +__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, + ble_gattc_handle_value_t *p_iter); + +/** @} */ + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION + +__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, + ble_gattc_handle_value_t *p_iter) +{ + uint32_t value_len = p_gattc_evt->params.char_val_by_uuid_read_rsp.value_len; + uint8_t *p_first = p_gattc_evt->params.char_val_by_uuid_read_rsp.handle_value; + uint8_t *p_next = p_iter->p_value ? p_iter->p_value + value_len : p_first; + + if ((p_next - p_first) / (sizeof(uint16_t) + value_len) < p_gattc_evt->params.char_val_by_uuid_read_rsp.count) { + p_iter->handle = (uint16_t)p_next[1] << 8 | p_next[0]; + p_iter->p_value = p_next + sizeof(uint16_t); + return NRF_SUCCESS; + } else { + return NRF_ERROR_NOT_FOUND; + } +} + +#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ + +#ifdef __cplusplus +} +#endif +#endif /* BLE_GATTC_H__ */ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gatts.h b/variants/wio-sdk-wm1110/softdevice/ble_gatts.h new file mode 100644 index 0000000000..dc94957cd1 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_gatts.h @@ -0,0 +1,904 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATTS Generic Attribute Profile (GATT) Server + @{ + @brief Definitions and prototypes for the GATTS interface. + */ + +#ifndef BLE_GATTS_H__ +#define BLE_GATTS_H__ + +#include "ble_err.h" +#include "ble_gap.h" +#include "ble_gatt.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATTS_ENUMERATIONS Enumerations + * @{ */ + +/** + * @brief GATTS API SVC numbers. + */ +enum BLE_GATTS_SVCS { + SD_BLE_GATTS_SERVICE_ADD = BLE_GATTS_SVC_BASE, /**< Add a service. */ + SD_BLE_GATTS_INCLUDE_ADD, /**< Add an included service. */ + SD_BLE_GATTS_CHARACTERISTIC_ADD, /**< Add a characteristic. */ + SD_BLE_GATTS_DESCRIPTOR_ADD, /**< Add a generic attribute. */ + SD_BLE_GATTS_VALUE_SET, /**< Set an attribute value. */ + SD_BLE_GATTS_VALUE_GET, /**< Get an attribute value. */ + SD_BLE_GATTS_HVX, /**< Handle Value Notification or Indication. */ + SD_BLE_GATTS_SERVICE_CHANGED, /**< Perform a Service Changed Indication to one or more peers. */ + SD_BLE_GATTS_RW_AUTHORIZE_REPLY, /**< Reply to an authorization request for a read or write operation on one or more + attributes. */ + SD_BLE_GATTS_SYS_ATTR_SET, /**< Set the persistent system attributes for a connection. */ + SD_BLE_GATTS_SYS_ATTR_GET, /**< Retrieve the persistent system attributes. */ + SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, /**< Retrieve the first valid user handle. */ + SD_BLE_GATTS_ATTR_GET, /**< Retrieve the UUID and/or metadata of an attribute. */ + SD_BLE_GATTS_EXCHANGE_MTU_REPLY /**< Reply to Exchange MTU Request. */ +}; + +/** + * @brief GATT Server Event IDs. + */ +enum BLE_GATTS_EVTS { + BLE_GATTS_EVT_WRITE = BLE_GATTS_EVT_BASE, /**< Write operation performed. \n See + @ref ble_gatts_evt_write_t. */ + BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST, /**< Read/Write Authorization request. \n Reply with + @ref sd_ble_gatts_rw_authorize_reply. \n See @ref ble_gatts_evt_rw_authorize_request_t. + */ + BLE_GATTS_EVT_SYS_ATTR_MISSING, /**< A persistent system attribute access is pending. \n Respond with @ref + sd_ble_gatts_sys_attr_set. \n See @ref ble_gatts_evt_sys_attr_missing_t. */ + BLE_GATTS_EVT_HVC, /**< Handle Value Confirmation. \n See @ref ble_gatts_evt_hvc_t. + */ + BLE_GATTS_EVT_SC_CONFIRM, /**< Service Changed Confirmation. \n No additional event + structure applies. */ + BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. \n Reply with + @ref sd_ble_gatts_exchange_mtu_reply. \n See @ref ble_gatts_evt_exchange_mtu_request_t. + */ + BLE_GATTS_EVT_TIMEOUT, /**< Peer failed to respond to an ATT request in time. \n See @ref + ble_gatts_evt_timeout_t. */ + BLE_GATTS_EVT_HVN_TX_COMPLETE /**< Handle Value Notification transmission complete. \n See @ref + ble_gatts_evt_hvn_tx_complete_t. */ +}; + +/**@brief GATTS Configuration IDs. + * + * IDs that uniquely identify a GATTS configuration. + */ +enum BLE_GATTS_CFGS { + BLE_GATTS_CFG_SERVICE_CHANGED = BLE_GATTS_CFG_BASE, /**< Service changed configuration. */ + BLE_GATTS_CFG_ATTR_TAB_SIZE, /**< Attribute table size configuration. */ + BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM, /**< Service changed CCCD permission configuration. */ +}; + +/** @} */ + +/** @addtogroup BLE_GATTS_DEFINES Defines + * @{ */ + +/** @defgroup BLE_ERRORS_GATTS SVC return values specific to GATTS + * @{ */ +#define BLE_ERROR_GATTS_INVALID_ATTR_TYPE (NRF_GATTS_ERR_BASE + 0x000) /**< Invalid attribute type. */ +#define BLE_ERROR_GATTS_SYS_ATTR_MISSING (NRF_GATTS_ERR_BASE + 0x001) /**< System Attributes missing. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_LENS_MAX Maximum attribute lengths + * @{ */ +#define BLE_GATTS_FIX_ATTR_LEN_MAX (510) /**< Maximum length for fixed length Attribute Values. */ +#define BLE_GATTS_VAR_ATTR_LEN_MAX (512) /**< Maximum length for variable length Attribute Values. */ +/** @} */ + +/** @defgroup BLE_GATTS_SRVC_TYPES GATT Server Service Types + * @{ */ +#define BLE_GATTS_SRVC_TYPE_INVALID 0x00 /**< Invalid Service Type. */ +#define BLE_GATTS_SRVC_TYPE_PRIMARY 0x01 /**< Primary Service. */ +#define BLE_GATTS_SRVC_TYPE_SECONDARY 0x02 /**< Secondary Type. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_TYPES GATT Server Attribute Types + * @{ */ +#define BLE_GATTS_ATTR_TYPE_INVALID 0x00 /**< Invalid Attribute Type. */ +#define BLE_GATTS_ATTR_TYPE_PRIM_SRVC_DECL 0x01 /**< Primary Service Declaration. */ +#define BLE_GATTS_ATTR_TYPE_SEC_SRVC_DECL 0x02 /**< Secondary Service Declaration. */ +#define BLE_GATTS_ATTR_TYPE_INC_DECL 0x03 /**< Include Declaration. */ +#define BLE_GATTS_ATTR_TYPE_CHAR_DECL 0x04 /**< Characteristic Declaration. */ +#define BLE_GATTS_ATTR_TYPE_CHAR_VAL 0x05 /**< Characteristic Value. */ +#define BLE_GATTS_ATTR_TYPE_DESC 0x06 /**< Descriptor. */ +#define BLE_GATTS_ATTR_TYPE_OTHER 0x07 /**< Other, non-GATT specific type. */ +/** @} */ + +/** @defgroup BLE_GATTS_OPS GATT Server Operations + * @{ */ +#define BLE_GATTS_OP_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATTS_OP_WRITE_REQ 0x01 /**< Write Request. */ +#define BLE_GATTS_OP_WRITE_CMD 0x02 /**< Write Command. */ +#define BLE_GATTS_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ +#define BLE_GATTS_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ +#define BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL 0x05 /**< Execute Write Request: Cancel all prepared writes. */ +#define BLE_GATTS_OP_EXEC_WRITE_REQ_NOW 0x06 /**< Execute Write Request: Immediately execute all prepared writes. */ +/** @} */ + +/** @defgroup BLE_GATTS_VLOCS GATT Value Locations + * @{ */ +#define BLE_GATTS_VLOC_INVALID 0x00 /**< Invalid Location. */ +#define BLE_GATTS_VLOC_STACK 0x01 /**< Attribute Value is located in stack memory, no user memory is required. */ +#define BLE_GATTS_VLOC_USER \ + 0x02 /**< Attribute Value is located in user memory. This requires the user to maintain a valid buffer through the lifetime \ + of the attribute, since the stack will read and write directly to the memory using the pointer provided in the APIs. \ + There are no alignment requirements for the buffer. */ +/** @} */ + +/** @defgroup BLE_GATTS_AUTHORIZE_TYPES GATT Server Authorization Types + * @{ */ +#define BLE_GATTS_AUTHORIZE_TYPE_INVALID 0x00 /**< Invalid Type. */ +#define BLE_GATTS_AUTHORIZE_TYPE_READ 0x01 /**< Authorize a Read Operation. */ +#define BLE_GATTS_AUTHORIZE_TYPE_WRITE 0x02 /**< Authorize a Write Request Operation. */ +/** @} */ + +/** @defgroup BLE_GATTS_SYS_ATTR_FLAGS System Attribute Flags + * @{ */ +#define BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS (1 << 0) /**< Restrict system attributes to system services only. */ +#define BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS (1 << 1) /**< Restrict system attributes to user services only. */ +/** @} */ + +/** @defgroup BLE_GATTS_SERVICE_CHANGED Service Changed Inclusion Values + * @{ + */ +#define BLE_GATTS_SERVICE_CHANGED_DEFAULT \ + (1) /**< Default is to include the Service Changed characteristic in the Attribute Table. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_TAB_SIZE Attribute Table size + * @{ + */ +#define BLE_GATTS_ATTR_TAB_SIZE_MIN (248) /**< Minimum Attribute Table size */ +#define BLE_GATTS_ATTR_TAB_SIZE_DEFAULT (1408) /**< Default Attribute Table size. */ +/** @} */ + +/** @defgroup BLE_GATTS_DEFAULTS GATT Server defaults + * @{ + */ +#define BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT \ + 1 /**< Default number of Handle Value Notifications that can be queued for transmission. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATTS_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATTS connection configuration parameters, set with @ref sd_ble_cfg_set. + */ +typedef struct { + uint8_t hvn_tx_queue_size; /**< Minimum guaranteed number of Handle Value Notifications that can be queued for transmission. + The default value is @ref BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT */ +} ble_gatts_conn_cfg_t; + +/**@brief Attribute metadata. */ +typedef struct { + ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */ + ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ + uint8_t vlen : 1; /**< Variable length attribute. */ + uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ + uint8_t rd_auth : 1; /**< Read authorization and value will be requested from the application on every read operation. */ + uint8_t wr_auth : 1; /**< Write authorization will be requested from the application on every Write Request operation (but not + Write Command). */ +} ble_gatts_attr_md_t; + +/**@brief GATT Attribute. */ +typedef struct { + ble_uuid_t const *p_uuid; /**< Pointer to the attribute UUID. */ + ble_gatts_attr_md_t const *p_attr_md; /**< Pointer to the attribute metadata structure. */ + uint16_t init_len; /**< Initial attribute value length in bytes. */ + uint16_t init_offs; /**< Initial attribute value offset in bytes. If different from zero, the first init_offs bytes of the + attribute value will be left uninitialized. */ + uint16_t max_len; /**< Maximum attribute value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */ + uint8_t *p_value; /**< Pointer to the attribute data. Please note that if the @ref BLE_GATTS_VLOC_USER value location is + selected in the attribute metadata, this will have to point to a buffer that remains valid through the + lifetime of the attribute. This excludes usage of automatic variables that may go out of scope or any + other temporary location. The stack may access that memory directly without the application's + knowledge. For writable characteristics, this value must not be a location in flash memory.*/ +} ble_gatts_attr_t; + +/**@brief GATT Attribute Value. */ +typedef struct { + uint16_t len; /**< Length in bytes to be written or read. Length in bytes written or read after successful return.*/ + uint16_t offset; /**< Attribute value offset. */ + uint8_t *p_value; /**< Pointer to where value is stored or will be stored. + If value is stored in user memory, only the attribute length is updated when p_value == NULL. + Set to NULL when reading to obtain the complete length of the attribute value */ +} ble_gatts_value_t; + +/**@brief GATT Characteristic Presentation Format. */ +typedef struct { + uint8_t format; /**< Format of the value, see @ref BLE_GATT_CPF_FORMATS. */ + int8_t exponent; /**< Exponent for integer data types. */ + uint16_t unit; /**< Unit from Bluetooth Assigned Numbers. */ + uint8_t name_space; /**< Namespace from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ + uint16_t desc; /**< Namespace description from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ +} ble_gatts_char_pf_t; + +/**@brief GATT Characteristic metadata. */ +typedef struct { + ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ + ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic Extended Properties. */ + uint8_t const * + p_char_user_desc; /**< Pointer to a UTF-8 encoded string (non-NULL terminated), NULL if the descriptor is not required. */ + uint16_t char_user_desc_max_size; /**< The maximum size in bytes of the user description descriptor. */ + uint16_t char_user_desc_size; /**< The size of the user description, must be smaller or equal to char_user_desc_max_size. */ + ble_gatts_char_pf_t const + *p_char_pf; /**< Pointer to a presentation format structure or NULL if the CPF descriptor is not required. */ + ble_gatts_attr_md_t const + *p_user_desc_md; /**< Attribute metadata for the User Description descriptor, or NULL for default values. */ + ble_gatts_attr_md_t const + *p_cccd_md; /**< Attribute metadata for the Client Characteristic Configuration Descriptor, or NULL for default values. */ + ble_gatts_attr_md_t const + *p_sccd_md; /**< Attribute metadata for the Server Characteristic Configuration Descriptor, or NULL for default values. */ +} ble_gatts_char_md_t; + +/**@brief GATT Characteristic Definition Handles. */ +typedef struct { + uint16_t value_handle; /**< Handle to the characteristic value. */ + uint16_t user_desc_handle; /**< Handle to the User Description descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */ + uint16_t cccd_handle; /**< Handle to the Client Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if + not present. */ + uint16_t sccd_handle; /**< Handle to the Server Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if + not present. */ +} ble_gatts_char_handles_t; + +/**@brief GATT HVx parameters. */ +typedef struct { + uint16_t handle; /**< Characteristic Value Handle. */ + uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ + uint16_t offset; /**< Offset within the attribute value. */ + uint16_t *p_len; /**< Length in bytes to be written, length in bytes written after return. */ + uint8_t const *p_data; /**< Actual data content, use NULL to use the current attribute value. */ +} ble_gatts_hvx_params_t; + +/**@brief GATT Authorization parameters. */ +typedef struct { + uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ + uint8_t update : 1; /**< If set, data supplied in p_data will be used to update the attribute value. + Please note that for @ref BLE_GATTS_AUTHORIZE_TYPE_WRITE operations this bit must always be set, + as the data to be written needs to be stored and later provided by the application. */ + uint16_t offset; /**< Offset of the attribute value being updated. */ + uint16_t len; /**< Length in bytes of the value in p_data pointer, see @ref BLE_GATTS_ATTR_LENS_MAX. */ + uint8_t const *p_data; /**< Pointer to new value used to update the attribute value. */ +} ble_gatts_authorize_params_t; + +/**@brief GATT Read or Write Authorize Reply parameters. */ +typedef struct { + uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ + union { + ble_gatts_authorize_params_t read; /**< Read authorization parameters. */ + ble_gatts_authorize_params_t write; /**< Write authorization parameters. */ + } params; /**< Reply Parameters. */ +} ble_gatts_rw_authorize_reply_params_t; + +/**@brief Service Changed Inclusion configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t service_changed : 1; /**< If 1, include the Service Changed characteristic in the Attribute Table. Default is @ref + BLE_GATTS_SERVICE_CHANGED_DEFAULT. */ +} ble_gatts_cfg_service_changed_t; + +/**@brief Service Changed CCCD permission configuration parameters, set with @ref sd_ble_cfg_set. + * + * @note @ref ble_gatts_attr_md_t::vlen is ignored and should be set to 0. + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - @ref ble_gatts_attr_md_t::write_perm is out of range. + * - @ref ble_gatts_attr_md_t::write_perm is @ref BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS, that is + * not allowed by the Bluetooth Specification. + * - wrong @ref ble_gatts_attr_md_t::read_perm, only @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN is + * allowed by the Bluetooth Specification. + * - wrong @ref ble_gatts_attr_md_t::vloc, only @ref BLE_GATTS_VLOC_STACK is allowed. + * @retval ::NRF_ERROR_NOT_SUPPORTED Security Mode 2 not supported + */ +typedef struct { + ble_gatts_attr_md_t + perm; /**< Permission for Service Changed CCCD. Default is @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN, no authorization. */ +} ble_gatts_cfg_service_changed_cccd_perm_t; + +/**@brief Attribute table size configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: + * - The specified Attribute Table size is too small. + * The minimum acceptable size is defined by @ref BLE_GATTS_ATTR_TAB_SIZE_MIN. + * - The specified Attribute Table size is not a multiple of 4. + */ +typedef struct { + uint32_t attr_tab_size; /**< Attribute table size. Default is @ref BLE_GATTS_ATTR_TAB_SIZE_DEFAULT, minimum is @ref + BLE_GATTS_ATTR_TAB_SIZE_MIN. */ +} ble_gatts_cfg_attr_tab_size_t; + +/**@brief Config structure for GATTS configurations. */ +typedef union { + ble_gatts_cfg_service_changed_t + service_changed; /**< Include service changed characteristic, cfg_id is @ref BLE_GATTS_CFG_SERVICE_CHANGED. */ + ble_gatts_cfg_service_changed_cccd_perm_t service_changed_cccd_perm; /**< Service changed CCCD permission, cfg_id is @ref + BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM. */ + ble_gatts_cfg_attr_tab_size_t attr_tab_size; /**< Attribute table size, cfg_id is @ref BLE_GATTS_CFG_ATTR_TAB_SIZE. */ +} ble_gatts_cfg_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_WRITE. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + ble_uuid_t uuid; /**< Attribute UUID. */ + uint8_t op; /**< Type of write operation, see @ref BLE_GATTS_OPS. */ + uint8_t auth_required; /**< Writing operation deferred due to authorization requirement. Application may use @ref + sd_ble_gatts_value_set to finalize the writing operation. */ + uint16_t offset; /**< Offset for the write operation. */ + uint16_t len; /**< Length of the received data. */ + uint8_t data[1]; /**< Received data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gatts_evt_write_t; + +/**@brief Event substructure for authorized read requests, see @ref ble_gatts_evt_rw_authorize_request_t. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + ble_uuid_t uuid; /**< Attribute UUID. */ + uint16_t offset; /**< Offset for the read operation. */ +} ble_gatts_evt_read_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST. */ +typedef struct { + uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ + union { + ble_gatts_evt_read_t read; /**< Attribute Read Parameters. */ + ble_gatts_evt_write_t write; /**< Attribute Write Parameters. */ + } request; /**< Request Parameters. */ +} ble_gatts_evt_rw_authorize_request_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. */ +typedef struct { + uint8_t hint; /**< Hint (currently unused). */ +} ble_gatts_evt_sys_attr_missing_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_HVC. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ +} ble_gatts_evt_hvc_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST. */ +typedef struct { + uint16_t client_rx_mtu; /**< Client RX MTU size. */ +} ble_gatts_evt_exchange_mtu_request_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ +} ble_gatts_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_HVN_TX_COMPLETE. */ +typedef struct { + uint8_t count; /**< Number of notification transmissions completed. */ +} ble_gatts_evt_hvn_tx_complete_t; + +/**@brief GATTS event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which the event occurred. */ + union { + ble_gatts_evt_write_t write; /**< Write Event Parameters. */ + ble_gatts_evt_rw_authorize_request_t authorize_request; /**< Read or Write Authorize Request Parameters. */ + ble_gatts_evt_sys_attr_missing_t sys_attr_missing; /**< System attributes missing. */ + ble_gatts_evt_hvc_t hvc; /**< Handle Value Confirmation Event Parameters. */ + ble_gatts_evt_exchange_mtu_request_t exchange_mtu_request; /**< Exchange MTU Request Event Parameters. */ + ble_gatts_evt_timeout_t timeout; /**< Timeout Event. */ + ble_gatts_evt_hvn_tx_complete_t hvn_tx_complete; /**< Handle Value Notification transmission complete Event Parameters. */ + } params; /**< Event Parameters. */ +} ble_gatts_evt_t; + +/** @} */ + +/** @addtogroup BLE_GATTS_FUNCTIONS Functions + * @{ */ + +/**@brief Add a service declaration to the Attribute Table. + * + * @note Secondary Services are only relevant in the context of the entity that references them, it is therefore forbidden to + * add a secondary service declaration that is not referenced by another service later in the Attribute Table. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] type Toggles between primary and secondary services, see @ref BLE_GATTS_SRVC_TYPES. + * @param[in] p_uuid Pointer to service UUID. + * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a service declaration. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, Vendor Specific UUIDs need to be present in the table. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type, ble_uuid_t const *p_uuid, uint16_t *p_handle)); + +/**@brief Add an include declaration to the Attribute Table. + * + * @note It is currently only possible to add an include declaration to the last added service (i.e. only sequential population is + * supported at this time). + * + * @note The included service must already be present in the Attribute Table prior to this call. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] service_handle Handle of the service where the included service is to be placed, if @ref BLE_GATT_HANDLE_INVALID + * is used, it will be placed sequentially. + * @param[in] inc_srvc_handle Handle of the included service. + * @param[out] p_include_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added an include declaration. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, handle values need to match previously added services. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. + * @retval ::NRF_ERROR_NOT_SUPPORTED Feature is not supported, service_handle must be that of the last added service. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, self inclusions are not allowed. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + */ +SVCALL(SD_BLE_GATTS_INCLUDE_ADD, uint32_t, + sd_ble_gatts_include_add(uint16_t service_handle, uint16_t inc_srvc_handle, uint16_t *p_include_handle)); + +/**@brief Add a characteristic declaration, a characteristic value declaration and optional characteristic descriptor declarations + * to the Attribute Table. + * + * @note It is currently only possible to add a characteristic to the last added service (i.e. only sequential population is + * supported at this time). + * + * @note Several restrictions apply to the parameters, such as matching permissions between the user description descriptor and + * the writable auxiliaries bits, readable (no security) and writable (selectable) CCCDs and SCCDs and valid presentation format + * values. + * + * @note If no metadata is provided for the optional descriptors, their permissions will be derived from the characteristic + * permissions. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] service_handle Handle of the service where the characteristic is to be placed, if @ref BLE_GATT_HANDLE_INVALID is + * used, it will be placed sequentially. + * @param[in] p_char_md Characteristic metadata. + * @param[in] p_attr_char_value Pointer to the attribute structure corresponding to the characteristic value. + * @param[out] p_handles Pointer to the structure where the assigned handles will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a characteristic. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, service handle, Vendor Specific UUIDs, lengths, and + * permissions need to adhere to the constraints. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + */ +SVCALL(SD_BLE_GATTS_CHARACTERISTIC_ADD, uint32_t, + sd_ble_gatts_characteristic_add(uint16_t service_handle, ble_gatts_char_md_t const *p_char_md, + ble_gatts_attr_t const *p_attr_char_value, ble_gatts_char_handles_t *p_handles)); + +/**@brief Add a descriptor to the Attribute Table. + * + * @note It is currently only possible to add a descriptor to the last added characteristic (i.e. only sequential population is + * supported at this time). + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] char_handle Handle of the characteristic where the descriptor is to be placed, if @ref BLE_GATT_HANDLE_INVALID is + * used, it will be placed sequentially. + * @param[in] p_attr Pointer to the attribute structure. + * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a descriptor. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, characteristic handle, Vendor Specific UUIDs, lengths, and + * permissions need to adhere to the constraints. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a characteristic context is required. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + */ +SVCALL(SD_BLE_GATTS_DESCRIPTOR_ADD, uint32_t, + sd_ble_gatts_descriptor_add(uint16_t char_handle, ble_gatts_attr_t const *p_attr, uint16_t *p_handle)); + +/**@brief Set the value of a given attribute. + * + * @note Values other than system attributes can be set at any time, regardless of whether any active connections exist. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. + * @param[in] handle Attribute handle. + * @param[in,out] p_value Attribute value information. + * + * @retval ::NRF_SUCCESS Successfully set the value of the attribute. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden handle supplied, certain attributes are not modifiable by the application. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. + */ +SVCALL(SD_BLE_GATTS_VALUE_SET, uint32_t, + sd_ble_gatts_value_set(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); + +/**@brief Get the value of a given attribute. + * + * @note If the attribute value is longer than the size of the supplied buffer, + * @ref ble_gatts_value_t::len will return the total attribute value length (excluding offset), + * and not the number of bytes actually returned in @ref ble_gatts_value_t::p_value. + * The application may use this information to allocate a suitable buffer size. + * + * @note When retrieving system attribute values with this function, the connection handle + * may refer to an already disconnected connection. Refer to the documentation of + * @ref sd_ble_gatts_sys_attr_get for further information. + * + * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. + * @param[in] handle Attribute handle. + * @param[in,out] p_value Attribute value information. + * + * @retval ::NRF_SUCCESS Successfully retrieved the value of the attribute. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid attribute offset supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + */ +SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, + sd_ble_gatts_value_get(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); + +/**@brief Notify or Indicate an attribute value. + * + * @details This function checks for the relevant Client Characteristic Configuration descriptor value to verify that the relevant + * operation (notification or indication) has been enabled by the client. It is also able to update the attribute value before + * issuing the PDU, so that the application can atomically perform a value update and a server initiated transaction with a single + * API call. + * + * @note The local attribute value may be updated even if an outgoing packet is not sent to the peer due to an error during + * execution. The Attribute Table has been updated if one of the following error codes is returned: @ref NRF_ERROR_INVALID_STATE, + * @ref NRF_ERROR_BUSY, + * @ref NRF_ERROR_FORBIDDEN, @ref BLE_ERROR_GATTS_SYS_ATTR_MISSING and @ref NRF_ERROR_RESOURCES. + * The caller can check whether the value has been updated by looking at the contents of *(@ref + * ble_gatts_hvx_params_t::p_len). + * + * @note Only one indication procedure can be ongoing per connection at a time. + * If the application tries to indicate an attribute value while another indication procedure is ongoing, + * the function call will return @ref NRF_ERROR_BUSY. + * A @ref BLE_GATTS_EVT_HVC event will be issued as soon as the confirmation arrives from the peer. + * + * @note The number of Handle Value Notifications that can be queued is configured by @ref + * ble_gatts_conn_cfg_t::hvn_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. A @ref + * BLE_GATTS_EVT_HVN_TX_COMPLETE event will be issued as soon as the transmission of the notification is complete. + * + * @note The application can keep track of the available queue element count for notifications by following the procedure + * below: + * - Store initial queue element count in a variable. + * - Decrement the variable, which stores the currently available queue element count, by one when a call to this + * function returns @ref NRF_SUCCESS. + * - Increment the variable, which stores the current available queue element count, by the count variable in @ref + * BLE_GATTS_EVT_HVN_TX_COMPLETE event. + * + * @events + * @event{@ref BLE_GATTS_EVT_HVN_TX_COMPLETE, Notification transmission complete.} + * @event{@ref BLE_GATTS_EVT_HVC, Confirmation received from the peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} + * @mmsc{@ref BLE_GATTS_HVN_MSC} + * @mmsc{@ref BLE_GATTS_HVI_MSC} + * @mmsc{@ref BLE_GATTS_HVX_DISABLED_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in,out] p_hvx_params Pointer to an HVx parameters structure. If @ref ble_gatts_hvx_params_t::p_data + * contains a non-NULL pointer the attribute value will be updated with the contents + * pointed by it before sending the notification or indication. If the attribute value + * is updated, @ref ble_gatts_hvx_params_t::p_len is updated by the SoftDevice to + * contain the number of actual bytes written, else it will be set to 0. + * + * @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute + * value. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: + * - Invalid Connection State + * - Notifications and/or indications not enabled in the CCCD + * - An ATT_MTU exchange is ongoing + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application + * are available to notify and indicate. + * @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and + * indicated. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_FORBIDDEN The connection's current security level is lower than the one required by the write permissions + * of the CCCD associated with this characteristic. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC + * event and retry. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + * @retval ::NRF_ERROR_RESOURCES Too many notifications queued. + * Wait for a @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event and retry. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_gatts_hvx_params_t const *p_hvx_params)); + +/**@brief Indicate the Service Changed attribute value. + * + * @details This call will send a Handle Value Indication to one or more peers connected to inform them that the Attribute + * Table layout has changed. As soon as the peer has confirmed the indication, a @ref BLE_GATTS_EVT_SC_CONFIRM event will + * be issued. + * + * @note Some of the restrictions and limitations that apply to @ref sd_ble_gatts_hvx also apply here. + * + * @events + * @event{@ref BLE_GATTS_EVT_SC_CONFIRM, Confirmation of attribute table change received from peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTS_SC_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] start_handle Start of affected attribute handle range. + * @param[in] end_handle End of affected attribute handle range. + * + * @retval ::NRF_SUCCESS Successfully queued the Service Changed indication for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_NOT_SUPPORTED Service Changed not enabled at initialization. See @ref + * sd_ble_cfg_set and @ref ble_gatts_cfg_service_changed_t. + * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: + * - Invalid Connection State + * - Notifications and/or indications not enabled in the CCCD + * - An ATT_MTU exchange is ongoing + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied, handles must be in the range populated by the + * application. + * @retval ::NRF_ERROR_BUSY Procedure already in progress. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t, + sd_ble_gatts_service_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle)); + +/**@brief Respond to a Read/Write authorization request. + * + * @note This call should only be used as a response to a @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event issued to the application. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_READ_REQ_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_WRITE_REQ_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_rw_authorize_reply_params Pointer to a structure with the attribute provided by the application. + * + * @note @ref ble_gatts_authorize_params_t::p_data is ignored when this function is used to respond + * to a @ref BLE_GATTS_AUTHORIZE_TYPE_READ event if @ref ble_gatts_authorize_params_t::update + * is set to 0. + * + * @retval ::NRF_SUCCESS Successfully queued a response to the peer, and in the case of a write operation, Attribute + * Table updated. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no authorization request pending. + * @retval ::NRF_ERROR_INVALID_PARAM Authorization op invalid, + * handle supplied does not match requested handle, + * or invalid data to be written provided by the application. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_RW_AUTHORIZE_REPLY, uint32_t, + sd_ble_gatts_rw_authorize_reply(uint16_t conn_handle, + ble_gatts_rw_authorize_reply_params_t const *p_rw_authorize_reply_params)); + +/**@brief Update persistent system attribute information. + * + * @details Supply information about persistent system attributes to the stack, + * previously obtained using @ref sd_ble_gatts_sys_attr_get. + * This call is only allowed for active connections, and is usually + * made immediately after a connection is established with an known bonded device, + * often as a response to a @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. + * + * p_sysattrs may point directly to the application's stored copy of the system attributes + * obtained using @ref sd_ble_gatts_sys_attr_get. + * If the pointer is NULL, the system attribute info is initialized, assuming that + * the application does not have any previously saved system attribute data for this device. + * + * @note The state of persistent system attributes is reset upon connection establishment and then remembered for its duration. + * + * @note If this call returns with an error code different from @ref NRF_SUCCESS, the storage of persistent system attributes may + * have been completed only partially. This means that the state of the attribute table is undefined, and the application should + * either provide a new set of attributes using this same call or reset the SoftDevice to return to a known state. + * + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system + * services will be modified. + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user + * services will be modified. + * + * @mscs + * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_UNK_PEER_MSC} + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_sys_attr_data Pointer to a saved copy of system attributes supplied to the stack, or NULL. + * @param[in] len Size of data pointed by p_sys_attr_data, in octets. + * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS + * + * @retval ::NRF_SUCCESS Successfully set the system attribute information. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. + * @retval ::NRF_ERROR_INVALID_DATA Invalid data supplied, the data should be exactly the same as retrieved with @ref + * sd_ble_gatts_sys_attr_get. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GATTS_SYS_ATTR_SET, uint32_t, + sd_ble_gatts_sys_attr_set(uint16_t conn_handle, uint8_t const *p_sys_attr_data, uint16_t len, uint32_t flags)); + +/**@brief Retrieve persistent system attribute information from the stack. + * + * @details This call is used to retrieve information about values to be stored persistently by the application + * during the lifetime of a connection or after it has been terminated. When a new connection is established with the + * same bonded device, the system attribute information retrieved with this function should be restored using using @ref + * sd_ble_gatts_sys_attr_set. If retrieved after disconnection, the data should be read before a new connection established. The + * connection handle for the previous, now disconnected, connection will remain valid until a new one is created to allow this API + * call to refer to it. Connection handles belonging to active connections can be used as well, but care should be taken since the + * system attributes may be written to at any time by the peer during a connection's lifetime. + * + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system + * services will be returned. + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user + * services will be returned. + * + * @mscs + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle of the recently terminated connection. + * @param[out] p_sys_attr_data Pointer to a buffer where updated information about system attributes will be filled in. The + * format of the data is described in @ref BLE_GATTS_SYS_ATTRS_FORMAT. NULL can be provided to obtain the length of the data. + * @param[in,out] p_len Size of application buffer if p_sys_attr_data is not NULL. Unconditionally updated to actual + * length of system attribute data. + * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS + * + * @retval ::NRF_SUCCESS Successfully retrieved the system attribute information. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. + * @retval ::NRF_ERROR_DATA_SIZE The system attribute information did not fit into the provided buffer. + * @retval ::NRF_ERROR_NOT_FOUND No system attributes found. + */ +SVCALL(SD_BLE_GATTS_SYS_ATTR_GET, uint32_t, + sd_ble_gatts_sys_attr_get(uint16_t conn_handle, uint8_t *p_sys_attr_data, uint16_t *p_len, uint32_t flags)); + +/**@brief Retrieve the first valid user attribute handle. + * + * @param[out] p_handle Pointer to an integer where the handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully retrieved the handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, uint32_t, sd_ble_gatts_initial_user_handle_get(uint16_t *p_handle)); + +/**@brief Retrieve the attribute UUID and/or metadata. + * + * @param[in] handle Attribute handle + * @param[out] p_uuid UUID of the attribute. Use NULL to omit this field. + * @param[out] p_md Metadata of the attribute. Use NULL to omit this field. + * + * @retval ::NRF_SUCCESS Successfully retrieved the attribute metadata, + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. Returned when both @c p_uuid and @c p_md are NULL. + * @retval ::NRF_ERROR_NOT_FOUND Attribute was not found. + */ +SVCALL(SD_BLE_GATTS_ATTR_GET, uint32_t, sd_ble_gatts_attr_get(uint16_t handle, ble_uuid_t *p_uuid, ble_gatts_attr_md_t *p_md)); + +/**@brief Reply to an ATT_MTU exchange request by sending an Exchange MTU Response to the client. + * + * @details This function is only used to reply to a @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event. + * + * @details The SoftDevice sets ATT_MTU to the minimum of: + * - The Client RX MTU value from @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, and + * - The Server RX MTU value. + * + * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. + * + * @mscs + * @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] server_rx_mtu Server RX MTU size. + * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration + * used for this connection. + * - The value must be equal to Client RX MTU size given in @ref sd_ble_gattc_exchange_mtu_request + * if an ATT_MTU exchange has already been performed in the other direction. + * + * @retval ::NRF_SUCCESS Successfully sent response to the client. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no ATT_MTU exchange request pending. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid Server RX MTU size supplied. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_EXCHANGE_MTU_REPLY, uint32_t, sd_ble_gatts_exchange_mtu_reply(uint16_t conn_handle, uint16_t server_rx_mtu)); +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GATTS_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_hci.h b/variants/wio-sdk-wm1110/softdevice/ble_hci.h new file mode 100644 index 0000000000..27f85d52ea --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_hci.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ +*/ + +#ifndef BLE_HCI_H__ +#define BLE_HCI_H__ +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup BLE_HCI_STATUS_CODES Bluetooth status codes + * @{ */ + +#define BLE_HCI_STATUS_CODE_SUCCESS 0x00 /**< Success. */ +#define BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND 0x01 /**< Unknown BLE Command. */ +#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02 /**< Unknown Connection Identifier. */ +/*0x03 Hardware Failure +0x04 Page Timeout +*/ +#define BLE_HCI_AUTHENTICATION_FAILURE 0x05 /**< Authentication Failure. */ +#define BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING 0x06 /**< Pin or Key missing. */ +#define BLE_HCI_MEMORY_CAPACITY_EXCEEDED 0x07 /**< Memory Capacity Exceeded. */ +#define BLE_HCI_CONNECTION_TIMEOUT 0x08 /**< Connection Timeout. */ +/*0x09 Connection Limit Exceeded +0x0A Synchronous Connection Limit To A Device Exceeded +0x0B ACL Connection Already Exists*/ +#define BLE_HCI_STATUS_CODE_COMMAND_DISALLOWED 0x0C /**< Command Disallowed. */ +/*0x0D Connection Rejected due to Limited Resources +0x0E Connection Rejected Due To Security Reasons +0x0F Connection Rejected due to Unacceptable BD_ADDR +0x10 Connection Accept Timeout Exceeded +0x11 Unsupported Feature or Parameter Value*/ +#define BLE_HCI_STATUS_CODE_INVALID_BTLE_COMMAND_PARAMETERS 0x12 /**< Invalid BLE Command Parameters. */ +#define BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION 0x13 /**< Remote User Terminated Connection. */ +#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES \ + 0x14 /**< Remote Device Terminated Connection due to low \ + resources.*/ +#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF 0x15 /**< Remote Device Terminated Connection due to power off. */ +#define BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION 0x16 /**< Local Host Terminated Connection. */ +/* +0x17 Repeated Attempts +0x18 Pairing Not Allowed +0x19 Unknown LMP PDU +*/ +#define BLE_HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A /**< Unsupported Remote Feature. */ +/* +0x1B SCO Offset Rejected +0x1C SCO Interval Rejected +0x1D SCO Air Mode Rejected*/ +#define BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS 0x1E /**< Invalid LMP Parameters. */ +#define BLE_HCI_STATUS_CODE_UNSPECIFIED_ERROR 0x1F /**< Unspecified Error. */ +/*0x20 Unsupported LMP Parameter Value +0x21 Role Change Not Allowed +*/ +#define BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT 0x22 /**< LMP Response Timeout. */ +#define BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION 0x23 /**< LMP Error Transaction Collision/LL Procedure Collision. */ +#define BLE_HCI_STATUS_CODE_LMP_PDU_NOT_ALLOWED 0x24 /**< LMP PDU Not Allowed. */ +/*0x25 Encryption Mode Not Acceptable +0x26 Link Key Can Not be Changed +0x27 Requested QoS Not Supported +*/ +#define BLE_HCI_INSTANT_PASSED 0x28 /**< Instant Passed. */ +#define BLE_HCI_PAIRING_WITH_UNIT_KEY_UNSUPPORTED 0x29 /**< Pairing with Unit Key Unsupported. */ +#define BLE_HCI_DIFFERENT_TRANSACTION_COLLISION 0x2A /**< Different Transaction Collision. */ +/* +0x2B Reserved +0x2C QoS Unacceptable Parameter +0x2D QoS Rejected +0x2E Channel Classification Not Supported +0x2F Insufficient Security +*/ +#define BLE_HCI_PARAMETER_OUT_OF_MANDATORY_RANGE 0x30 /**< Parameter Out Of Mandatory Range. */ +/* +0x31 Reserved +0x32 Role Switch Pending +0x33 Reserved +0x34 Reserved Slot Violation +0x35 Role Switch Failed +0x36 Extended Inquiry Response Too Large +0x37 Secure Simple Pairing Not Supported By Host. +0x38 Host Busy - Pairing +0x39 Connection Rejected due to No Suitable Channel Found*/ +#define BLE_HCI_CONTROLLER_BUSY 0x3A /**< Controller Busy. */ +#define BLE_HCI_CONN_INTERVAL_UNACCEPTABLE 0x3B /**< Connection Interval Unacceptable. */ +#define BLE_HCI_DIRECTED_ADVERTISER_TIMEOUT 0x3C /**< Directed Advertisement Timeout. */ +#define BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE 0x3D /**< Connection Terminated due to MIC Failure. */ +#define BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED 0x3E /**< Connection Failed to be Established. */ + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_HCI_H__ + +/** @} */ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h b/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h new file mode 100644 index 0000000000..5f4bd277d3 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h @@ -0,0 +1,495 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_L2CAP Logical Link Control and Adaptation Protocol (L2CAP) + @{ + @brief Definitions and prototypes for the L2CAP interface. + */ + +#ifndef BLE_L2CAP_H__ +#define BLE_L2CAP_H__ + +#include "ble_err.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup BLE_L2CAP_TERMINOLOGY Terminology + * @{ + * @details + * + * L2CAP SDU + * - A data unit that the application can send/receive to/from a peer. + * + * L2CAP PDU + * - A data unit that is exchanged between local and remote L2CAP entities. + * It consists of L2CAP protocol control information and payload fields. + * The payload field can contain an L2CAP SDU or a part of an L2CAP SDU. + * + * L2CAP MTU + * - The maximum length of an L2CAP SDU. + * + * L2CAP MPS + * - The maximum length of an L2CAP PDU payload field. + * + * Credits + * - A value indicating the number of L2CAP PDUs that the receiver of the credit can send to the peer. + * @} */ + +/**@addtogroup BLE_L2CAP_ENUMERATIONS Enumerations + * @{ */ + +/**@brief L2CAP API SVC numbers. */ +enum BLE_L2CAP_SVCS { + SD_BLE_L2CAP_CH_SETUP = BLE_L2CAP_SVC_BASE + 0, /**< Set up an L2CAP channel. */ + SD_BLE_L2CAP_CH_RELEASE = BLE_L2CAP_SVC_BASE + 1, /**< Release an L2CAP channel. */ + SD_BLE_L2CAP_CH_RX = BLE_L2CAP_SVC_BASE + 2, /**< Receive an SDU on an L2CAP channel. */ + SD_BLE_L2CAP_CH_TX = BLE_L2CAP_SVC_BASE + 3, /**< Transmit an SDU on an L2CAP channel. */ + SD_BLE_L2CAP_CH_FLOW_CONTROL = BLE_L2CAP_SVC_BASE + 4, /**< Advanced SDU reception flow control. */ +}; + +/**@brief L2CAP Event IDs. */ +enum BLE_L2CAP_EVTS { + BLE_L2CAP_EVT_CH_SETUP_REQUEST = BLE_L2CAP_EVT_BASE + 0, /**< L2CAP Channel Setup Request event. + \n Reply with @ref sd_ble_l2cap_ch_setup. + \n See @ref ble_l2cap_evt_ch_setup_request_t. */ + BLE_L2CAP_EVT_CH_SETUP_REFUSED = BLE_L2CAP_EVT_BASE + 1, /**< L2CAP Channel Setup Refused event. + \n See @ref ble_l2cap_evt_ch_setup_refused_t. */ + BLE_L2CAP_EVT_CH_SETUP = BLE_L2CAP_EVT_BASE + 2, /**< L2CAP Channel Setup Completed event. + \n See @ref ble_l2cap_evt_ch_setup_t. */ + BLE_L2CAP_EVT_CH_RELEASED = BLE_L2CAP_EVT_BASE + 3, /**< L2CAP Channel Released event. + \n No additional event structure applies. */ + BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED = BLE_L2CAP_EVT_BASE + 4, /**< L2CAP Channel SDU data buffer released event. + \n See @ref ble_l2cap_evt_ch_sdu_buf_released_t. */ + BLE_L2CAP_EVT_CH_CREDIT = BLE_L2CAP_EVT_BASE + 5, /**< L2CAP Channel Credit received. + \n See @ref ble_l2cap_evt_ch_credit_t. */ + BLE_L2CAP_EVT_CH_RX = BLE_L2CAP_EVT_BASE + 6, /**< L2CAP Channel SDU received. + \n See @ref ble_l2cap_evt_ch_rx_t. */ + BLE_L2CAP_EVT_CH_TX = BLE_L2CAP_EVT_BASE + 7, /**< L2CAP Channel SDU transmitted. + \n See @ref ble_l2cap_evt_ch_tx_t. */ +}; + +/** @} */ + +/**@addtogroup BLE_L2CAP_DEFINES Defines + * @{ */ + +/**@brief Maximum number of L2CAP channels per connection. */ +#define BLE_L2CAP_CH_COUNT_MAX (64) + +/**@brief Minimum L2CAP MTU, in bytes. */ +#define BLE_L2CAP_MTU_MIN (23) + +/**@brief Minimum L2CAP MPS, in bytes. */ +#define BLE_L2CAP_MPS_MIN (23) + +/**@brief Invalid CID. */ +#define BLE_L2CAP_CID_INVALID (0x0000) + +/**@brief Default number of credits for @ref sd_ble_l2cap_ch_flow_control. */ +#define BLE_L2CAP_CREDITS_DEFAULT (1) + +/**@defgroup BLE_L2CAP_CH_SETUP_REFUSED_SRCS L2CAP channel setup refused sources + * @{ */ +#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_LOCAL (0x01) /**< Local. */ +#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_REMOTE (0x02) /**< Remote. */ + /** @} */ + +/** @defgroup BLE_L2CAP_CH_STATUS_CODES L2CAP channel status codes + * @{ */ +#define BLE_L2CAP_CH_STATUS_CODE_SUCCESS (0x0000) /**< Success. */ +#define BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED (0x0002) /**< LE_PSM not supported. */ +#define BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES (0x0004) /**< No resources available. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHENTICATION (0x0005) /**< Insufficient authentication. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHORIZATION (0x0006) /**< Insufficient authorization. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC_KEY_SIZE (0x0007) /**< Insufficient encryption key size. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC (0x0008) /**< Insufficient encryption. */ +#define BLE_L2CAP_CH_STATUS_CODE_INVALID_SCID (0x0009) /**< Invalid Source CID. */ +#define BLE_L2CAP_CH_STATUS_CODE_SCID_ALLOCATED (0x000A) /**< Source CID already allocated. */ +#define BLE_L2CAP_CH_STATUS_CODE_UNACCEPTABLE_PARAMS (0x000B) /**< Unacceptable parameters. */ +#define BLE_L2CAP_CH_STATUS_CODE_NOT_UNDERSTOOD \ + (0x8000) /**< Command Reject received instead of LE Credit Based Connection Response. */ +#define BLE_L2CAP_CH_STATUS_CODE_TIMEOUT (0xC000) /**< Operation timed out. */ +/** @} */ + +/** @} */ + +/**@addtogroup BLE_L2CAP_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE L2CAP connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @note These parameters are set per connection, so all L2CAP channels created on this connection + * will have the same parameters. + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - rx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. + * - tx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. + * - ch_count is greater than @ref BLE_L2CAP_CH_COUNT_MAX. + * @retval ::NRF_ERROR_NO_MEM rx_mps or tx_mps is set too high. + */ +typedef struct { + uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall + be able to receive on L2CAP channels on connections with this + configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ + uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall + be able to transmit on L2CAP channels on connections with this + configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ + uint8_t rx_queue_size; /**< Number of SDU data buffers that can be queued for reception per + L2CAP channel. The minimum value is one. */ + uint8_t tx_queue_size; /**< Number of SDU data buffers that can be queued for transmission + per L2CAP channel. The minimum value is one. */ + uint8_t ch_count; /**< Number of L2CAP channels the application can create per connection + with this configuration. The default value is zero, the maximum + value is @ref BLE_L2CAP_CH_COUNT_MAX. + @note if this parameter is set to zero, all other parameters in + @ref ble_l2cap_conn_cfg_t are ignored. */ +} ble_l2cap_conn_cfg_t; + +/**@brief L2CAP channel RX parameters. */ +typedef struct { + uint16_t rx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP shall be able to + receive on this L2CAP channel. + - Must be equal to or greater than @ref BLE_L2CAP_MTU_MIN. */ + uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall be + able to receive on this L2CAP channel. + - Must be equal to or greater than @ref BLE_L2CAP_MPS_MIN. + - Must be equal to or less than @ref ble_l2cap_conn_cfg_t::rx_mps. */ + ble_data_t sdu_buf; /**< SDU data buffer for reception. + - If @ref ble_data_t::p_data is non-NULL, initial credits are + issued to the peer. + - If @ref ble_data_t::p_data is NULL, no initial credits are + issued to the peer. */ +} ble_l2cap_ch_rx_params_t; + +/**@brief L2CAP channel setup parameters. */ +typedef struct { + ble_l2cap_ch_rx_params_t rx_params; /**< L2CAP channel RX parameters. */ + uint16_t le_psm; /**< LE Protocol/Service Multiplexer. Used when requesting + setup of an L2CAP channel, ignored otherwise. */ + uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES. + Used when replying to a setup request of an L2CAP + channel, ignored otherwise. */ +} ble_l2cap_ch_setup_params_t; + +/**@brief L2CAP channel TX parameters. */ +typedef struct { + uint16_t tx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP is able to + transmit on this L2CAP channel. */ + uint16_t peer_mps; /**< The maximum L2CAP PDU payload size, in bytes, that the peer is + able to receive on this L2CAP channel. */ + uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP is able + to transmit on this L2CAP channel. This is effective tx_mps, + selected by the SoftDevice as + MIN( @ref ble_l2cap_ch_tx_params_t::peer_mps, @ref ble_l2cap_conn_cfg_t::tx_mps ) */ + uint16_t credits; /**< Initial credits given by the peer. */ +} ble_l2cap_ch_tx_params_t; + +/**@brief L2CAP Channel Setup Request event. */ +typedef struct { + ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ + uint16_t le_psm; /**< LE Protocol/Service Multiplexer. */ +} ble_l2cap_evt_ch_setup_request_t; + +/**@brief L2CAP Channel Setup Refused event. */ +typedef struct { + uint8_t source; /**< Source, see @ref BLE_L2CAP_CH_SETUP_REFUSED_SRCS */ + uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES */ +} ble_l2cap_evt_ch_setup_refused_t; + +/**@brief L2CAP Channel Setup Completed event. */ +typedef struct { + ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ +} ble_l2cap_evt_ch_setup_t; + +/**@brief L2CAP Channel SDU Data Buffer Released event. */ +typedef struct { + ble_data_t sdu_buf; /**< Returned reception or transmission SDU data buffer. The SoftDevice + returns SDU data buffers supplied by the application, which have + not yet been returned previously via a @ref BLE_L2CAP_EVT_CH_RX or + @ref BLE_L2CAP_EVT_CH_TX event. */ +} ble_l2cap_evt_ch_sdu_buf_released_t; + +/**@brief L2CAP Channel Credit received event. */ +typedef struct { + uint16_t credits; /**< Additional credits given by the peer. */ +} ble_l2cap_evt_ch_credit_t; + +/**@brief L2CAP Channel received SDU event. */ +typedef struct { + uint16_t sdu_len; /**< Total SDU length, in bytes. */ + ble_data_t sdu_buf; /**< SDU data buffer. + @note If there is not enough space in the buffer + (sdu_buf.len < sdu_len) then the rest of the SDU will be + silently discarded by the SoftDevice. */ +} ble_l2cap_evt_ch_rx_t; + +/**@brief L2CAP Channel transmitted SDU event. */ +typedef struct { + ble_data_t sdu_buf; /**< SDU data buffer. */ +} ble_l2cap_evt_ch_tx_t; + +/**@brief L2CAP event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which the event occured. */ + uint16_t local_cid; /**< Local Channel ID of the L2CAP channel, or + @ref BLE_L2CAP_CID_INVALID if not present. */ + union { + ble_l2cap_evt_ch_setup_request_t ch_setup_request; /**< L2CAP Channel Setup Request Event Parameters. */ + ble_l2cap_evt_ch_setup_refused_t ch_setup_refused; /**< L2CAP Channel Setup Refused Event Parameters. */ + ble_l2cap_evt_ch_setup_t ch_setup; /**< L2CAP Channel Setup Completed Event Parameters. */ + ble_l2cap_evt_ch_sdu_buf_released_t ch_sdu_buf_released; /**< L2CAP Channel SDU Data Buffer Released Event Parameters. */ + ble_l2cap_evt_ch_credit_t credit; /**< L2CAP Channel Credit Received Event Parameters. */ + ble_l2cap_evt_ch_rx_t rx; /**< L2CAP Channel SDU Received Event Parameters. */ + ble_l2cap_evt_ch_tx_t tx; /**< L2CAP Channel SDU Transmitted Event Parameters. */ + } params; /**< Event Parameters. */ +} ble_l2cap_evt_t; + +/** @} */ + +/**@addtogroup BLE_L2CAP_FUNCTIONS Functions + * @{ */ + +/**@brief Set up an L2CAP channel. + * + * @details This function is used to: + * - Request setup of an L2CAP channel: sends an LE Credit Based Connection Request packet to a peer. + * - Reply to a setup request of an L2CAP channel (if called in response to a + * @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST event): sends an LE Credit Based Connection + * Response packet to a peer. + * + * @note A call to this function will require the application to keep the SDU data buffer alive + * until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX or + * @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_SETUP, Setup successful.} + * @event{@ref BLE_L2CAP_EVT_CH_SETUP_REFUSED, Setup failed.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_SETUP_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in,out] p_local_cid Pointer to a uint16_t containing Local Channel ID of the L2CAP channel: + * - As input: @ref BLE_L2CAP_CID_INVALID when requesting setup of an L2CAP + * channel or local_cid provided in the @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST + * event when replying to a setup request of an L2CAP channel. + * - As output: local_cid for this channel. + * @param[in] p_params L2CAP channel parameters. + * + * @retval ::NRF_SUCCESS Successfully queued request or response for transmission. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_LENGTH Supplied higher rx_mps than has been configured on this link. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (L2CAP channel already set up). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_RESOURCES The limit has been reached for available L2CAP channels, + * see @ref ble_l2cap_conn_cfg_t::ch_count. + */ +SVCALL(SD_BLE_L2CAP_CH_SETUP, uint32_t, + sd_ble_l2cap_ch_setup(uint16_t conn_handle, uint16_t *p_local_cid, ble_l2cap_ch_setup_params_t const *p_params)); + +/**@brief Release an L2CAP channel. + * + * @details This sends a Disconnection Request packet to a peer. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_RELEASED, Release complete.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_RELEASE_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * + * @retval ::NRF_SUCCESS Successfully queued request for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for the L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + */ +SVCALL(SD_BLE_L2CAP_CH_RELEASE, uint32_t, sd_ble_l2cap_ch_release(uint16_t conn_handle, uint16_t local_cid)); + +/**@brief Receive an SDU on an L2CAP channel. + * + * @details This may issue additional credits to the peer using an LE Flow Control Credit packet. + * + * @note A call to this function will require the application to keep the memory pointed by + * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX + * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::rx_queue_size SDU data buffers + * for reception per L2CAP channel. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_RX, The SDU is received.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_RX_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * @param[in] p_sdu_buf Pointer to the SDU data buffer. + * + * @retval ::NRF_SUCCESS Buffer accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for an L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_RESOURCES Too many SDU data buffers supplied. Wait for a + * @ref BLE_L2CAP_EVT_CH_RX event and retry. + */ +SVCALL(SD_BLE_L2CAP_CH_RX, uint32_t, sd_ble_l2cap_ch_rx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); + +/**@brief Transmit an SDU on an L2CAP channel. + * + * @note A call to this function will require the application to keep the memory pointed by + * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_TX + * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::tx_queue_size SDUs for + * transmission per L2CAP channel. + * + * @note The application can keep track of the available credits for transmission by following + * the procedure below: + * - Store initial credits given by the peer in a variable. + * (Initial credits are provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) + * - Decrement the variable, which stores the currently available credits, by + * ceiling((@ref ble_data_t::len + 2) / tx_mps) when a call to this function returns + * @ref NRF_SUCCESS. (tx_mps is provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) + * - Increment the variable, which stores the currently available credits, by additional + * credits given by the peer in a @ref BLE_L2CAP_EVT_CH_CREDIT event. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_TX, The SDU is transmitted.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_TX_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * @param[in] p_sdu_buf Pointer to the SDU data buffer. + * + * @retval ::NRF_SUCCESS Successfully queued L2CAP SDU for transmission. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for the L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_DATA_SIZE Invalid SDU length supplied, must not be more than + * @ref ble_l2cap_ch_tx_params_t::tx_mtu provided in + * @ref BLE_L2CAP_EVT_CH_SETUP event. + * @retval ::NRF_ERROR_RESOURCES Too many SDUs queued for transmission. Wait for a + * @ref BLE_L2CAP_EVT_CH_TX event and retry. + */ +SVCALL(SD_BLE_L2CAP_CH_TX, uint32_t, sd_ble_l2cap_ch_tx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); + +/**@brief Advanced SDU reception flow control. + * + * @details Adjust the way the SoftDevice issues credits to the peer. + * This may issue additional credits to the peer using an LE Flow Control Credit packet. + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_FLOW_CONTROL_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel or @ref BLE_L2CAP_CID_INVALID to set + * the value that will be used for newly created channels. + * @param[in] credits Number of credits that the SoftDevice will make sure the peer has every + * time it starts using a new reception buffer. + * - @ref BLE_L2CAP_CREDITS_DEFAULT is the default value the SoftDevice will + * use if this function is not called. + * - If set to zero, the SoftDevice will stop issuing credits for new reception + * buffers the application provides or has provided. SDU reception that is + * currently ongoing will be allowed to complete. + * @param[out] p_credits NULL or pointer to a uint16_t. If a valid pointer is provided, it will be + * written by the SoftDevice with the number of credits that is or will be + * available to the peer. If the value written by the SoftDevice is 0 when + * credits parameter was set to 0, the peer will not be able to send more + * data until more credits are provided by calling this function again with + * credits > 0. This parameter is ignored when local_cid is set to + * @ref BLE_L2CAP_CID_INVALID. + * + * @note Application should take care when setting number of credits higher than default value. In + * this case the application must make sure that the SoftDevice always has reception buffers + * available (see @ref sd_ble_l2cap_ch_rx) for that channel. If the SoftDevice does not have + * such buffers available, packets may be NACKed on the Link Layer and all Bluetooth traffic + * on the connection handle may be stalled until the SoftDevice again has an available + * reception buffer. This applies even if the application has used this call to set the + * credits back to default, or zero. + * + * @retval ::NRF_SUCCESS Flow control parameters accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for an L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + */ +SVCALL(SD_BLE_L2CAP_CH_FLOW_CONTROL, uint32_t, + sd_ble_l2cap_ch_flow_control(uint16_t conn_handle, uint16_t local_cid, uint16_t credits, uint16_t *p_credits)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_L2CAP_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_ranges.h b/variants/wio-sdk-wm1110/softdevice/ble_ranges.h new file mode 100644 index 0000000000..2768e49967 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_ranges.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @defgroup ble_ranges Module specific SVC, event and option number subranges + @{ + + @brief Definition of SVC, event and option number subranges for each API module. + + @note + SVCs, event and option numbers are split into subranges for each API module. + Each module receives its entire allocated range of SVC calls, whether implemented or not, + but return BLE_ERROR_NOT_SUPPORTED for unimplemented or undefined calls in its range. + + Note that the symbols BLE__SVC_LAST is the end of the allocated SVC range, + rather than the last SVC function call actually defined and implemented. + + Specific SVC, event and option values are defined in each module's ble_.h file, + which defines names of each individual SVC code based on the range start value. +*/ + +#ifndef BLE_RANGES_H__ +#define BLE_RANGES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_SVC_BASE 0x60 /**< Common BLE SVC base. */ +#define BLE_SVC_LAST 0x6B /**< Common BLE SVC last. */ + +#define BLE_GAP_SVC_BASE 0x6C /**< GAP BLE SVC base. */ +#define BLE_GAP_SVC_LAST 0x9A /**< GAP BLE SVC last. */ + +#define BLE_GATTC_SVC_BASE 0x9B /**< GATTC BLE SVC base. */ +#define BLE_GATTC_SVC_LAST 0xA7 /**< GATTC BLE SVC last. */ + +#define BLE_GATTS_SVC_BASE 0xA8 /**< GATTS BLE SVC base. */ +#define BLE_GATTS_SVC_LAST 0xB7 /**< GATTS BLE SVC last. */ + +#define BLE_L2CAP_SVC_BASE 0xB8 /**< L2CAP BLE SVC base. */ +#define BLE_L2CAP_SVC_LAST 0xBF /**< L2CAP BLE SVC last. */ + +#define BLE_EVT_INVALID 0x00 /**< Invalid BLE Event. */ + +#define BLE_EVT_BASE 0x01 /**< Common BLE Event base. */ +#define BLE_EVT_LAST 0x0F /**< Common BLE Event last. */ + +#define BLE_GAP_EVT_BASE 0x10 /**< GAP BLE Event base. */ +#define BLE_GAP_EVT_LAST 0x2F /**< GAP BLE Event last. */ + +#define BLE_GATTC_EVT_BASE 0x30 /**< GATTC BLE Event base. */ +#define BLE_GATTC_EVT_LAST 0x4F /**< GATTC BLE Event last. */ + +#define BLE_GATTS_EVT_BASE 0x50 /**< GATTS BLE Event base. */ +#define BLE_GATTS_EVT_LAST 0x6F /**< GATTS BLE Event last. */ + +#define BLE_L2CAP_EVT_BASE 0x70 /**< L2CAP BLE Event base. */ +#define BLE_L2CAP_EVT_LAST 0x8F /**< L2CAP BLE Event last. */ + +#define BLE_OPT_INVALID 0x00 /**< Invalid BLE Option. */ + +#define BLE_OPT_BASE 0x01 /**< Common BLE Option base. */ +#define BLE_OPT_LAST 0x1F /**< Common BLE Option last. */ + +#define BLE_GAP_OPT_BASE 0x20 /**< GAP BLE Option base. */ +#define BLE_GAP_OPT_LAST 0x3F /**< GAP BLE Option last. */ + +#define BLE_GATT_OPT_BASE 0x40 /**< GATT BLE Option base. */ +#define BLE_GATT_OPT_LAST 0x5F /**< GATT BLE Option last. */ + +#define BLE_GATTC_OPT_BASE 0x60 /**< GATTC BLE Option base. */ +#define BLE_GATTC_OPT_LAST 0x7F /**< GATTC BLE Option last. */ + +#define BLE_GATTS_OPT_BASE 0x80 /**< GATTS BLE Option base. */ +#define BLE_GATTS_OPT_LAST 0x9F /**< GATTS BLE Option last. */ + +#define BLE_L2CAP_OPT_BASE 0xA0 /**< L2CAP BLE Option base. */ +#define BLE_L2CAP_OPT_LAST 0xBF /**< L2CAP BLE Option last. */ + +#define BLE_CFG_INVALID 0x00 /**< Invalid BLE configuration. */ + +#define BLE_CFG_BASE 0x01 /**< Common BLE configuration base. */ +#define BLE_CFG_LAST 0x1F /**< Common BLE configuration last. */ + +#define BLE_CONN_CFG_BASE 0x20 /**< BLE connection configuration base. */ +#define BLE_CONN_CFG_LAST 0x3F /**< BLE connection configuration last. */ + +#define BLE_GAP_CFG_BASE 0x40 /**< GAP BLE configuration base. */ +#define BLE_GAP_CFG_LAST 0x5F /**< GAP BLE configuration last. */ + +#define BLE_GATT_CFG_BASE 0x60 /**< GATT BLE configuration base. */ +#define BLE_GATT_CFG_LAST 0x7F /**< GATT BLE configuration last. */ + +#define BLE_GATTC_CFG_BASE 0x80 /**< GATTC BLE configuration base. */ +#define BLE_GATTC_CFG_LAST 0x9F /**< GATTC BLE configuration last. */ + +#define BLE_GATTS_CFG_BASE 0xA0 /**< GATTS BLE configuration base. */ +#define BLE_GATTS_CFG_LAST 0xBF /**< GATTS BLE configuration last. */ + +#define BLE_L2CAP_CFG_BASE 0xC0 /**< L2CAP BLE configuration base. */ +#define BLE_L2CAP_CFG_LAST 0xDF /**< L2CAP BLE configuration last. */ + +#ifdef __cplusplus +} +#endif +#endif /* BLE_RANGES_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_types.h b/variants/wio-sdk-wm1110/softdevice/ble_types.h new file mode 100644 index 0000000000..db3656cfdd --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/ble_types.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @defgroup ble_types Common types and macro definitions + @{ + + @brief Common types and macro definitions for the BLE SoftDevice. + */ + +#ifndef BLE_TYPES_H__ +#define BLE_TYPES_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_TYPES_DEFINES Defines + * @{ */ + +/** @defgroup BLE_CONN_HANDLES BLE Connection Handles + * @{ */ +#define BLE_CONN_HANDLE_INVALID 0xFFFF /**< Invalid Connection Handle. */ +#define BLE_CONN_HANDLE_ALL 0xFFFE /**< Applies to all Connection Handles. */ +/** @} */ + +/** @defgroup BLE_UUID_VALUES Assigned Values for BLE UUIDs + * @{ */ +/* Generic UUIDs, applicable to all services */ +#define BLE_UUID_UNKNOWN 0x0000 /**< Reserved UUID. */ +#define BLE_UUID_SERVICE_PRIMARY 0x2800 /**< Primary Service. */ +#define BLE_UUID_SERVICE_SECONDARY 0x2801 /**< Secondary Service. */ +#define BLE_UUID_SERVICE_INCLUDE 0x2802 /**< Include. */ +#define BLE_UUID_CHARACTERISTIC 0x2803 /**< Characteristic. */ +#define BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP 0x2900 /**< Characteristic Extended Properties Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_USER_DESC 0x2901 /**< Characteristic User Description Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG 0x2902 /**< Client Characteristic Configuration Descriptor. */ +#define BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG 0x2903 /**< Server Characteristic Configuration Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT 0x2904 /**< Characteristic Presentation Format Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_AGGREGATE_FORMAT 0x2905 /**< Characteristic Aggregate Format Descriptor. */ +/* GATT specific UUIDs */ +#define BLE_UUID_GATT 0x1801 /**< Generic Attribute Profile. */ +#define BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED 0x2A05 /**< Service Changed Characteristic. */ +/* GAP specific UUIDs */ +#define BLE_UUID_GAP 0x1800 /**< Generic Access Profile. */ +#define BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME 0x2A00 /**< Device Name Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_APPEARANCE 0x2A01 /**< Appearance Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_RECONN_ADDR 0x2A03 /**< Reconnection Address Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_PPCP 0x2A04 /**< Peripheral Preferred Connection Parameters Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_CAR 0x2AA6 /**< Central Address Resolution Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_RPA_ONLY 0x2AC9 /**< Resolvable Private Address Only Characteristic. */ +/** @} */ + +/** @defgroup BLE_UUID_TYPES Types of UUID + * @{ */ +#define BLE_UUID_TYPE_UNKNOWN 0x00 /**< Invalid UUID type. */ +#define BLE_UUID_TYPE_BLE 0x01 /**< Bluetooth SIG UUID (16-bit). */ +#define BLE_UUID_TYPE_VENDOR_BEGIN 0x02 /**< Vendor UUID types start at this index (128-bit). */ +/** @} */ + +/** @defgroup BLE_APPEARANCES Bluetooth Appearance values + * @note Retrieved from + * http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml + * @{ */ +#define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */ +#define BLE_APPEARANCE_GENERIC_PHONE 64 /**< Generic Phone. */ +#define BLE_APPEARANCE_GENERIC_COMPUTER 128 /**< Generic Computer. */ +#define BLE_APPEARANCE_GENERIC_WATCH 192 /**< Generic Watch. */ +#define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /**< Watch: Sports Watch. */ +#define BLE_APPEARANCE_GENERIC_CLOCK 256 /**< Generic Clock. */ +#define BLE_APPEARANCE_GENERIC_DISPLAY 320 /**< Generic Display. */ +#define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /**< Generic Remote Control. */ +#define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /**< Generic Eye-glasses. */ +#define BLE_APPEARANCE_GENERIC_TAG 512 /**< Generic Tag. */ +#define BLE_APPEARANCE_GENERIC_KEYRING 576 /**< Generic Keyring. */ +#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /**< Generic Media Player. */ +#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /**< Generic Barcode Scanner. */ +#define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /**< Generic Thermometer. */ +#define BLE_APPEARANCE_THERMOMETER_EAR 769 /**< Thermometer: Ear. */ +#define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /**< Generic Heart rate Sensor. */ +#define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /**< Heart Rate Sensor: Heart Rate Belt. */ +#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /**< Generic Blood Pressure. */ +#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /**< Blood Pressure: Arm. */ +#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /**< Blood Pressure: Wrist. */ +#define BLE_APPEARANCE_GENERIC_HID 960 /**< Human Interface Device (HID). */ +#define BLE_APPEARANCE_HID_KEYBOARD 961 /**< Keyboard (HID Subtype). */ +#define BLE_APPEARANCE_HID_MOUSE 962 /**< Mouse (HID Subtype). */ +#define BLE_APPEARANCE_HID_JOYSTICK 963 /**< Joystick (HID Subtype). */ +#define BLE_APPEARANCE_HID_GAMEPAD 964 /**< Gamepad (HID Subtype). */ +#define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /**< Digitizer Tablet (HID Subtype). */ +#define BLE_APPEARANCE_HID_CARD_READER 966 /**< Card Reader (HID Subtype). */ +#define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /**< Digital Pen (HID Subtype). */ +#define BLE_APPEARANCE_HID_BARCODE 968 /**< Barcode Scanner (HID Subtype). */ +#define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /**< Generic Glucose Meter. */ +#define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /**< Generic Running Walking Sensor. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /**< Running Walking Sensor: In-Shoe. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /**< Running Walking Sensor: On-Shoe. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /**< Running Walking Sensor: On-Hip. */ +#define BLE_APPEARANCE_GENERIC_CYCLING 1152 /**< Generic Cycling. */ +#define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /**< Cycling: Cycling Computer. */ +#define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /**< Cycling: Speed Sensor. */ +#define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /**< Cycling: Cadence Sensor. */ +#define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /**< Cycling: Power Sensor. */ +#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /**< Cycling: Speed and Cadence Sensor. */ +#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /**< Generic Pulse Oximeter. */ +#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /**< Fingertip (Pulse Oximeter subtype). */ +#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /**< Wrist Worn(Pulse Oximeter subtype). */ +#define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /**< Generic Weight Scale. */ +#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /**< Generic Outdoor Sports Activity. */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /**< Location Display Device (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP \ + 5186 /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /**< Location Pod (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD \ + 5188 /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */ +/** @} */ + +/** @brief Set .type and .uuid fields of ble_uuid_struct to specified UUID value. */ +#define BLE_UUID_BLE_ASSIGN(instance, value) \ + do { \ + instance.type = BLE_UUID_TYPE_BLE; \ + instance.uuid = value; \ + } while (0) + +/** @brief Copy type and uuid members from src to dst ble_uuid_t pointer. Both pointers must be valid/non-null. */ +#define BLE_UUID_COPY_PTR(dst, src) \ + do { \ + (dst)->type = (src)->type; \ + (dst)->uuid = (src)->uuid; \ + } while (0) + +/** @brief Copy type and uuid members from src to dst ble_uuid_t struct. */ +#define BLE_UUID_COPY_INST(dst, src) \ + do { \ + (dst).type = (src).type; \ + (dst).uuid = (src).uuid; \ + } while (0) + +/** @brief Compare for equality both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ +#define BLE_UUID_EQ(p_uuid1, p_uuid2) (((p_uuid1)->type == (p_uuid2)->type) && ((p_uuid1)->uuid == (p_uuid2)->uuid)) + +/** @brief Compare for difference both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ +#define BLE_UUID_NEQ(p_uuid1, p_uuid2) (((p_uuid1)->type != (p_uuid2)->type) || ((p_uuid1)->uuid != (p_uuid2)->uuid)) + +/** @} */ + +/** @addtogroup BLE_TYPES_STRUCTURES Structures + * @{ */ + +/** @brief 128 bit UUID values. */ +typedef struct { + uint8_t uuid128[16]; /**< Little-Endian UUID bytes. */ +} ble_uuid128_t; + +/** @brief Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */ +typedef struct { + uint16_t uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */ + uint8_t + type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is @ref BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */ +} ble_uuid_t; + +/**@brief Data structure. */ +typedef struct { + uint8_t *p_data; /**< Pointer to the data buffer provided to/from the application. */ + uint16_t len; /**< Length of the data buffer, in bytes. */ +} ble_data_t; + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* BLE_TYPES_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h b/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h new file mode 100644 index 0000000000..4e0bd752ab --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2014 - 2017, Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_mbr_api Master Boot Record API + @{ + + @brief APIs for updating SoftDevice and BootLoader + +*/ + +#ifndef NRF_MBR_H__ +#define NRF_MBR_H__ + +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup NRF_MBR_DEFINES Defines + * @{ */ + +/**@brief MBR SVC Base number. */ +#define MBR_SVC_BASE (0x18) + +/**@brief Page size in words. */ +#define MBR_PAGE_SIZE_IN_WORDS (1024) + +/** @brief The size that must be reserved for the MBR when a SoftDevice is written to flash. +This is the offset where the first byte of the SoftDevice hex file is written. */ +#define MBR_SIZE (0x1000) + +/** @brief Location (in the flash memory) of the bootloader address. */ +#define MBR_BOOTLOADER_ADDR (0xFF8) + +/** @brief Location (in UICR) of the bootloader address. */ +#define MBR_UICR_BOOTLOADER_ADDR (&(NRF_UICR->NRFFW[0])) + +/** @brief Location (in the flash memory) of the address of the MBR parameter page. */ +#define MBR_PARAM_PAGE_ADDR (0xFFC) + +/** @brief Location (in UICR) of the address of the MBR parameter page. */ +#define MBR_UICR_PARAM_PAGE_ADDR (&(NRF_UICR->NRFFW[1])) + +/** @} */ + +/** @addtogroup NRF_MBR_ENUMS Enumerations + * @{ */ + +/**@brief nRF Master Boot Record API SVC numbers. */ +enum NRF_MBR_SVCS { + SD_MBR_COMMAND = MBR_SVC_BASE, /**< ::sd_mbr_command */ +}; + +/**@brief Possible values for ::sd_mbr_command_t.command */ +enum NRF_MBR_COMMANDS { + SD_MBR_COMMAND_COPY_BL, /**< Copy a new BootLoader. @see ::sd_mbr_command_copy_bl_t*/ + SD_MBR_COMMAND_COPY_SD, /**< Copy a new SoftDevice. @see ::sd_mbr_command_copy_sd_t*/ + SD_MBR_COMMAND_INIT_SD, /**< Initialize forwarding interrupts to SD, and run reset function in SD. Does not require any + parameters in ::sd_mbr_command_t params.*/ + SD_MBR_COMMAND_COMPARE, /**< This command works like memcmp. @see ::sd_mbr_command_compare_t*/ + SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET, /**< Change the address the MBR starts after a reset. @see + ::sd_mbr_command_vector_table_base_set_t*/ + SD_MBR_COMMAND_RESERVED, + SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET, /**< Start forwarding all interrupts to this address. @see + ::sd_mbr_command_irq_forward_address_set_t*/ +}; + +/** @} */ + +/** @addtogroup NRF_MBR_TYPES Types + * @{ */ + +/**@brief This command copies part of a new SoftDevice + * + * The destination area is erased before copying. + * If dst is in the middle of a flash page, that whole flash page will be erased. + * If (dst+len) is in the middle of a flash page, that whole flash page will be erased. + * + * The user of this function is responsible for setting the BPROT registers. + * + * @retval ::NRF_SUCCESS indicates that the contents of the memory blocks where copied correctly. + * @retval ::NRF_ERROR_INTERNAL indicates that the contents of the memory blocks where not verified correctly after copying. + */ +typedef struct { + uint32_t *src; /**< Pointer to the source of data to be copied.*/ + uint32_t *dst; /**< Pointer to the destination where the content is to be copied.*/ + uint32_t len; /**< Number of 32 bit words to copy. Must be a multiple of @ref MBR_PAGE_SIZE_IN_WORDS words.*/ +} sd_mbr_command_copy_sd_t; + +/**@brief This command works like memcmp, but takes the length in words. + * + * @retval ::NRF_SUCCESS indicates that the contents of both memory blocks are equal. + * @retval ::NRF_ERROR_NULL indicates that the contents of the memory blocks are not equal. + */ +typedef struct { + uint32_t *ptr1; /**< Pointer to block of memory. */ + uint32_t *ptr2; /**< Pointer to block of memory. */ + uint32_t len; /**< Number of 32 bit words to compare.*/ +} sd_mbr_command_compare_t; + +/**@brief This command copies a new BootLoader. + * + * The MBR assumes that either @ref MBR_BOOTLOADER_ADDR or @ref MBR_UICR_BOOTLOADER_ADDR is set to + * the address where the bootloader will be copied. If both addresses are set, the MBR will prioritize + * @ref MBR_BOOTLOADER_ADDR. + * + * The bootloader destination is erased by this function. + * If (destination+bl_len) is in the middle of a flash page, that whole flash page will be erased. + * + * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, + * see @ref sd_mbr_command. + * + * This command will use the flash protect peripheral (BPROT or ACL) to protect the flash that is + * not intended to be written. + * + * On success, this function will not return. It will start the new bootloader from reset-vector as normal. + * + * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. + * @retval ::NRF_ERROR_FORBIDDEN if the bootloader address is not set. + * @retval ::NRF_ERROR_INVALID_LENGTH if parameters attempts to read or write outside flash area. + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. + */ +typedef struct { + uint32_t *bl_src; /**< Pointer to the source of the bootloader to be be copied.*/ + uint32_t bl_len; /**< Number of 32 bit words to copy for BootLoader. */ +} sd_mbr_command_copy_bl_t; + +/**@brief Change the address the MBR starts after a reset + * + * Once this function has been called, this address is where the MBR will start to forward + * interrupts to after a reset. + * + * To restore default forwarding, this function should be called with @ref address set to 0. If a + * bootloader is present, interrupts will be forwarded to the bootloader. If not, interrupts will + * be forwarded to the SoftDevice. + * + * The location of a bootloader can be specified in @ref MBR_BOOTLOADER_ADDR or + * @ref MBR_UICR_BOOTLOADER_ADDR. If both addresses are set, the MBR will prioritize + * @ref MBR_BOOTLOADER_ADDR. + * + * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, + * see @ref sd_mbr_command. + * + * On success, this function will not return. It will reset the device. + * + * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. + * @retval ::NRF_ERROR_INVALID_ADDR if parameter address is outside of the flash size. + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. + */ +typedef struct { + uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ +} sd_mbr_command_vector_table_base_set_t; + +/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the MBR + * + * Unlike sd_mbr_command_vector_table_base_set_t, this function does not reset, and it does not + * change where the MBR starts after reset. + * + * @retval ::NRF_SUCCESS + */ +typedef struct { + uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ +} sd_mbr_command_irq_forward_address_set_t; + +/**@brief Input structure containing data used when calling ::sd_mbr_command + * + * Depending on what command value that is set, the corresponding params value type must also be + * set. See @ref NRF_MBR_COMMANDS for command types and corresponding params value type. If command + * @ref SD_MBR_COMMAND_INIT_SD is set, it is not necessary to set any values under params. + */ +typedef struct { + uint32_t command; /**< Type of command to be issued. See @ref NRF_MBR_COMMANDS. */ + union { + sd_mbr_command_copy_sd_t copy_sd; /**< Parameters for copy SoftDevice.*/ + sd_mbr_command_compare_t compare; /**< Parameters for verify.*/ + sd_mbr_command_copy_bl_t copy_bl; /**< Parameters for copy BootLoader. Requires parameter page. */ + sd_mbr_command_vector_table_base_set_t base_set; /**< Parameters for vector table base set. Requires parameter page.*/ + sd_mbr_command_irq_forward_address_set_t irq_forward_address_set; /**< Parameters for irq forward address set*/ + } params; /**< Command parameters. */ +} sd_mbr_command_t; + +/** @} */ + +/** @addtogroup NRF_MBR_FUNCTIONS Functions + * @{ */ + +/**@brief Issue Master Boot Record commands + * + * Commands used when updating a SoftDevice and bootloader. + * + * The @ref SD_MBR_COMMAND_COPY_BL and @ref SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET requires + * parameters to be retained by the MBR when resetting the IC. This is done in a separate flash + * page. The location of the flash page should be provided by the application in either + * @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR. If both addresses are set, the MBR + * will prioritize @ref MBR_PARAM_PAGE_ADDR. This page will be cleared by the MBR and is used to + * store the command before reset. When an address is specified, the page it refers to must not be + * used by the application. If no address is provided by the application, i.e. both + * @ref MBR_PARAM_PAGE_ADDR and @ref MBR_UICR_PARAM_PAGE_ADDR is 0xFFFFFFFF, MBR commands which use + * flash will be unavailable and return @ref NRF_ERROR_NO_MEM. + * + * @param[in] param Pointer to a struct describing the command. + * + * @note For a complete set of return values, see ::sd_mbr_command_copy_sd_t, + * ::sd_mbr_command_copy_bl_t, ::sd_mbr_command_compare_t, + * ::sd_mbr_command_vector_table_base_set_t, ::sd_mbr_command_irq_forward_address_set_t + * + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page provided + * @retval ::NRF_ERROR_INVALID_PARAM if an invalid command is given. + */ +SVCALL(SD_MBR_COMMAND, uint32_t, sd_mbr_command(sd_mbr_command_t *param)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_MBR_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error.h b/variants/wio-sdk-wm1110/softdevice/nrf_error.h new file mode 100644 index 0000000000..fb2831e191 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_error.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_error SoftDevice Global Error Codes + @{ + + @brief Global Error definitions +*/ + +/* Header guard */ +#ifndef NRF_ERROR_H__ +#define NRF_ERROR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup NRF_ERRORS_BASE Error Codes Base number definitions + * @{ */ +#define NRF_ERROR_BASE_NUM (0x0) ///< Global error base +#define NRF_ERROR_SDM_BASE_NUM (0x1000) ///< SDM error base +#define NRF_ERROR_SOC_BASE_NUM (0x2000) ///< SoC error base +#define NRF_ERROR_STK_BASE_NUM (0x3000) ///< STK error base +/** @} */ + +#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command +#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing +#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled +#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error +#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation +#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found +#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported +#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter +#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state +#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length +#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags +#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data +#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Invalid Data size +#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out +#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer +#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation +#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address +#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy +#define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded. +#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h b/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h new file mode 100644 index 0000000000..2fd6210576 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup nrf_sdm_api + @{ + @defgroup nrf_sdm_error SoftDevice Manager Error Codes + @{ + + @brief Error definitions for the SDM API +*/ + +/* Header guard */ +#ifndef NRF_ERROR_SDM_H__ +#define NRF_ERROR_SDM_H__ + +#include "nrf_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN (NRF_ERROR_SDM_BASE_NUM + 0) ///< Unknown LFCLK source. +#define NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION \ + (NRF_ERROR_SDM_BASE_NUM + 1) ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having + ///< enabled SoftDevice interrupts). +#define NRF_ERROR_SDM_INCORRECT_CLENR0 \ + (NRF_ERROR_SDM_BASE_NUM + 2) ///< Incorrect CLENR0 (can be caused by erroneous SoftDevice flashing). + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_SDM_H__ + +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h b/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h new file mode 100644 index 0000000000..cbd0ba8ac4 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup nrf_soc_api + @{ + @defgroup nrf_soc_error SoC Library Error Codes + @{ + + @brief Error definitions for the SoC library + +*/ + +/* Header guard */ +#ifndef NRF_ERROR_SOC_H__ +#define NRF_ERROR_SOC_H__ + +#include "nrf_error.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* Mutex Errors */ +#define NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN (NRF_ERROR_SOC_BASE_NUM + 0) ///< Mutex already taken + +/* NVIC errors */ +#define NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE (NRF_ERROR_SOC_BASE_NUM + 1) ///< NVIC interrupt not available +#define NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED (NRF_ERROR_SOC_BASE_NUM + 2) ///< NVIC interrupt priority not allowed +#define NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 3) ///< NVIC should not return + +/* Power errors */ +#define NRF_ERROR_SOC_POWER_MODE_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 4) ///< Power mode unknown +#define NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 5) ///< Power POF threshold unknown +#define NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 6) ///< Power off should not return + +/* Rand errors */ +#define NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES (NRF_ERROR_SOC_BASE_NUM + 7) ///< RAND not enough values + +/* PPI errors */ +#define NRF_ERROR_SOC_PPI_INVALID_CHANNEL (NRF_ERROR_SOC_BASE_NUM + 8) ///< Invalid PPI Channel +#define NRF_ERROR_SOC_PPI_INVALID_GROUP (NRF_ERROR_SOC_BASE_NUM + 9) ///< Invalid PPI Group + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_SOC_H__ +/** + @} + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h b/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h new file mode 100644 index 0000000000..d4ab204d96 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h @@ -0,0 +1,449 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup nrf_nvic_api SoftDevice NVIC API + * @{ + * + * @note In order to use this module, the following code has to be added to a .c file: + * \code + * nrf_nvic_state_t nrf_nvic_state = {0}; + * \endcode + * + * @note Definitions and declarations starting with __ (double underscore) in this header file are + * not intended for direct use by the application. + * + * @brief APIs for the accessing NVIC when using a SoftDevice. + * + */ + +#ifndef NRF_NVIC_H__ +#define NRF_NVIC_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup NRF_NVIC_DEFINES Defines + * @{ */ + +/**@defgroup NRF_NVIC_ISER_DEFINES SoftDevice NVIC internal definitions + * @{ */ + +#define __NRF_NVIC_NVMC_IRQn \ + (30) /**< The peripheral ID of the NVMC. IRQ numbers are used to identify peripherals, but the NVMC doesn't have an IRQ \ + number in the MDK. */ + +#define __NRF_NVIC_ISER_COUNT (2) /**< The number of ISER/ICER registers in the NVIC that are used. */ + +/**@brief Interrupt priority levels used by the SoftDevice. */ +#define __NRF_NVIC_SD_IRQ_PRIOS \ + ((uint8_t)((1U << 0) /**< Priority level high .*/ \ + | (1U << 1) /**< Priority level medium. */ \ + | (1U << 4) /**< Priority level low. */ \ + )) + +/**@brief Interrupt priority levels available to the application. */ +#define __NRF_NVIC_APP_IRQ_PRIOS ((uint8_t)~__NRF_NVIC_SD_IRQ_PRIOS) + +/**@brief Interrupts used by the SoftDevice, with IRQn in the range 0-31. */ +#define __NRF_NVIC_SD_IRQS_0 \ + ((uint32_t)((1U << POWER_CLOCK_IRQn) | (1U << RADIO_IRQn) | (1U << RTC0_IRQn) | (1U << TIMER0_IRQn) | (1U << RNG_IRQn) | \ + (1U << ECB_IRQn) | (1U << CCM_AAR_IRQn) | (1U << TEMP_IRQn) | (1U << __NRF_NVIC_NVMC_IRQn) | \ + (1U << (uint32_t)SWI5_IRQn))) + +/**@brief Interrupts used by the SoftDevice, with IRQn in the range 32-63. */ +#define __NRF_NVIC_SD_IRQS_1 ((uint32_t)0) + +/**@brief Interrupts available for to application, with IRQn in the range 0-31. */ +#define __NRF_NVIC_APP_IRQS_0 (~__NRF_NVIC_SD_IRQS_0) + +/**@brief Interrupts available for to application, with IRQn in the range 32-63. */ +#define __NRF_NVIC_APP_IRQS_1 (~__NRF_NVIC_SD_IRQS_1) + +/**@} */ + +/**@} */ + +/**@addtogroup NRF_NVIC_VARIABLES Variables + * @{ */ + +/**@brief Type representing the state struct for the SoftDevice NVIC module. */ +typedef struct { + uint32_t volatile __irq_masks[__NRF_NVIC_ISER_COUNT]; /**< IRQs enabled by the application in the NVIC. */ + uint32_t volatile __cr_flag; /**< Non-zero if already in a critical region */ +} nrf_nvic_state_t; + +/**@brief Variable keeping the state for the SoftDevice NVIC module. This must be declared in an + * application source file. */ +extern nrf_nvic_state_t nrf_nvic_state; + +/**@} */ + +/**@addtogroup NRF_NVIC_INTERNAL_FUNCTIONS SoftDevice NVIC internal functions + * @{ */ + +/**@brief Disables IRQ interrupts globally, including the SoftDevice's interrupts. + * + * @retval The value of PRIMASK prior to disabling the interrupts. + */ +__STATIC_INLINE int __sd_nvic_irq_disable(void); + +/**@brief Enables IRQ interrupts globally, including the SoftDevice's interrupts. + */ +__STATIC_INLINE void __sd_nvic_irq_enable(void); + +/**@brief Checks if IRQn is available to application + * @param[in] IRQn IRQ to check + * + * @retval 1 (true) if the IRQ to check is available to the application + */ +__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn); + +/**@brief Checks if priority is available to application + * @param[in] priority priority to check + * + * @retval 1 (true) if the priority to check is available to the application + */ +__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority); + +/**@} */ + +/**@addtogroup NRF_NVIC_FUNCTIONS SoftDevice NVIC public functions + * @{ */ + +/**@brief Enable External Interrupt. + * @note Corresponds to NVIC_EnableIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_EnableIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt was enabled. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt has a priority not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn); + +/**@brief Disable External Interrupt. + * @note Corresponds to NVIC_DisableIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_DisableIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt was disabled. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn); + +/**@brief Get Pending Interrupt. + * @note Corresponds to NVIC_GetPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_GetPendingIRQ documentation in CMSIS. + * @param[out] p_pending_irq Return value from NVIC_GetPendingIRQ. + * + * @retval ::NRF_SUCCESS The interrupt is available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq); + +/**@brief Set Pending Interrupt. + * @note Corresponds to NVIC_SetPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_SetPendingIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt is set pending. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn); + +/**@brief Clear Pending Interrupt. + * @note Corresponds to NVIC_ClearPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_ClearPendingIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt pending flag is cleared. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn); + +/**@brief Set Interrupt Priority. + * @note Corresponds to NVIC_SetPriority in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * @pre Priority is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_SetPriority documentation in CMSIS. + * @param[in] priority A valid IRQ priority for use by the application. + * + * @retval ::NRF_SUCCESS The interrupt and priority level is available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt priority is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority); + +/**@brief Get Interrupt Priority. + * @note Corresponds to NVIC_GetPriority in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_GetPriority documentation in CMSIS. + * @param[out] p_priority Return value from NVIC_GetPriority. + * + * @retval ::NRF_SUCCESS The interrupt priority is returned in p_priority. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE - IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority); + +/**@brief System Reset. + * @note Corresponds to NVIC_SystemReset in CMSIS. + * + * @retval ::NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN + */ +__STATIC_INLINE uint32_t sd_nvic_SystemReset(void); + +/**@brief Enter critical region. + * + * @post Application interrupts will be disabled. + * @note sd_nvic_critical_region_enter() and ::sd_nvic_critical_region_exit() must be called in matching pairs inside each + * execution context + * @sa sd_nvic_critical_region_exit + * + * @param[out] p_is_nested_critical_region If 1, the application is now in a nested critical region. + * + * @retval ::NRF_SUCCESS + */ +__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region); + +/**@brief Exit critical region. + * + * @pre Application has entered a critical region using ::sd_nvic_critical_region_enter. + * @post If not in a nested critical region, the application interrupts will restored to the state before + * ::sd_nvic_critical_region_enter was called. + * + * @param[in] is_nested_critical_region If this is set to 1, the critical region won't be exited. @sa + * sd_nvic_critical_region_enter. + * + * @retval ::NRF_SUCCESS + */ +__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region); + +/**@} */ + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION + +__STATIC_INLINE int __sd_nvic_irq_disable(void) +{ + int pm = __get_PRIMASK(); + __disable_irq(); + return pm; +} + +__STATIC_INLINE void __sd_nvic_irq_enable(void) +{ + __enable_irq(); +} + +__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn) +{ + if (IRQn < 32) { + return ((1UL << IRQn) & __NRF_NVIC_APP_IRQS_0) != 0; + } else if (IRQn < 64) { + return ((1UL << (IRQn - 32)) & __NRF_NVIC_APP_IRQS_1) != 0; + } else { + return 1; + } +} + +__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority) +{ + if ((priority >= (1 << __NVIC_PRIO_BITS)) || (((1 << priority) & __NRF_NVIC_APP_IRQ_PRIOS) == 0)) { + return 0; + } + return 1; +} + +__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + if (!__sd_nvic_is_app_accessible_priority(NVIC_GetPriority(IRQn))) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; + } + + if (nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] |= + (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F)); + } else { + NVIC_EnableIRQ(IRQn); + } + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + + if (nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] &= ~(1UL << ((uint32_t)(IRQn)&0x1F)); + } else { + NVIC_DisableIRQ(IRQn); + } + + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + *p_pending_irq = NVIC_GetPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + NVIC_SetPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + NVIC_ClearPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + + if (!__sd_nvic_is_app_accessible_priority(priority)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; + } + + NVIC_SetPriority(IRQn, (uint32_t)priority); + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + *p_priority = (NVIC_GetPriority(IRQn) & 0xFF); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SystemReset(void) +{ + NVIC_SystemReset(); + return NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN; +} + +__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region) +{ + int was_masked = __sd_nvic_irq_disable(); + if (!nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__cr_flag = 1; + nrf_nvic_state.__irq_masks[0] = (NVIC->ICER[0] & __NRF_NVIC_APP_IRQS_0); + NVIC->ICER[0] = __NRF_NVIC_APP_IRQS_0; + nrf_nvic_state.__irq_masks[1] = (NVIC->ICER[1] & __NRF_NVIC_APP_IRQS_1); + NVIC->ICER[1] = __NRF_NVIC_APP_IRQS_1; + *p_is_nested_critical_region = 0; + } else { + *p_is_nested_critical_region = 1; + } + if (!was_masked) { + __sd_nvic_irq_enable(); + } + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region) +{ + if (nrf_nvic_state.__cr_flag && (is_nested_critical_region == 0)) { + int was_masked = __sd_nvic_irq_disable(); + NVIC->ISER[0] = nrf_nvic_state.__irq_masks[0]; + NVIC->ISER[1] = nrf_nvic_state.__irq_masks[1]; + nrf_nvic_state.__cr_flag = 0; + if (!was_masked) { + __sd_nvic_irq_enable(); + } + } + + return NRF_SUCCESS; +} + +#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ + +#ifdef __cplusplus +} +#endif + +#endif // NRF_NVIC_H__ + +/**@} */ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h b/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h new file mode 100644 index 0000000000..2786a86a45 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_sdm_api SoftDevice Manager API + @{ + + @brief APIs for SoftDevice management. + +*/ + +#ifndef NRF_SDM_H__ +#define NRF_SDM_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_sdm.h" +#include "nrf_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup NRF_SDM_DEFINES Defines + * @{ */ +#ifdef NRFSOC_DOXYGEN +/// Declared in nrf_mbr.h +#define MBR_SIZE 0 +#warning test +#endif + +/** @brief The major version for the SoftDevice binary distributed with this header file. */ +#define SD_MAJOR_VERSION (7) + +/** @brief The minor version for the SoftDevice binary distributed with this header file. */ +#define SD_MINOR_VERSION (3) + +/** @brief The bugfix version for the SoftDevice binary distributed with this header file. */ +#define SD_BUGFIX_VERSION (0) + +/** @brief The SoftDevice variant of this firmware. */ +#define SD_VARIANT_ID 140 + +/** @brief The full version number for the SoftDevice binary this header file was distributed + * with, as a decimal number in the form Mmmmbbb, where: + * - M is major version (one or more digits) + * - mmm is minor version (three digits) + * - bbb is bugfix version (three digits). */ +#define SD_VERSION (SD_MAJOR_VERSION * 1000000 + SD_MINOR_VERSION * 1000 + SD_BUGFIX_VERSION) + +/** @brief SoftDevice Manager SVC Base number. */ +#define SDM_SVC_BASE 0x10 + +/** @brief SoftDevice unique string size in bytes. */ +#define SD_UNIQUE_STR_SIZE 20 + +/** @brief Invalid info field. Returned when an info field does not exist. */ +#define SDM_INFO_FIELD_INVALID (0) + +/** @brief Defines the SoftDevice Information Structure location (address) as an offset from +the start of the SoftDevice (without MBR)*/ +#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000) + +/** @brief Defines the absolute SoftDevice Information Structure location (address) when the + * SoftDevice is installed just above the MBR (the usual case). */ +#define SOFTDEVICE_INFO_STRUCT_ADDRESS (SOFTDEVICE_INFO_STRUCT_OFFSET + MBR_SIZE) + +/** @brief Defines the offset for the SoftDevice Information Structure size value relative to the + * SoftDevice base address. The size value is of type uint8_t. */ +#define SD_INFO_STRUCT_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET) + +/** @brief Defines the offset for the SoftDevice size value relative to the SoftDevice base address. + * The size value is of type uint32_t. */ +#define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08) + +/** @brief Defines the offset for FWID value relative to the SoftDevice base address. The FWID value + * is of type uint16_t. */ +#define SD_FWID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x0C) + +/** @brief Defines the offset for the SoftDevice ID relative to the SoftDevice base address. The ID + * is of type uint32_t. */ +#define SD_ID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x10) + +/** @brief Defines the offset for the SoftDevice version relative to the SoftDevice base address in + * the same format as @ref SD_VERSION, stored as an uint32_t. */ +#define SD_VERSION_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x14) + +/** @brief Defines the offset for the SoftDevice unique string relative to the SoftDevice base address. + * The SD_UNIQUE_STR is stored as an array of uint8_t. The size of array is @ref SD_UNIQUE_STR_SIZE. + */ +#define SD_UNIQUE_STR_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x18) + +/** @brief Defines a macro for retrieving the actual SoftDevice Information Structure size value + * from a given base address. Use @ref MBR_SIZE as the argument when the SoftDevice is + * installed just above the MBR (the usual case). */ +#define SD_INFO_STRUCT_SIZE_GET(baseaddr) (*((uint8_t *)((baseaddr) + SD_INFO_STRUCT_SIZE_OFFSET))) + +/** @brief Defines a macro for retrieving the actual SoftDevice size value from a given base + * address. Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above + * the MBR (the usual case). */ +#define SD_SIZE_GET(baseaddr) (*((uint32_t *)((baseaddr) + SD_SIZE_OFFSET))) + +/** @brief Defines the amount of flash that is used by the SoftDevice. + * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed + * just above the MBR (the usual case). + */ +#define SD_FLASH_SIZE 0x26000 + +/** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use + * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual + * case). */ +#define SD_FWID_GET(baseaddr) (*((uint16_t *)((baseaddr) + SD_FWID_OFFSET))) + +/** @brief Defines a macro for retrieving the actual SoftDevice ID from a given base address. Use + * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the + * usual case). */ +#define SD_ID_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_ID_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (*((uint32_t *)((baseaddr) + SD_ID_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/** @brief Defines a macro for retrieving the actual SoftDevice version from a given base address. + * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR + * (the usual case). */ +#define SD_VERSION_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_VERSION_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (*((uint32_t *)((baseaddr) + SD_VERSION_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/** @brief Defines a macro for retrieving the address of SoftDevice unique str based on a given base address. + * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR + * (the usual case). */ +#define SD_UNIQUE_STR_ADDR_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_UNIQUE_STR_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (((uint8_t *)((baseaddr) + SD_UNIQUE_STR_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/**@defgroup NRF_FAULT_ID_RANGES Fault ID ranges + * @{ */ +#define NRF_FAULT_ID_SD_RANGE_START 0x00000000 /**< SoftDevice ID range start. */ +#define NRF_FAULT_ID_APP_RANGE_START 0x00001000 /**< Application ID range start. */ +/**@} */ + +/**@defgroup NRF_FAULT_IDS Fault ID types + * @{ */ +#define NRF_FAULT_ID_SD_ASSERT \ + (NRF_FAULT_ID_SD_RANGE_START + 1) /**< SoftDevice assertion. The info parameter is reserved for future used. */ +#define NRF_FAULT_ID_APP_MEMACC \ + (NRF_FAULT_ID_APP_RANGE_START + 1) /**< Application invalid memory access. The info parameter will contain 0x00000000, \ + in case of SoftDevice RAM access violation. In case of SoftDevice peripheral \ + register violation the info parameter will contain the sub-region number of \ + PREGION[0], on whose address range the disallowed write access caused the \ + memory access fault. */ +/**@} */ + +/** @} */ + +/** @addtogroup NRF_SDM_ENUMS Enumerations + * @{ */ + +/**@brief nRF SoftDevice Manager API SVC numbers. */ +enum NRF_SD_SVCS { + SD_SOFTDEVICE_ENABLE = SDM_SVC_BASE, /**< ::sd_softdevice_enable */ + SD_SOFTDEVICE_DISABLE, /**< ::sd_softdevice_disable */ + SD_SOFTDEVICE_IS_ENABLED, /**< ::sd_softdevice_is_enabled */ + SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, /**< ::sd_softdevice_vector_table_base_set */ + SVC_SDM_LAST /**< Placeholder for last SDM SVC */ +}; + +/** @} */ + +/** @addtogroup NRF_SDM_DEFINES Defines + * @{ */ + +/**@defgroup NRF_CLOCK_LF_ACCURACY Clock accuracy + * @{ */ + +#define NRF_CLOCK_LF_ACCURACY_250_PPM (0) /**< Default: 250 ppm */ +#define NRF_CLOCK_LF_ACCURACY_500_PPM (1) /**< 500 ppm */ +#define NRF_CLOCK_LF_ACCURACY_150_PPM (2) /**< 150 ppm */ +#define NRF_CLOCK_LF_ACCURACY_100_PPM (3) /**< 100 ppm */ +#define NRF_CLOCK_LF_ACCURACY_75_PPM (4) /**< 75 ppm */ +#define NRF_CLOCK_LF_ACCURACY_50_PPM (5) /**< 50 ppm */ +#define NRF_CLOCK_LF_ACCURACY_30_PPM (6) /**< 30 ppm */ +#define NRF_CLOCK_LF_ACCURACY_20_PPM (7) /**< 20 ppm */ +#define NRF_CLOCK_LF_ACCURACY_10_PPM (8) /**< 10 ppm */ +#define NRF_CLOCK_LF_ACCURACY_5_PPM (9) /**< 5 ppm */ +#define NRF_CLOCK_LF_ACCURACY_2_PPM (10) /**< 2 ppm */ +#define NRF_CLOCK_LF_ACCURACY_1_PPM (11) /**< 1 ppm */ + +/** @} */ + +/**@defgroup NRF_CLOCK_LF_SRC Possible LFCLK oscillator sources + * @{ */ + +#define NRF_CLOCK_LF_SRC_RC (0) /**< LFCLK RC oscillator. */ +#define NRF_CLOCK_LF_SRC_XTAL (1) /**< LFCLK crystal oscillator. */ +#define NRF_CLOCK_LF_SRC_SYNTH (2) /**< LFCLK Synthesized from HFCLK. */ + +/** @} */ + +/** @} */ + +/** @addtogroup NRF_SDM_TYPES Types + * @{ */ + +/**@brief Type representing LFCLK oscillator source. */ +typedef struct { + uint8_t source; /**< LF oscillator clock source, see @ref NRF_CLOCK_LF_SRC. */ + uint8_t rc_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: Calibration timer interval in 1/4 second + units (nRF52: 1-32). + @note To avoid excessive clock drift, 0.5 degrees Celsius is the + maximum temperature change allowed in one calibration timer + interval. The interval should be selected to ensure this. + + @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. */ + uint8_t rc_temp_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: How often (in number of calibration + intervals) the RC oscillator shall be calibrated if the temperature + hasn't changed. + 0: Always calibrate even if the temperature hasn't changed. + 1: Only calibrate if the temperature has changed (legacy - nRF51 only). + 2-33: Check the temperature and only calibrate if it has changed, + however calibration will take place every rc_temp_ctiv + intervals in any case. + + @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. + + @note For nRF52, the application must ensure calibration at least once + every 8 seconds to ensure +/-500 ppm clock stability. The + recommended configuration for ::NRF_CLOCK_LF_SRC_RC on nRF52 is + rc_ctiv=16 and rc_temp_ctiv=2. This will ensure calibration at + least once every 8 seconds and for temperature changes of 0.5 + degrees Celsius every 4 seconds. See the Product Specification + for the nRF52 device being used for more information.*/ + uint8_t accuracy; /**< External clock accuracy used in the LL to compute timing + windows, see @ref NRF_CLOCK_LF_ACCURACY.*/ +} nrf_clock_lf_cfg_t; + +/**@brief Fault Handler type. + * + * When certain unrecoverable errors occur within the application or SoftDevice the fault handler will be called back. + * The protocol stack will be in an undefined state when this happens and the only way to recover will be to + * perform a reset, using e.g. CMSIS NVIC_SystemReset(). + * If the application returns from the fault handler the SoftDevice will call NVIC_SystemReset(). + * + * @note It is recommended to either perform a reset in the fault handler or to let the SoftDevice reset the device. + * Otherwise SoC peripherals may behave in an undefined way. For example, the RADIO peripherial may + * continously transmit packets. + * + * @note This callback is executed in HardFault context, thus SVC functions cannot be called from the fault callback. + * + * @param[in] id Fault identifier. See @ref NRF_FAULT_IDS. + * @param[in] pc The program counter of the instruction that triggered the fault. + * @param[in] info Optional additional information regarding the fault. Refer to each Fault identifier for details. + * + * @note When id is set to @ref NRF_FAULT_ID_APP_MEMACC, pc will contain the address of the instruction being executed at the time + * when the fault is detected by the CPU. The CPU program counter may have advanced up to 2 instructions (no branching) after the + * one that triggered the fault. + */ +typedef void (*nrf_fault_handler_t)(uint32_t id, uint32_t pc, uint32_t info); + +/** @} */ + +/** @addtogroup NRF_SDM_FUNCTIONS Functions + * @{ */ + +/**@brief Enables the SoftDevice and by extension the protocol stack. + * + * @note Some care must be taken if a low frequency clock source is already running when calling this function: + * If the LF clock has a different source then the one currently running, it will be stopped. Then, the new + * clock source will be started. + * + * @note This function has no effect when returning with an error. + * + * @post If return code is ::NRF_SUCCESS + * - SoC library and protocol stack APIs are made available. + * - A portion of RAM will be unavailable (see relevant SDS documentation). + * - Some peripherals will be unavailable or available only through the SoC API (see relevant SDS documentation). + * - Interrupts will not arrive from protected peripherals or interrupts. + * - nrf_nvic_ functions must be used instead of CMSIS NVIC_ functions for reliable usage of the SoftDevice. + * - Interrupt latency may be affected by the SoftDevice (see relevant SDS documentation). + * - Chosen low frequency clock source will be running. + * + * @param p_clock_lf_cfg Low frequency clock source and accuracy. + If NULL the clock will be configured as an RC source with rc_ctiv = 16 and .rc_temp_ctiv = 2 + In the case of XTAL source, the PPM accuracy of the chosen clock source must be greater than or equal to + the actual characteristics of your XTAL clock. + * @param fault_handler Callback to be invoked in case of fault, cannot be NULL. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE SoftDevice is already enabled, and the clock source and fault handler cannot be updated. + * @retval ::NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION SoftDevice interrupt is already enabled, or an enabled interrupt has + an illegal priority level. + * @retval ::NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN Unknown low frequency clock source selected. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid clock source configuration supplied in p_clock_lf_cfg. + */ +SVCALL(SD_SOFTDEVICE_ENABLE, uint32_t, + sd_softdevice_enable(nrf_clock_lf_cfg_t const *p_clock_lf_cfg, nrf_fault_handler_t fault_handler)); + +/**@brief Disables the SoftDevice and by extension the protocol stack. + * + * Idempotent function to disable the SoftDevice. + * + * @post SoC library and protocol stack APIs are made unavailable. + * @post All interrupts that was protected by the SoftDevice will be disabled and initialized to priority 0 (highest). + * @post All peripherals used by the SoftDevice will be reset to default values. + * @post All of RAM become available. + * @post All interrupts are forwarded to the application. + * @post LFCLK source chosen in ::sd_softdevice_enable will be left running. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_DISABLE, uint32_t, sd_softdevice_disable(void)); + +/**@brief Check if the SoftDevice is enabled. + * + * @param[out] p_softdevice_enabled If the SoftDevice is enabled: 1 else 0. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_IS_ENABLED, uint32_t, sd_softdevice_is_enabled(uint8_t *p_softdevice_enabled)); + +/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the SoftDevice + * + * This function is only intended to be called when a bootloader is enabled. + * + * @param[in] address The base address of the interrupt vector table for forwarded interrupts. + + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table_base_set(uint32_t address)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_SDM_H__ + +/** + @} +*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_soc.h b/variants/wio-sdk-wm1110/softdevice/nrf_soc.h new file mode 100644 index 0000000000..c649ca836d --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_soc.h @@ -0,0 +1,1046 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup nrf_soc_api SoC Library API + * @{ + * + * @brief APIs for the SoC library. + * + */ + +#ifndef NRF_SOC_H__ +#define NRF_SOC_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup NRF_SOC_DEFINES Defines + * @{ */ + +/**@brief The number of the lowest SVC number reserved for the SoC library. */ +#define SOC_SVC_BASE (0x20) /**< Base value for SVCs that are available when the SoftDevice is disabled. */ +#define SOC_SVC_BASE_NOT_AVAILABLE (0x2C) /**< Base value for SVCs that are not available when the SoftDevice is disabled. */ + +/**@brief Guaranteed time for application to process radio inactive notification. */ +#define NRF_RADIO_NOTIFICATION_INACTIVE_GUARANTEED_TIME_US (62) + +/**@brief The minimum allowed timeslot extension time. */ +#define NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US (200) + +/**@brief The maximum processing time to handle a timeslot extension. */ +#define NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US (20) + +/**@brief The latest time before the end of a timeslot the timeslot can be extended. */ +#define NRF_RADIO_MIN_EXTENSION_MARGIN_US (82) + +#define SOC_ECB_KEY_LENGTH (16) /**< ECB key length. */ +#define SOC_ECB_CLEARTEXT_LENGTH (16) /**< ECB cleartext length. */ +#define SOC_ECB_CIPHERTEXT_LENGTH (SOC_ECB_CLEARTEXT_LENGTH) /**< ECB ciphertext length. */ + +#define SD_EVT_IRQn (SWI2_IRQn) /**< SoftDevice Event IRQ number. Used for both protocol events and SoC events. */ +#define SD_EVT_IRQHandler \ + (SWI2_IRQHandler) /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. \ + The default interrupt priority for this handler is set to 6 */ +#define RADIO_NOTIFICATION_IRQn (SWI1_IRQn) /**< The radio notification IRQ number. */ +#define RADIO_NOTIFICATION_IRQHandler \ + (SWI1_IRQHandler) /**< The radio notification IRQ handler. \ + The default interrupt priority for this handler is set to 6 */ +#define NRF_RADIO_LENGTH_MIN_US (100) /**< The shortest allowed radio timeslot, in microseconds. */ +#define NRF_RADIO_LENGTH_MAX_US (100000) /**< The longest allowed radio timeslot, in microseconds. */ + +#define NRF_RADIO_DISTANCE_MAX_US \ + (128000000UL - 1UL) /**< The longest timeslot distance, in microseconds, allowed for the distance parameter (see @ref \ + nrf_radio_request_normal_t) in the request. */ + +#define NRF_RADIO_EARLIEST_TIMEOUT_MAX_US \ + (128000000UL - 1UL) /**< The longest timeout, in microseconds, allowed when requesting the earliest possible timeslot. */ + +#define NRF_RADIO_START_JITTER_US \ + (2) /**< The maximum jitter in @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START relative to the requested start time. */ + +/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is disabled. */ +#define NRF_SOC_SD_PPI_CHANNELS_SD_DISABLED_MSK ((uint32_t)(0)) + +/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is enabled. */ +#define NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK \ + ((uint32_t)((1U << 17) | (1U << 18) | (1U << 19) | (1U << 20) | (1U << 21) | (1U << 22) | (1U << 23) | (1U << 24) | \ + (1U << 25) | (1U << 26) | (1U << 27) | (1U << 28) | (1U << 29) | (1U << 30) | (1U << 31))) + +/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is disabled. */ +#define NRF_SOC_SD_PPI_GROUPS_SD_DISABLED_MSK ((uint32_t)(0)) + +/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is enabled. */ +#define NRF_SOC_SD_PPI_GROUPS_SD_ENABLED_MSK ((uint32_t)((1U << 4) | (1U << 5))) + +/**@} */ + +/**@addtogroup NRF_SOC_ENUMS Enumerations + * @{ */ + +/**@brief The SVC numbers used by the SVC functions in the SoC library. */ +enum NRF_SOC_SVCS { + SD_PPI_CHANNEL_ENABLE_GET = SOC_SVC_BASE, + SD_PPI_CHANNEL_ENABLE_SET = SOC_SVC_BASE + 1, + SD_PPI_CHANNEL_ENABLE_CLR = SOC_SVC_BASE + 2, + SD_PPI_CHANNEL_ASSIGN = SOC_SVC_BASE + 3, + SD_PPI_GROUP_TASK_ENABLE = SOC_SVC_BASE + 4, + SD_PPI_GROUP_TASK_DISABLE = SOC_SVC_BASE + 5, + SD_PPI_GROUP_ASSIGN = SOC_SVC_BASE + 6, + SD_PPI_GROUP_GET = SOC_SVC_BASE + 7, + SD_FLASH_PAGE_ERASE = SOC_SVC_BASE + 8, + SD_FLASH_WRITE = SOC_SVC_BASE + 9, + SD_PROTECTED_REGISTER_WRITE = SOC_SVC_BASE + 11, + SD_MUTEX_NEW = SOC_SVC_BASE_NOT_AVAILABLE, + SD_MUTEX_ACQUIRE = SOC_SVC_BASE_NOT_AVAILABLE + 1, + SD_MUTEX_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 2, + SD_RAND_APPLICATION_POOL_CAPACITY_GET = SOC_SVC_BASE_NOT_AVAILABLE + 3, + SD_RAND_APPLICATION_BYTES_AVAILABLE_GET = SOC_SVC_BASE_NOT_AVAILABLE + 4, + SD_RAND_APPLICATION_VECTOR_GET = SOC_SVC_BASE_NOT_AVAILABLE + 5, + SD_POWER_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 6, + SD_POWER_SYSTEM_OFF = SOC_SVC_BASE_NOT_AVAILABLE + 7, + SD_POWER_RESET_REASON_GET = SOC_SVC_BASE_NOT_AVAILABLE + 8, + SD_POWER_RESET_REASON_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 9, + SD_POWER_POF_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 10, + SD_POWER_POF_THRESHOLD_SET = SOC_SVC_BASE_NOT_AVAILABLE + 11, + SD_POWER_POF_THRESHOLDVDDH_SET = SOC_SVC_BASE_NOT_AVAILABLE + 12, + SD_POWER_RAM_POWER_SET = SOC_SVC_BASE_NOT_AVAILABLE + 13, + SD_POWER_RAM_POWER_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 14, + SD_POWER_RAM_POWER_GET = SOC_SVC_BASE_NOT_AVAILABLE + 15, + SD_POWER_GPREGRET_SET = SOC_SVC_BASE_NOT_AVAILABLE + 16, + SD_POWER_GPREGRET_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 17, + SD_POWER_GPREGRET_GET = SOC_SVC_BASE_NOT_AVAILABLE + 18, + SD_POWER_DCDC_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 19, + SD_POWER_DCDC0_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 20, + SD_APP_EVT_WAIT = SOC_SVC_BASE_NOT_AVAILABLE + 21, + SD_CLOCK_HFCLK_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 22, + SD_CLOCK_HFCLK_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 23, + SD_CLOCK_HFCLK_IS_RUNNING = SOC_SVC_BASE_NOT_AVAILABLE + 24, + SD_RADIO_NOTIFICATION_CFG_SET = SOC_SVC_BASE_NOT_AVAILABLE + 25, + SD_ECB_BLOCK_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 26, + SD_ECB_BLOCKS_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 27, + SD_RADIO_SESSION_OPEN = SOC_SVC_BASE_NOT_AVAILABLE + 28, + SD_RADIO_SESSION_CLOSE = SOC_SVC_BASE_NOT_AVAILABLE + 29, + SD_RADIO_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 30, + SD_EVT_GET = SOC_SVC_BASE_NOT_AVAILABLE + 31, + SD_TEMP_GET = SOC_SVC_BASE_NOT_AVAILABLE + 32, + SD_POWER_USBPWRRDY_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 33, + SD_POWER_USBDETECTED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 34, + SD_POWER_USBREMOVED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 35, + SD_POWER_USBREGSTATUS_GET = SOC_SVC_BASE_NOT_AVAILABLE + 36, + SVC_SOC_LAST = SOC_SVC_BASE_NOT_AVAILABLE + 37 +}; + +/**@brief Possible values of a ::nrf_mutex_t. */ +enum NRF_MUTEX_VALUES { NRF_MUTEX_FREE, NRF_MUTEX_TAKEN }; + +/**@brief Power modes. */ +enum NRF_POWER_MODES { + NRF_POWER_MODE_CONSTLAT, /**< Constant latency mode. See power management in the reference manual. */ + NRF_POWER_MODE_LOWPWR /**< Low power mode. See power management in the reference manual. */ +}; + +/**@brief Power failure thresholds */ +enum NRF_POWER_THRESHOLDS { + NRF_POWER_THRESHOLD_V17 = 4UL, /**< 1.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V18, /**< 1.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V19, /**< 1.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V20, /**< 2.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V21, /**< 2.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V22, /**< 2.2 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V23, /**< 2.3 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V24, /**< 2.4 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V25, /**< 2.5 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V26, /**< 2.6 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V27, /**< 2.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V28 /**< 2.8 Volts power failure threshold. */ +}; + +/**@brief Power failure thresholds for high voltage */ +enum NRF_POWER_THRESHOLDVDDHS { + NRF_POWER_THRESHOLDVDDH_V27, /**< 2.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V28, /**< 2.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V29, /**< 2.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V30, /**< 3.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V31, /**< 3.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V32, /**< 3.2 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V33, /**< 3.3 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V34, /**< 3.4 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V35, /**< 3.5 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V36, /**< 3.6 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V37, /**< 3.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V38, /**< 3.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V39, /**< 3.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V40, /**< 4.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V41, /**< 4.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V42 /**< 4.2 Volts power failure threshold. */ +}; + +/**@brief DC/DC converter modes. */ +enum NRF_POWER_DCDC_MODES { + NRF_POWER_DCDC_DISABLE, /**< The DCDC is disabled. */ + NRF_POWER_DCDC_ENABLE /**< The DCDC is enabled. */ +}; + +/**@brief Radio notification distances. */ +enum NRF_RADIO_NOTIFICATION_DISTANCES { + NRF_RADIO_NOTIFICATION_DISTANCE_NONE = 0, /**< The event does not have a notification. */ + NRF_RADIO_NOTIFICATION_DISTANCE_800US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_1740US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_2680US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_3620US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_4560US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_5500US /**< The distance from the active notification to start of radio activity. */ +}; + +/**@brief Radio notification types. */ +enum NRF_RADIO_NOTIFICATION_TYPES { + NRF_RADIO_NOTIFICATION_TYPE_NONE = 0, /**< The event does not have a radio notification signal. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, /**< Using interrupt for notification when the radio will be enabled. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, /**< Using interrupt for notification when the radio has been disabled. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, /**< Using interrupt for notification both when the radio will be enabled and + disabled. */ +}; + +/**@brief The Radio signal callback types. */ +enum NRF_RADIO_CALLBACK_SIGNAL_TYPE { + NRF_RADIO_CALLBACK_SIGNAL_TYPE_START, /**< This signal indicates the start of the radio timeslot. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0, /**< This signal indicates the NRF_TIMER0 interrupt. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO, /**< This signal indicates the NRF_RADIO interrupt. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED, /**< This signal indicates extend action failed. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED /**< This signal indicates extend action succeeded. */ +}; + +/**@brief The actions requested by the signal callback. + * + * This code gives the SOC instructions about what action to take when the signal callback has + * returned. + */ +enum NRF_RADIO_SIGNAL_CALLBACK_ACTION { + NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE, /**< Return without action. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND, /**< Request an extension of the current + timeslot. Maximum execution time for this action: + @ref NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US. + This action must be started at least + @ref NRF_RADIO_MIN_EXTENSION_MARGIN_US before + the end of the timeslot. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_END, /**< End the current radio timeslot. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END /**< Request a new radio timeslot and end the current timeslot. */ +}; + +/**@brief Radio timeslot high frequency clock source configuration. */ +enum NRF_RADIO_HFCLK_CFG { + NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED, /**< The SoftDevice will guarantee that the high frequency clock source is the + external crystal for the whole duration of the timeslot. This should be the + preferred option for events that use the radio or require high timing accuracy. + @note The SoftDevice will automatically turn on and off the external crystal, + at the beginning and end of the timeslot, respectively. The crystal may also + intentionally be left running after the timeslot, in cases where it is needed + by the SoftDevice shortly after the end of the timeslot. */ + NRF_RADIO_HFCLK_CFG_NO_GUARANTEE /**< This configuration allows for earlier and tighter scheduling of timeslots. + The RC oscillator may be the clock source in part or for the whole duration of the + timeslot. The RC oscillator's accuracy must therefore be taken into consideration. + @note If the application will use the radio peripheral in timeslots with this + configuration, it must make sure that the crystal is running and stable before + starting the radio. */ +}; + +/**@brief Radio timeslot priorities. */ +enum NRF_RADIO_PRIORITY { + NRF_RADIO_PRIORITY_HIGH, /**< High (equal priority as the normal connection priority of the SoftDevice stack(s)). */ + NRF_RADIO_PRIORITY_NORMAL, /**< Normal (equal priority as the priority of secondary activities of the SoftDevice stack(s)). */ +}; + +/**@brief Radio timeslot request type. */ +enum NRF_RADIO_REQUEST_TYPE { + NRF_RADIO_REQ_TYPE_EARLIEST, /**< Request radio timeslot as early as possible. This should always be used for the first + request in a session. */ + NRF_RADIO_REQ_TYPE_NORMAL /**< Normal radio timeslot request. */ +}; + +/**@brief SoC Events. */ +enum NRF_SOC_EVTS { + NRF_EVT_HFCLKSTARTED, /**< Event indicating that the HFCLK has started. */ + NRF_EVT_POWER_FAILURE_WARNING, /**< Event indicating that a power failure warning has occurred. */ + NRF_EVT_FLASH_OPERATION_SUCCESS, /**< Event indicating that the ongoing flash operation has completed successfully. */ + NRF_EVT_FLASH_OPERATION_ERROR, /**< Event indicating that the ongoing flash operation has timed out with an error. */ + NRF_EVT_RADIO_BLOCKED, /**< Event indicating that a radio timeslot was blocked. */ + NRF_EVT_RADIO_CANCELED, /**< Event indicating that a radio timeslot was canceled by SoftDevice. */ + NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN, /**< Event indicating that a radio timeslot signal callback handler return was + invalid. */ + NRF_EVT_RADIO_SESSION_IDLE, /**< Event indicating that a radio timeslot session is idle. */ + NRF_EVT_RADIO_SESSION_CLOSED, /**< Event indicating that a radio timeslot session is closed. */ + NRF_EVT_POWER_USB_POWER_READY, /**< Event indicating that a USB 3.3 V supply is ready. */ + NRF_EVT_POWER_USB_DETECTED, /**< Event indicating that voltage supply is detected on VBUS. */ + NRF_EVT_POWER_USB_REMOVED, /**< Event indicating that voltage supply is removed from VBUS. */ + NRF_EVT_NUMBER_OF_EVTS +}; + +/**@} */ + +/**@addtogroup NRF_SOC_STRUCTURES Structures + * @{ */ + +/**@brief Represents a mutex for use with the nrf_mutex functions. + * @note Accessing the value directly is not safe, use the mutex functions! + */ +typedef volatile uint8_t nrf_mutex_t; + +/**@brief Parameters for a request for a timeslot as early as possible. */ +typedef struct { + uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ + uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ + uint32_t length_us; /**< The radio timeslot length (in the range 100 to 100,000] microseconds). */ + uint32_t timeout_us; /**< Longest acceptable delay until the start of the requested timeslot (up to @ref + NRF_RADIO_EARLIEST_TIMEOUT_MAX_US microseconds). */ +} nrf_radio_request_earliest_t; + +/**@brief Parameters for a normal radio timeslot request. */ +typedef struct { + uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ + uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ + uint32_t distance_us; /**< Distance from the start of the previous radio timeslot (up to @ref NRF_RADIO_DISTANCE_MAX_US + microseconds). */ + uint32_t length_us; /**< The radio timeslot length (in the range [100..100,000] microseconds). */ +} nrf_radio_request_normal_t; + +/**@brief Radio timeslot request parameters. */ +typedef struct { + uint8_t request_type; /**< Type of request, see @ref NRF_RADIO_REQUEST_TYPE. */ + union { + nrf_radio_request_earliest_t earliest; /**< Parameters for requesting a radio timeslot as early as possible. */ + nrf_radio_request_normal_t normal; /**< Parameters for requesting a normal radio timeslot. */ + } params; /**< Parameter union. */ +} nrf_radio_request_t; + +/**@brief Return parameters of the radio timeslot signal callback. */ +typedef struct { + uint8_t callback_action; /**< The action requested by the application when returning from the signal callback, see @ref + NRF_RADIO_SIGNAL_CALLBACK_ACTION. */ + union { + struct { + nrf_radio_request_t *p_next; /**< The request parameters for the next radio timeslot. */ + } request; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END. */ + struct { + uint32_t length_us; /**< Requested extension of the radio timeslot duration (microseconds) (for minimum time see @ref + NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US). */ + } extend; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND. */ + } params; /**< Parameter union. */ +} nrf_radio_signal_callback_return_param_t; + +/**@brief The radio timeslot signal callback type. + * + * @note In case of invalid return parameters, the radio timeslot will automatically end + * immediately after returning from the signal callback and the + * @ref NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN event will be sent. + * @note The returned struct pointer must remain valid after the signal callback + * function returns. For instance, this means that it must not point to a stack variable. + * + * @param[in] signal_type Type of signal, see @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE. + * + * @return Pointer to structure containing action requested by the application. + */ +typedef nrf_radio_signal_callback_return_param_t *(*nrf_radio_signal_callback_t)(uint8_t signal_type); + +/**@brief AES ECB parameter typedefs */ +typedef uint8_t soc_ecb_key_t[SOC_ECB_KEY_LENGTH]; /**< Encryption key type. */ +typedef uint8_t soc_ecb_cleartext_t[SOC_ECB_CLEARTEXT_LENGTH]; /**< Cleartext data type. */ +typedef uint8_t soc_ecb_ciphertext_t[SOC_ECB_CIPHERTEXT_LENGTH]; /**< Ciphertext data type. */ + +/**@brief AES ECB data structure */ +typedef struct { + soc_ecb_key_t key; /**< Encryption key. */ + soc_ecb_cleartext_t cleartext; /**< Cleartext data. */ + soc_ecb_ciphertext_t ciphertext; /**< Ciphertext data. */ +} nrf_ecb_hal_data_t; + +/**@brief AES ECB block. Used to provide multiple blocks in a single call + to @ref sd_ecb_blocks_encrypt.*/ +typedef struct { + soc_ecb_key_t const *p_key; /**< Pointer to the Encryption key. */ + soc_ecb_cleartext_t const *p_cleartext; /**< Pointer to the Cleartext data. */ + soc_ecb_ciphertext_t *p_ciphertext; /**< Pointer to the Ciphertext data. */ +} nrf_ecb_hal_data_block_t; + +/**@} */ + +/**@addtogroup NRF_SOC_FUNCTIONS Functions + * @{ */ + +/**@brief Initialize a mutex. + * + * @param[in] p_mutex Pointer to the mutex to initialize. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_MUTEX_NEW, uint32_t, sd_mutex_new(nrf_mutex_t *p_mutex)); + +/**@brief Attempt to acquire a mutex. + * + * @param[in] p_mutex Pointer to the mutex to acquire. + * + * @retval ::NRF_SUCCESS The mutex was successfully acquired. + * @retval ::NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN The mutex could not be acquired. + */ +SVCALL(SD_MUTEX_ACQUIRE, uint32_t, sd_mutex_acquire(nrf_mutex_t *p_mutex)); + +/**@brief Release a mutex. + * + * @param[in] p_mutex Pointer to the mutex to release. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_MUTEX_RELEASE, uint32_t, sd_mutex_release(nrf_mutex_t *p_mutex)); + +/**@brief Query the capacity of the application random pool. + * + * @param[out] p_pool_capacity The capacity of the pool. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RAND_APPLICATION_POOL_CAPACITY_GET, uint32_t, sd_rand_application_pool_capacity_get(uint8_t *p_pool_capacity)); + +/**@brief Get number of random bytes available to the application. + * + * @param[out] p_bytes_available The number of bytes currently available in the pool. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RAND_APPLICATION_BYTES_AVAILABLE_GET, uint32_t, sd_rand_application_bytes_available_get(uint8_t *p_bytes_available)); + +/**@brief Get random bytes from the application pool. + * + * @param[out] p_buff Pointer to unit8_t buffer for storing the bytes. + * @param[in] length Number of bytes to take from pool and place in p_buff. + * + * @retval ::NRF_SUCCESS The requested bytes were written to p_buff. + * @retval ::NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES No bytes were written to the buffer, because there were not enough bytes + * available. + */ +SVCALL(SD_RAND_APPLICATION_VECTOR_GET, uint32_t, sd_rand_application_vector_get(uint8_t *p_buff, uint8_t length)); + +/**@brief Gets the reset reason register. + * + * @param[out] p_reset_reason Contents of the NRF_POWER->RESETREAS register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RESET_REASON_GET, uint32_t, sd_power_reset_reason_get(uint32_t *p_reset_reason)); + +/**@brief Clears the bits of the reset reason register. + * + * @param[in] reset_reason_clr_msk Contains the bits to clear from the reset reason register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RESET_REASON_CLR, uint32_t, sd_power_reset_reason_clr(uint32_t reset_reason_clr_msk)); + +/**@brief Sets the power mode when in CPU sleep. + * + * @param[in] power_mode The power mode to use when in CPU sleep, see @ref NRF_POWER_MODES. @sa sd_app_evt_wait + * + * @retval ::NRF_SUCCESS The power mode was set. + * @retval ::NRF_ERROR_SOC_POWER_MODE_UNKNOWN The power mode was unknown. + */ +SVCALL(SD_POWER_MODE_SET, uint32_t, sd_power_mode_set(uint8_t power_mode)); + +/**@brief Puts the chip in System OFF mode. + * + * @retval ::NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN + */ +SVCALL(SD_POWER_SYSTEM_OFF, uint32_t, sd_power_system_off(void)); + +/**@brief Enables or disables the power-fail comparator. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_FAILURE_WARNING) when the power failure warning occurs. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] pof_enable True if the power-fail comparator should be enabled, false if it should be disabled. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_POF_ENABLE, uint32_t, sd_power_pof_enable(uint8_t pof_enable)); + +/**@brief Enables or disables the USB power ready event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_POWER_READY) when a USB 3.3 V supply is ready. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbpwrrdy_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBPWRRDY_ENABLE, uint32_t, sd_power_usbpwrrdy_enable(uint8_t usbpwrrdy_enable)); + +/**@brief Enables or disables the power USB-detected event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_DETECTED) when a voltage supply is detected on VBUS. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbdetected_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBDETECTED_ENABLE, uint32_t, sd_power_usbdetected_enable(uint8_t usbdetected_enable)); + +/**@brief Enables or disables the power USB-removed event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_REMOVED) when a voltage supply is removed from VBUS. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbremoved_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBREMOVED_ENABLE, uint32_t, sd_power_usbremoved_enable(uint8_t usbremoved_enable)); + +/**@brief Get USB supply status register content. + * + * @param[out] usbregstatus The content of USBREGSTATUS register. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBREGSTATUS_GET, uint32_t, sd_power_usbregstatus_get(uint32_t *usbregstatus)); + +/**@brief Sets the power failure comparator threshold value. + * + * @note: Power failure comparator threshold setting. This setting applies both for normal voltage + * mode (supply connected to both VDD and VDDH) and high voltage mode (supply connected to + * VDDH only). + * + * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDS. + * + * @retval ::NRF_SUCCESS The power failure threshold was set. + * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. + */ +SVCALL(SD_POWER_POF_THRESHOLD_SET, uint32_t, sd_power_pof_threshold_set(uint8_t threshold)); + +/**@brief Sets the power failure comparator threshold value for high voltage. + * + * @note: Power failure comparator threshold setting for high voltage mode (supply connected to + * VDDH only). This setting does not apply for normal voltage mode (supply connected to both + * VDD and VDDH). + * + * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDVDDHS. + * + * @retval ::NRF_SUCCESS The power failure threshold was set. + * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. + */ +SVCALL(SD_POWER_POF_THRESHOLDVDDH_SET, uint32_t, sd_power_pof_thresholdvddh_set(uint8_t threshold)); + +/**@brief Writes the NRF_POWER->RAM[index].POWERSET register. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERSET register to write to. + * @param[in] ram_powerset Contains the word to write to the NRF_POWER->RAM[index].POWERSET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_SET, uint32_t, sd_power_ram_power_set(uint8_t index, uint32_t ram_powerset)); + +/**@brief Writes the NRF_POWER->RAM[index].POWERCLR register. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERCLR register to write to. + * @param[in] ram_powerclr Contains the word to write to the NRF_POWER->RAM[index].POWERCLR register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_CLR, uint32_t, sd_power_ram_power_clr(uint8_t index, uint32_t ram_powerclr)); + +/**@brief Get contents of NRF_POWER->RAM[index].POWER register, indicates power status of RAM[index] blocks. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWER register to read from. + * @param[out] p_ram_power Content of NRF_POWER->RAM[index].POWER register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_GET, uint32_t, sd_power_ram_power_get(uint8_t index, uint32_t *p_ram_power)); + +/**@brief Set bits in the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[in] gpregret_msk Bits to be set in the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_SET, uint32_t, sd_power_gpregret_set(uint32_t gpregret_id, uint32_t gpregret_msk)); + +/**@brief Clear bits in the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[in] gpregret_msk Bits to be clear in the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_CLR, uint32_t, sd_power_gpregret_clr(uint32_t gpregret_id, uint32_t gpregret_msk)); + +/**@brief Get contents of the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[out] p_gpregret Contents of the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_GET, uint32_t, sd_power_gpregret_get(uint32_t gpregret_id, uint32_t *p_gpregret)); + +/**@brief Enable or disable the DC/DC regulator for the regulator stage 1 (REG1). + * + * @param[in] dcdc_mode The mode of the DCDC, see @ref NRF_POWER_DCDC_MODES. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_PARAM The DCDC mode is invalid. + */ +SVCALL(SD_POWER_DCDC_MODE_SET, uint32_t, sd_power_dcdc_mode_set(uint8_t dcdc_mode)); + +/**@brief Enable or disable the DC/DC regulator for the regulator stage 0 (REG0). + * + * For more details on the REG0 stage, please see product specification. + * + * @param[in] dcdc_mode The mode of the DCDC0, see @ref NRF_POWER_DCDC_MODES. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_PARAM The dcdc_mode is invalid. + */ +SVCALL(SD_POWER_DCDC0_MODE_SET, uint32_t, sd_power_dcdc0_mode_set(uint8_t dcdc_mode)); + +/**@brief Request the high frequency crystal oscillator. + * + * Will start the high frequency crystal oscillator, the startup time of the crystal varies + * and the ::sd_clock_hfclk_is_running function can be polled to check if it has started. + * + * @see sd_clock_hfclk_is_running + * @see sd_clock_hfclk_release + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_REQUEST, uint32_t, sd_clock_hfclk_request(void)); + +/**@brief Releases the high frequency crystal oscillator. + * + * Will stop the high frequency crystal oscillator, this happens immediately. + * + * @see sd_clock_hfclk_is_running + * @see sd_clock_hfclk_request + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_RELEASE, uint32_t, sd_clock_hfclk_release(void)); + +/**@brief Checks if the high frequency crystal oscillator is running. + * + * @see sd_clock_hfclk_request + * @see sd_clock_hfclk_release + * + * @param[out] p_is_running 1 if the external crystal oscillator is running, 0 if not. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_IS_RUNNING, uint32_t, sd_clock_hfclk_is_running(uint32_t *p_is_running)); + +/**@brief Waits for an application event. + * + * An application event is either an application interrupt or a pended interrupt when the interrupt + * is disabled. + * + * When the application waits for an application event by calling this function, an interrupt that + * is enabled will be taken immediately on pending since this function will wait in thread mode, + * then the execution will return in the application's main thread. + * + * In order to wake up from disabled interrupts, the SEVONPEND flag has to be set in the Cortex-M + * MCU's System Control Register (SCR), CMSIS_SCB. In that case, when a disabled interrupt gets + * pended, this function will return to the application's main thread. + * + * @note The application must ensure that the pended flag is cleared using ::sd_nvic_ClearPendingIRQ + * in order to sleep using this function. This is only necessary for disabled interrupts, as + * the interrupt handler will clear the pending flag automatically for enabled interrupts. + * + * @note If an application interrupt has happened since the last time sd_app_evt_wait was + * called this function will return immediately and not go to sleep. This is to avoid race + * conditions that can occur when a flag is updated in the interrupt handler and processed + * in the main loop. + * + * @post An application interrupt has happened or a interrupt pending flag is set. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_APP_EVT_WAIT, uint32_t, sd_app_evt_wait(void)); + +/**@brief Get PPI channel enable register contents. + * + * @param[out] p_channel_enable The contents of the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_GET, uint32_t, sd_ppi_channel_enable_get(uint32_t *p_channel_enable)); + +/**@brief Set PPI channel enable register. + * + * @param[in] channel_enable_set_msk Mask containing the bits to set in the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_SET, uint32_t, sd_ppi_channel_enable_set(uint32_t channel_enable_set_msk)); + +/**@brief Clear PPI channel enable register. + * + * @param[in] channel_enable_clr_msk Mask containing the bits to clear in the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_CLR, uint32_t, sd_ppi_channel_enable_clr(uint32_t channel_enable_clr_msk)); + +/**@brief Assign endpoints to a PPI channel. + * + * @param[in] channel_num Number of the PPI channel to assign. + * @param[in] evt_endpoint Event endpoint of the PPI channel. + * @param[in] task_endpoint Task endpoint of the PPI channel. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_CHANNEL The channel number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ASSIGN, uint32_t, + sd_ppi_channel_assign(uint8_t channel_num, const volatile void *evt_endpoint, const volatile void *task_endpoint)); + +/**@brief Task to enable a channel group. + * + * @param[in] group_num Number of the channel group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_TASK_ENABLE, uint32_t, sd_ppi_group_task_enable(uint8_t group_num)); + +/**@brief Task to disable a channel group. + * + * @param[in] group_num Number of the PPI group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_TASK_DISABLE, uint32_t, sd_ppi_group_task_disable(uint8_t group_num)); + +/**@brief Assign PPI channels to a channel group. + * + * @param[in] group_num Number of the channel group. + * @param[in] channel_msk Mask of the channels to assign to the group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_ASSIGN, uint32_t, sd_ppi_group_assign(uint8_t group_num, uint32_t channel_msk)); + +/**@brief Gets the PPI channels of a channel group. + * + * @param[in] group_num Number of the channel group. + * @param[out] p_channel_msk Mask of the channels assigned to the group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_GET, uint32_t, sd_ppi_group_get(uint8_t group_num, uint32_t *p_channel_msk)); + +/**@brief Configures the Radio Notification signal. + * + * @note + * - The notification signal latency depends on the interrupt priority settings of SWI used + * for notification signal. + * - To ensure that the radio notification signal behaves in a consistent way, the radio + * notifications must be configured when there is no protocol stack or other SoftDevice + * activity in progress. It is recommended that the radio notification signal is + * configured directly after the SoftDevice has been enabled. + * - In the period between the ACTIVE signal and the start of the Radio Event, the SoftDevice + * will interrupt the application to do Radio Event preparation. + * - Using the Radio Notification feature may limit the bandwidth, as the SoftDevice may have + * to shorten the connection events to have time for the Radio Notification signals. + * + * @param[in] type Type of notification signal, see @ref NRF_RADIO_NOTIFICATION_TYPES. + * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE shall be used to turn off radio + * notification. Using @ref NRF_RADIO_NOTIFICATION_DISTANCE_NONE is + * recommended (but not required) to be used with + * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE. + * + * @param[in] distance Distance between the notification signal and start of radio activity, see @ref + * NRF_RADIO_NOTIFICATION_DISTANCES. This parameter is ignored when @ref NRF_RADIO_NOTIFICATION_TYPE_NONE or + * @ref NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE is used. + * + * @retval ::NRF_ERROR_INVALID_PARAM The group number is invalid. + * @retval ::NRF_ERROR_INVALID_STATE A protocol stack or other SoftDevice is running. Stop all + * running activities and retry. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RADIO_NOTIFICATION_CFG_SET, uint32_t, sd_radio_notification_cfg_set(uint8_t type, uint8_t distance)); + +/**@brief Encrypts a block according to the specified parameters. + * + * 128-bit AES encryption. + * + * @note: + * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while + * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application + * main or low interrupt level. + * + * @param[in, out] p_ecb_data Pointer to the ECB parameters' struct (two input + * parameters and one output parameter). + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_ECB_BLOCK_ENCRYPT, uint32_t, sd_ecb_block_encrypt(nrf_ecb_hal_data_t *p_ecb_data)); + +/**@brief Encrypts multiple data blocks provided as an array of data block structures. + * + * @details: Performs 128-bit AES encryption on multiple data blocks + * + * @note: + * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while + * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application + * main or low interrupt level. + * + * @param[in] block_count Count of blocks in the p_data_blocks array. + * @param[in,out] p_data_blocks Pointer to the first entry in a contiguous array of + * @ref nrf_ecb_hal_data_block_t structures. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_ECB_BLOCKS_ENCRYPT, uint32_t, sd_ecb_blocks_encrypt(uint8_t block_count, nrf_ecb_hal_data_block_t *p_data_blocks)); + +/**@brief Gets any pending events generated by the SoC API. + * + * The application should keep calling this function to get events, until ::NRF_ERROR_NOT_FOUND is returned. + * + * @param[out] p_evt_id Set to one of the values in @ref NRF_SOC_EVTS, if any events are pending. + * + * @retval ::NRF_SUCCESS An event was pending. The event id is written in the p_evt_id parameter. + * @retval ::NRF_ERROR_NOT_FOUND No pending events. + */ +SVCALL(SD_EVT_GET, uint32_t, sd_evt_get(uint32_t *p_evt_id)); + +/**@brief Get the temperature measured on the chip + * + * This function will block until the temperature measurement is done. + * It takes around 50 us from call to return. + * + * @param[out] p_temp Result of temperature measurement. Die temperature in 0.25 degrees Celsius. + * + * @retval ::NRF_SUCCESS A temperature measurement was done, and the temperature was written to temp + */ +SVCALL(SD_TEMP_GET, uint32_t, sd_temp_get(int32_t *p_temp)); + +/**@brief Flash Write + * + * Commands to write a buffer to flash + * + * If the SoftDevice is enabled: + * This call initiates the flash access command, and its completion will be communicated to the + * application with exactly one of the following events: + * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. + * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. + * + * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the + * write has been completed + * + * @note + * - This call takes control over the radio and the CPU during flash erase and write to make sure that + * they will not interfere with the flash access. This means that all interrupts will be blocked + * for a predictable time (depending on the NVMC specification in the device's Product Specification + * and the command parameters). + * - The data in the p_src buffer should not be modified before the @ref NRF_EVT_FLASH_OPERATION_SUCCESS + * or the @ref NRF_EVT_FLASH_OPERATION_ERROR have been received if the SoftDevice is enabled. + * - This call will make the SoftDevice trigger a hardfault when the page is written, if it is + * protected. + * + * + * @param[in] p_dst Pointer to start of flash location to be written. + * @param[in] p_src Pointer to buffer with data to be written. + * @param[in] size Number of 32-bit words to write. Maximum size is the number of words in one + * flash page. See the device's Product Specification for details. + * + * @retval ::NRF_ERROR_INVALID_ADDR Tried to write to a non existing flash address, or p_dst or p_src was unaligned. + * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. + * @retval ::NRF_ERROR_INVALID_LENGTH Size was 0, or higher than the maximum allowed size. + * @retval ::NRF_ERROR_FORBIDDEN Tried to write to an address outside the application flash area. + * @retval ::NRF_SUCCESS The command was accepted. + */ +SVCALL(SD_FLASH_WRITE, uint32_t, sd_flash_write(uint32_t *p_dst, uint32_t const *p_src, uint32_t size)); + +/**@brief Flash Erase page + * + * Commands to erase a flash page + * If the SoftDevice is enabled: + * This call initiates the flash access command, and its completion will be communicated to the + * application with exactly one of the following events: + * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. + * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. + * + * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the + * erase has been completed + * + * @note + * - This call takes control over the radio and the CPU during flash erase and write to make sure that + * they will not interfere with the flash access. This means that all interrupts will be blocked + * for a predictable time (depending on the NVMC specification in the device's Product Specification + * and the command parameters). + * - This call will make the SoftDevice trigger a hardfault when the page is erased, if it is + * protected. + * + * + * @param[in] page_number Page number of the page to erase + * + * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. + * @retval ::NRF_ERROR_INVALID_ADDR Tried to erase to a non existing flash page. + * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. + * @retval ::NRF_ERROR_FORBIDDEN Tried to erase a page outside the application flash area. + * @retval ::NRF_SUCCESS The command was accepted. + */ +SVCALL(SD_FLASH_PAGE_ERASE, uint32_t, sd_flash_page_erase(uint32_t page_number)); + +/**@brief Opens a session for radio timeslot requests. + * + * @note Only one session can be open at a time. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) will be called when the radio timeslot + * starts. From this point the NRF_RADIO and NRF_TIMER0 peripherals can be freely accessed + * by the application. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0) is called whenever the NRF_TIMER0 + * interrupt occurs. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO) is called whenever the NRF_RADIO + * interrupt occurs. + * @note p_radio_signal_callback() will be called at ARM interrupt priority level 0. This + * implies that none of the sd_* API calls can be used from p_radio_signal_callback(). + * + * @param[in] p_radio_signal_callback The signal callback. + * + * @retval ::NRF_ERROR_INVALID_ADDR p_radio_signal_callback is an invalid function pointer. + * @retval ::NRF_ERROR_BUSY If session cannot be opened. + * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_SESSION_OPEN, uint32_t, sd_radio_session_open(nrf_radio_signal_callback_t p_radio_signal_callback)); + +/**@brief Closes a session for radio timeslot requests. + * + * @note Any current radio timeslot will be finished before the session is closed. + * @note If a radio timeslot is scheduled when the session is closed, it will be canceled. + * @note The application cannot consider the session closed until the @ref NRF_EVT_RADIO_SESSION_CLOSED + * event is received. + * + * @retval ::NRF_ERROR_FORBIDDEN If session not opened. + * @retval ::NRF_ERROR_BUSY If session is currently being closed. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_SESSION_CLOSE, uint32_t, sd_radio_session_close(void)); + +/**@brief Requests a radio timeslot. + * + * @note The request type is determined by p_request->request_type, and can be one of @ref NRF_RADIO_REQ_TYPE_EARLIEST + * and @ref NRF_RADIO_REQ_TYPE_NORMAL. The first request in a session must always be of type @ref + * NRF_RADIO_REQ_TYPE_EARLIEST. + * @note For a normal request (@ref NRF_RADIO_REQ_TYPE_NORMAL), the start time of a radio timeslot is specified by + * p_request->distance_us and is given relative to the start of the previous timeslot. + * @note A too small p_request->distance_us will lead to a @ref NRF_EVT_RADIO_BLOCKED event. + * @note Timeslots scheduled too close will lead to a @ref NRF_EVT_RADIO_BLOCKED event. + * @note See the SoftDevice Specification for more on radio timeslot scheduling, distances and lengths. + * @note If an opportunity for the first radio timeslot is not found before 100 ms after the call to this + * function, it is not scheduled, and instead a @ref NRF_EVT_RADIO_BLOCKED event is sent. + * The application may then try to schedule the first radio timeslot again. + * @note Successful requests will result in nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START). + * Unsuccessful requests will result in a @ref NRF_EVT_RADIO_BLOCKED event, see @ref NRF_SOC_EVTS. + * @note The jitter in the start time of the radio timeslots is +/- @ref NRF_RADIO_START_JITTER_US us. + * @note The nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) call has a latency relative to the + * specified radio timeslot start, but this does not affect the actual start time of the timeslot. + * @note NRF_TIMER0 is reset at the start of the radio timeslot, and is clocked at 1MHz from the high frequency + * (16 MHz) clock source. If p_request->hfclk_force_xtal is true, the high frequency clock is + * guaranteed to be clocked from the external crystal. + * @note The SoftDevice will neither access the NRF_RADIO peripheral nor the NRF_TIMER0 peripheral + * during the radio timeslot. + * + * @param[in] p_request Pointer to the request parameters. + * + * @retval ::NRF_ERROR_FORBIDDEN Either: + * - The session is not open. + * - The session is not IDLE. + * - This is the first request and its type is not @ref NRF_RADIO_REQ_TYPE_EARLIEST. + * - The request type was set to @ref NRF_RADIO_REQ_TYPE_NORMAL after a + * @ref NRF_RADIO_REQ_TYPE_EARLIEST request was blocked. + * @retval ::NRF_ERROR_INVALID_ADDR If the p_request pointer is invalid. + * @retval ::NRF_ERROR_INVALID_PARAM If the parameters of p_request are not valid. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_REQUEST, uint32_t, sd_radio_request(nrf_radio_request_t const *p_request)); + +/**@brief Write register protected by the SoftDevice + * + * This function writes to a register that is write-protected by the SoftDevice. Please refer to your + * SoftDevice Specification for more details about which registers that are protected by SoftDevice. + * This function can write to the following protected peripheral: + * - ACL + * + * @note Protected registers may be read directly. + * @note Register that are write-once will return @ref NRF_SUCCESS on second set, even the value in + * the register has not changed. See the Product Specification for more details about register + * properties. + * + * @param[in] p_register Pointer to register to be written. + * @param[in] value Value to be written to the register. + * + * @retval ::NRF_ERROR_INVALID_ADDR This function can not write to the reguested register. + * @retval ::NRF_SUCCESS Value successfully written to register. + * + */ +SVCALL(SD_PROTECTED_REGISTER_WRITE, uint32_t, sd_protected_register_write(volatile uint32_t *p_register, uint32_t value)); + +/**@} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_SOC_H__ + +/**@} */ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_svc.h b/variants/wio-sdk-wm1110/softdevice/nrf_svc.h new file mode 100644 index 0000000000..1de44656f3 --- /dev/null +++ b/variants/wio-sdk-wm1110/softdevice/nrf_svc.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NRF_SVC__ +#define NRF_SVC__ + +#include "stdint.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Supervisor call declaration. + * + * A call to a function marked with @ref SVCALL, will trigger a Supervisor Call (SVC) Exception. + * The SVCs with SVC numbers 0x00-0x0F are forwared to the application. All other SVCs are handled by the SoftDevice. + * + * @param[in] number The SVC number to be used. + * @param[in] return_type The return type of the SVC function. + * @param[in] signature Function signature. The function can have at most four arguments. + */ + +#ifdef SVCALL_AS_NORMAL_FUNCTION +#define SVCALL(number, return_type, signature) return_type signature +#else + +#ifndef SVCALL +#if defined(__CC_ARM) +#define SVCALL(number, return_type, signature) return_type __svc(number) signature +#elif defined(__GNUC__) +#ifdef __cplusplus +#define GCC_CAST_CPP (uint16_t) +#else +#define GCC_CAST_CPP +#endif +#define SVCALL(number, return_type, signature) \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") __attribute__((naked)) \ + __attribute__((unused)) static return_type signature \ + { \ + __asm("svc %0\n" \ + "bx r14" \ + : \ + : "I"(GCC_CAST_CPP number) \ + : "r0"); \ + } \ + _Pragma("GCC diagnostic pop") + +#elif defined(__ICCARM__) +#define PRAGMA(x) _Pragma(#x) +#define SVCALL(number, return_type, signature) \ + PRAGMA(swi_number = (number)) \ + __swi return_type signature; +#else +#define SVCALL(number, return_type, signature) return_type signature +#endif +#endif // SVCALL + +#endif // SVCALL_AS_NORMAL_FUNCTION + +#ifdef __cplusplus +} +#endif +#endif // NRF_SVC__ diff --git a/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld b/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld new file mode 100644 index 0000000000..6aaeb4034f --- /dev/null +++ b/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld @@ -0,0 +1,38 @@ +/* Linker script to configure memory regions. */ + +SEARCH_DIR(.) +GROUP(-lgcc -lc -lnosys) + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xED000 - 0x27000 + + /* SRAM required by Softdevice depend on + * - Attribute Table Size (Number of Services and Characteristics) + * - Vendor UUID count + * - Max ATT MTU + * - Concurrent connection peripheral + central + secure links + * - Event Len, HVN queue, Write CMD queue + */ + RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x20040000 - 0x20006000 +} + +SECTIONS +{ + . = ALIGN(4); + .svc_data : + { + PROVIDE(__start_svc_data = .); + KEEP(*(.svc_data)) + PROVIDE(__stop_svc_data = .); + } > RAM + + .fs_data : + { + PROVIDE(__start_fs_data = .); + KEEP(*(.fs_data)) + PROVIDE(__stop_fs_data = .); + } > RAM +} INSERT AFTER .data; + +INCLUDE "nrf52_common.ld" diff --git a/variants/wio-tracker-wm1110/platformio.ini b/variants/wio-tracker-wm1110/platformio.ini index 03d7d047a7..9c04e36f16 100644 --- a/variants/wio-tracker-wm1110/platformio.ini +++ b/variants/wio-tracker-wm1110/platformio.ini @@ -5,10 +5,10 @@ board = wio-tracker-wm1110 build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-tracker-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld +board_build.ldscript = variants/wio-tracker-wm1110/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-tracker-wm1110> lib_deps = ${nrf52840_base.lib_deps} debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink \ No newline at end of file +;upload_protocol = jlink diff --git a/variants/wio-tracker-wm1110/softdevice/ble.h b/variants/wio-tracker-wm1110/softdevice/ble.h new file mode 100644 index 0000000000..177b436ad8 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble.h @@ -0,0 +1,652 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON BLE SoftDevice Common + @{ + @defgroup ble_api Events, type definitions and API calls + @{ + + @brief Module independent events, type definitions and API calls for the BLE SoftDevice. + + */ + +#ifndef BLE_H__ +#define BLE_H__ + +#include "ble_err.h" +#include "ble_gap.h" +#include "ble_gatt.h" +#include "ble_gattc.h" +#include "ble_gatts.h" +#include "ble_l2cap.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_COMMON_ENUMERATIONS Enumerations + * @{ */ + +/** + * @brief Common API SVC numbers. + */ +enum BLE_COMMON_SVCS { + SD_BLE_ENABLE = BLE_SVC_BASE, /**< Enable and initialize the BLE stack */ + SD_BLE_EVT_GET, /**< Get an event from the pending events queue. */ + SD_BLE_UUID_VS_ADD, /**< Add a Vendor Specific base UUID. */ + SD_BLE_UUID_DECODE, /**< Decode UUID bytes. */ + SD_BLE_UUID_ENCODE, /**< Encode UUID bytes. */ + SD_BLE_VERSION_GET, /**< Get the local version information (company ID, Link Layer Version, Link Layer Subversion). */ + SD_BLE_USER_MEM_REPLY, /**< User Memory Reply. */ + SD_BLE_OPT_SET, /**< Set a BLE option. */ + SD_BLE_OPT_GET, /**< Get a BLE option. */ + SD_BLE_CFG_SET, /**< Add a configuration to the BLE stack. */ + SD_BLE_UUID_VS_REMOVE, /**< Remove a Vendor Specific base UUID. */ +}; + +/** + * @brief BLE Module Independent Event IDs. + */ +enum BLE_COMMON_EVTS { + BLE_EVT_USER_MEM_REQUEST = BLE_EVT_BASE + 0, /**< User Memory request. See @ref ble_evt_user_mem_request_t + \n Reply with @ref sd_ble_user_mem_reply. */ + BLE_EVT_USER_MEM_RELEASE = BLE_EVT_BASE + 1, /**< User Memory release. See @ref ble_evt_user_mem_release_t */ +}; + +/**@brief BLE Connection Configuration IDs. + * + * IDs that uniquely identify a connection configuration. + */ +enum BLE_CONN_CFGS { + BLE_CONN_CFG_GAP = BLE_CONN_CFG_BASE + 0, /**< BLE GAP specific connection configuration. */ + BLE_CONN_CFG_GATTC = BLE_CONN_CFG_BASE + 1, /**< BLE GATTC specific connection configuration. */ + BLE_CONN_CFG_GATTS = BLE_CONN_CFG_BASE + 2, /**< BLE GATTS specific connection configuration. */ + BLE_CONN_CFG_GATT = BLE_CONN_CFG_BASE + 3, /**< BLE GATT specific connection configuration. */ + BLE_CONN_CFG_L2CAP = BLE_CONN_CFG_BASE + 4, /**< BLE L2CAP specific connection configuration. */ +}; + +/**@brief BLE Common Configuration IDs. + * + * IDs that uniquely identify a common configuration. + */ +enum BLE_COMMON_CFGS { + BLE_COMMON_CFG_VS_UUID = BLE_CFG_BASE, /**< Vendor specific base UUID configuration */ +}; + +/**@brief Common Option IDs. + * IDs that uniquely identify a common option. + */ +enum BLE_COMMON_OPTS { + BLE_COMMON_OPT_PA_LNA = BLE_OPT_BASE + 0, /**< PA and LNA options */ + BLE_COMMON_OPT_CONN_EVT_EXT = BLE_OPT_BASE + 1, /**< Extended connection events option */ + BLE_COMMON_OPT_EXTENDED_RC_CAL = BLE_OPT_BASE + 2, /**< Extended RC calibration option */ +}; + +/** @} */ + +/** @addtogroup BLE_COMMON_DEFINES Defines + * @{ */ + +/** @brief Required pointer alignment for BLE Events. + */ +#define BLE_EVT_PTR_ALIGNMENT 4 + +/** @brief Leaves the maximum of the two arguments. + */ +#define BLE_MAX(a, b) ((a) < (b) ? (b) : (a)) + +/** @brief Maximum possible length for BLE Events. + * @note The highest value used for @ref ble_gatt_conn_cfg_t::att_mtu in any connection configuration shall be used as a + * parameter. If that value has not been configured for any connections then @ref BLE_GATT_ATT_MTU_DEFAULT must be used instead. + */ +#define BLE_EVT_LEN_MAX(ATT_MTU) \ + (offsetof(ble_evt_t, evt.gattc_evt.params.prim_srvc_disc_rsp.services) + ((ATT_MTU)-1) / 4 * sizeof(ble_gattc_service_t)) + +/** @defgroup BLE_USER_MEM_TYPES User Memory Types + * @{ */ +#define BLE_USER_MEM_TYPE_INVALID 0x00 /**< Invalid User Memory Types. */ +#define BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES 0x01 /**< User Memory for GATTS queued writes. */ +/** @} */ + +/** @defgroup BLE_UUID_VS_COUNTS Vendor Specific base UUID counts + * @{ + */ +#define BLE_UUID_VS_COUNT_DEFAULT 10 /**< Default VS UUID count. */ +#define BLE_UUID_VS_COUNT_MAX 254 /**< Maximum VS UUID count. */ +/** @} */ + +/** @defgroup BLE_COMMON_CFG_DEFAULTS Configuration defaults. + * @{ + */ +#define BLE_CONN_CFG_TAG_DEFAULT 0 /**< Default configuration tag, SoftDevice default connection configuration. */ + +/** @} */ + +/** @} */ + +/** @addtogroup BLE_COMMON_STRUCTURES Structures + * @{ */ + +/**@brief User Memory Block. */ +typedef struct { + uint8_t *p_mem; /**< Pointer to the start of the user memory block. */ + uint16_t len; /**< Length in bytes of the user memory block. */ +} ble_user_mem_block_t; + +/**@brief Event structure for @ref BLE_EVT_USER_MEM_REQUEST. */ +typedef struct { + uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ +} ble_evt_user_mem_request_t; + +/**@brief Event structure for @ref BLE_EVT_USER_MEM_RELEASE. */ +typedef struct { + uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ + ble_user_mem_block_t mem_block; /**< User memory block */ +} ble_evt_user_mem_release_t; + +/**@brief Event structure for events not associated with a specific function module. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which this event occurred. */ + union { + ble_evt_user_mem_request_t user_mem_request; /**< User Memory Request Event Parameters. */ + ble_evt_user_mem_release_t user_mem_release; /**< User Memory Release Event Parameters. */ + } params; /**< Event parameter union. */ +} ble_common_evt_t; + +/**@brief BLE Event header. */ +typedef struct { + uint16_t evt_id; /**< Value from a BLE__EVT series. */ + uint16_t evt_len; /**< Length in octets including this header. */ +} ble_evt_hdr_t; + +/**@brief Common BLE Event type, wrapping the module specific event reports. */ +typedef struct { + ble_evt_hdr_t header; /**< Event header. */ + union { + ble_common_evt_t common_evt; /**< Common Event, evt_id in BLE_EVT_* series. */ + ble_gap_evt_t gap_evt; /**< GAP originated event, evt_id in BLE_GAP_EVT_* series. */ + ble_gattc_evt_t gattc_evt; /**< GATT client originated event, evt_id in BLE_GATTC_EVT* series. */ + ble_gatts_evt_t gatts_evt; /**< GATT server originated event, evt_id in BLE_GATTS_EVT* series. */ + ble_l2cap_evt_t l2cap_evt; /**< L2CAP originated event, evt_id in BLE_L2CAP_EVT* series. */ + } evt; /**< Event union. */ +} ble_evt_t; + +/** + * @brief Version Information. + */ +typedef struct { + uint8_t version_number; /**< Link Layer Version number. See + https://www.bluetooth.org/en-us/specification/assigned-numbers/link-layer for assigned values. */ + uint16_t company_id; /**< Company ID, Nordic Semiconductor's company ID is 89 (0x0059) + (https://www.bluetooth.org/apps/content/Default.aspx?doc_id=49708). */ + uint16_t + subversion_number; /**< Link Layer Sub Version number, corresponds to the SoftDevice Config ID or Firmware ID (FWID). */ +} ble_version_t; + +/** + * @brief Configuration parameters for the PA and LNA. + */ +typedef struct { + uint8_t enable : 1; /**< Enable toggling for this amplifier */ + uint8_t active_high : 1; /**< Set the pin to be active high */ + uint8_t gpio_pin : 6; /**< The GPIO pin to toggle for this amplifier */ +} ble_pa_lna_cfg_t; + +/** + * @brief PA & LNA GPIO toggle configuration + * + * This option configures the SoftDevice to toggle pins when the radio is active for use with a power amplifier and/or + * a low noise amplifier. + * + * Toggling the pins is achieved by using two PPI channels and a GPIOTE channel. The hardware channel IDs are provided + * by the application and should be regarded as reserved as long as any PA/LNA toggling is enabled. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * @note Setting this option while the radio is in use (i.e. any of the roles are active) may have undefined consequences + * and must be avoided by the application. + */ +typedef struct { + ble_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */ + ble_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */ + + uint8_t ppi_ch_id_set; /**< PPI channel used for radio pin setting */ + uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */ + uint8_t gpiote_ch_id; /**< GPIOTE channel used for radio pin toggling */ +} ble_common_opt_pa_lna_t; + +/** + * @brief Configuration of extended BLE connection events. + * + * When enabled the SoftDevice will dynamically extend the connection event when possible. + * + * The connection event length is controlled by the connection configuration as set by @ref ble_gap_conn_cfg_t::event_length. + * The connection event can be extended if there is time to send another packet pair before the start of the next connection + * interval, and if there are no conflicts with other BLE roles requesting radio time. + * + * @note @ref sd_ble_opt_get is not supported for this option. + */ +typedef struct { + uint8_t enable : 1; /**< Enable extended BLE connection events, disabled by default. */ +} ble_common_opt_conn_evt_ext_t; + +/** + * @brief Enable/disable extended RC calibration. + * + * If extended RC calibration is enabled and the internal RC oscillator (@ref NRF_CLOCK_LF_SRC_RC) is used as the SoftDevice + * LFCLK source, the SoftDevice as a peripheral will by default try to increase the receive window if two consecutive packets + * are not received. If it turns out that the packets were not received due to clock drift, the RC calibration is started. + * This calibration comes in addition to the periodic calibration that is configured by @ref sd_softdevice_enable(). When + * using only peripheral connections, the periodic calibration can therefore be configured with a much longer interval as the + * peripheral will be able to detect and adjust automatically to clock drift, and calibrate on demand. + * + * If extended RC calibration is disabled and the internal RC oscillator is used as the SoftDevice LFCLK source, the + * RC oscillator is calibrated periodically as configured by @ref sd_softdevice_enable(). + * + * @note @ref sd_ble_opt_get is not supported for this option. + */ +typedef struct { + uint8_t enable : 1; /**< Enable extended RC calibration, enabled by default. */ +} ble_common_opt_extended_rc_cal_t; + +/**@brief Option structure for common options. */ +typedef union { + ble_common_opt_pa_lna_t pa_lna; /**< Parameters for controlling PA and LNA pin toggling. */ + ble_common_opt_conn_evt_ext_t conn_evt_ext; /**< Parameters for enabling extended connection events. */ + ble_common_opt_extended_rc_cal_t extended_rc_cal; /**< Parameters for enabling extended RC calibration. */ +} ble_common_opt_t; + +/**@brief Common BLE Option type, wrapping the module specific options. */ +typedef union { + ble_common_opt_t common_opt; /**< COMMON options, opt_id in @ref BLE_COMMON_OPTS series. */ + ble_gap_opt_t gap_opt; /**< GAP option, opt_id in @ref BLE_GAP_OPTS series. */ + ble_gattc_opt_t gattc_opt; /**< GATTC option, opt_id in @ref BLE_GATTC_OPTS series. */ +} ble_opt_t; + +/**@brief BLE connection configuration type, wrapping the module specific configurations, set with + * @ref sd_ble_cfg_set. + * + * @note Connection configurations don't have to be set. + * In the case that no configurations has been set, or fewer connection configurations has been set than enabled connections, + * the default connection configuration will be automatically added for the remaining connections. + * When creating connections with the default configuration, @ref BLE_CONN_CFG_TAG_DEFAULT should be used in + * place of @ref ble_conn_cfg_t::conn_cfg_tag. + * + * @sa sd_ble_gap_adv_start() + * @sa sd_ble_gap_connect() + * + * @mscs + * @mmsc{@ref BLE_CONN_CFG} + * @endmscs + + */ +typedef struct { + uint8_t conn_cfg_tag; /**< The application chosen tag it can use with the + @ref sd_ble_gap_adv_start() and @ref sd_ble_gap_connect() calls + to select this configuration when creating a connection. + Must be different for all connection configurations added and not @ref BLE_CONN_CFG_TAG_DEFAULT. */ + union { + ble_gap_conn_cfg_t gap_conn_cfg; /**< GAP connection configuration, cfg_id is @ref BLE_CONN_CFG_GAP. */ + ble_gattc_conn_cfg_t gattc_conn_cfg; /**< GATTC connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTC. */ + ble_gatts_conn_cfg_t gatts_conn_cfg; /**< GATTS connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTS. */ + ble_gatt_conn_cfg_t gatt_conn_cfg; /**< GATT connection configuration, cfg_id is @ref BLE_CONN_CFG_GATT. */ + ble_l2cap_conn_cfg_t l2cap_conn_cfg; /**< L2CAP connection configuration, cfg_id is @ref BLE_CONN_CFG_L2CAP. */ + } params; /**< Connection configuration union. */ +} ble_conn_cfg_t; + +/** + * @brief Configuration of Vendor Specific base UUIDs, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_PARAM Too many UUIDs configured. + */ +typedef struct { + uint8_t vs_uuid_count; /**< Number of 128-bit Vendor Specific base UUID bases to allocate memory for. + Default value is @ref BLE_UUID_VS_COUNT_DEFAULT. Maximum value is + @ref BLE_UUID_VS_COUNT_MAX. */ +} ble_common_cfg_vs_uuid_t; + +/**@brief Common BLE Configuration type, wrapping the common configurations. */ +typedef union { + ble_common_cfg_vs_uuid_t vs_uuid_cfg; /**< Vendor Specific base UUID configuration, cfg_id is @ref BLE_COMMON_CFG_VS_UUID. */ +} ble_common_cfg_t; + +/**@brief BLE Configuration type, wrapping the module specific configurations. */ +typedef union { + ble_conn_cfg_t conn_cfg; /**< Connection specific configurations, cfg_id in @ref BLE_CONN_CFGS series. */ + ble_common_cfg_t common_cfg; /**< Global common configurations, cfg_id in @ref BLE_COMMON_CFGS series. */ + ble_gap_cfg_t gap_cfg; /**< Global GAP configurations, cfg_id in @ref BLE_GAP_CFGS series. */ + ble_gatts_cfg_t gatts_cfg; /**< Global GATTS configuration, cfg_id in @ref BLE_GATTS_CFGS series. */ +} ble_cfg_t; + +/** @} */ + +/** @addtogroup BLE_COMMON_FUNCTIONS Functions + * @{ */ + +/**@brief Enable the BLE stack + * + * @param[in, out] p_app_ram_base Pointer to a variable containing the start address of the + * application RAM region (APP_RAM_BASE). On return, this will + * contain the minimum start address of the application RAM region + * required by the SoftDevice for this configuration. + * @warning After this call, the SoftDevice may generate several events. The list of events provided + * below require the application to initiate a SoftDevice API call. The corresponding API call + * is referenced in the event documentation. + * If the application fails to do so, the BLE connection may timeout, or the SoftDevice may stop + * communicating with the peer device. + * - @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST + * - @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST + * - @ref BLE_GAP_EVT_SEC_INFO_REQUEST + * - @ref BLE_GAP_EVT_SEC_REQUEST + * - @ref BLE_GAP_EVT_AUTH_KEY_REQUEST + * - @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST + * - @ref BLE_EVT_USER_MEM_REQUEST + * - @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST + * + * @note The memory requirement for a specific configuration will not increase between SoftDevices + * with the same major version number. + * + * @note At runtime the IC's RAM is split into 2 regions: The SoftDevice RAM region is located + * between 0x20000000 and APP_RAM_BASE-1 and the application's RAM region is located between + * APP_RAM_BASE and the start of the call stack. + * + * @details This call initializes the BLE stack, no BLE related function other than @ref + * sd_ble_cfg_set can be called before this one. + * + * @mscs + * @mmsc{@ref BLE_COMMON_ENABLE} + * @endmscs + * + * @retval ::NRF_SUCCESS The BLE stack has been initialized successfully. + * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized and cannot be reinitialized. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_NO_MEM One or more of the following is true: + * - The amount of memory assigned to the SoftDevice by *p_app_ram_base is not + * large enough to fit this configuration's memory requirement. Check *p_app_ram_base + * and set the start address of the application RAM region accordingly. + * - Dynamic part of the SoftDevice RAM region is larger then 64 kB which + * is currently not supported. + * @retval ::NRF_ERROR_RESOURCES The total number of L2CAP Channels configured using @ref sd_ble_cfg_set is too large. + */ +SVCALL(SD_BLE_ENABLE, uint32_t, sd_ble_enable(uint32_t *p_app_ram_base)); + +/**@brief Add configurations for the BLE stack + * + * @param[in] cfg_id Config ID, see @ref BLE_CONN_CFGS, @ref BLE_COMMON_CFGS, @ref + * BLE_GAP_CFGS or @ref BLE_GATTS_CFGS. + * @param[in] p_cfg Pointer to a ble_cfg_t structure containing the configuration value. + * @param[in] app_ram_base The start address of the application RAM region (APP_RAM_BASE). + * See @ref sd_ble_enable for details about APP_RAM_BASE. + * + * @note The memory requirement for a specific configuration will not increase between SoftDevices + * with the same major version number. + * + * @note If a configuration is set more than once, the last one set is the one that takes effect on + * @ref sd_ble_enable. + * + * @note Any part of the BLE stack that is NOT configured with @ref sd_ble_cfg_set will have default + * configuration. + * + * @note @ref sd_ble_cfg_set may be called at any time when the SoftDevice is enabled (see @ref + * sd_softdevice_enable) while the BLE part of the SoftDevice is not enabled (see @ref + * sd_ble_enable). + * + * @note Error codes for the configurations are described in the configuration structs. + * + * @mscs + * @mmsc{@ref BLE_COMMON_ENABLE} + * @endmscs + * + * @retval ::NRF_SUCCESS The configuration has been added successfully. + * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid cfg_id supplied. + * @retval ::NRF_ERROR_NO_MEM The amount of memory assigned to the SoftDevice by app_ram_base is not + * large enough to fit this configuration's memory requirement. + */ +SVCALL(SD_BLE_CFG_SET, uint32_t, sd_ble_cfg_set(uint32_t cfg_id, ble_cfg_t const *p_cfg, uint32_t app_ram_base)); + +/**@brief Get an event from the pending events queue. + * + * @param[out] p_dest Pointer to buffer to be filled in with an event, or NULL to retrieve the event length. + * This buffer must be aligned to the extend defined by @ref BLE_EVT_PTR_ALIGNMENT. + * The buffer should be interpreted as a @ref ble_evt_t struct. + * @param[in, out] p_len Pointer the length of the buffer, on return it is filled with the event length. + * + * @details This call allows the application to pull a BLE event from the BLE stack. The application is signaled that + * an event is available from the BLE stack by the triggering of the SD_EVT_IRQn interrupt. + * The application is free to choose whether to call this function from thread mode (main context) or directly from the + * Interrupt Service Routine that maps to SD_EVT_IRQn. In any case however, and because the BLE stack runs at a higher + * priority than the application, this function should be called in a loop (until @ref NRF_ERROR_NOT_FOUND is returned) + * every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the BLE stack. Failure to do so + * could potentially leave events in the internal queue without the application being aware of this fact. + * + * Sizing the p_dest buffer is equally important, since the application needs to provide all the memory necessary for the event to + * be copied into application memory. If the buffer provided is not large enough to fit the entire contents of the event, + * @ref NRF_ERROR_DATA_SIZE will be returned and the application can then call again with a larger buffer size. + * The maximum possible event length is defined by @ref BLE_EVT_LEN_MAX. The application may also "peek" the event length + * by providing p_dest as a NULL pointer and inspecting the value of *p_len upon return: + * + * \code + * uint16_t len; + * errcode = sd_ble_evt_get(NULL, &len); + * \endcode + * + * @mscs + * @mmsc{@ref BLE_COMMON_IRQ_EVT_MSC} + * @mmsc{@ref BLE_COMMON_THREAD_EVT_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Event pulled and stored into the supplied buffer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. + * @retval ::NRF_ERROR_NOT_FOUND No events ready to be pulled. + * @retval ::NRF_ERROR_DATA_SIZE Event ready but could not fit into the supplied buffer. + */ +SVCALL(SD_BLE_EVT_GET, uint32_t, sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len)); + +/**@brief Add a Vendor Specific base UUID. + * + * @details This call enables the application to add a Vendor Specific base UUID to the BLE stack's table, for later + * use with all other modules and APIs. This then allows the application to use the shorter, 24-bit @ref ble_uuid_t + * format when dealing with both 16-bit and 128-bit UUIDs without having to check for lengths and having split code + * paths. This is accomplished by extending the grouping mechanism that the Bluetooth SIG standard base UUID uses + * for all other 128-bit UUIDs. The type field in the @ref ble_uuid_t structure is an index (relative to + * @ref BLE_UUID_TYPE_VENDOR_BEGIN) to the table populated by multiple calls to this function, and the UUID field + * in the same structure contains the 2 bytes at indexes 12 and 13. The number of possible 128-bit UUIDs available to + * the application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536, + * although restricted to modifying bytes 12 and 13 for each of the entries in the supplied array. + * + * @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by + * the 16-bit uuid field in @ref ble_uuid_t. + * + * @note If a UUID is already present in the BLE stack's internal table, the corresponding index will be returned in + * p_uuid_type along with an @ref NRF_SUCCESS error code. + * + * @param[in] p_vs_uuid Pointer to a 16-octet (128-bit) little endian Vendor Specific base UUID disregarding + * bytes 12 and 13. + * @param[out] p_uuid_type Pointer to a uint8_t where the type field in @ref ble_uuid_t corresponding to this UUID will be + * stored. + * + * @retval ::NRF_SUCCESS Successfully added the Vendor Specific base UUID. + * @retval ::NRF_ERROR_INVALID_ADDR If p_vs_uuid or p_uuid_type is NULL or invalid. + * @retval ::NRF_ERROR_NO_MEM If there are no more free slots for VS UUIDs. + */ +SVCALL(SD_BLE_UUID_VS_ADD, uint32_t, sd_ble_uuid_vs_add(ble_uuid128_t const *p_vs_uuid, uint8_t *p_uuid_type)); + +/**@brief Remove a Vendor Specific base UUID. + * + * @details This call removes a Vendor Specific base UUID. This function allows + * the application to reuse memory allocated for Vendor Specific base UUIDs. + * + * @note Currently this function can only be called with a p_uuid_type set to @ref BLE_UUID_TYPE_UNKNOWN or the last added UUID + * type. + * + * @param[inout] p_uuid_type Pointer to a uint8_t where its value matches the UUID type in @ref ble_uuid_t::type to be removed. + * If the type is set to @ref BLE_UUID_TYPE_UNKNOWN, or the pointer is NULL, the last Vendor Specific + * base UUID will be removed. If the function returns successfully, the UUID type that was removed will + * be written back to @p p_uuid_type. If function returns with a failure, it contains the last type that + * is in use by the ATT Server. + * + * @retval ::NRF_SUCCESS Successfully removed the Vendor Specific base UUID. + * @retval ::NRF_ERROR_INVALID_ADDR If p_uuid_type is invalid. + * @retval ::NRF_ERROR_INVALID_PARAM If p_uuid_type points to a non-valid UUID type. + * @retval ::NRF_ERROR_FORBIDDEN If the Vendor Specific base UUID is in use by the ATT Server. + */ +SVCALL(SD_BLE_UUID_VS_REMOVE, uint32_t, sd_ble_uuid_vs_remove(uint8_t *p_uuid_type)); + +/** @brief Decode little endian raw UUID bytes (16-bit or 128-bit) into a 24 bit @ref ble_uuid_t structure. + * + * @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared + * to the corresponding ones in each entry of the table of Vendor Specific base UUIDs + * to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index + * relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type. + * + * @note If the UUID length supplied is 2, then the type set by this call will always be @ref BLE_UUID_TYPE_BLE. + * + * @param[in] uuid_le_len Length in bytes of the buffer pointed to by p_uuid_le (must be 2 or 16 bytes). + * @param[in] p_uuid_le Pointer pointing to little endian raw UUID bytes. + * @param[out] p_uuid Pointer to a @ref ble_uuid_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Successfully decoded into the @ref ble_uuid_t structure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid UUID length. + * @retval ::NRF_ERROR_NOT_FOUND For a 128-bit UUID, no match in the populated table of UUIDs. + */ +SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uint8_t const *p_uuid_le, ble_uuid_t *p_uuid)); + +/** @brief Encode a @ref ble_uuid_t structure into little endian raw UUID bytes (16-bit or 128-bit). + * + * @note The pointer to the destination buffer p_uuid_le may be NULL, in which case only the validity and size of p_uuid is + * computed. + * + * @param[in] p_uuid Pointer to a @ref ble_uuid_t structure that will be encoded into bytes. + * @param[out] p_uuid_le_len Pointer to a uint8_t that will be filled with the encoded length (2 or 16 bytes). + * @param[out] p_uuid_le Pointer to a buffer where the little endian raw UUID bytes (2 or 16) will be stored. + * + * @retval ::NRF_SUCCESS Successfully encoded into the buffer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid UUID type. + */ +SVCALL(SD_BLE_UUID_ENCODE, uint32_t, sd_ble_uuid_encode(ble_uuid_t const *p_uuid, uint8_t *p_uuid_le_len, uint8_t *p_uuid_le)); + +/**@brief Get Version Information. + * + * @details This call allows the application to get the BLE stack version information. + * + * @param[out] p_version Pointer to a ble_version_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Version information stored successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy (typically doing a locally-initiated disconnection procedure). + */ +SVCALL(SD_BLE_VERSION_GET, uint32_t, sd_ble_version_get(ble_version_t *p_version)); + +/**@brief Provide a user memory block. + * + * @note This call can only be used as a response to a @ref BLE_EVT_USER_MEM_REQUEST event issued to the application. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_block Pointer to a user memory block structure or NULL if memory is managed by the application. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully queued a response to the peer. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid user memory block length supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection state or no user memory request pending. + */ +SVCALL(SD_BLE_USER_MEM_REPLY, uint32_t, sd_ble_user_mem_reply(uint16_t conn_handle, ble_user_mem_block_t const *p_block)); + +/**@brief Set a BLE option. + * + * @details This call allows the application to set the value of an option. + * + * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS, @ref BLE_GAP_OPTS, and @ref BLE_GATTC_OPTS. + * @param[in] p_opt Pointer to a @ref ble_opt_t structure containing the option value. + * + * @retval ::NRF_SUCCESS Option set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Unable to set the parameter at this time. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. + */ +SVCALL(SD_BLE_OPT_SET, uint32_t, sd_ble_opt_set(uint32_t opt_id, ble_opt_t const *p_opt)); + +/**@brief Get a BLE option. + * + * @details This call allows the application to retrieve the value of an option. + * + * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS and @ref BLE_GAP_OPTS. + * @param[out] p_opt Pointer to a ble_opt_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Option retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Unable to retrieve the parameter at this time. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. + * @retval ::NRF_ERROR_NOT_SUPPORTED This option is not supported. + * + */ +SVCALL(SD_BLE_OPT_GET, uint32_t, sd_ble_opt_get(uint32_t opt_id, ble_opt_t *p_opt)); + +/** @} */ +#ifdef __cplusplus +} +#endif +#endif /* BLE_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_err.h b/variants/wio-tracker-wm1110/softdevice/ble_err.h new file mode 100644 index 0000000000..d20f6d1416 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_err.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @addtogroup nrf_error + @{ + @ingroup BLE_COMMON + @} + + @defgroup ble_err General error codes + @{ + + @brief General error code definitions for the BLE API. + + @ingroup BLE_COMMON +*/ +#ifndef NRF_BLE_ERR_H__ +#define NRF_BLE_ERR_H__ + +#include "nrf_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* @defgroup BLE_ERRORS Error Codes + * @{ */ +#define BLE_ERROR_NOT_ENABLED (NRF_ERROR_STK_BASE_NUM + 0x001) /**< @ref sd_ble_enable has not been called. */ +#define BLE_ERROR_INVALID_CONN_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x002) /**< Invalid connection handle. */ +#define BLE_ERROR_INVALID_ATTR_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x003) /**< Invalid attribute handle. */ +#define BLE_ERROR_INVALID_ADV_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x004) /**< Invalid advertising handle. */ +#define BLE_ERROR_INVALID_ROLE (NRF_ERROR_STK_BASE_NUM + 0x005) /**< Invalid role. */ +#define BLE_ERROR_BLOCKED_BY_OTHER_LINKS \ + (NRF_ERROR_STK_BASE_NUM + 0x006) /**< The attempt to change link settings failed due to the scheduling of other links. */ +/** @} */ + +/** @defgroup BLE_ERROR_SUBRANGES Module specific error code subranges + * @brief Assignment of subranges for module specific error codes. + * @note For specific error codes, see ble_.h or ble_error_.h. + * @{ */ +#define NRF_L2CAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x100) /**< L2CAP specific errors. */ +#define NRF_GAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x200) /**< GAP specific errors. */ +#define NRF_GATTC_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x300) /**< GATT client specific errors. */ +#define NRF_GATTS_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x400) /**< GATT server specific errors. */ +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif + +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gap.h b/variants/wio-tracker-wm1110/softdevice/ble_gap.h new file mode 100644 index 0000000000..8ebdfa82b0 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_gap.h @@ -0,0 +1,2895 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GAP Generic Access Profile (GAP) + @{ + @brief Definitions and prototypes for the GAP interface. + */ + +#ifndef BLE_GAP_H__ +#define BLE_GAP_H__ + +#include "ble_err.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup BLE_GAP_ENUMERATIONS Enumerations + * @{ */ + +/**@brief GAP API SVC numbers. + */ +enum BLE_GAP_SVCS { + SD_BLE_GAP_ADDR_SET = BLE_GAP_SVC_BASE, /**< Set own Bluetooth Address. */ + SD_BLE_GAP_ADDR_GET = BLE_GAP_SVC_BASE + 1, /**< Get own Bluetooth Address. */ + SD_BLE_GAP_WHITELIST_SET = BLE_GAP_SVC_BASE + 2, /**< Set active whitelist. */ + SD_BLE_GAP_DEVICE_IDENTITIES_SET = BLE_GAP_SVC_BASE + 3, /**< Set device identity list. */ + SD_BLE_GAP_PRIVACY_SET = BLE_GAP_SVC_BASE + 4, /**< Set Privacy settings*/ + SD_BLE_GAP_PRIVACY_GET = BLE_GAP_SVC_BASE + 5, /**< Get Privacy settings*/ + SD_BLE_GAP_ADV_SET_CONFIGURE = BLE_GAP_SVC_BASE + 6, /**< Configure an advertising set. */ + SD_BLE_GAP_ADV_START = BLE_GAP_SVC_BASE + 7, /**< Start Advertising. */ + SD_BLE_GAP_ADV_STOP = BLE_GAP_SVC_BASE + 8, /**< Stop Advertising. */ + SD_BLE_GAP_CONN_PARAM_UPDATE = BLE_GAP_SVC_BASE + 9, /**< Connection Parameter Update. */ + SD_BLE_GAP_DISCONNECT = BLE_GAP_SVC_BASE + 10, /**< Disconnect. */ + SD_BLE_GAP_TX_POWER_SET = BLE_GAP_SVC_BASE + 11, /**< Set TX Power. */ + SD_BLE_GAP_APPEARANCE_SET = BLE_GAP_SVC_BASE + 12, /**< Set Appearance. */ + SD_BLE_GAP_APPEARANCE_GET = BLE_GAP_SVC_BASE + 13, /**< Get Appearance. */ + SD_BLE_GAP_PPCP_SET = BLE_GAP_SVC_BASE + 14, /**< Set PPCP. */ + SD_BLE_GAP_PPCP_GET = BLE_GAP_SVC_BASE + 15, /**< Get PPCP. */ + SD_BLE_GAP_DEVICE_NAME_SET = BLE_GAP_SVC_BASE + 16, /**< Set Device Name. */ + SD_BLE_GAP_DEVICE_NAME_GET = BLE_GAP_SVC_BASE + 17, /**< Get Device Name. */ + SD_BLE_GAP_AUTHENTICATE = BLE_GAP_SVC_BASE + 18, /**< Initiate Pairing/Bonding. */ + SD_BLE_GAP_SEC_PARAMS_REPLY = BLE_GAP_SVC_BASE + 19, /**< Reply with Security Parameters. */ + SD_BLE_GAP_AUTH_KEY_REPLY = BLE_GAP_SVC_BASE + 20, /**< Reply with an authentication key. */ + SD_BLE_GAP_LESC_DHKEY_REPLY = BLE_GAP_SVC_BASE + 21, /**< Reply with an LE Secure Connections DHKey. */ + SD_BLE_GAP_KEYPRESS_NOTIFY = BLE_GAP_SVC_BASE + 22, /**< Notify of a keypress during an authentication procedure. */ + SD_BLE_GAP_LESC_OOB_DATA_GET = BLE_GAP_SVC_BASE + 23, /**< Get the local LE Secure Connections OOB data. */ + SD_BLE_GAP_LESC_OOB_DATA_SET = BLE_GAP_SVC_BASE + 24, /**< Set the remote LE Secure Connections OOB data. */ + SD_BLE_GAP_ENCRYPT = BLE_GAP_SVC_BASE + 25, /**< Initiate encryption procedure. */ + SD_BLE_GAP_SEC_INFO_REPLY = BLE_GAP_SVC_BASE + 26, /**< Reply with Security Information. */ + SD_BLE_GAP_CONN_SEC_GET = BLE_GAP_SVC_BASE + 27, /**< Obtain connection security level. */ + SD_BLE_GAP_RSSI_START = BLE_GAP_SVC_BASE + 28, /**< Start reporting of changes in RSSI. */ + SD_BLE_GAP_RSSI_STOP = BLE_GAP_SVC_BASE + 29, /**< Stop reporting of changes in RSSI. */ + SD_BLE_GAP_SCAN_START = BLE_GAP_SVC_BASE + 30, /**< Start Scanning. */ + SD_BLE_GAP_SCAN_STOP = BLE_GAP_SVC_BASE + 31, /**< Stop Scanning. */ + SD_BLE_GAP_CONNECT = BLE_GAP_SVC_BASE + 32, /**< Connect. */ + SD_BLE_GAP_CONNECT_CANCEL = BLE_GAP_SVC_BASE + 33, /**< Cancel ongoing connection procedure. */ + SD_BLE_GAP_RSSI_GET = BLE_GAP_SVC_BASE + 34, /**< Get the last RSSI sample. */ + SD_BLE_GAP_PHY_UPDATE = BLE_GAP_SVC_BASE + 35, /**< Initiate or respond to a PHY Update Procedure. */ + SD_BLE_GAP_DATA_LENGTH_UPDATE = BLE_GAP_SVC_BASE + 36, /**< Initiate or respond to a Data Length Update Procedure. */ + SD_BLE_GAP_QOS_CHANNEL_SURVEY_START = BLE_GAP_SVC_BASE + 37, /**< Start Quality of Service (QoS) channel survey module. */ + SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP = BLE_GAP_SVC_BASE + 38, /**< Stop Quality of Service (QoS) channel survey module. */ + SD_BLE_GAP_ADV_ADDR_GET = BLE_GAP_SVC_BASE + 39, /**< Get the Address used on air while Advertising. */ + SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET = BLE_GAP_SVC_BASE + 40, /**< Get the next connection event counter. */ + SD_BLE_GAP_CONN_EVT_TRIGGER_START = BLE_GAP_SVC_BASE + 41, /** Start triggering a given task on connection event start. */ + SD_BLE_GAP_CONN_EVT_TRIGGER_STOP = + BLE_GAP_SVC_BASE + 42, /** Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. */ +}; + +/**@brief GAP Event IDs. + * IDs that uniquely identify an event coming from the stack to the application. + */ +enum BLE_GAP_EVTS { + BLE_GAP_EVT_CONNECTED = + BLE_GAP_EVT_BASE, /**< Connected to peer. \n See @ref ble_gap_evt_connected_t */ + BLE_GAP_EVT_DISCONNECTED = + BLE_GAP_EVT_BASE + 1, /**< Disconnected from peer. \n See @ref ble_gap_evt_disconnected_t. */ + BLE_GAP_EVT_CONN_PARAM_UPDATE = + BLE_GAP_EVT_BASE + 2, /**< Connection Parameters updated. \n See @ref ble_gap_evt_conn_param_update_t. */ + BLE_GAP_EVT_SEC_PARAMS_REQUEST = + BLE_GAP_EVT_BASE + 3, /**< Request to provide security parameters. \n Reply with @ref sd_ble_gap_sec_params_reply. + \n See @ref ble_gap_evt_sec_params_request_t. */ + BLE_GAP_EVT_SEC_INFO_REQUEST = + BLE_GAP_EVT_BASE + 4, /**< Request to provide security information. \n Reply with @ref sd_ble_gap_sec_info_reply. + \n See @ref ble_gap_evt_sec_info_request_t. */ + BLE_GAP_EVT_PASSKEY_DISPLAY = + BLE_GAP_EVT_BASE + 5, /**< Request to display a passkey to the user. \n In LESC Numeric Comparison, reply with @ref + sd_ble_gap_auth_key_reply. \n See @ref ble_gap_evt_passkey_display_t. */ + BLE_GAP_EVT_KEY_PRESSED = + BLE_GAP_EVT_BASE + 6, /**< Notification of a keypress on the remote device.\n See @ref ble_gap_evt_key_pressed_t */ + BLE_GAP_EVT_AUTH_KEY_REQUEST = + BLE_GAP_EVT_BASE + 7, /**< Request to provide an authentication key. \n Reply with @ref sd_ble_gap_auth_key_reply. + \n See @ref ble_gap_evt_auth_key_request_t. */ + BLE_GAP_EVT_LESC_DHKEY_REQUEST = + BLE_GAP_EVT_BASE + 8, /**< Request to calculate an LE Secure Connections DHKey. \n Reply with @ref + sd_ble_gap_lesc_dhkey_reply. \n See @ref ble_gap_evt_lesc_dhkey_request_t */ + BLE_GAP_EVT_AUTH_STATUS = + BLE_GAP_EVT_BASE + 9, /**< Authentication procedure completed with status. \n See @ref ble_gap_evt_auth_status_t. */ + BLE_GAP_EVT_CONN_SEC_UPDATE = + BLE_GAP_EVT_BASE + 10, /**< Connection security updated. \n See @ref ble_gap_evt_conn_sec_update_t. */ + BLE_GAP_EVT_TIMEOUT = + BLE_GAP_EVT_BASE + 11, /**< Timeout expired. \n See @ref ble_gap_evt_timeout_t. */ + BLE_GAP_EVT_RSSI_CHANGED = + BLE_GAP_EVT_BASE + 12, /**< RSSI report. \n See @ref ble_gap_evt_rssi_changed_t. */ + BLE_GAP_EVT_ADV_REPORT = + BLE_GAP_EVT_BASE + 13, /**< Advertising report. \n See @ref ble_gap_evt_adv_report_t. */ + BLE_GAP_EVT_SEC_REQUEST = + BLE_GAP_EVT_BASE + 14, /**< Security Request. \n Reply with @ref sd_ble_gap_authenticate +\n or with @ref sd_ble_gap_encrypt if required security information is available +. \n See @ref ble_gap_evt_sec_request_t. */ + BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 15, /**< Connection Parameter Update Request. \n Reply with @ref + sd_ble_gap_conn_param_update. \n See @ref ble_gap_evt_conn_param_update_request_t. */ + BLE_GAP_EVT_SCAN_REQ_REPORT = + BLE_GAP_EVT_BASE + 16, /**< Scan request report. \n See @ref ble_gap_evt_scan_req_report_t. */ + BLE_GAP_EVT_PHY_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 17, /**< PHY Update Request. \n Reply with @ref sd_ble_gap_phy_update. \n + See @ref ble_gap_evt_phy_update_request_t. */ + BLE_GAP_EVT_PHY_UPDATE = + BLE_GAP_EVT_BASE + 18, /**< PHY Update Procedure is complete. \n See @ref ble_gap_evt_phy_update_t. */ + BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST = + BLE_GAP_EVT_BASE + 19, /**< Data Length Update Request. \n Reply with @ref + sd_ble_gap_data_length_update. \n See @ref ble_gap_evt_data_length_update_request_t. */ + BLE_GAP_EVT_DATA_LENGTH_UPDATE = + BLE_GAP_EVT_BASE + + 20, /**< LL Data Channel PDU payload length updated. \n See @ref ble_gap_evt_data_length_update_t. */ + BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT = + BLE_GAP_EVT_BASE + + 21, /**< Channel survey report. \n See @ref ble_gap_evt_qos_channel_survey_report_t. */ + BLE_GAP_EVT_ADV_SET_TERMINATED = + BLE_GAP_EVT_BASE + + 22, /**< Advertising set terminated. \n See @ref ble_gap_evt_adv_set_terminated_t. */ +}; + +/**@brief GAP Option IDs. + * IDs that uniquely identify a GAP option. + */ +enum BLE_GAP_OPTS { + BLE_GAP_OPT_CH_MAP = BLE_GAP_OPT_BASE, /**< Channel Map. @ref ble_gap_opt_ch_map_t */ + BLE_GAP_OPT_LOCAL_CONN_LATENCY = BLE_GAP_OPT_BASE + 1, /**< Local connection latency. @ref ble_gap_opt_local_conn_latency_t */ + BLE_GAP_OPT_PASSKEY = BLE_GAP_OPT_BASE + 2, /**< Set passkey. @ref ble_gap_opt_passkey_t */ + BLE_GAP_OPT_COMPAT_MODE_1 = BLE_GAP_OPT_BASE + 3, /**< Compatibility mode. @ref ble_gap_opt_compat_mode_1_t */ + BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT = + BLE_GAP_OPT_BASE + 4, /**< Set Authenticated payload timeout. @ref ble_gap_opt_auth_payload_timeout_t */ + BLE_GAP_OPT_SLAVE_LATENCY_DISABLE = + BLE_GAP_OPT_BASE + 5, /**< Disable slave latency. @ref ble_gap_opt_slave_latency_disable_t */ +}; + +/**@brief GAP Configuration IDs. + * + * IDs that uniquely identify a GAP configuration. + */ +enum BLE_GAP_CFGS { + BLE_GAP_CFG_ROLE_COUNT = BLE_GAP_CFG_BASE, /**< Role count configuration. */ + BLE_GAP_CFG_DEVICE_NAME = BLE_GAP_CFG_BASE + 1, /**< Device name configuration. */ + BLE_GAP_CFG_PPCP_INCL_CONFIG = BLE_GAP_CFG_BASE + 2, /**< Peripheral Preferred Connection Parameters characteristic + inclusion configuration. */ + BLE_GAP_CFG_CAR_INCL_CONFIG = BLE_GAP_CFG_BASE + 3, /**< Central Address Resolution characteristic + inclusion configuration. */ +}; + +/**@brief GAP TX Power roles. + */ +enum BLE_GAP_TX_POWER_ROLES { + BLE_GAP_TX_POWER_ROLE_ADV = 1, /**< Advertiser role. */ + BLE_GAP_TX_POWER_ROLE_SCAN_INIT = 2, /**< Scanner and initiator role. */ + BLE_GAP_TX_POWER_ROLE_CONN = 3, /**< Connection role. */ +}; + +/** @} */ + +/**@addtogroup BLE_GAP_DEFINES Defines + * @{ */ + +/**@defgroup BLE_ERRORS_GAP SVC return values specific to GAP + * @{ */ +#define BLE_ERROR_GAP_UUID_LIST_MISMATCH \ + (NRF_GAP_ERR_BASE + 0x000) /**< UUID list does not contain an integral number of UUIDs. */ +#define BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST \ + (NRF_GAP_ERR_BASE + 0x001) /**< Use of Whitelist not permitted with discoverable advertising. */ +#define BLE_ERROR_GAP_INVALID_BLE_ADDR \ + (NRF_GAP_ERR_BASE + 0x002) /**< The upper two bits of the address do not correspond to the specified address type. */ +#define BLE_ERROR_GAP_WHITELIST_IN_USE \ + (NRF_GAP_ERR_BASE + 0x003) /**< Attempt to modify the whitelist while already in use by another operation. */ +#define BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE \ + (NRF_GAP_ERR_BASE + 0x004) /**< Attempt to modify the device identity list while already in use by another operation. */ +#define BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE \ + (NRF_GAP_ERR_BASE + 0x005) /**< The device identity list contains entries with duplicate identity addresses. */ +/**@} */ + +/**@defgroup BLE_GAP_ROLES GAP Roles + * @{ */ +#define BLE_GAP_ROLE_INVALID 0x0 /**< Invalid Role. */ +#define BLE_GAP_ROLE_PERIPH 0x1 /**< Peripheral Role. */ +#define BLE_GAP_ROLE_CENTRAL 0x2 /**< Central Role. */ +/**@} */ + +/**@defgroup BLE_GAP_TIMEOUT_SOURCES GAP Timeout sources + * @{ */ +#define BLE_GAP_TIMEOUT_SRC_SCAN 0x01 /**< Scanning timeout. */ +#define BLE_GAP_TIMEOUT_SRC_CONN 0x02 /**< Connection timeout. */ +#define BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD 0x03 /**< Authenticated payload timeout. */ +/**@} */ + +/**@defgroup BLE_GAP_ADDR_TYPES GAP Address types + * @{ */ +#define BLE_GAP_ADDR_TYPE_PUBLIC 0x00 /**< Public (identity) address.*/ +#define BLE_GAP_ADDR_TYPE_RANDOM_STATIC 0x01 /**< Random static (identity) address. */ +#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE 0x02 /**< Random private resolvable address. */ +#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE 0x03 /**< Random private non-resolvable address. */ +#define BLE_GAP_ADDR_TYPE_ANONYMOUS \ + 0x7F /**< An advertiser may advertise without its address. \ + This type of advertising is called anonymous. */ +/**@} */ + +/**@brief The default interval in seconds at which a private address is refreshed. */ +#define BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S (900) /* 15 minutes. */ +/**@brief The maximum interval in seconds at which a private address can be refreshed. */ +#define BLE_GAP_MAX_PRIVATE_ADDR_CYCLE_INTERVAL_S (41400) /* 11 hours 30 minutes. */ + +/** @brief BLE address length. */ +#define BLE_GAP_ADDR_LEN (6) + +/**@defgroup BLE_GAP_PRIVACY_MODES Privacy modes + * @{ */ +#define BLE_GAP_PRIVACY_MODE_OFF 0x00 /**< Device will send and accept its identity address for its own address. */ +#define BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY 0x01 /**< Device will send and accept only private addresses for its own address. */ +#define BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY \ + 0x02 /**< Device will send and accept only private addresses for its own address, \ + and will not accept a peer using identity address as sender address when \ + the peer IRK is exchanged, non-zero and added to the identity list. */ +/**@} */ + +/** @brief Invalid power level. */ +#define BLE_GAP_POWER_LEVEL_INVALID 127 + +/** @brief Advertising set handle not set. */ +#define BLE_GAP_ADV_SET_HANDLE_NOT_SET (0xFF) + +/** @brief The default number of advertising sets. */ +#define BLE_GAP_ADV_SET_COUNT_DEFAULT (1) + +/** @brief The maximum number of advertising sets supported by this SoftDevice. */ +#define BLE_GAP_ADV_SET_COUNT_MAX (1) + +/**@defgroup BLE_GAP_ADV_SET_DATA_SIZES Advertising data sizes. + * @{ */ +#define BLE_GAP_ADV_SET_DATA_SIZE_MAX \ + (31) /**< Maximum data length for an advertising set. \ + If more advertising data is required, use extended advertising instead. */ +#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED \ + (255) /**< Maximum supported data length for an extended advertising set. */ + +#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED \ + (238) /**< Maximum supported data length for an extended connectable advertising set. */ +/**@}. */ + +/** @brief Set ID not available in advertising report. */ +#define BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE 0xFF + +/**@defgroup BLE_GAP_EVT_ADV_SET_TERMINATED_REASON GAP Advertising Set Terminated reasons + * @{ */ +#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT 0x01 /**< Timeout value reached. */ +#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED 0x02 /**< @ref ble_gap_adv_params_t::max_adv_evts was reached. */ +/**@} */ + +/**@defgroup BLE_GAP_AD_TYPE_DEFINITIONS GAP Advertising and Scan Response Data format + * @note Found at https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm + * @{ */ +#define BLE_GAP_AD_TYPE_FLAGS 0x01 /**< Flags for discoverability. */ +#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 /**< Partial list of 16 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 /**< Complete list of 16 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 /**< Partial list of 32 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 /**< Complete list of 32 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 /**< Partial list of 128 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 /**< Complete list of 128 bit service UUIDs. */ +#define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 /**< Short local device name. */ +#define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 /**< Complete local device name. */ +#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A /**< Transmit power level. */ +#define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D /**< Class of device. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E /**< Simple Pairing Hash C. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F /**< Simple Pairing Randomizer R. */ +#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 /**< Security Manager TK Value. */ +#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 /**< Security Manager Out Of Band Flags. */ +#define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 /**< Slave Connection Interval Range. */ +#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 /**< List of 16-bit Service Solicitation UUIDs. */ +#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 /**< List of 128-bit Service Solicitation UUIDs. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 /**< Service Data - 16-bit UUID. */ +#define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 /**< Public Target Address. */ +#define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 /**< Random Target Address. */ +#define BLE_GAP_AD_TYPE_APPEARANCE 0x19 /**< Appearance. */ +#define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A /**< Advertising Interval. */ +#define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B /**< LE Bluetooth Device Address. */ +#define BLE_GAP_AD_TYPE_LE_ROLE 0x1C /**< LE Role. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D /**< Simple Pairing Hash C-256. */ +#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E /**< Simple Pairing Randomizer R-256. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 /**< Service Data - 32-bit UUID. */ +#define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 /**< Service Data - 128-bit UUID. */ +#define BLE_GAP_AD_TYPE_LESC_CONFIRMATION_VALUE 0x22 /**< LE Secure Connections Confirmation Value */ +#define BLE_GAP_AD_TYPE_LESC_RANDOM_VALUE 0x23 /**< LE Secure Connections Random Value */ +#define BLE_GAP_AD_TYPE_URI 0x24 /**< URI */ +#define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D /**< 3D Information Data. */ +#define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF /**< Manufacturer Specific Data. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_FLAGS GAP Advertisement Flags + * @{ */ +#define BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE (0x01) /**< LE Limited Discoverable Mode. */ +#define BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) /**< LE General Discoverable Mode. */ +#define BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) /**< BR/EDR not supported. */ +#define BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER (0x08) /**< Simultaneous LE and BR/EDR, Controller. */ +#define BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST (0x10) /**< Simultaneous LE and BR/EDR, Host. */ +#define BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE \ + (BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE | \ + BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE Limited Discoverable Mode, BR/EDR not supported. */ +#define BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE \ + (BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | \ + BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE General Discoverable Mode, BR/EDR not supported. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_INTERVALS GAP Advertising interval max and min + * @{ */ +#define BLE_GAP_ADV_INTERVAL_MIN 0x000020 /**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */ +#define BLE_GAP_ADV_INTERVAL_MAX 0x004000 /**< Maximum Advertising interval in 625 us units, i.e. 10.24 s. */ + /**@} */ + +/**@defgroup BLE_GAP_SCAN_INTERVALS GAP Scan interval max and min + * @{ */ +#define BLE_GAP_SCAN_INTERVAL_MIN 0x0004 /**< Minimum Scan interval in 625 us units, i.e. 2.5 ms. */ +#define BLE_GAP_SCAN_INTERVAL_MAX 0xFFFF /**< Maximum Scan interval in 625 us units, i.e. 40,959.375 s. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_WINDOW GAP Scan window max and min + * @{ */ +#define BLE_GAP_SCAN_WINDOW_MIN 0x0004 /**< Minimum Scan window in 625 us units, i.e. 2.5 ms. */ +#define BLE_GAP_SCAN_WINDOW_MAX 0xFFFF /**< Maximum Scan window in 625 us units, i.e. 40,959.375 s. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_TIMEOUT GAP Scan timeout max and min + * @{ */ +#define BLE_GAP_SCAN_TIMEOUT_MIN 0x0001 /**< Minimum Scan timeout in 10 ms units, i.e 10 ms. */ +#define BLE_GAP_SCAN_TIMEOUT_UNLIMITED 0x0000 /**< Continue to scan forever. */ + /** @} */ + +/**@defgroup BLE_GAP_SCAN_BUFFER_SIZE GAP Minimum scanner buffer size + * + * Scan buffers are used for storing advertising data received from an advertiser. + * If ble_gap_scan_params_t::extended is set to 0, @ref BLE_GAP_SCAN_BUFFER_MIN is the minimum scan buffer length. + * else the minimum scan buffer size is @ref BLE_GAP_SCAN_BUFFER_EXTENDED_MIN. + * @{ */ +#define BLE_GAP_SCAN_BUFFER_MIN \ + (31) /**< Minimum data length for an \ + advertising set. */ +#define BLE_GAP_SCAN_BUFFER_MAX \ + (31) /**< Maximum data length for an \ + advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MIN \ + (255) /**< Minimum data length for an \ + extended advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX \ + (1650) /**< Maximum data length for an \ + extended advertising set. */ +#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED \ + (255) /**< Maximum supported data length for \ + an extended advertising set. */ +/** @} */ + +/**@defgroup BLE_GAP_ADV_TYPES GAP Advertising types + * + * Advertising types defined in Bluetooth Core Specification v5.0, Vol 6, Part B, Section 4.4.2. + * + * The maximum advertising data length is defined by @ref BLE_GAP_ADV_SET_DATA_SIZE_MAX. + * The maximum supported data length for an extended advertiser is defined by + * @ref BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED + * Note that some of the advertising types do not support advertising data. Non-scannable types do not support + * scan response data. + * + * @{ */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x01 /**< Connectable and scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE \ + 0x02 /**< Connectable non-scannable directed advertising \ + events. Advertising interval is less that 3.75 ms. \ + Use this type for fast reconnections. \ + @note Advertising data is not supported. */ +#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x03 /**< Connectable non-scannable directed advertising \ + events. \ + @note Advertising data is not supported. */ +#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x04 /**< Non-connectable scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x05 /**< Non-connectable non-scannable undirected \ + advertising events. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x06 /**< Connectable non-scannable undirected advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x07 /**< Connectable non-scannable directed advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ + 0x08 /**< Non-connectable scannable undirected advertising \ + events using extended advertising PDUs. \ + @note Only scan response data is supported. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED \ + 0x09 /**< Non-connectable scannable directed advertising \ + events using extended advertising PDUs. \ + @note Only scan response data is supported. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ + 0x0A /**< Non-connectable non-scannable undirected advertising \ + events using extended advertising PDUs. */ +#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED \ + 0x0B /**< Non-connectable non-scannable directed advertising \ + events using extended advertising PDUs. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_FILTER_POLICIES GAP Advertising filter policies + * @{ */ +#define BLE_GAP_ADV_FP_ANY 0x00 /**< Allow scan requests and connect requests from any device. */ +#define BLE_GAP_ADV_FP_FILTER_SCANREQ 0x01 /**< Filter scan requests with whitelist. */ +#define BLE_GAP_ADV_FP_FILTER_CONNREQ 0x02 /**< Filter connect requests with whitelist. */ +#define BLE_GAP_ADV_FP_FILTER_BOTH 0x03 /**< Filter both scan and connect requests with whitelist. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_DATA_STATUS GAP Advertising data status + * @{ */ +#define BLE_GAP_ADV_DATA_STATUS_COMPLETE 0x00 /**< All data in the advertising event have been received. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA \ + 0x01 /**< More data to be received. \ + @note This value will only be used if \ + @ref ble_gap_scan_params_t::report_incomplete_evts and \ + @ref ble_gap_adv_report_type_t::extended_pdu are set to true. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED \ + 0x02 /**< Incomplete data. Buffer size insufficient to receive more. \ + @note This value will only be used if \ + @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ +#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MISSED \ + 0x03 /**< Failed to receive the remaining data. \ + @note This value will only be used if \ + @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ +/**@} */ + +/**@defgroup BLE_GAP_SCAN_FILTER_POLICIES GAP Scanner filter policies + * @{ */ +#define BLE_GAP_SCAN_FP_ACCEPT_ALL \ + 0x00 /**< Accept all advertising packets except directed advertising packets \ + not addressed to this device. */ +#define BLE_GAP_SCAN_FP_WHITELIST \ + 0x01 /**< Accept advertising packets from devices in the whitelist except directed \ + packets not addressed to this device. */ +#define BLE_GAP_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED \ + 0x02 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL. \ + In addition, accept directed advertising packets, where the advertiser's \ + address is a resolvable private address that cannot be resolved. */ +#define BLE_GAP_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED \ + 0x03 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST. \ + In addition, accept directed advertising packets, where the advertiser's \ + address is a resolvable private address that cannot be resolved. */ +/**@} */ + +/**@defgroup BLE_GAP_ADV_TIMEOUT_VALUES GAP Advertising timeout values in 10 ms units + * @{ */ +#define BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX \ + (128) /**< Maximum high duty advertising time in 10 ms units. Corresponds to 1.28 s. \ + */ +#define BLE_GAP_ADV_TIMEOUT_LIMITED_MAX \ + (18000) /**< Maximum advertising time in 10 ms units corresponding to TGAP(lim_adv_timeout) = 180 s in limited discoverable \ + mode. */ +#define BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED \ + (0) /**< Unlimited advertising in general discoverable mode. \ + For high duty cycle advertising, this corresponds to @ref BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX. */ +/**@} */ + +/**@defgroup BLE_GAP_DISC_MODES GAP Discovery modes + * @{ */ +#define BLE_GAP_DISC_MODE_NOT_DISCOVERABLE 0x00 /**< Not discoverable discovery Mode. */ +#define BLE_GAP_DISC_MODE_LIMITED 0x01 /**< Limited Discovery Mode. */ +#define BLE_GAP_DISC_MODE_GENERAL 0x02 /**< General Discovery Mode. */ +/**@} */ + +/**@defgroup BLE_GAP_IO_CAPS GAP IO Capabilities + * @{ */ +#define BLE_GAP_IO_CAPS_DISPLAY_ONLY 0x00 /**< Display Only. */ +#define BLE_GAP_IO_CAPS_DISPLAY_YESNO 0x01 /**< Display and Yes/No entry. */ +#define BLE_GAP_IO_CAPS_KEYBOARD_ONLY 0x02 /**< Keyboard Only. */ +#define BLE_GAP_IO_CAPS_NONE 0x03 /**< No I/O capabilities. */ +#define BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY 0x04 /**< Keyboard and Display. */ +/**@} */ + +/**@defgroup BLE_GAP_AUTH_KEY_TYPES GAP Authentication Key Types + * @{ */ +#define BLE_GAP_AUTH_KEY_TYPE_NONE 0x00 /**< No key (may be used to reject). */ +#define BLE_GAP_AUTH_KEY_TYPE_PASSKEY 0x01 /**< 6-digit Passkey. */ +#define BLE_GAP_AUTH_KEY_TYPE_OOB 0x02 /**< Out Of Band data. */ +/**@} */ + +/**@defgroup BLE_GAP_KP_NOT_TYPES GAP Keypress Notification Types + * @{ */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_START 0x00 /**< Passkey entry started. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_IN 0x01 /**< Passkey digit entered. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_OUT 0x02 /**< Passkey digit erased. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_CLEAR 0x03 /**< Passkey cleared. */ +#define BLE_GAP_KP_NOT_TYPE_PASSKEY_END 0x04 /**< Passkey entry completed. */ +/**@} */ + +/**@defgroup BLE_GAP_SEC_STATUS GAP Security status + * @{ */ +#define BLE_GAP_SEC_STATUS_SUCCESS 0x00 /**< Procedure completed with success. */ +#define BLE_GAP_SEC_STATUS_TIMEOUT 0x01 /**< Procedure timed out. */ +#define BLE_GAP_SEC_STATUS_PDU_INVALID 0x02 /**< Invalid PDU received. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE1_BEGIN 0x03 /**< Reserved for Future Use range #1 begin. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE1_END 0x80 /**< Reserved for Future Use range #1 end. */ +#define BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED 0x81 /**< Passkey entry failed (user canceled or other). */ +#define BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE 0x82 /**< Out of Band Key not available. */ +#define BLE_GAP_SEC_STATUS_AUTH_REQ 0x83 /**< Authentication requirements not met. */ +#define BLE_GAP_SEC_STATUS_CONFIRM_VALUE 0x84 /**< Confirm value failed. */ +#define BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP 0x85 /**< Pairing not supported. */ +#define BLE_GAP_SEC_STATUS_ENC_KEY_SIZE 0x86 /**< Encryption key size. */ +#define BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED 0x87 /**< Unsupported SMP command. */ +#define BLE_GAP_SEC_STATUS_UNSPECIFIED 0x88 /**< Unspecified reason. */ +#define BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS 0x89 /**< Too little time elapsed since last attempt. */ +#define BLE_GAP_SEC_STATUS_INVALID_PARAMS 0x8A /**< Invalid parameters. */ +#define BLE_GAP_SEC_STATUS_DHKEY_FAILURE 0x8B /**< DHKey check failure. */ +#define BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE 0x8C /**< Numeric Comparison failure. */ +#define BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG 0x8D /**< BR/EDR pairing in progress. */ +#define BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED 0x8E /**< BR/EDR Link Key cannot be used for LE keys. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE2_BEGIN 0x8F /**< Reserved for Future Use range #2 begin. */ +#define BLE_GAP_SEC_STATUS_RFU_RANGE2_END 0xFF /**< Reserved for Future Use range #2 end. */ +/**@} */ + +/**@defgroup BLE_GAP_SEC_STATUS_SOURCES GAP Security status sources + * @{ */ +#define BLE_GAP_SEC_STATUS_SOURCE_LOCAL 0x00 /**< Local failure. */ +#define BLE_GAP_SEC_STATUS_SOURCE_REMOTE 0x01 /**< Remote failure. */ +/**@} */ + +/**@defgroup BLE_GAP_CP_LIMITS GAP Connection Parameters Limits + * @{ */ +#define BLE_GAP_CP_MIN_CONN_INTVL_NONE 0xFFFF /**< No new minimum connection interval specified in connect parameters. */ +#define BLE_GAP_CP_MIN_CONN_INTVL_MIN \ + 0x0006 /**< Lowest minimum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ +#define BLE_GAP_CP_MIN_CONN_INTVL_MAX \ + 0x0C80 /**< Highest minimum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ + */ +#define BLE_GAP_CP_MAX_CONN_INTVL_NONE 0xFFFF /**< No new maximum connection interval specified in connect parameters. */ +#define BLE_GAP_CP_MAX_CONN_INTVL_MIN \ + 0x0006 /**< Lowest maximum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ +#define BLE_GAP_CP_MAX_CONN_INTVL_MAX \ + 0x0C80 /**< Highest maximum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ + */ +#define BLE_GAP_CP_SLAVE_LATENCY_MAX 0x01F3 /**< Highest slave latency permitted, in connection events. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_NONE 0xFFFF /**< No new supervision timeout specified in connect parameters. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN 0x000A /**< Lowest supervision timeout permitted, in units of 10 ms, i.e. 100 ms. */ +#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX 0x0C80 /**< Highest supervision timeout permitted, in units of 10 ms, i.e. 32 s. */ +/**@} */ + +/**@defgroup BLE_GAP_DEVNAME GAP device name defines. + * @{ */ +#define BLE_GAP_DEVNAME_DEFAULT "nRF5x" /**< Default device name value. */ +#define BLE_GAP_DEVNAME_DEFAULT_LEN 31 /**< Default number of octets in device name. */ +#define BLE_GAP_DEVNAME_MAX_LEN 248 /**< Maximum number of octets in device name. */ +/**@} */ + +/**@brief Disable RSSI events for connections */ +#define BLE_GAP_RSSI_THRESHOLD_INVALID 0xFF + +/**@defgroup BLE_GAP_PHYS GAP PHYs + * @{ */ +#define BLE_GAP_PHY_AUTO 0x00 /**< Automatic PHY selection. Refer @ref sd_ble_gap_phy_update for more information.*/ +#define BLE_GAP_PHY_1MBPS 0x01 /**< 1 Mbps PHY. */ +#define BLE_GAP_PHY_2MBPS 0x02 /**< 2 Mbps PHY. */ +#define BLE_GAP_PHY_CODED 0x04 /**< Coded PHY. */ +#define BLE_GAP_PHY_NOT_SET 0xFF /**< PHY is not configured. */ + +/**@brief Supported PHYs in connections, for scanning, and for advertising. */ +#define BLE_GAP_PHYS_SUPPORTED (BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_CODED) /**< All PHYs are supported. */ + +/**@} */ + +/**@defgroup BLE_GAP_CONN_SEC_MODE_SET_MACROS GAP attribute security requirement setters + * + * See @ref ble_gap_conn_sec_mode_t. + * @{ */ +/**@brief Set sec_mode pointed to by ptr to have no access rights.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(ptr) \ + do { \ + (ptr)->sm = 0; \ + (ptr)->lv = 0; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require no protection, open link.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_OPEN(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 1; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require encryption, but no MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 2; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require encryption and MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 3; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require LESC encryption and MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 1; \ + (ptr)->lv = 4; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require signing or encryption, no MITM protection needed.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(ptr) \ + do { \ + (ptr)->sm = 2; \ + (ptr)->lv = 1; \ + } while (0) +/**@brief Set sec_mode pointed to by ptr to require signing or encryption with MITM protection.*/ +#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(ptr) \ + do { \ + (ptr)->sm = 2; \ + (ptr)->lv = 2; \ + } while (0) +/**@} */ + +/**@brief GAP Security Random Number Length. */ +#define BLE_GAP_SEC_RAND_LEN 8 + +/**@brief GAP Security Key Length. */ +#define BLE_GAP_SEC_KEY_LEN 16 + +/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key Length. */ +#define BLE_GAP_LESC_P256_PK_LEN 64 + +/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman DHKey Length. */ +#define BLE_GAP_LESC_DHKEY_LEN 32 + +/**@brief GAP Passkey Length. */ +#define BLE_GAP_PASSKEY_LEN 6 + +/**@brief Maximum amount of addresses in the whitelist. */ +#define BLE_GAP_WHITELIST_ADDR_MAX_COUNT (8) + +/**@brief Maximum amount of identities in the device identities list. */ +#define BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT (8) + +/**@brief Default connection count for a configuration. */ +#define BLE_GAP_CONN_COUNT_DEFAULT (1) + +/**@defgroup BLE_GAP_EVENT_LENGTH GAP event length defines. + * @{ */ +#define BLE_GAP_EVENT_LENGTH_MIN (2) /**< Minimum event length, in 1.25 ms units. */ +#define BLE_GAP_EVENT_LENGTH_CODED_PHY_MIN (6) /**< The shortest event length in 1.25 ms units supporting LE Coded PHY. */ +#define BLE_GAP_EVENT_LENGTH_DEFAULT (3) /**< Default event length, in 1.25 ms units. */ +/**@} */ + +/**@defgroup BLE_GAP_ROLE_COUNT GAP concurrent connection count defines. + * @{ */ +#define BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT (1) /**< Default maximum number of connections concurrently acting as peripherals. */ +#define BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT (3) /**< Default maximum number of connections concurrently acting as centrals. */ +#define BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT \ + (1) /**< Default number of SMP instances shared between all connections acting as centrals. */ +#define BLE_GAP_ROLE_COUNT_COMBINED_MAX \ + (20) /**< Maximum supported number of concurrent connections in the peripheral and central roles combined. */ + +/**@} */ + +/**@brief Automatic data length parameter. */ +#define BLE_GAP_DATA_LENGTH_AUTO 0 + +/**@defgroup BLE_GAP_AUTH_PAYLOAD_TIMEOUT Authenticated payload timeout defines. + * @{ */ +#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX (48000) /**< Maximum authenticated payload timeout in 10 ms units, i.e. 8 minutes. */ +#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MIN (1) /**< Minimum authenticated payload timeout in 10 ms units, i.e. 10 ms. */ +/**@} */ + +/**@defgroup GAP_SEC_MODES GAP Security Modes + * @{ */ +#define BLE_GAP_SEC_MODE 0x00 /**< No key (may be used to reject). */ +/**@} */ + +/**@brief The total number of channels in Bluetooth Low Energy. */ +#define BLE_GAP_CHANNEL_COUNT (40) + +/**@defgroup BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS Quality of Service (QoS) Channel survey interval defines + * @{ */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS (0) /**< Continuous channel survey. */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MIN_US (7500) /**< Minimum channel survey interval in microseconds (7.5 ms). */ +#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MAX_US (4000000) /**< Maximum channel survey interval in microseconds (4 s). */ + /**@} */ + +/** @} */ + +/** @defgroup BLE_GAP_CHAR_INCL_CONFIG GAP Characteristic inclusion configurations + * @{ + */ +#define BLE_GAP_CHAR_INCL_CONFIG_INCLUDE (0) /**< Include the characteristic in the Attribute Table */ +#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITH_SPACE \ + (1) /**< Do not include the characteristic in the Attribute table. \ + The SoftDevice will reserve the attribute handles \ + which are otherwise used for this characteristic. \ + By reserving the attribute handles it will be possible \ + to upgrade the SoftDevice without changing handle of the \ + Service Changed characteristic. */ +#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITHOUT_SPACE \ + (2) /**< Do not include the characteristic in the Attribute table. \ + The SoftDevice will not reserve the attribute handles \ + which are otherwise used for this characteristic. */ +/**@} */ + +/** @defgroup BLE_GAP_CHAR_INCL_CONFIG_DEFAULTS Characteristic inclusion default values + * @{ */ +#define BLE_GAP_PPCP_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ +#define BLE_GAP_CAR_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ +/**@} */ + +/** @defgroup BLE_GAP_SLAVE_LATENCY Slave latency configuration options + * @{ */ +#define BLE_GAP_SLAVE_LATENCY_ENABLE \ + (0) /**< Slave latency is enabled. When slave latency is enabled, \ + the slave will wake up every time it has data to send, \ + and/or every slave latency number of connection events. */ +#define BLE_GAP_SLAVE_LATENCY_DISABLE \ + (1) /**< Disable slave latency. The slave will wake up every connection event \ + regardless of the requested slave latency. \ + This option consumes the most power. */ +#define BLE_GAP_SLAVE_LATENCY_WAIT_FOR_ACK \ + (2) /**< The slave will wake up every connection event if it has not received \ + an ACK from the master for at least slave latency events. This \ + configuration may increase the power consumption in environments \ + with a lot of radio activity. */ +/**@} */ + +/**@addtogroup BLE_GAP_STRUCTURES Structures + * @{ */ + +/**@brief Advertising event properties. */ +typedef struct { + uint8_t type; /**< Advertising type. See @ref BLE_GAP_ADV_TYPES. */ + uint8_t anonymous : 1; /**< Omit advertiser's address from all PDUs. + @note Anonymous advertising is only available for + @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED and + @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED. */ + uint8_t include_tx_power : 1; /**< This feature is not supported on this SoftDevice. */ +} ble_gap_adv_properties_t; + +/**@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 Advertising Auxiliary Pointer. */ +typedef struct { + uint16_t aux_offset; /**< Time offset from the beginning of advertising packet to the auxiliary packet in 100 us units. */ + uint8_t aux_phy; /**< Indicates the PHY on which the auxiliary advertising packet is sent. See @ref BLE_GAP_PHYS. */ +} ble_gap_aux_pointer_t; + +/**@brief Bluetooth Low Energy address. */ +typedef struct { + uint8_t + addr_id_peer : 1; /**< Only valid for peer addresses. + This bit is set by the SoftDevice to indicate whether the address has been resolved from + a Resolvable Private Address (when the peer is using privacy). + If set to 1, @ref addr and @ref addr_type refer to the identity address of the resolved address. + + This bit is ignored when a variable of type @ref ble_gap_addr_t is used as input to API functions. + */ + uint8_t addr_type : 7; /**< See @ref BLE_GAP_ADDR_TYPES. */ + uint8_t addr[BLE_GAP_ADDR_LEN]; /**< 48-bit address, LSB format. + @ref addr is not used if @ref addr_type is @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. */ +} ble_gap_addr_t; + +/**@brief GAP connection parameters. + * + * @note When ble_conn_params_t is received in an event, both min_conn_interval and + * max_conn_interval will be equal to the connection interval set by the central. + * + * @note If both conn_sup_timeout and max_conn_interval are specified, then the following constraint applies: + * conn_sup_timeout * 4 > (1 + slave_latency) * max_conn_interval + * that corresponds to the following Bluetooth Spec requirement: + * The Supervision_Timeout in milliseconds shall be larger than + * (1 + Conn_Latency) * Conn_Interval_Max * 2, where Conn_Interval_Max is given in milliseconds. + */ +typedef struct { + uint16_t min_conn_interval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t max_conn_interval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t slave_latency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ + uint16_t conn_sup_timeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ +} ble_gap_conn_params_t; + +/**@brief GAP connection security modes. + * + * Security Mode 0 Level 0: No access permissions at all (this level is not defined by the Bluetooth Core specification).\n + * Security Mode 1 Level 1: No security is needed (aka open link).\n + * Security Mode 1 Level 2: Encrypted link required, MITM protection not necessary.\n + * Security Mode 1 Level 3: MITM protected encrypted link required.\n + * Security Mode 1 Level 4: LESC MITM protected encrypted link using a 128-bit strength encryption key required.\n + * Security Mode 2 Level 1: Signing or encryption required, MITM protection not necessary.\n + * Security Mode 2 Level 2: MITM protected signing required, unless link is MITM protected encrypted.\n + */ +typedef struct { + uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ + uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */ + +} ble_gap_conn_sec_mode_t; + +/**@brief GAP connection security status.*/ +typedef struct { + ble_gap_conn_sec_mode_t sec_mode; /**< Currently active security mode for this connection.*/ + uint8_t + encr_key_size; /**< Length of currently active encryption key, 7 to 16 octets (only applicable for bonding procedures). */ +} ble_gap_conn_sec_t; + +/**@brief Identity Resolving Key. */ +typedef struct { + uint8_t irk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing IRK. */ +} ble_gap_irk_t; + +/**@brief Channel mask (40 bits). + * Every channel is represented with a bit positioned as per channel index defined in Bluetooth Core Specification v5.0, + * Vol 6, Part B, Section 1.4.1. The LSB contained in array element 0 represents channel index 0, and bit 39 represents + * channel index 39. If a bit is set to 1, the channel is not used. + */ +typedef uint8_t ble_gap_ch_mask_t[5]; + +/**@brief GAP advertising parameters. */ +typedef struct { + ble_gap_adv_properties_t properties; /**< The properties of the advertising events. */ + ble_gap_addr_t const *p_peer_addr; /**< Address of a known peer. + @note ble_gap_addr_t::addr_type cannot be + @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. + - When privacy is enabled and the local device uses + @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE addresses, + the device identity list is searched for a matching entry. If + the local IRK for that device identity is set, the local IRK + for that device will be used to generate the advertiser address + field in the advertising packet. + - If @ref ble_gap_adv_properties_t::type is directed, this must be + set to the targeted scanner or initiator. If the peer address is + in the device identity list, the peer IRK for that device will be + used to generate @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE + target addresses used in the advertising event PDUs. */ + uint32_t interval; /**< Advertising interval in 625 us units. @sa BLE_GAP_ADV_INTERVALS. + @note If @ref ble_gap_adv_properties_t::type is set to + @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE + advertising, this parameter is ignored. */ + uint16_t duration; /**< Advertising duration in 10 ms units. When timeout is reached, + an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. + @sa BLE_GAP_ADV_TIMEOUT_VALUES. + @note The SoftDevice will always complete at least one advertising + event even if the duration is set too low. */ + uint8_t max_adv_evts; /**< Maximum advertising events that shall be sent prior to disabling + advertising. Setting the value to 0 disables the limitation. When + the count of advertising events specified by this parameter + (if not 0) is reached, advertising will be automatically stopped + and an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised + @note If @ref ble_gap_adv_properties_t::type is set to + @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE, + this parameter is ignored. */ + ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. + At least one of the primary channels, that is channel index 37-39, must be used. + Masking away secondary advertising channels is not supported. */ + uint8_t filter_policy; /**< Filter Policy. @sa BLE_GAP_ADV_FILTER_POLICIES. */ + uint8_t primary_phy; /**< Indicates the PHY on which the primary advertising channel packets + are transmitted. If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS + will be used. + Valid values are @ref BLE_GAP_PHY_1MBPS and @ref BLE_GAP_PHY_CODED. + @note The primary_phy shall indicate @ref BLE_GAP_PHY_1MBPS if + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t secondary_phy; /**< Indicates the PHY on which the secondary advertising channel packets + are transmitted. + If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS will be used. + Valid values are + @ref BLE_GAP_PHY_1MBPS, @ref BLE_GAP_PHY_2MBPS, and @ref BLE_GAP_PHY_CODED. + If @ref ble_gap_adv_properties_t::type is an extended advertising type + and connectable, this is the PHY that will be used to establish a + connection and send AUX_ADV_IND packets on. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t set_id : 4; /**< The advertising set identifier distinguishes this advertising set from other + advertising sets transmitted by this and other devices. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ + uint8_t scan_req_notification : 1; /**< Enable scan request notifications for this advertising set. When a + scan request is received and the scanner address is allowed + by the filter policy, @ref BLE_GAP_EVT_SCAN_REQ_REPORT is raised. + @note This parameter will be ignored when + @ref ble_gap_adv_properties_t::type is a non-scannable + advertising type. */ +} ble_gap_adv_params_t; + +/**@brief GAP advertising data buffers. + * + * The application must provide the buffers for advertisement. The memory shall reside in application RAM, and + * shall never be modified while advertising. The data shall be kept alive until either: + * - @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. + * - @ref BLE_GAP_EVT_CONNECTED is raised with @ref ble_gap_evt_connected_t::adv_handle set to the corresponding + * advertising handle. + * - Advertising is stopped. + * - Advertising data is changed. + * To update advertising data while advertising, provide new buffers to @ref sd_ble_gap_adv_set_configure. */ +typedef struct { + ble_data_t adv_data; /**< Advertising data. + @note + Advertising data can only be specified for a @ref ble_gap_adv_properties_t::type + that is allowed to contain advertising data. */ + ble_data_t scan_rsp_data; /**< Scan response data. + @note + Scan response data can only be specified for a @ref ble_gap_adv_properties_t::type + that is scannable. */ +} ble_gap_adv_data_t; + +/**@brief GAP scanning parameters. */ +typedef struct { + uint8_t extended : 1; /**< If 1, the scanner will accept extended advertising packets. + If set to 0, the scanner will not receive advertising packets + on secondary advertising channels, and will not be able + to receive long advertising PDUs. */ + uint8_t report_incomplete_evts : 1; /**< If 1, events of type @ref ble_gap_evt_adv_report_t may have + @ref ble_gap_adv_report_type_t::status set to + @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. + This parameter is ignored when used with @ref sd_ble_gap_connect + @note This may be used to abort receiving more packets from an extended + advertising event, and is only available for extended + scanning, see @ref sd_ble_gap_scan_start. + @note This feature is not supported by this SoftDevice. */ + uint8_t active : 1; /**< If 1, perform active scanning by sending scan requests. + This parameter is ignored when used with @ref sd_ble_gap_connect. */ + uint8_t filter_policy : 2; /**< Scanning filter policy. @sa BLE_GAP_SCAN_FILTER_POLICIES. + @note Only @ref BLE_GAP_SCAN_FP_ACCEPT_ALL and + @ref BLE_GAP_SCAN_FP_WHITELIST are valid when used with + @ref sd_ble_gap_connect */ + uint8_t scan_phys; /**< Bitfield of PHYs to scan on. If set to @ref BLE_GAP_PHY_AUTO, + scan_phys will default to @ref BLE_GAP_PHY_1MBPS. + - If @ref ble_gap_scan_params_t::extended is set to 0, the only + supported PHY is @ref BLE_GAP_PHY_1MBPS. + - When used with @ref sd_ble_gap_scan_start, + the bitfield indicates the PHYs the scanner will use for scanning + on primary advertising channels. The scanner will accept + @ref BLE_GAP_PHYS_SUPPORTED as secondary advertising channel PHYs. + - When used with @ref sd_ble_gap_connect, the bitfield indicates + the PHYs the initiator will use for scanning on primary advertising + channels. The initiator will accept connections initiated on either + of the @ref BLE_GAP_PHYS_SUPPORTED PHYs. + If scan_phys contains @ref BLE_GAP_PHY_1MBPS and/or @ref BLE_GAP_PHY_2MBPS, + the primary scan PHY is @ref BLE_GAP_PHY_1MBPS. + If scan_phys also contains @ref BLE_GAP_PHY_CODED, the primary scan + PHY will also contain @ref BLE_GAP_PHY_CODED. If the only scan PHY is + @ref BLE_GAP_PHY_CODED, the primary scan PHY is + @ref BLE_GAP_PHY_CODED only. */ + uint16_t interval; /**< Scan interval in 625 us units. @sa BLE_GAP_SCAN_INTERVALS. */ + uint16_t window; /**< Scan window in 625 us units. @sa BLE_GAP_SCAN_WINDOW. + If scan_phys contains both @ref BLE_GAP_PHY_1MBPS and + @ref BLE_GAP_PHY_CODED interval shall be larger than or + equal to twice the scan window. */ + uint16_t timeout; /**< Scan timeout in 10 ms units. @sa BLE_GAP_SCAN_TIMEOUT. */ + ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. + At least one of the primary channels, that is channel index 37-39, must be + set to 0. + Masking away secondary channels is not supported. */ +} ble_gap_scan_params_t; + +/**@brief Privacy. + * + * The privacy feature provides a way for the device to avoid being tracked over a period of time. + * The privacy feature, when enabled, hides the local device identity and replaces it with a private address + * that is automatically refreshed at a specified interval. + * + * If a device still wants to be recognized by other peers, it needs to share it's Identity Resolving Key (IRK). + * With this key, a device can generate a random private address that can only be recognized by peers in possession of that + * key, and devices can establish connections without revealing their real identities. + * + * Both network privacy (@ref BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY) and device privacy (@ref + * BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY) are supported. + * + * @note If the device IRK is updated, the new IRK becomes the one to be distributed in all + * bonding procedures performed after @ref sd_ble_gap_privacy_set returns. + * The IRK distributed during bonding procedure is the device IRK that is active when @ref sd_ble_gap_sec_params_reply is + * called. + */ +typedef struct { + uint8_t privacy_mode; /**< Privacy mode, see @ref BLE_GAP_PRIVACY_MODES. Default is @ref BLE_GAP_PRIVACY_MODE_OFF. */ + uint8_t private_addr_type; /**< The private address type must be either @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE or + @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE. */ + uint16_t private_addr_cycle_s; /**< Private address cycle interval in seconds. Providing an address cycle value of 0 will use + the default value defined by @ref BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S. */ + ble_gap_irk_t + *p_device_irk; /**< When used as input, pointer to IRK structure that will be used as the default IRK. If NULL, the device + default IRK will be used. When used as output, pointer to IRK structure where the current default IRK + will be written to. If NULL, this argument is ignored. By default, the default IRK is used to generate + random private resolvable addresses for the local device unless instructed otherwise. */ +} ble_gap_privacy_params_t; + +/**@brief PHY preferences for TX and RX + * @note tx_phys and rx_phys are bit fields. Multiple bits can be set in them to indicate multiple preferred PHYs for each + * direction. + * @code + * p_gap_phys->tx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; + * p_gap_phys->rx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; + * @endcode + * + */ +typedef struct { + uint8_t tx_phys; /**< Preferred transmit PHYs, see @ref BLE_GAP_PHYS. */ + uint8_t rx_phys; /**< Preferred receive PHYs, see @ref BLE_GAP_PHYS. */ +} ble_gap_phys_t; + +/** @brief Keys that can be exchanged during a bonding procedure. */ +typedef struct { + uint8_t enc : 1; /**< Long Term Key and Master Identification. */ + uint8_t id : 1; /**< Identity Resolving Key and Identity Address Information. */ + uint8_t sign : 1; /**< Connection Signature Resolving Key. */ + uint8_t link : 1; /**< Derive the Link Key from the LTK. */ +} ble_gap_sec_kdist_t; + +/**@brief GAP security parameters. */ +typedef struct { + uint8_t bond : 1; /**< Perform bonding. */ + uint8_t mitm : 1; /**< Enable Man In The Middle protection. */ + uint8_t lesc : 1; /**< Enable LE Secure Connection pairing. */ + uint8_t keypress : 1; /**< Enable generation of keypress notifications. */ + uint8_t io_caps : 3; /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */ + uint8_t oob : 1; /**< The OOB data flag. + - In LE legacy pairing, this flag is set if a device has out of band authentication data. + The OOB method is used if both of the devices have out of band authentication data. + - In LE Secure Connections pairing, this flag is set if a device has the peer device's out of band + authentication data. The OOB method is used if at least one device has the peer device's OOB data + available. */ + uint8_t + min_key_size; /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */ + uint8_t max_key_size; /**< Maximum encryption key size in octets between min_key_size and 16. */ + ble_gap_sec_kdist_t kdist_own; /**< Key distribution bitmap: keys that the local device will distribute. */ + ble_gap_sec_kdist_t kdist_peer; /**< Key distribution bitmap: keys that the remote device will distribute. */ +} ble_gap_sec_params_t; + +/**@brief GAP Encryption Information. */ +typedef struct { + uint8_t ltk[BLE_GAP_SEC_KEY_LEN]; /**< Long Term Key. */ + uint8_t lesc : 1; /**< Key generated using LE Secure Connections. */ + uint8_t auth : 1; /**< Authenticated Key. */ + uint8_t ltk_len : 6; /**< LTK length in octets. */ +} ble_gap_enc_info_t; + +/**@brief GAP Master Identification. */ +typedef struct { + uint16_t ediv; /**< Encrypted Diversifier. */ + uint8_t rand[BLE_GAP_SEC_RAND_LEN]; /**< Random Number. */ +} ble_gap_master_id_t; + +/**@brief GAP Signing Information. */ +typedef struct { + uint8_t csrk[BLE_GAP_SEC_KEY_LEN]; /**< Connection Signature Resolving Key. */ +} ble_gap_sign_info_t; + +/**@brief GAP LE Secure Connections P-256 Public Key. */ +typedef struct { + uint8_t pk[BLE_GAP_LESC_P256_PK_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key. Stored in the + standard SMP protocol format: {X,Y} both in little-endian. */ +} ble_gap_lesc_p256_pk_t; + +/**@brief GAP LE Secure Connections DHKey. */ +typedef struct { + uint8_t key[BLE_GAP_LESC_DHKEY_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman Key. Stored in little-endian. */ +} ble_gap_lesc_dhkey_t; + +/**@brief GAP LE Secure Connections OOB data. */ +typedef struct { + ble_gap_addr_t addr; /**< Bluetooth address of the device. */ + uint8_t r[BLE_GAP_SEC_KEY_LEN]; /**< Random Number. */ + uint8_t c[BLE_GAP_SEC_KEY_LEN]; /**< Confirm Value. */ +} ble_gap_lesc_oob_data_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONNECTED. */ +typedef struct { + ble_gap_addr_t + peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref + ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ + uint8_t role; /**< BLE role for this connection, see @ref BLE_GAP_ROLES */ + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ + uint8_t adv_handle; /**< Advertising handle in which advertising has ended. + This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ + ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated + advertising set. The advertising buffers provided in + @ref sd_ble_gap_adv_set_configure are now released. + This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ +} ble_gap_evt_connected_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DISCONNECTED. */ +typedef struct { + uint8_t reason; /**< HCI error code, see @ref BLE_HCI_STATUS_CODES. */ +} ble_gap_evt_disconnected_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE. */ +typedef struct { + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ +} ble_gap_evt_conn_param_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST. */ +typedef struct { + ble_gap_phys_t peer_preferred_phys; /**< The PHYs the peer prefers to use. */ +} ble_gap_evt_phy_update_request_t; + +/**@brief Event Structure for @ref BLE_GAP_EVT_PHY_UPDATE. */ +typedef struct { + uint8_t status; /**< Status of the procedure, see @ref BLE_HCI_STATUS_CODES.*/ + uint8_t tx_phy; /**< TX PHY for this connection, see @ref BLE_GAP_PHYS. */ + uint8_t rx_phy; /**< RX PHY for this connection, see @ref BLE_GAP_PHYS. */ +} ble_gap_evt_phy_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. */ +typedef struct { + ble_gap_sec_params_t peer_params; /**< Initiator Security Parameters. */ +} ble_gap_evt_sec_params_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_INFO_REQUEST. */ +typedef struct { + ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. */ + ble_gap_master_id_t master_id; /**< Master Identification for LTK lookup. */ + uint8_t enc_info : 1; /**< If 1, Encryption Information required. */ + uint8_t id_info : 1; /**< If 1, Identity Information required. */ + uint8_t sign_info : 1; /**< If 1, Signing Information required. */ +} ble_gap_evt_sec_info_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_PASSKEY_DISPLAY. */ +typedef struct { + uint8_t passkey[BLE_GAP_PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */ + uint8_t match_request : 1; /**< If 1 requires the application to report the match using @ref sd_ble_gap_auth_key_reply + with either @ref BLE_GAP_AUTH_KEY_TYPE_NONE if there is no match or + @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY if there is a match. */ +} ble_gap_evt_passkey_display_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_KEY_PRESSED. */ +typedef struct { + uint8_t kp_not; /**< Keypress notification type, see @ref BLE_GAP_KP_NOT_TYPES. */ +} ble_gap_evt_key_pressed_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_KEY_REQUEST. */ +typedef struct { + uint8_t key_type; /**< See @ref BLE_GAP_AUTH_KEY_TYPES. */ +} ble_gap_evt_auth_key_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST. */ +typedef struct { + ble_gap_lesc_p256_pk_t + *p_pk_peer; /**< LE Secure Connections remote P-256 Public Key. This will point to the application-supplied memory + inside the keyset during the call to @ref sd_ble_gap_sec_params_reply. */ + uint8_t oobd_req : 1; /**< LESC OOB data required. A call to @ref sd_ble_gap_lesc_oob_data_set is required to complete the + procedure. */ +} ble_gap_evt_lesc_dhkey_request_t; + +/**@brief Security levels supported. + * @note See Bluetooth Specification Version 4.2 Volume 3, Part C, Chapter 10, Section 10.2.1. + */ +typedef struct { + uint8_t lv1 : 1; /**< If 1: Level 1 is supported. */ + uint8_t lv2 : 1; /**< If 1: Level 2 is supported. */ + uint8_t lv3 : 1; /**< If 1: Level 3 is supported. */ + uint8_t lv4 : 1; /**< If 1: Level 4 is supported. */ +} ble_gap_sec_levels_t; + +/**@brief Encryption Key. */ +typedef struct { + ble_gap_enc_info_t enc_info; /**< Encryption Information. */ + ble_gap_master_id_t master_id; /**< Master Identification. */ +} ble_gap_enc_key_t; + +/**@brief Identity Key. */ +typedef struct { + ble_gap_irk_t id_info; /**< Identity Resolving Key. */ + ble_gap_addr_t id_addr_info; /**< Identity Address. */ +} ble_gap_id_key_t; + +/**@brief Security Keys. */ +typedef struct { + ble_gap_enc_key_t *p_enc_key; /**< Encryption Key, or NULL. */ + ble_gap_id_key_t *p_id_key; /**< Identity Key, or NULL. */ + ble_gap_sign_info_t *p_sign_key; /**< Signing Key, or NULL. */ + ble_gap_lesc_p256_pk_t *p_pk; /**< LE Secure Connections P-256 Public Key. When in debug mode the application must use the + value defined in the Core Bluetooth Specification v4.2 Vol.3, Part H, Section 2.3.5.6.1 */ +} ble_gap_sec_keys_t; + +/**@brief Security key set for both local and peer keys. */ +typedef struct { + ble_gap_sec_keys_t keys_own; /**< Keys distributed by the local device. For LE Secure Connections the encryption key will be + generated locally and will always be stored if bonding. */ + ble_gap_sec_keys_t + keys_peer; /**< Keys distributed by the remote device. For LE Secure Connections, p_enc_key must always be NULL. */ +} ble_gap_sec_keyset_t; + +/**@brief Data Length Update Procedure parameters. */ +typedef struct { + uint16_t max_tx_octets; /**< Maximum number of payload octets that a Controller supports for transmission of a single Link + Layer Data Channel PDU. */ + uint16_t max_rx_octets; /**< Maximum number of payload octets that a Controller supports for reception of a single Link Layer + Data Channel PDU. */ + uint16_t max_tx_time_us; /**< Maximum time, in microseconds, that a Controller supports for transmission of a single Link + Layer Data Channel PDU. */ + uint16_t max_rx_time_us; /**< Maximum time, in microseconds, that a Controller supports for reception of a single Link Layer + Data Channel PDU. */ +} ble_gap_data_length_params_t; + +/**@brief Data Length Update Procedure local limitation. */ +typedef struct { + uint16_t tx_payload_limited_octets; /**< If > 0, the requested TX packet length is too long by this many octets. */ + uint16_t rx_payload_limited_octets; /**< If > 0, the requested RX packet length is too long by this many octets. */ + uint16_t tx_rx_time_limited_us; /**< If > 0, the requested combination of TX and RX packet lengths is too long by this many + microseconds. */ +} ble_gap_data_length_limitation_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_STATUS. */ +typedef struct { + uint8_t auth_status; /**< Authentication status, see @ref BLE_GAP_SEC_STATUS. */ + uint8_t error_src : 2; /**< On error, source that caused the failure, see @ref BLE_GAP_SEC_STATUS_SOURCES. */ + uint8_t bonded : 1; /**< Procedure resulted in a bond. */ + uint8_t lesc : 1; /**< Procedure resulted in a LE Secure Connection. */ + ble_gap_sec_levels_t sm1_levels; /**< Levels supported in Security Mode 1. */ + ble_gap_sec_levels_t sm2_levels; /**< Levels supported in Security Mode 2. */ + ble_gap_sec_kdist_t kdist_own; /**< Bitmap stating which keys were exchanged (distributed) by the local device. If bonding + with LE Secure Connections, the enc bit will be always set. */ + ble_gap_sec_kdist_t kdist_peer; /**< Bitmap stating which keys were exchanged (distributed) by the remote device. If bonding + with LE Secure Connections, the enc bit will never be set. */ +} ble_gap_evt_auth_status_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_SEC_UPDATE. */ +typedef struct { + ble_gap_conn_sec_t conn_sec; /**< Connection security level. */ +} ble_gap_evt_conn_sec_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Source of timeout event, see @ref BLE_GAP_TIMEOUT_SOURCES. */ + union { + ble_data_t adv_report_buffer; /**< If source is set to @ref BLE_GAP_TIMEOUT_SRC_SCAN, the released + scan buffer is contained in this field. */ + } params; /**< Event Parameters. */ +} ble_gap_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_RSSI_CHANGED. */ +typedef struct { + int8_t rssi; /**< Received Signal Strength Indication in dBm. + @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature + measurement. */ + uint8_t ch_index; /**< Data Channel Index on which the Signal Strength is measured (0-36). */ +} ble_gap_evt_rssi_changed_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_ADV_SET_TERMINATED */ +typedef struct { + uint8_t reason; /**< Reason for why the advertising set terminated. See + @ref BLE_GAP_EVT_ADV_SET_TERMINATED_REASON. */ + uint8_t adv_handle; /**< Advertising handle in which advertising has ended. */ + uint8_t num_completed_adv_events; /**< If @ref ble_gap_adv_params_t::max_adv_evts was not set to 0, + this field indicates the number of completed advertising events. */ + ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated + advertising set. The advertising buffers provided in + @ref sd_ble_gap_adv_set_configure are now released. */ +} ble_gap_evt_adv_set_terminated_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; + +/**@brief Event structure for @ref BLE_GAP_EVT_SEC_REQUEST. */ +typedef struct { + uint8_t bond : 1; /**< Perform bonding. */ + uint8_t mitm : 1; /**< Man In The Middle protection requested. */ + uint8_t lesc : 1; /**< LE Secure Connections requested. */ + uint8_t keypress : 1; /**< Generation of keypress notifications requested. */ +} ble_gap_evt_sec_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST. */ +typedef struct { + ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ +} ble_gap_evt_conn_param_update_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_SCAN_REQ_REPORT. */ +typedef struct { + uint8_t adv_handle; /**< Advertising handle for the advertising set which received the Scan Request */ + int8_t rssi; /**< Received Signal Strength Indication in dBm. + @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature + measurement. */ + ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref + ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ +} ble_gap_evt_scan_req_report_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST. */ +typedef struct { + ble_gap_data_length_params_t peer_params; /**< Peer data length parameters. */ +} ble_gap_evt_data_length_update_request_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE. + * + * @note This event may also be raised after a PHY Update procedure. + */ +typedef struct { + ble_gap_data_length_params_t effective_params; /**< The effective data length parameters. */ +} ble_gap_evt_data_length_update_t; + +/**@brief Event structure for @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT. */ +typedef struct { + int8_t + channel_energy[BLE_GAP_CHANNEL_COUNT]; /**< The measured energy on the Bluetooth Low Energy + channels, in dBm, indexed by Channel Index. + If no measurement is available for the given channel, channel_energy is set to + @ref BLE_GAP_POWER_LEVEL_INVALID. */ +} ble_gap_evt_qos_channel_survey_report_t; + +/**@brief GAP event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which event occurred. */ + union /**< union alternative identified by evt_id in enclosing struct. */ + { + ble_gap_evt_connected_t connected; /**< Connected Event Parameters. */ + ble_gap_evt_disconnected_t disconnected; /**< Disconnected Event Parameters. */ + ble_gap_evt_conn_param_update_t conn_param_update; /**< Connection Parameter Update Parameters. */ + ble_gap_evt_sec_params_request_t sec_params_request; /**< Security Parameters Request Event Parameters. */ + ble_gap_evt_sec_info_request_t sec_info_request; /**< Security Information Request Event Parameters. */ + ble_gap_evt_passkey_display_t passkey_display; /**< Passkey Display Event Parameters. */ + ble_gap_evt_key_pressed_t key_pressed; /**< Key Pressed Event Parameters. */ + ble_gap_evt_auth_key_request_t auth_key_request; /**< Authentication Key Request Event Parameters. */ + ble_gap_evt_lesc_dhkey_request_t lesc_dhkey_request; /**< LE Secure Connections DHKey calculation request. */ + ble_gap_evt_auth_status_t auth_status; /**< Authentication Status Event Parameters. */ + ble_gap_evt_conn_sec_update_t conn_sec_update; /**< Connection Security Update Event Parameters. */ + ble_gap_evt_timeout_t timeout; /**< Timeout Event Parameters. */ + ble_gap_evt_rssi_changed_t rssi_changed; /**< RSSI Event Parameters. */ + ble_gap_evt_adv_report_t adv_report; /**< Advertising Report Event Parameters. */ + ble_gap_evt_adv_set_terminated_t adv_set_terminated; /**< Advertising Set Terminated Event Parameters. */ + ble_gap_evt_sec_request_t sec_request; /**< Security Request Event Parameters. */ + ble_gap_evt_conn_param_update_request_t conn_param_update_request; /**< Connection Parameter Update Parameters. */ + ble_gap_evt_scan_req_report_t scan_req_report; /**< Scan Request Report Parameters. */ + ble_gap_evt_phy_update_request_t phy_update_request; /**< PHY Update Request Event Parameters. */ + ble_gap_evt_phy_update_t phy_update; /**< PHY Update Parameters. */ + ble_gap_evt_data_length_update_request_t data_length_update_request; /**< Data Length Update Request Event Parameters. */ + ble_gap_evt_data_length_update_t data_length_update; /**< Data Length Update Event Parameters. */ + ble_gap_evt_qos_channel_survey_report_t + qos_channel_survey_report; /**< Quality of Service (QoS) Channel Survey Report Parameters. */ + } params; /**< Event Parameters. */ +} ble_gap_evt_t; + +/** + * @brief BLE GAP connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_CONN_COUNT The connection count for the connection configurations is zero. + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - The sum of conn_count for all connection configurations combined exceeds UINT8_MAX. + * - The event length is smaller than @ref BLE_GAP_EVENT_LENGTH_MIN. + */ +typedef struct { + uint8_t conn_count; /**< The number of concurrent connections the application can create with this configuration. + The default and minimum value is @ref BLE_GAP_CONN_COUNT_DEFAULT. */ + uint16_t event_length; /**< The time set aside for this connection on every connection interval in 1.25 ms units. + The default value is @ref BLE_GAP_EVENT_LENGTH_DEFAULT, the minimum value is @ref + BLE_GAP_EVENT_LENGTH_MIN. The event length and the connection interval are the primary parameters + for setting the throughput of a connection. + See the SoftDevice Specification for details on throughput. */ +} ble_gap_conn_cfg_t; + +/** + * @brief Configuration of maximum concurrent connections in the different connected roles, set with + * @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_CONN_COUNT The sum of periph_role_count and central_role_count is too + * large. The maximum supported sum of concurrent connections is + * @ref BLE_GAP_ROLE_COUNT_COMBINED_MAX. + * @retval ::NRF_ERROR_INVALID_PARAM central_sec_count is larger than central_role_count. + * @retval ::NRF_ERROR_RESOURCES The adv_set_count is too large. The maximum + * supported advertising handles is + * @ref BLE_GAP_ADV_SET_COUNT_MAX. + */ +typedef struct { + uint8_t adv_set_count; /**< Maximum number of advertising sets. Default value is @ref BLE_GAP_ADV_SET_COUNT_DEFAULT. */ + uint8_t periph_role_count; /**< Maximum number of connections concurrently acting as a peripheral. Default value is @ref + BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT. */ + uint8_t central_role_count; /**< Maximum number of connections concurrently acting as a central. Default value is @ref + BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT. */ + uint8_t central_sec_count; /**< Number of SMP instances shared between all connections acting as a central. Default value is + @ref BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT. */ + uint8_t qos_channel_survey_role_available : 1; /**< If set, the Quality of Service (QoS) channel survey module is available to + the application using @ref sd_ble_gap_qos_channel_survey_start. */ +} ble_gap_cfg_role_count_t; + +/** + * @brief Device name and its properties, set with @ref sd_ble_cfg_set. + * + * @note If the device name is not configured, the default device name will be + * @ref BLE_GAP_DEVNAME_DEFAULT, the maximum device name length will be + * @ref BLE_GAP_DEVNAME_DEFAULT_LEN, vloc will be set to @ref BLE_GATTS_VLOC_STACK and the device name + * will have no write access. + * + * @note If @ref max_len is more than @ref BLE_GAP_DEVNAME_DEFAULT_LEN and vloc is set to @ref BLE_GATTS_VLOC_STACK, + * the attribute table size must be increased to have room for the longer device name (see + * @ref sd_ble_cfg_set and @ref ble_gatts_cfg_attr_tab_size_t). + * + * @note If vloc is @ref BLE_GATTS_VLOC_STACK : + * - p_value must point to non-volatile memory (flash) or be NULL. + * - If p_value is NULL, the device name will initially be empty. + * + * @note If vloc is @ref BLE_GATTS_VLOC_USER : + * - p_value cannot be NULL. + * - If the device name is writable, p_value must point to volatile memory (RAM). + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - Invalid device name location (vloc). + * - Invalid device name security mode. + * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: + * - The device name length is invalid (must be between 0 and @ref BLE_GAP_DEVNAME_MAX_LEN). + * - The device name length is too long for the given Attribute Table. + * @retval ::NRF_ERROR_NOT_SUPPORTED Device name security mode is not supported. + */ +typedef struct { + ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ + uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ + uint8_t *p_value; /**< Pointer to where the value (device name) is stored or will be stored. */ + uint16_t current_len; /**< Current length in bytes of the memory pointed to by p_value.*/ + uint16_t max_len; /**< Maximum length in bytes of the memory pointed to by p_value.*/ +} ble_gap_cfg_device_name_t; + +/**@brief Peripheral Preferred Connection Parameters include configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t include_cfg; /**< Inclusion configuration of the Peripheral Preferred Connection Parameters characteristic. + See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_PPCP_INCL_CONFIG_DEFAULT. */ +} ble_gap_cfg_ppcp_incl_cfg_t; + +/**@brief Central Address Resolution include configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t include_cfg; /**< Inclusion configuration of the Central Address Resolution characteristic. + See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_CAR_INCL_CONFIG_DEFAULT. */ +} ble_gap_cfg_car_incl_cfg_t; + +/**@brief Configuration structure for GAP configurations. */ +typedef union { + ble_gap_cfg_role_count_t role_count_cfg; /**< Role count configuration, cfg_id is @ref BLE_GAP_CFG_ROLE_COUNT. */ + ble_gap_cfg_device_name_t device_name_cfg; /**< Device name configuration, cfg_id is @ref BLE_GAP_CFG_DEVICE_NAME. */ + ble_gap_cfg_ppcp_incl_cfg_t ppcp_include_cfg; /**< Peripheral Preferred Connection Parameters characteristic include + configuration, cfg_id is @ref BLE_GAP_CFG_PPCP_INCL_CONFIG. */ + ble_gap_cfg_car_incl_cfg_t car_include_cfg; /**< Central Address Resolution characteristic include configuration, + cfg_id is @ref BLE_GAP_CFG_CAR_INCL_CONFIG. */ +} ble_gap_cfg_t; + +/**@brief Channel Map option. + * + * @details Used with @ref sd_ble_opt_get to get the current channel map + * or @ref sd_ble_opt_set to set a new channel map. When setting the + * channel map, it applies to all current and future connections. When getting the + * current channel map, it applies to a single connection and the connection handle + * must be supplied. + * + * @note Setting the channel map may take some time, depending on connection parameters. + * The time taken may be different for each connection and the get operation will + * return the previous channel map until the new one has taken effect. + * + * @note After setting the channel map, by spec it can not be set again until at least 1 s has passed. + * See Bluetooth Specification Version 4.1 Volume 2, Part E, Section 7.3.46. + * + * @retval ::NRF_SUCCESS Get or set successful. + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - Less then two bits in @ref ch_map are set. + * - Bits for primary advertising channels (37-39) are set. + * @retval ::NRF_ERROR_BUSY Channel map was set again before enough time had passed. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied for get. + * + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle (only applicable for get) */ + uint8_t ch_map[5]; /**< Channel Map (37-bit). */ +} ble_gap_opt_ch_map_t; + +/**@brief Local connection latency option. + * + * @details Local connection latency is a feature which enables the slave to improve + * current consumption by ignoring the slave latency set by the peer. The + * local connection latency can only be set to a multiple of the slave latency, + * and cannot be longer than half of the supervision timeout. + * + * @details Used with @ref sd_ble_opt_set to set the local connection latency. The + * @ref sd_ble_opt_get is not supported for this option, but the actual + * local connection latency (unless set to NULL) is set as a return parameter + * when setting the option. + * + * @note The latency set will be truncated down to the closest slave latency event + * multiple, or the nearest multiple before half of the supervision timeout. + * + * @note The local connection latency is disabled by default, and needs to be enabled for new + * connections and whenever the connection is updated. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint16_t requested_latency; /**< Requested local connection latency. */ + uint16_t *p_actual_latency; /**< Pointer to storage for the actual local connection latency (can be set to NULL to skip return + value). */ +} ble_gap_opt_local_conn_latency_t; + +/**@brief Disable slave latency + * + * @details Used with @ref sd_ble_opt_set to temporarily disable slave latency of a peripheral connection + * (see @ref ble_gap_conn_params_t::slave_latency). And to re-enable it again. When disabled, the + * peripheral will ignore the slave_latency set by the central. + * + * @note Shall only be called on peripheral links. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint8_t disable; /**< For allowed values see @ref BLE_GAP_SLAVE_LATENCY */ +} ble_gap_opt_slave_latency_disable_t; + +/**@brief Passkey Option. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} + * @endmscs + * + * @details Structure containing the passkey to be used during pairing. This can be used with @ref + * sd_ble_opt_set to make the SoftDevice use a preprogrammed passkey for authentication + * instead of generating a random one. + * + * @note Repeated pairing attempts using the same preprogrammed passkey makes pairing vulnerable to MITM attacks. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * + */ +typedef struct { + uint8_t const *p_passkey; /**< Pointer to 6-digit ASCII string (digit 0..9 only, no NULL termination) passkey to be used + during pairing. If this is NULL, the SoftDevice will generate a random passkey if required.*/ +} ble_gap_opt_passkey_t; + +/**@brief Compatibility mode 1 option. + * + * @details This can be used with @ref sd_ble_opt_set to enable and disable + * compatibility mode 1. Compatibility mode 1 is disabled by default. + * + * @note Compatibility mode 1 enables interoperability with devices that do not support a value of + * 0 for the WinOffset parameter in the Link Layer CONNECT_IND packet. This applies to a + * limited set of legacy peripheral devices from another vendor. Enabling this compatibility + * mode will only have an effect if the local device will act as a central device and + * initiate a connection to a peripheral device. In that case it may lead to the connection + * creation taking up to one connection interval longer to complete for all connections. + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_INVALID_STATE When connection creation is ongoing while mode 1 is set. + */ +typedef struct { + uint8_t enable : 1; /**< Enable compatibility mode 1.*/ +} ble_gap_opt_compat_mode_1_t; + +/**@brief Authenticated payload timeout option. + * + * @details This can be used with @ref sd_ble_opt_set to change the Authenticated payload timeout to a value other + * than the default of @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX. + * + * @note The authenticated payload timeout event ::BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD will be generated + * if auth_payload_timeout time has elapsed without receiving a packet with a valid MIC on an encrypted + * link. + * + * @note The LE ping procedure will be initiated before the timer expires to give the peer a chance + * to reset the timer. In addition the stack will try to prioritize running of LE ping over other + * activities to increase chances of finishing LE ping before timer expires. To avoid side-effects + * on other activities, it is recommended to use high timeout values. + * Recommended timeout > 2*(connInterval * (6 + connSlaveLatency)). + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. auth_payload_timeout was outside of allowed range. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. + */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle */ + uint16_t auth_payload_timeout; /**< Requested timeout in 10 ms unit, see @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT. */ +} ble_gap_opt_auth_payload_timeout_t; + +/**@brief Option structure for GAP options. */ +typedef union { + ble_gap_opt_ch_map_t ch_map; /**< Parameters for the Channel Map option. */ + ble_gap_opt_local_conn_latency_t local_conn_latency; /**< Parameters for the Local connection latency option */ + ble_gap_opt_passkey_t passkey; /**< Parameters for the Passkey option.*/ + ble_gap_opt_compat_mode_1_t compat_mode_1; /**< Parameters for the compatibility mode 1 option.*/ + ble_gap_opt_auth_payload_timeout_t auth_payload_timeout; /**< Parameters for the authenticated payload timeout option.*/ + ble_gap_opt_slave_latency_disable_t slave_latency_disable; /**< Parameters for the Disable slave latency option */ +} ble_gap_opt_t; + +/**@brief Connection event triggering parameters. */ +typedef struct { + uint8_t ppi_ch_id; /**< PPI channel to use. This channel should be regarded as reserved until + connection event PPI task triggering is stopped. + The PPI channel ID can not be one of the PPI channels reserved by + the SoftDevice. See @ref NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK. */ + uint32_t task_endpoint; /**< Task Endpoint to trigger. */ + uint16_t conn_evt_counter_start; /**< The connection event on which the task triggering should start. */ + uint16_t period_in_events; /**< Trigger period. Valid range is [1, 32767]. + If the device is in slave role and slave latency is enabled, + this parameter should be set to a multiple of (slave latency + 1) + to ensure low power operation. */ +} ble_gap_conn_event_trigger_t; +/**@} */ + +/**@addtogroup BLE_GAP_FUNCTIONS Functions + * @{ */ + +/**@brief Set the local Bluetooth identity address. + * + * The local Bluetooth identity address is the address that identifies this device to other peers. + * The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. + * + * @note The identity address cannot be changed while advertising, scanning or creating a connection. + * + * @note This address will be distributed to the peer during bonding. + * If the address changes, the address stored in the peer device will not be valid and the ability to + * reconnect using the old address will be lost. + * + * @note By default the SoftDevice will set an address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC upon being + * enabled. The address is a random number populated during the IC manufacturing process and remains unchanged + * for the lifetime of each IC. + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @endmscs + * + * @param[in] p_addr Pointer to address structure. + * + * @retval ::NRF_SUCCESS Address successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_STATE The identity address cannot be changed while advertising, + * scanning or creating a connection. + */ +SVCALL(SD_BLE_GAP_ADDR_SET, uint32_t, sd_ble_gap_addr_set(ble_gap_addr_t const *p_addr)); + +/**@brief Get local Bluetooth identity address. + * + * @note This will always return the identity address irrespective of the privacy settings, + * i.e. the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. + * + * @param[out] p_addr Pointer to address structure to be filled in. + * + * @retval ::NRF_SUCCESS Address successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + */ +SVCALL(SD_BLE_GAP_ADDR_GET, uint32_t, sd_ble_gap_addr_get(ble_gap_addr_t *p_addr)); + +/**@brief Get the Bluetooth device address used by the advertiser. + * + * @note This function will return the local Bluetooth address used in advertising PDUs. When + * using privacy, the SoftDevice will generate a new private address every + * @ref ble_gap_privacy_params_t::private_addr_cycle_s configured using + * @ref sd_ble_gap_privacy_set. Hence depending on when the application calls this API, the + * address returned may not be the latest address that is used in the advertising PDUs. + * + * @param[in] adv_handle The advertising handle to get the address from. + * @param[out] p_addr Pointer to address structure to be filled in. + * + * @retval ::NRF_SUCCESS Address successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. + * @retval ::NRF_ERROR_INVALID_STATE The advertising set is currently not advertising. + */ +SVCALL(SD_BLE_GAP_ADV_ADDR_GET, uint32_t, sd_ble_gap_adv_addr_get(uint8_t adv_handle, ble_gap_addr_t *p_addr)); + +/**@brief Set the active whitelist in the SoftDevice. + * + * @note Only one whitelist can be used at a time and the whitelist is shared between the BLE roles. + * The whitelist cannot be set if a BLE role is using the whitelist. + * + * @note If an address is resolved using the information in the device identity list, then the whitelist + * filter policy applies to the peer identity address and not the resolvable address sent on air. + * + * @mscs + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} + * @endmscs + * + * @param[in] pp_wl_addrs Pointer to a whitelist of peer addresses, if NULL the whitelist will be cleared. + * @param[in] len Length of the whitelist, maximum @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT. + * + * @retval ::NRF_SUCCESS The whitelist is successfully set/cleared. + * @retval ::NRF_ERROR_INVALID_ADDR The whitelist (or one of its entries) provided is invalid. + * @retval ::BLE_ERROR_GAP_WHITELIST_IN_USE The whitelist is in use by a BLE role and cannot be set or cleared. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_DATA_SIZE The given whitelist size is invalid (zero or too large); this can only return when + * pp_wl_addrs is not NULL. + */ +SVCALL(SD_BLE_GAP_WHITELIST_SET, uint32_t, sd_ble_gap_whitelist_set(ble_gap_addr_t const *const *pp_wl_addrs, uint8_t len)); + +/**@brief Set device identity list. + * + * @note Only one device identity list can be used at a time and the list is shared between the BLE roles. + * The device identity list cannot be set if a BLE role is using the list. + * + * @param[in] pp_id_keys Pointer to an array of peer identity addresses and peer IRKs, if NULL the device identity list will + * be cleared. + * @param[in] pp_local_irks Pointer to an array of local IRKs. Each entry in the array maps to the entry in pp_id_keys at the + * same index. To fill in the list with the currently set device IRK for all peers, set to NULL. + * @param[in] len Length of the device identity list, maximum @ref BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT. + * + * @mscs + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS The device identity list successfully set/cleared. + * @retval ::NRF_ERROR_INVALID_ADDR The device identity list (or one of its entries) provided is invalid. + * This code may be returned if the local IRK list also has an invalid entry. + * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE The device identity list is in use and cannot be set or cleared. + * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE The device identity list contains multiple entries with the same identity + * address. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_DATA_SIZE The given device identity list size invalid (zero or too large); this can + * only return when pp_id_keys is not NULL. + */ +SVCALL(SD_BLE_GAP_DEVICE_IDENTITIES_SET, uint32_t, + sd_ble_gap_device_identities_set(ble_gap_id_key_t const *const *pp_id_keys, ble_gap_irk_t const *const *pp_local_irks, + uint8_t len)); + +/**@brief Set privacy settings. + * + * @note Privacy settings cannot be changed while advertising, scanning or creating a connection. + * + * @param[in] p_privacy_params Privacy settings. + * + * @mscs + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Set successfully. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. + * @retval ::NRF_ERROR_INVALID_ADDR The pointer to privacy settings is NULL or invalid. + * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. + * @retval ::NRF_ERROR_INVALID_PARAM Out of range parameters are provided. + * @retval ::NRF_ERROR_NOT_SUPPORTED The SoftDevice does not support privacy if the Central Address Resolution + characteristic is not configured to be included and the SoftDevice is configured + to support central roles. + See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + * @retval ::NRF_ERROR_INVALID_STATE Privacy settings cannot be changed while advertising, scanning + * or creating a connection. + */ +SVCALL(SD_BLE_GAP_PRIVACY_SET, uint32_t, sd_ble_gap_privacy_set(ble_gap_privacy_params_t const *p_privacy_params)); + +/**@brief Get privacy settings. + * + * @note ::ble_gap_privacy_params_t::p_device_irk must be initialized to NULL or a valid address before this function is called. + * If it is initialized to a valid address, the address pointed to will contain the current device IRK on return. + * + * @param[in,out] p_privacy_params Privacy settings. + * + * @retval ::NRF_SUCCESS Privacy settings read. + * @retval ::NRF_ERROR_INVALID_ADDR The pointer given for returning the privacy settings may be NULL or invalid. + * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. + */ +SVCALL(SD_BLE_GAP_PRIVACY_GET, uint32_t, sd_ble_gap_privacy_get(ble_gap_privacy_params_t *p_privacy_params)); + +/**@brief Configure an advertising set. Set, clear or update advertising and scan response data. + * + * @note The format of the advertising data will be checked by this call to ensure interoperability. + * Limitations imposed by this API call to the data provided include having a flags data type in the scan response data and + * duplicating the local name in the advertising data and scan response data. + * + * @note In order to update advertising data while advertising, new advertising buffers must be provided. + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in,out] p_adv_handle Provide a pointer to a handle containing @ref + * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising set. On success, a new handle is then returned through the + * pointer. Provide a pointer to an existing advertising handle to configure an existing advertising set. + * @param[in] p_adv_data Advertising data. If set to NULL, no advertising data will be used. See + * @ref ble_gap_adv_data_t. + * @param[in] p_adv_params Advertising parameters. When this function is used to update advertising + * data while advertising, this parameter must be NULL. See @ref ble_gap_adv_params_t. + * + * @retval ::NRF_SUCCESS Advertising set successfully configured. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: + * - Invalid advertising data configuration specified. See @ref + * ble_gap_adv_data_t. + * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. + * - Use of whitelist requested but whitelist has not been set, + * see @ref sd_ble_gap_whitelist_set. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR ble_gap_adv_params_t::p_peer_addr is invalid. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - It is invalid to provide non-NULL advertising set parameters while + * advertising. + * - It is invalid to provide the same data buffers while advertising. To + * update advertising data, provide new advertising buffers. + * @retval ::BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST Discoverable mode and whitelist incompatible. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. Use @ref + * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_FLAGS Invalid combination of advertising flags supplied. + * @retval ::NRF_ERROR_INVALID_DATA Invalid data type(s) supplied. Check the advertising data format + * specification given in Bluetooth Specification Version 5.0, Volume 3, Part C, Chapter 11. + * @retval ::NRF_ERROR_INVALID_LENGTH Invalid data length(s) supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported data length or advertising parameter configuration. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to configure a new advertising handle. Update an + * existing advertising handle instead. + * @retval ::BLE_ERROR_GAP_UUID_LIST_MISMATCH Invalid UUID list supplied. + */ +SVCALL(SD_BLE_GAP_ADV_SET_CONFIGURE, uint32_t, + sd_ble_gap_adv_set_configure(uint8_t *p_adv_handle, ble_gap_adv_data_t const *p_adv_data, + ble_gap_adv_params_t const *p_adv_params)); + +/**@brief Start advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). + * + * @note Only one advertiser may be active at any time. + * + * @note If privacy is enabled, the advertiser's private address will be refreshed when this function is called. + * See @ref sd_ble_gap_privacy_set(). + * + * @events + * @event{@ref BLE_GAP_EVT_CONNECTED, Generated after connection has been established through connectable advertising.} + * @event{@ref BLE_GAP_EVT_ADV_SET_TERMINATED, Advertising set has terminated.} + * @event{@ref BLE_GAP_EVT_SCAN_REQ_REPORT, A scan request was received.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] adv_handle Advertising handle to advertise on, received from @ref sd_ble_gap_adv_set_configure. + * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or + * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. For non-connectable + * advertising, this is ignored. + * + * @retval ::NRF_SUCCESS The BLE stack has started advertising. + * @retval ::NRF_ERROR_INVALID_STATE adv_handle is not configured or already advertising. + * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration + * tag has been reached; connectable advertiser cannot be started. + * To increase the number of available connections, + * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. Configure a new adveriting handle with @ref + sd_ble_gap_adv_set_configure. + * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: + * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. + * - Use of whitelist requested but whitelist has not been set, see @ref + sd_ble_gap_whitelist_set. + * @retval ::NRF_ERROR_RESOURCES Either: + * - adv_handle is configured with connectable advertising, but the event_length parameter + * associated with conn_cfg_tag is too small to be able to establish a connection on + * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. + * - Not enough BLE role slots available. + Stop one or more currently active roles (Central, Peripheral, Broadcaster or Observer) + and try again. + * - p_adv_params is configured with connectable advertising, but the event_length + parameter + * associated with conn_cfg_tag is too small to be able to establish a connection on + * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. + */ +SVCALL(SD_BLE_GAP_ADV_START, uint32_t, sd_ble_gap_adv_start(uint8_t adv_handle, uint8_t conn_cfg_tag)); + +/**@brief Stop advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). + * + * @mscs + * @mmsc{@ref BLE_GAP_ADV_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] adv_handle The advertising handle that should stop advertising. + * + * @retval ::NRF_SUCCESS The BLE stack has stopped advertising. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Invalid advertising handle. + * @retval ::NRF_ERROR_INVALID_STATE The advertising handle is not advertising. + */ +SVCALL(SD_BLE_GAP_ADV_STOP, uint32_t, sd_ble_gap_adv_stop(uint8_t adv_handle)); + +/**@brief Update connection parameters. + * + * @details In the central role this will initiate a Link Layer connection parameter update procedure, + * otherwise in the peripheral role, this will send the corresponding L2CAP request and wait for + * the central to perform the procedure. In both cases, and regardless of success or failure, the application + * will be informed of the result with a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE event. + * + * @details This function can be used as a central both to reply to a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST or to start the + * procedure unrequested. + * + * @events + * @event{@ref BLE_GAP_EVT_CONN_PARAM_UPDATE, Result of the connection parameter update procedure.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CPU_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CPU_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CPU_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_conn_params Pointer to desired connection parameters. If NULL is provided on a peripheral role, + * the parameters in the PPCP characteristic of the GAP service will be used instead. + * If NULL is provided on a central role and in response to a @ref + * BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST, the peripheral request will be rejected + * + * @retval ::NRF_SUCCESS The Connection Update procedure has been started successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. + * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. + * @retval ::NRF_ERROR_BUSY Procedure already in progress, wait for pending procedures to complete and retry. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GAP_CONN_PARAM_UPDATE, uint32_t, + sd_ble_gap_conn_param_update(uint16_t conn_handle, ble_gap_conn_params_t const *p_conn_params)); + +/**@brief Disconnect (GAP Link Termination). + * + * @details This call initiates the disconnection procedure, and its completion will be communicated to the application + * with a @ref BLE_GAP_EVT_DISCONNECTED event. + * + * @events + * @event{@ref BLE_GAP_EVT_DISCONNECTED, Generated when disconnection procedure is complete.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CONN_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] hci_status_code HCI status code, see @ref BLE_HCI_STATUS_CODES (accepted values are @ref + * BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION and @ref BLE_HCI_CONN_INTERVAL_UNACCEPTABLE). + * + * @retval ::NRF_SUCCESS The disconnection procedure has been started successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. + */ +SVCALL(SD_BLE_GAP_DISCONNECT, uint32_t, sd_ble_gap_disconnect(uint16_t conn_handle, uint8_t hci_status_code)); + +/**@brief Set the radio's transmit power. + * + * @param[in] role The role to set the transmit power for, see @ref BLE_GAP_TX_POWER_ROLES for + * possible roles. + * @param[in] handle The handle parameter is interpreted depending on role: + * - If role is @ref BLE_GAP_TX_POWER_ROLE_CONN, this value is the specific connection handle. + * - If role is @ref BLE_GAP_TX_POWER_ROLE_ADV, the advertising set identified with the advertising handle, + * will use the specified transmit power, and include it in the advertising packet headers if + * @ref ble_gap_adv_properties_t::include_tx_power set. + * - For all other roles handle is ignored. + * @param[in] tx_power Radio transmit power in dBm (see note for accepted values). + * + * @note Supported tx_power values: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm and +4dBm. + * In addition, on some chips following values are supported: +2dBm, +5dBm, +6dBm, +7dBm and +8dBm. + * Setting these values on a chip that does not support them will result in undefined behaviour. + * @note The initiator will have the same transmit power as the scanner. + * @note When a connection is created it will inherit the transmit power from the initiator or + * advertiser leading to the connection. + * + * @retval ::NRF_SUCCESS Successfully changed the transmit power. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_TX_POWER_SET, uint32_t, sd_ble_gap_tx_power_set(uint8_t role, uint16_t handle, int8_t tx_power)); + +/**@brief Set GAP Appearance value. + * + * @param[in] appearance Appearance (16-bit), see @ref BLE_APPEARANCES. + * + * @retval ::NRF_SUCCESS Appearance value set successfully. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + */ +SVCALL(SD_BLE_GAP_APPEARANCE_SET, uint32_t, sd_ble_gap_appearance_set(uint16_t appearance)); + +/**@brief Get GAP Appearance value. + * + * @param[out] p_appearance Pointer to appearance (16-bit) to be filled in, see @ref BLE_APPEARANCES. + * + * @retval ::NRF_SUCCESS Appearance value retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GAP_APPEARANCE_GET, uint32_t, sd_ble_gap_appearance_get(uint16_t *p_appearance)); + +/**@brief Set GAP Peripheral Preferred Connection Parameters. + * + * @param[in] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure with the desired parameters. + * + * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, + see @ref ble_gap_cfg_ppcp_incl_cfg_t. + */ +SVCALL(SD_BLE_GAP_PPCP_SET, uint32_t, sd_ble_gap_ppcp_set(ble_gap_conn_params_t const *p_conn_params)); + +/**@brief Get GAP Peripheral Preferred Connection Parameters. + * + * @param[out] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure where the parameters will be stored. + * + * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, + see @ref ble_gap_cfg_ppcp_incl_cfg_t. + */ +SVCALL(SD_BLE_GAP_PPCP_GET, uint32_t, sd_ble_gap_ppcp_get(ble_gap_conn_params_t *p_conn_params)); + +/**@brief Set GAP device name. + * + * @note If the device name is located in application flash memory (see @ref ble_gap_cfg_device_name_t), + * it cannot be changed. Then @ref NRF_ERROR_FORBIDDEN will be returned. + * + * @param[in] p_write_perm Write permissions for the Device Name characteristic, see @ref ble_gap_conn_sec_mode_t. + * @param[in] p_dev_name Pointer to a UTF-8 encoded, non NULL-terminated string. + * @param[in] len Length of the UTF-8, non NULL-terminated string pointed to by p_dev_name in octets (must be smaller or + * equal than @ref BLE_GAP_DEVNAME_MAX_LEN). + * + * @retval ::NRF_SUCCESS GAP device name and permissions set successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_FORBIDDEN Device name is not writable. + */ +SVCALL(SD_BLE_GAP_DEVICE_NAME_SET, uint32_t, + sd_ble_gap_device_name_set(ble_gap_conn_sec_mode_t const *p_write_perm, uint8_t const *p_dev_name, uint16_t len)); + +/**@brief Get GAP device name. + * + * @note If the device name is longer than the size of the supplied buffer, + * p_len will return the complete device name length, + * and not the number of bytes actually returned in p_dev_name. + * The application may use this information to allocate a suitable buffer size. + * + * @param[out] p_dev_name Pointer to an empty buffer where the UTF-8 non NULL-terminated string will be placed. Set to + * NULL to obtain the complete device name length. + * @param[in,out] p_len Length of the buffer pointed by p_dev_name, complete device name length on output. + * + * @retval ::NRF_SUCCESS GAP device name retrieved successfully. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + */ +SVCALL(SD_BLE_GAP_DEVICE_NAME_GET, uint32_t, sd_ble_gap_device_name_get(uint8_t *p_dev_name, uint16_t *p_len)); + +/**@brief Initiate the GAP Authentication procedure. + * + * @details In the central role, this function will send an SMP Pairing Request (or an SMP Pairing Failed if rejected), + * otherwise in the peripheral role, an SMP Security Request will be sent. + * + * @events + * @event{Depending on the security parameters set and the packet exchanges with the peer\, the following events may be + * generated:} + * @event{@ref BLE_GAP_EVT_SEC_PARAMS_REQUEST} + * @event{@ref BLE_GAP_EVT_SEC_INFO_REQUEST} + * @event{@ref BLE_GAP_EVT_PASSKEY_DISPLAY} + * @event{@ref BLE_GAP_EVT_KEY_PRESSED} + * @event{@ref BLE_GAP_EVT_AUTH_KEY_REQUEST} + * @event{@ref BLE_GAP_EVT_LESC_DHKEY_REQUEST} + * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE} + * @event{@ref BLE_GAP_EVT_AUTH_STATUS} + * @event{@ref BLE_GAP_EVT_TIMEOUT} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_SEC_REQ_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_sec_params Pointer to the @ref ble_gap_sec_params_t structure with the security parameters to be used during the + * pairing or bonding procedure. In the peripheral role, only the bond, mitm, lesc and keypress fields of this structure are used. + * In the central role, this pointer may be NULL to reject a Security Request. + * + * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - No link has been established. + * - An encryption is already executing or queued. + * @retval ::NRF_ERROR_NO_MEM The maximum number of authentication procedures that can run in parallel for the given role is + * reached. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. + * Distribution of own Identity Information is only supported if the Central + * Address Resolution characteristic is configured to be included or + * the Softdevice is configured to support peripheral roles only. + * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + * @retval ::NRF_ERROR_TIMEOUT A SMP timeout has occurred, and further SMP operations on this link is prohibited. + */ +SVCALL(SD_BLE_GAP_AUTHENTICATE, uint32_t, + sd_ble_gap_authenticate(uint16_t conn_handle, ble_gap_sec_params_t const *p_sec_params)); + +/**@brief Reply with GAP security parameters. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST, calling it at other times will result in + * an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_CONFIRM_FAIL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_KS_TOO_SMALL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_APP_ERROR_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_REMOTE_PAIRING_FAIL_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_TIMEOUT_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] sec_status Security status, see @ref BLE_GAP_SEC_STATUS. + * @param[in] p_sec_params Pointer to a @ref ble_gap_sec_params_t security parameters structure. In the central role this must be + * set to NULL, as the parameters have already been provided during a previous call to @ref sd_ble_gap_authenticate. + * @param[in,out] p_sec_keyset Pointer to a @ref ble_gap_sec_keyset_t security keyset structure. Any keys generated and/or + * distributed as a result of the ongoing security procedure will be stored into the memory referenced by the pointers inside this + * structure. The keys will be stored and available to the application upon reception of a @ref BLE_GAP_EVT_AUTH_STATUS event. + * Note that the SoftDevice expects the application to provide memory for storing the + * peer's keys. So it must be ensured that the relevant pointers inside this structure are not NULL. The + * pointers to the local key can, however, be NULL, in which case, the local key data will not be available to the application + * upon reception of the + * @ref BLE_GAP_EVT_AUTH_STATUS event. + * + * @retval ::NRF_SUCCESS Successfully accepted security parameter from the application. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Security parameters has not been requested. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. + * Distribution of own Identity Information is only supported if the Central + * Address Resolution characteristic is configured to be included or + * the Softdevice is configured to support peripheral roles only. + * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. + */ +SVCALL(SD_BLE_GAP_SEC_PARAMS_REPLY, uint32_t, + sd_ble_gap_sec_params_reply(uint16_t conn_handle, uint8_t sec_status, ble_gap_sec_params_t const *p_sec_params, + ble_gap_sec_keyset_t const *p_sec_keyset)); + +/**@brief Reply with an authentication key. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_AUTH_KEY_REQUEST or a @ref BLE_GAP_EVT_PASSKEY_DISPLAY, + * calling it at other times will result in an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] key_type See @ref BLE_GAP_AUTH_KEY_TYPES. + * @param[in] p_key If key type is @ref BLE_GAP_AUTH_KEY_TYPE_NONE, then NULL. + * If key type is @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY, then a 6-byte ASCII string (digit 0..9 only, no NULL + * termination) or NULL when confirming LE Secure Connections Numeric Comparison. If key type is @ref BLE_GAP_AUTH_KEY_TYPE_OOB, + * then a 16-byte OOB key value in little-endian format. + * + * @retval ::NRF_SUCCESS Authentication key successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Authentication key has not been requested. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_AUTH_KEY_REPLY, uint32_t, + sd_ble_gap_auth_key_reply(uint16_t conn_handle, uint8_t key_type, uint8_t const *p_key)); + +/**@brief Reply with an LE Secure connections DHKey. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST, calling it at other times will result in + * an @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_dhkey LE Secure Connections DHKey. + * + * @retval ::NRF_SUCCESS DHKey successfully set. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - The peer is not authenticated. + * - The application has not pulled a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_DHKEY_REPLY, uint32_t, + sd_ble_gap_lesc_dhkey_reply(uint16_t conn_handle, ble_gap_lesc_dhkey_t const *p_dhkey)); + +/**@brief Notify the peer of a local keypress. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] kp_not See @ref BLE_GAP_KP_NOT_TYPES. + * + * @retval ::NRF_SUCCESS Keypress notification successfully queued for transmission. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Authentication key not requested. + * - Passkey has not been entered. + * - Keypresses have not been enabled by both peers. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_BUSY The BLE stack is busy. Retry at later time. + */ +SVCALL(SD_BLE_GAP_KEYPRESS_NOTIFY, uint32_t, sd_ble_gap_keypress_notify(uint16_t conn_handle, uint8_t kp_not)); + +/**@brief Generate a set of OOB data to send to a peer out of band. + * + * @note The @ref ble_gap_addr_t included in the OOB data returned will be the currently active one (or, if a connection has + * already been established, the one used during connection setup). The application may manually overwrite it with an updated + * value. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. Can be @ref BLE_CONN_HANDLE_INVALID if a BLE connection has not been established yet. + * @param[in] p_pk_own LE Secure Connections local P-256 Public Key. + * @param[out] p_oobd_own The OOB data to be sent out of band to a peer. + * + * @retval ::NRF_SUCCESS OOB data successfully generated. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_OOB_DATA_GET, uint32_t, + sd_ble_gap_lesc_oob_data_get(uint16_t conn_handle, ble_gap_lesc_p256_pk_t const *p_pk_own, + ble_gap_lesc_oob_data_t *p_oobd_own)); + +/**@brief Provide the OOB data sent/received out of band. + * + * @note An authentication procedure with OOB selected as an algorithm must be in progress when calling this function. + * @note A @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event with the oobd_req set to 1 must have been received prior to calling this + * function. + * + * @events + * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref + * sd_ble_gap_authenticate.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_oobd_own The OOB data sent out of band to a peer or NULL if the peer has not received OOB data. + * Must correspond to @ref ble_gap_sec_params_t::oob flag in @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. + * @param[in] p_oobd_peer The OOB data received out of band from a peer or NULL if none received. + * Must correspond to @ref ble_gap_sec_params_t::oob flag + * in @ref sd_ble_gap_authenticate in the central role or + * in @ref sd_ble_gap_sec_params_reply in the peripheral role. + * + * @retval ::NRF_SUCCESS OOB data accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Authentication key not requested + * - Not expecting LESC OOB data + * - Have not actually exchanged passkeys. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_LESC_OOB_DATA_SET, uint32_t, + sd_ble_gap_lesc_oob_data_set(uint16_t conn_handle, ble_gap_lesc_oob_data_t const *p_oobd_own, + ble_gap_lesc_oob_data_t const *p_oobd_peer)); + +/**@brief Initiate GAP Encryption procedure. + * + * @details In the central role, this function will initiate the encryption procedure using the encryption information provided. + * + * @events + * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE, The connection security has been updated.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_ENC_MSC} + * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_master_id Pointer to a @ref ble_gap_master_id_t master identification structure. + * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. + * + * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::BLE_ERROR_INVALID_ROLE Operation is not supported in the Peripheral role. + * @retval ::NRF_ERROR_BUSY Procedure already in progress or not allowed at this time, wait for pending procedures to complete and + * retry. + */ +SVCALL(SD_BLE_GAP_ENCRYPT, uint32_t, + sd_ble_gap_encrypt(uint16_t conn_handle, ble_gap_master_id_t const *p_master_id, ble_gap_enc_info_t const *p_enc_info)); + +/**@brief Reply with GAP security information. + * + * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_INFO_REQUEST, calling it at other times will result in + * @ref NRF_ERROR_INVALID_STATE. + * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected + * parameters. + * @note Data signing is not yet supported, and p_sign_info must therefore be NULL. + * + * @mscs + * @mmsc{@ref BLE_GAP_PERIPH_ENC_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. May be NULL to signal none is + * available. + * @param[in] p_id_info Pointer to a @ref ble_gap_irk_t identity information structure. May be NULL to signal none is available. + * @param[in] p_sign_info Pointer to a @ref ble_gap_sign_info_t signing information structure. May be NULL to signal none is + * available. + * + * @retval ::NRF_SUCCESS Successfully accepted security information. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - No link has been established. + * - No @ref BLE_GAP_EVT_SEC_INFO_REQUEST pending. + * - Encryption information provided by the app without being requested. See @ref + * ble_gap_evt_sec_info_request_t::enc_info. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_SEC_INFO_REPLY, uint32_t, + sd_ble_gap_sec_info_reply(uint16_t conn_handle, ble_gap_enc_info_t const *p_enc_info, ble_gap_irk_t const *p_id_info, + ble_gap_sign_info_t const *p_sign_info)); + +/**@brief Get the current connection security. + * + * @param[in] conn_handle Connection handle. + * @param[out] p_conn_sec Pointer to a @ref ble_gap_conn_sec_t structure to be filled in. + * + * @retval ::NRF_SUCCESS Current connection security successfully retrieved. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_CONN_SEC_GET, uint32_t, sd_ble_gap_conn_sec_get(uint16_t conn_handle, ble_gap_conn_sec_t *p_conn_sec)); + +/**@brief Start reporting the received signal strength to the application. + * + * A new event is reported whenever the RSSI value changes, until @ref sd_ble_gap_rssi_stop is called. + * + * @events + * @event{@ref BLE_GAP_EVT_RSSI_CHANGED, New RSSI data available. How often the event is generated is + * dependent on the settings of the threshold_dbm + * and skip_count input parameters.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] threshold_dbm Minimum change in dBm before triggering the @ref BLE_GAP_EVT_RSSI_CHANGED event. Events are + * disabled if threshold_dbm equals @ref BLE_GAP_RSSI_THRESHOLD_INVALID. + * @param[in] skip_count Number of RSSI samples with a change of threshold_dbm or more before sending a new @ref + * BLE_GAP_EVT_RSSI_CHANGED event. + * + * @retval ::NRF_SUCCESS Successfully activated RSSI reporting. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is already ongoing. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_RSSI_START, uint32_t, sd_ble_gap_rssi_start(uint16_t conn_handle, uint8_t threshold_dbm, uint8_t skip_count)); + +/**@brief Stop reporting the received signal strength. + * + * @note An RSSI change detected before the call but not yet received by the application + * may be reported after @ref sd_ble_gap_rssi_stop has been called. + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * + * @retval ::NRF_SUCCESS Successfully deactivated RSSI reporting. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + */ +SVCALL(SD_BLE_GAP_RSSI_STOP, uint32_t, sd_ble_gap_rssi_stop(uint16_t conn_handle)); + +/**@brief Get the received signal strength for the last connection event. + * + * @ref sd_ble_gap_rssi_start must be called to start reporting RSSI before using this function. @ref NRF_ERROR_NOT_FOUND + * will be returned until RSSI was sampled for the first time after calling @ref sd_ble_gap_rssi_start. + * @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature measurement. + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[out] p_rssi Pointer to the location where the RSSI measurement shall be stored. + * @param[out] p_ch_index Pointer to the location where Channel Index for the RSSI measurement shall be stored. + * + * @retval ::NRF_SUCCESS Successfully read the RSSI. + * @retval ::NRF_ERROR_NOT_FOUND No sample is available. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. + */ +SVCALL(SD_BLE_GAP_RSSI_GET, uint32_t, sd_ble_gap_rssi_get(uint16_t conn_handle, int8_t *p_rssi, uint8_t *p_ch_index)); + +/**@brief Start or continue scanning (GAP Discovery procedure, Observer Procedure). + * + * @note A call to this function will require the application to keep the memory pointed by + * p_adv_report_buffer alive until the buffer is released. The buffer is released when the scanner is stopped + * or when this function is called with another buffer. + * + * @note The scanner will automatically stop in the following cases: + * - @ref sd_ble_gap_scan_stop is called. + * - @ref sd_ble_gap_connect is called. + * - A @ref BLE_GAP_EVT_TIMEOUT with source set to @ref BLE_GAP_TIMEOUT_SRC_SCAN is received. + * - When a @ref BLE_GAP_EVT_ADV_REPORT event is received and @ref ble_gap_adv_report_type_t::status is not set to + * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. In this case scanning is only paused to let the application + * access received data. The application must call this function to continue scanning, or call @ref + * sd_ble_gap_scan_stop to stop scanning. + * + * @note If a @ref BLE_GAP_EVT_ADV_REPORT event is received with @ref ble_gap_adv_report_type_t::status set to + * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the scanner will continue scanning, and the application will + * receive more reports from this advertising event. The following reports will include the old and new received data. + * + * @events + * @event{@ref BLE_GAP_EVT_ADV_REPORT, An advertising or scan response packet has been received.} + * @event{@ref BLE_GAP_EVT_TIMEOUT, Scanner has timed out.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_SCAN_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @param[in] p_scan_params Pointer to scan parameters structure. When this function is used to continue + * scanning, this parameter must be NULL. + * @param[in] p_adv_report_buffer Pointer to buffer used to store incoming advertising data. + * The memory pointed to should be kept alive until the scanning is stopped. + * See @ref BLE_GAP_SCAN_BUFFER_SIZE for minimum and maximum buffer size. + * If the scanner receives advertising data larger than can be stored in the buffer, + * a @ref BLE_GAP_EVT_ADV_REPORT will be raised with @ref ble_gap_adv_report_type_t::status + * set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED. + * + * @retval ::NRF_SUCCESS Successfully initiated scanning procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: + * - Scanning is already ongoing and p_scan_params was not NULL + * - Scanning is not running and p_scan_params was NULL. + * - The scanner has timed out when this function is called to continue scanning. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. See @ref ble_gap_scan_params_t. + * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported parameters supplied. See @ref ble_gap_scan_params_t. + * @retval ::NRF_ERROR_INVALID_LENGTH The provided buffer length is invalid. See @ref BLE_GAP_SCAN_BUFFER_MIN. + * @retval ::NRF_ERROR_RESOURCES Not enough BLE role slots available. + * Stop one or more currently active roles (Central, Peripheral or Broadcaster) and try again + */ +SVCALL(SD_BLE_GAP_SCAN_START, uint32_t, + sd_ble_gap_scan_start(ble_gap_scan_params_t const *p_scan_params, ble_data_t const *p_adv_report_buffer)); + +/**@brief Stop scanning (GAP Discovery procedure, Observer Procedure). + * + * @note The buffer provided in @ref sd_ble_gap_scan_start is released. + * + * @mscs + * @mmsc{@ref BLE_GAP_SCAN_MSC} + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully stopped scanning procedure. + * @retval ::NRF_ERROR_INVALID_STATE Not in the scanning state. + */ +SVCALL(SD_BLE_GAP_SCAN_STOP, uint32_t, sd_ble_gap_scan_stop(void)); + +/**@brief Create a connection (GAP Link Establishment). + * + * @note If a scanning procedure is currently in progress it will be automatically stopped when calling this function. + * The scanning procedure will be stopped even if the function returns an error. + * + * @events + * @event{@ref BLE_GAP_EVT_CONNECTED, A connection was established.} + * @event{@ref BLE_GAP_EVT_TIMEOUT, Failed to establish a connection.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} + * @endmscs + * + * @param[in] p_peer_addr Pointer to peer identity address. If @ref ble_gap_scan_params_t::filter_policy is set to use + * whitelist, then p_peer_addr is ignored. + * @param[in] p_scan_params Pointer to scan parameters structure. + * @param[in] p_conn_params Pointer to desired connection parameters. + * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or + * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. + * + * @retval ::NRF_SUCCESS Successfully initiated connection procedure. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid parameter(s) pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * - Invalid parameter(s) in p_scan_params or p_conn_params. + * - Use of whitelist requested but whitelist has not been set, see @ref + * sd_ble_gap_whitelist_set. + * - Peer address was not present in the device identity list, see @ref + * sd_ble_gap_device_identities_set. + * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. + * @retval ::NRF_ERROR_INVALID_STATE The SoftDevice is in an invalid state to perform this operation. This may be due to an + * existing locally initiated connect procedure, which must complete before initiating again. + * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid Peer address. + * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration tag has been reached. + * To increase the number of available connections, + * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. + * @retval ::NRF_ERROR_RESOURCES Either: + * - Not enough BLE role slots available. + * Stop one or more currently active roles (Central, Peripheral or Observer) and try again. + * - The event_length parameter associated with conn_cfg_tag is too small to be able to + * establish a connection on the selected @ref ble_gap_scan_params_t::scan_phys. + * Use @ref sd_ble_cfg_set to increase the event length. + */ +SVCALL(SD_BLE_GAP_CONNECT, uint32_t, + sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params, + ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag)); + +/**@brief Cancel a connection establishment. + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully canceled an ongoing connection procedure. + * @retval ::NRF_ERROR_INVALID_STATE No locally initiated connect procedure started or connection + * completed occurred. + */ +SVCALL(SD_BLE_GAP_CONNECT_CANCEL, uint32_t, sd_ble_gap_connect_cancel(void)); + +/**@brief Initiate or respond to a PHY Update Procedure + * + * @details This function is used to initiate or respond to a PHY Update Procedure. It will always + * generate a @ref BLE_GAP_EVT_PHY_UPDATE event if successfully executed. + * If this function is used to initiate a PHY Update procedure and the only option + * provided in @ref ble_gap_phys_t::tx_phys and @ref ble_gap_phys_t::rx_phys is the + * currently active PHYs in the respective directions, the SoftDevice will generate a + * @ref BLE_GAP_EVT_PHY_UPDATE with the current PHYs set and will not initiate the + * procedure in the Link Layer. + * + * If @ref ble_gap_phys_t::tx_phys or @ref ble_gap_phys_t::rx_phys is @ref BLE_GAP_PHY_AUTO, + * then the stack will select PHYs based on the peer's PHY preferences and the local link + * configuration. The PHY Update procedure will for this case result in a PHY combination + * that respects the time constraints configured with @ref sd_ble_cfg_set and the current + * link layer data length. + * + * When acting as a central, the SoftDevice will select the fastest common PHY in each direction. + * + * If the peer does not support the PHY Update Procedure, then the resulting + * @ref BLE_GAP_EVT_PHY_UPDATE event will have a status set to + * @ref BLE_HCI_UNSUPPORTED_REMOTE_FEATURE. + * + * If the PHY Update procedure was rejected by the peer due to a procedure collision, the status + * will be @ref BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION or + * @ref BLE_HCI_DIFFERENT_TRANSACTION_COLLISION. + * If the peer responds to the PHY Update procedure with invalid parameters, the status + * will be @ref BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS. + * If the PHY Update procedure was rejected by the peer for a different reason, the status will + * contain the reason as specified by the peer. + * + * @events + * @event{@ref BLE_GAP_EVT_PHY_UPDATE, Result of the PHY Update Procedure.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GAP_CENTRAL_PHY_UPDATE} + * @mmsc{@ref BLE_GAP_PERIPHERAL_PHY_UPDATE} + * @endmscs + * + * @param[in] conn_handle Connection handle to indicate the connection for which the PHY Update is requested. + * @param[in] p_gap_phys Pointer to PHY structure. + * + * @retval ::NRF_SUCCESS Successfully requested a PHY Update. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the combination of + * @ref ble_gap_phys_t::tx_phys, @ref ble_gap_phys_t::rx_phys, and @ref + * ble_gap_data_length_params_t. The connection event length is configured with @ref BLE_CONN_CFG_GAP using @ref sd_ble_cfg_set. + * @retval ::NRF_ERROR_BUSY Procedure is already in progress or not allowed at this time. Process pending events and wait for the + * pending procedure to complete and retry. + * + */ +SVCALL(SD_BLE_GAP_PHY_UPDATE, uint32_t, sd_ble_gap_phy_update(uint16_t conn_handle, ble_gap_phys_t const *p_gap_phys)); + +/**@brief Initiate or respond to a Data Length Update Procedure. + * + * @note If the application uses @ref BLE_GAP_DATA_LENGTH_AUTO for one or more members of + * p_dl_params, the SoftDevice will choose the highest value supported in current + * configuration and connection parameters. + * @note If the link PHY is Coded, the SoftDevice will ensure that the MaxTxTime and/or MaxRxTime + * used in the Data Length Update procedure is at least 2704 us. Otherwise, MaxTxTime and + * MaxRxTime will be limited to maximum 2120 us. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_dl_params Pointer to local parameters to be used in Data Length Update + * Procedure. Set any member to @ref BLE_GAP_DATA_LENGTH_AUTO to let + * the SoftDevice automatically decide the value for that member. + * Set to NULL to use automatic values for all members. + * @param[out] p_dl_limitation Pointer to limitation to be written when local device does not + * have enough resources or does not support the requested Data Length + * Update parameters. Ignored if NULL. + * + * @mscs + * @mmsc{@ref BLE_GAP_DATA_LENGTH_UPDATE_PROCEDURE_MSC} + * @endmscs + * + * @retval ::NRF_SUCCESS Successfully set Data Length Extension initiation/response parameters. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. + * @retval ::NRF_ERROR_INVALID_STATE No link has been established. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. + * @retval ::NRF_ERROR_NOT_SUPPORTED The requested parameters are not supported by the SoftDevice. Inspect + * p_dl_limitation to see which parameter is not supported. + * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the requested + * parameters. Use @ref sd_ble_cfg_set with @ref BLE_CONN_CFG_GAP to increase the connection event length. Inspect p_dl_limitation + * to see where the limitation is. + * @retval ::NRF_ERROR_BUSY Peer has already initiated a Data Length Update Procedure. Process the + * pending @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event to respond. + */ +SVCALL(SD_BLE_GAP_DATA_LENGTH_UPDATE, uint32_t, + sd_ble_gap_data_length_update(uint16_t conn_handle, ble_gap_data_length_params_t const *p_dl_params, + ble_gap_data_length_limitation_t *p_dl_limitation)); + +/**@brief Start the Quality of Service (QoS) channel survey module. + * + * @details The channel survey module provides measurements of the energy levels on + * the Bluetooth Low Energy channels. When the module is enabled, @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT + * events will periodically report the measured energy levels for each channel. + * + * @note The measurements are scheduled with lower priority than other Bluetooth Low Energy roles, + * Radio Timeslot API events and Flash API events. + * + * @note The channel survey module will attempt to do measurements so that the average interval + * between measurements will be interval_us. However due to the channel survey module + * having the lowest priority of all roles and modules, this may not be possible. In that + * case fewer than expected channel survey reports may be given. + * + * @note In order to use the channel survey module, @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available + * must be set. This is done using @ref sd_ble_cfg_set. + * + * @param[in] interval_us Requested average interval for the measurements and reports. See + * @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS for valid ranges. If set + * to @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS, the channel + * survey role will be scheduled at every available opportunity. + * + * @retval ::NRF_SUCCESS The module is successfully started. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. interval_us is out of the + * allowed range. + * @retval ::NRF_ERROR_INVALID_STATE Trying to start the module when already running. + * @retval ::NRF_ERROR_RESOURCES The channel survey module is not available to the application. + * Set @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available using + * @ref sd_ble_cfg_set. + */ +SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_START, uint32_t, sd_ble_gap_qos_channel_survey_start(uint32_t interval_us)); + +/**@brief Stop the Quality of Service (QoS) channel survey module. + * + * @note The SoftDevice may generate one @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT event after this + * function is called. + * + * @retval ::NRF_SUCCESS The module is successfully stopped. + * @retval ::NRF_ERROR_INVALID_STATE Trying to stop the module when it is not running. + */ +SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP, uint32_t, sd_ble_gap_qos_channel_survey_stop(void)); + +/**@brief Obtain the next connection event counter value. + * + * @details The connection event counter is initialized to zero on the first connection event. The value is incremented + * by one for each connection event. For more information see Bluetooth Core Specification v5.0, Vol 6, Part B, + * Section 4.5.1. + * + * @note The connection event counter obtained through this API will be outdated if this API is called + * at the same time as the connection event counter is incremented. + * + * @note This API will always return the last connection event counter + 1. + * The actual connection event may be multiple connection events later if: + * - Slave latency is enabled and there is no data to transmit or receive. + * - Another role is scheduled with a higher priority at the same time as the next connection event. + * + * @param[in] conn_handle Connection handle. + * @param[out] p_counter Pointer to the variable where the next connection event counter will be written. + * + * @retval ::NRF_SUCCESS The connection event counter was successfully retrieved. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET, uint32_t, + sd_ble_gap_next_conn_evt_counter_get(uint16_t conn_handle, uint16_t *p_counter)); + +/**@brief Start triggering a given task on connection event start. + * + * @details When enabled, this feature will trigger a PPI task at the start of connection events. + * The application can configure the SoftDevice to trigger every N connection events starting from + * a given connection event counter. See also @ref ble_gap_conn_event_trigger_t. + * + * @param[in] conn_handle Connection handle. + * @param[in] p_params Connection event trigger parameters. + * + * @retval ::NRF_SUCCESS Success. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. See @ref ble_gap_conn_event_trigger_t. + * @retval ::NRF_ERROR_INVALID_STATE Either: + * - Trying to start connection event triggering when it is already ongoing. + * - @ref ble_gap_conn_event_trigger_t::conn_evt_counter_start is in the past. + * Use @ref sd_ble_gap_next_conn_evt_counter_get to find a new value + to be used as ble_gap_conn_event_trigger_t::conn_evt_counter_start. + */ +SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_START, uint32_t, + sd_ble_gap_conn_evt_trigger_start(uint16_t conn_handle, ble_gap_conn_event_trigger_t const *p_params)); + +/**@brief Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. + * + * @param[in] conn_handle Connection handle. + * + * @retval ::NRF_SUCCESS Success. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. + * @retval ::NRF_ERROR_INVALID_STATE Trying to stop connection event triggering when it is not enabled. + */ +SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_STOP, uint32_t, sd_ble_gap_conn_evt_trigger_stop(uint16_t conn_handle)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GAP_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gatt.h b/variants/wio-tracker-wm1110/softdevice/ble_gatt.h new file mode 100644 index 0000000000..df0d728fc8 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_gatt.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATT Generic Attribute Profile (GATT) Common + @{ + @brief Common definitions and prototypes for the GATT interfaces. + */ + +#ifndef BLE_GATT_H__ +#define BLE_GATT_H__ + +#include "ble_err.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATT_DEFINES Defines + * @{ */ + +/** @brief Default ATT MTU, in bytes. */ +#define BLE_GATT_ATT_MTU_DEFAULT 23 + +/**@brief Invalid Attribute Handle. */ +#define BLE_GATT_HANDLE_INVALID 0x0000 + +/**@brief First Attribute Handle. */ +#define BLE_GATT_HANDLE_START 0x0001 + +/**@brief Last Attribute Handle. */ +#define BLE_GATT_HANDLE_END 0xFFFF + +/** @defgroup BLE_GATT_TIMEOUT_SOURCES GATT Timeout sources + * @{ */ +#define BLE_GATT_TIMEOUT_SRC_PROTOCOL 0x00 /**< ATT Protocol timeout. */ +/** @} */ + +/** @defgroup BLE_GATT_WRITE_OPS GATT Write operations + * @{ */ +#define BLE_GATT_OP_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATT_OP_WRITE_REQ 0x01 /**< Write Request. */ +#define BLE_GATT_OP_WRITE_CMD 0x02 /**< Write Command. */ +#define BLE_GATT_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ +#define BLE_GATT_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ +#define BLE_GATT_OP_EXEC_WRITE_REQ 0x05 /**< Execute Write Request. */ +/** @} */ + +/** @defgroup BLE_GATT_EXEC_WRITE_FLAGS GATT Execute Write flags + * @{ */ +#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL 0x00 /**< Cancel prepared write. */ +#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE 0x01 /**< Execute prepared write. */ +/** @} */ + +/** @defgroup BLE_GATT_HVX_TYPES GATT Handle Value operations + * @{ */ +#define BLE_GATT_HVX_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATT_HVX_NOTIFICATION 0x01 /**< Handle Value Notification. */ +#define BLE_GATT_HVX_INDICATION 0x02 /**< Handle Value Indication. */ +/** @} */ + +/** @defgroup BLE_GATT_STATUS_CODES GATT Status Codes + * @{ */ +#define BLE_GATT_STATUS_SUCCESS 0x0000 /**< Success. */ +#define BLE_GATT_STATUS_UNKNOWN 0x0001 /**< Unknown or not applicable status. */ +#define BLE_GATT_STATUS_ATTERR_INVALID 0x0100 /**< ATT Error: Invalid Error Code. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_HANDLE 0x0101 /**< ATT Error: Invalid Attribute Handle. */ +#define BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED 0x0102 /**< ATT Error: Read not permitted. */ +#define BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED 0x0103 /**< ATT Error: Write not permitted. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_PDU 0x0104 /**< ATT Error: Used in ATT as Invalid PDU. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION 0x0105 /**< ATT Error: Authenticated link required. */ +#define BLE_GATT_STATUS_ATTERR_REQUEST_NOT_SUPPORTED 0x0106 /**< ATT Error: Used in ATT as Request Not Supported. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_OFFSET 0x0107 /**< ATT Error: Offset specified was past the end of the attribute. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION 0x0108 /**< ATT Error: Used in ATT as Insufficient Authorization. */ +#define BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL 0x0109 /**< ATT Error: Used in ATT as Prepare Queue Full. */ +#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND 0x010A /**< ATT Error: Used in ATT as Attribute not found. */ +#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_LONG \ + 0x010B /**< ATT Error: Attribute cannot be read or written using read/write blob requests. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_ENC_KEY_SIZE 0x010C /**< ATT Error: Encryption key size used is insufficient. */ +#define BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH 0x010D /**< ATT Error: Invalid value size. */ +#define BLE_GATT_STATUS_ATTERR_UNLIKELY_ERROR 0x010E /**< ATT Error: Very unlikely error. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION 0x010F /**< ATT Error: Encrypted link required. */ +#define BLE_GATT_STATUS_ATTERR_UNSUPPORTED_GROUP_TYPE \ + 0x0110 /**< ATT Error: Attribute type is not a supported grouping attribute. */ +#define BLE_GATT_STATUS_ATTERR_INSUF_RESOURCES 0x0111 /**< ATT Error: Insufficient resources. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_BEGIN 0x0112 /**< ATT Error: Reserved for Future Use range #1 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_END 0x017F /**< ATT Error: Reserved for Future Use range #1 end. */ +#define BLE_GATT_STATUS_ATTERR_APP_BEGIN 0x0180 /**< ATT Error: Application range begin. */ +#define BLE_GATT_STATUS_ATTERR_APP_END 0x019F /**< ATT Error: Application range end. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_BEGIN 0x01A0 /**< ATT Error: Reserved for Future Use range #2 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_END 0x01DF /**< ATT Error: Reserved for Future Use range #2 end. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_BEGIN 0x01E0 /**< ATT Error: Reserved for Future Use range #3 begin. */ +#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_END 0x01FC /**< ATT Error: Reserved for Future Use range #3 end. */ +#define BLE_GATT_STATUS_ATTERR_CPS_WRITE_REQ_REJECTED \ + 0x01FC /**< ATT Common Profile and Service Error: Write request rejected. \ + */ +#define BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR \ + 0x01FD /**< ATT Common Profile and Service Error: Client Characteristic Configuration Descriptor improperly configured. */ +#define BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG \ + 0x01FE /**< ATT Common Profile and Service Error: Procedure Already in Progress. */ +#define BLE_GATT_STATUS_ATTERR_CPS_OUT_OF_RANGE 0x01FF /**< ATT Common Profile and Service Error: Out Of Range. */ +/** @} */ + +/** @defgroup BLE_GATT_CPF_FORMATS Characteristic Presentation Formats + * @note Found at + * http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml + * @{ */ +#define BLE_GATT_CPF_FORMAT_RFU 0x00 /**< Reserved For Future Use. */ +#define BLE_GATT_CPF_FORMAT_BOOLEAN 0x01 /**< Boolean. */ +#define BLE_GATT_CPF_FORMAT_2BIT 0x02 /**< Unsigned 2-bit integer. */ +#define BLE_GATT_CPF_FORMAT_NIBBLE 0x03 /**< Unsigned 4-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT8 0x04 /**< Unsigned 8-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT12 0x05 /**< Unsigned 12-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT16 0x06 /**< Unsigned 16-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT24 0x07 /**< Unsigned 24-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT32 0x08 /**< Unsigned 32-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT48 0x09 /**< Unsigned 48-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT64 0x0A /**< Unsigned 64-bit integer. */ +#define BLE_GATT_CPF_FORMAT_UINT128 0x0B /**< Unsigned 128-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT8 0x0C /**< Signed 2-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT12 0x0D /**< Signed 12-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT16 0x0E /**< Signed 16-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT24 0x0F /**< Signed 24-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT32 0x10 /**< Signed 32-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT48 0x11 /**< Signed 48-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT64 0x12 /**< Signed 64-bit integer. */ +#define BLE_GATT_CPF_FORMAT_SINT128 0x13 /**< Signed 128-bit integer. */ +#define BLE_GATT_CPF_FORMAT_FLOAT32 0x14 /**< IEEE-754 32-bit floating point. */ +#define BLE_GATT_CPF_FORMAT_FLOAT64 0x15 /**< IEEE-754 64-bit floating point. */ +#define BLE_GATT_CPF_FORMAT_SFLOAT 0x16 /**< IEEE-11073 16-bit SFLOAT. */ +#define BLE_GATT_CPF_FORMAT_FLOAT 0x17 /**< IEEE-11073 32-bit FLOAT. */ +#define BLE_GATT_CPF_FORMAT_DUINT16 0x18 /**< IEEE-20601 format. */ +#define BLE_GATT_CPF_FORMAT_UTF8S 0x19 /**< UTF-8 string. */ +#define BLE_GATT_CPF_FORMAT_UTF16S 0x1A /**< UTF-16 string. */ +#define BLE_GATT_CPF_FORMAT_STRUCT 0x1B /**< Opaque Structure. */ +/** @} */ + +/** @defgroup BLE_GATT_CPF_NAMESPACES GATT Bluetooth Namespaces + * @{ + */ +#define BLE_GATT_CPF_NAMESPACE_BTSIG 0x01 /**< Bluetooth SIG defined Namespace. */ +#define BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN 0x0000 /**< Namespace Description Unknown. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATT_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATT connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_PARAM att_mtu is smaller than @ref BLE_GATT_ATT_MTU_DEFAULT. + */ +typedef struct { + uint16_t att_mtu; /**< Maximum size of ATT packet the SoftDevice can send or receive. + The default and minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + @mscs + @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} + @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} + @endmscs + */ +} ble_gatt_conn_cfg_t; + +/**@brief GATT Characteristic Properties. */ +typedef struct { + /* Standard properties */ + uint8_t broadcast : 1; /**< Broadcasting of the value permitted. */ + uint8_t read : 1; /**< Reading the value permitted. */ + uint8_t write_wo_resp : 1; /**< Writing the value with Write Command permitted. */ + uint8_t write : 1; /**< Writing the value with Write Request permitted. */ + uint8_t notify : 1; /**< Notification of the value permitted. */ + uint8_t indicate : 1; /**< Indications of the value permitted. */ + uint8_t auth_signed_wr : 1; /**< Writing the value with Signed Write Command permitted. */ +} ble_gatt_char_props_t; + +/**@brief GATT Characteristic Extended Properties. */ +typedef struct { + /* Extended properties */ + uint8_t reliable_wr : 1; /**< Writing the value with Queued Write operations permitted. */ + uint8_t wr_aux : 1; /**< Writing the Characteristic User Description descriptor permitted. */ +} ble_gatt_char_ext_props_t; + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GATT_H__ + +/** @} */ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gattc.h b/variants/wio-tracker-wm1110/softdevice/ble_gattc.h new file mode 100644 index 0000000000..f1df1782ca --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_gattc.h @@ -0,0 +1,764 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATTC Generic Attribute Profile (GATT) Client + @{ + @brief Definitions and prototypes for the GATT Client interface. + */ + +#ifndef BLE_GATTC_H__ +#define BLE_GATTC_H__ + +#include "ble_err.h" +#include "ble_gatt.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATTC_ENUMERATIONS Enumerations + * @{ */ + +/**@brief GATTC API SVC numbers. */ +enum BLE_GATTC_SVCS { + SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER = BLE_GATTC_SVC_BASE, /**< Primary Service Discovery. */ + SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, /**< Relationship Discovery. */ + SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, /**< Characteristic Discovery. */ + SD_BLE_GATTC_DESCRIPTORS_DISCOVER, /**< Characteristic Descriptor Discovery. */ + SD_BLE_GATTC_ATTR_INFO_DISCOVER, /**< Attribute Information Discovery. */ + SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, /**< Read Characteristic Value by UUID. */ + SD_BLE_GATTC_READ, /**< Generic read. */ + SD_BLE_GATTC_CHAR_VALUES_READ, /**< Read multiple Characteristic Values. */ + SD_BLE_GATTC_WRITE, /**< Generic write. */ + SD_BLE_GATTC_HV_CONFIRM, /**< Handle Value Confirmation. */ + SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. */ +}; + +/** + * @brief GATT Client Event IDs. + */ +enum BLE_GATTC_EVTS { + BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP = BLE_GATTC_EVT_BASE, /**< Primary Service Discovery Response event. \n See @ref + ble_gattc_evt_prim_srvc_disc_rsp_t. */ + BLE_GATTC_EVT_REL_DISC_RSP, /**< Relationship Discovery Response event. \n See @ref ble_gattc_evt_rel_disc_rsp_t. + */ + BLE_GATTC_EVT_CHAR_DISC_RSP, /**< Characteristic Discovery Response event. \n See @ref + ble_gattc_evt_char_disc_rsp_t. */ + BLE_GATTC_EVT_DESC_DISC_RSP, /**< Descriptor Discovery Response event. \n See @ref + ble_gattc_evt_desc_disc_rsp_t. */ + BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, /**< Attribute Information Response event. \n See @ref + ble_gattc_evt_attr_info_disc_rsp_t. */ + BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP, /**< Read By UUID Response event. \n See @ref + ble_gattc_evt_char_val_by_uuid_read_rsp_t. */ + BLE_GATTC_EVT_READ_RSP, /**< Read Response event. \n See @ref ble_gattc_evt_read_rsp_t. */ + BLE_GATTC_EVT_CHAR_VALS_READ_RSP, /**< Read multiple Response event. \n See @ref + ble_gattc_evt_char_vals_read_rsp_t. */ + BLE_GATTC_EVT_WRITE_RSP, /**< Write Response event. \n See @ref ble_gattc_evt_write_rsp_t. */ + BLE_GATTC_EVT_HVX, /**< Handle Value Notification or Indication event. \n Confirm indication with @ref + sd_ble_gattc_hv_confirm. \n See @ref ble_gattc_evt_hvx_t. */ + BLE_GATTC_EVT_EXCHANGE_MTU_RSP, /**< Exchange MTU Response event. \n See @ref + ble_gattc_evt_exchange_mtu_rsp_t. */ + BLE_GATTC_EVT_TIMEOUT, /**< Timeout event. \n See @ref ble_gattc_evt_timeout_t. */ + BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE /**< Write without Response transmission complete. \n See @ref + ble_gattc_evt_write_cmd_tx_complete_t. */ +}; + +/**@brief GATTC Option IDs. + * IDs that uniquely identify a GATTC option. + */ +enum BLE_GATTC_OPTS { + BLE_GATTC_OPT_UUID_DISC = BLE_GATTC_OPT_BASE, /**< UUID discovery. @ref ble_gattc_opt_uuid_disc_t */ +}; + +/** @} */ + +/** @addtogroup BLE_GATTC_DEFINES Defines + * @{ */ + +/** @defgroup BLE_ERRORS_GATTC SVC return values specific to GATTC + * @{ */ +#define BLE_ERROR_GATTC_PROC_NOT_PERMITTED (NRF_GATTC_ERR_BASE + 0x000) /**< Procedure not Permitted. */ +/** @} */ + +/** @defgroup BLE_GATTC_ATTR_INFO_FORMAT Attribute Information Formats + * @{ */ +#define BLE_GATTC_ATTR_INFO_FORMAT_16BIT 1 /**< 16-bit Attribute Information Format. */ +#define BLE_GATTC_ATTR_INFO_FORMAT_128BIT 2 /**< 128-bit Attribute Information Format. */ +/** @} */ + +/** @defgroup BLE_GATTC_DEFAULTS GATT Client defaults + * @{ */ +#define BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT \ + 1 /**< Default number of Write without Response that can be queued for transmission. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATTC_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATTC connection configuration parameters, set with @ref sd_ble_cfg_set. + */ +typedef struct { + uint8_t write_cmd_tx_queue_size; /**< The guaranteed minimum number of Write without Response that can be queued for + transmission. The default value is @ref BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT */ +} ble_gattc_conn_cfg_t; + +/**@brief Operation Handle Range. */ +typedef struct { + uint16_t start_handle; /**< Start Handle. */ + uint16_t end_handle; /**< End Handle. */ +} ble_gattc_handle_range_t; + +/**@brief GATT service. */ +typedef struct { + ble_uuid_t uuid; /**< Service UUID. */ + ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */ +} ble_gattc_service_t; + +/**@brief GATT include. */ +typedef struct { + uint16_t handle; /**< Include Handle. */ + ble_gattc_service_t included_srvc; /**< Handle of the included service. */ +} ble_gattc_include_t; + +/**@brief GATT characteristic. */ +typedef struct { + ble_uuid_t uuid; /**< Characteristic UUID. */ + ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ + uint8_t char_ext_props : 1; /**< Extended properties present. */ + uint16_t handle_decl; /**< Handle of the Characteristic Declaration. */ + uint16_t handle_value; /**< Handle of the Characteristic Value. */ +} ble_gattc_char_t; + +/**@brief GATT descriptor. */ +typedef struct { + uint16_t handle; /**< Descriptor Handle. */ + ble_uuid_t uuid; /**< Descriptor UUID. */ +} ble_gattc_desc_t; + +/**@brief Write Parameters. */ +typedef struct { + uint8_t write_op; /**< Write Operation to be performed, see @ref BLE_GATT_WRITE_OPS. */ + uint8_t flags; /**< Flags, see @ref BLE_GATT_EXEC_WRITE_FLAGS. */ + uint16_t handle; /**< Handle to the attribute to be written. */ + uint16_t offset; /**< Offset in bytes. @note For WRITE_CMD and WRITE_REQ, offset must be 0. */ + uint16_t len; /**< Length of data in bytes. */ + uint8_t const *p_value; /**< Pointer to the value data. */ +} ble_gattc_write_params_t; + +/**@brief Attribute Information for 16-bit Attribute UUID. */ +typedef struct { + uint16_t handle; /**< Attribute handle. */ + ble_uuid_t uuid; /**< 16-bit Attribute UUID. */ +} ble_gattc_attr_info16_t; + +/**@brief Attribute Information for 128-bit Attribute UUID. */ +typedef struct { + uint16_t handle; /**< Attribute handle. */ + ble_uuid128_t uuid; /**< 128-bit Attribute UUID. */ +} ble_gattc_attr_info128_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Service count. */ + ble_gattc_service_t services[1]; /**< Service data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use + event structures with variable length array members. */ +} ble_gattc_evt_prim_srvc_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_REL_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Include count. */ + ble_gattc_include_t includes[1]; /**< Include data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use + event structures with variable length array members. */ +} ble_gattc_evt_rel_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Characteristic count. */ + ble_gattc_char_t chars[1]; /**< Characteristic data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event + structures with variable length array members. */ +} ble_gattc_evt_char_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_DESC_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Descriptor count. */ + ble_gattc_desc_t descs[1]; /**< Descriptor data. @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event + structures with variable length array members. */ +} ble_gattc_evt_desc_disc_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP. */ +typedef struct { + uint16_t count; /**< Attribute count. */ + uint8_t format; /**< Attribute information format, see @ref BLE_GATTC_ATTR_INFO_FORMAT. */ + union { + ble_gattc_attr_info16_t attr_info16[1]; /**< Attribute information for 16-bit Attribute UUID. + @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on + how to use event structures with variable length array members. */ + ble_gattc_attr_info128_t attr_info128[1]; /**< Attribute information for 128-bit Attribute UUID. + @note This is a variable length array. The size of 1 indicated is only a + placeholder for compilation. See @ref sd_ble_evt_get for more information on + how to use event structures with variable length array members. */ + } info; /**< Attribute information union. */ +} ble_gattc_evt_attr_info_disc_rsp_t; + +/**@brief GATT read by UUID handle value pair. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint8_t *p_value; /**< Pointer to the Attribute Value, length is available in @ref + ble_gattc_evt_char_val_by_uuid_read_rsp_t::value_len. */ +} ble_gattc_handle_value_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP. */ +typedef struct { + uint16_t count; /**< Handle-Value Pair Count. */ + uint16_t value_len; /**< Length of the value in Handle-Value(s) list. */ + uint8_t handle_value[1]; /**< Handle-Value(s) list. To iterate through the list use @ref + sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter. + @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with + variable length array members. */ +} ble_gattc_evt_char_val_by_uuid_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_READ_RSP. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint16_t offset; /**< Offset of the attribute data. */ + uint16_t len; /**< Attribute data length. */ + uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP. */ +typedef struct { + uint16_t len; /**< Concatenated Attribute values length. */ + uint8_t values[1]; /**< Attribute values. @note This is a variable length array. The size of 1 indicated is only a placeholder + for compilation. See @ref sd_ble_evt_get for more information on how to use event structures with + variable length array members. */ +} ble_gattc_evt_char_vals_read_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_RSP. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + uint8_t write_op; /**< Type of write operation, see @ref BLE_GATT_WRITE_OPS. */ + uint16_t offset; /**< Data offset. */ + uint16_t len; /**< Data length. */ + uint8_t data[1]; /**< Data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_write_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_HVX. */ +typedef struct { + uint16_t handle; /**< Handle to which the HVx operation applies. */ + uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ + uint16_t len; /**< Attribute data length. */ + uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gattc_evt_hvx_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. */ +typedef struct { + uint16_t server_rx_mtu; /**< Server RX MTU size. */ +} ble_gattc_evt_exchange_mtu_rsp_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ +} ble_gattc_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE. */ +typedef struct { + uint8_t count; /**< Number of write without response transmissions completed. */ +} ble_gattc_evt_write_cmd_tx_complete_t; + +/**@brief GATTC event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which event occurred. */ + uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ + uint16_t + error_handle; /**< In case of error: The handle causing the error. In all other cases @ref BLE_GATT_HANDLE_INVALID. */ + union { + ble_gattc_evt_prim_srvc_disc_rsp_t prim_srvc_disc_rsp; /**< Primary Service Discovery Response Event Parameters. */ + ble_gattc_evt_rel_disc_rsp_t rel_disc_rsp; /**< Relationship Discovery Response Event Parameters. */ + ble_gattc_evt_char_disc_rsp_t char_disc_rsp; /**< Characteristic Discovery Response Event Parameters. */ + ble_gattc_evt_desc_disc_rsp_t desc_disc_rsp; /**< Descriptor Discovery Response Event Parameters. */ + ble_gattc_evt_char_val_by_uuid_read_rsp_t + char_val_by_uuid_read_rsp; /**< Characteristic Value Read by UUID Response Event Parameters. */ + ble_gattc_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. */ + ble_gattc_evt_char_vals_read_rsp_t char_vals_read_rsp; /**< Characteristic Values Read Response Event Parameters. */ + ble_gattc_evt_write_rsp_t write_rsp; /**< Write Response Event Parameters. */ + ble_gattc_evt_hvx_t hvx; /**< Handle Value Notification/Indication Event Parameters. */ + ble_gattc_evt_exchange_mtu_rsp_t exchange_mtu_rsp; /**< Exchange MTU Response Event Parameters. */ + ble_gattc_evt_timeout_t timeout; /**< Timeout Event Parameters. */ + ble_gattc_evt_attr_info_disc_rsp_t attr_info_disc_rsp; /**< Attribute Information Discovery Event Parameters. */ + ble_gattc_evt_write_cmd_tx_complete_t + write_cmd_tx_complete; /**< Write without Response transmission complete Event Parameters. */ + } params; /**< Event Parameters. @note Only valid if @ref gatt_status == @ref BLE_GATT_STATUS_SUCCESS. */ +} ble_gattc_evt_t; + +/**@brief UUID discovery option. + * + * @details Used with @ref sd_ble_opt_set to enable and disable automatic insertion of discovered 128-bit UUIDs to the + * Vendor Specific UUID table. Disabled by default. + * - When disabled, if a procedure initiated by + * @ref sd_ble_gattc_primary_services_discover, + * @ref sd_ble_gattc_relationships_discover, + * @ref sd_ble_gattc_characteristics_discover, + * @ref sd_ble_gattc_descriptors_discover + * finds a 128-bit UUID which was not added by @ref sd_ble_uuid_vs_add, @ref ble_uuid_t::type will be set + * to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. + * - When enabled, all found 128-bit UUIDs will be automatically added. The application can use + * @ref sd_ble_uuid_encode to retrieve the 128-bit UUID from @ref ble_uuid_t received in the corresponding + * event. If the total number of Vendor Specific UUIDs exceeds the table capacity, @ref ble_uuid_t::type will + * be set to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. + * See also @ref ble_common_cfg_vs_uuid_t, @ref sd_ble_uuid_vs_remove. + * + * @note @ref sd_ble_opt_get is not supported for this option. + * + * @retval ::NRF_SUCCESS Set successfully. + * + */ +typedef struct { + uint8_t auto_add_vs_enable : 1; /**< Set to 1 to enable (or 0 to disable) automatic insertion of discovered 128-bit UUIDs. */ +} ble_gattc_opt_uuid_disc_t; + +/**@brief Option structure for GATTC options. */ +typedef union { + ble_gattc_opt_uuid_disc_t uuid_disc; /**< Parameters for the UUID discovery option. */ +} ble_gattc_opt_t; + +/** @} */ + +/** @addtogroup BLE_GATTC_FUNCTIONS Functions + * @{ */ + +/**@brief Initiate or continue a GATT Primary Service Discovery procedure. + * + * @details This function initiates or resumes a Primary Service discovery procedure, starting from the supplied handle. + * If the last service has not been reached, this function must be called again with an updated start handle value to + * continue the search. See also @ref ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_PRIM_SRVC_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] start_handle Handle to start searching from. + * @param[in] p_srvc_uuid Pointer to the service UUID to be found. If it is NULL, all primary services will be returned. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Primary Service Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER, uint32_t, + sd_ble_gattc_primary_services_discover(uint16_t conn_handle, uint16_t start_handle, ble_uuid_t const *p_srvc_uuid)); + +/**@brief Initiate or continue a GATT Relationship Discovery procedure. + * + * @details This function initiates or resumes the Find Included Services sub-procedure. If the last included service has not been + * reached, this must be called again with an updated handle range to continue the search. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_REL_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_REL_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Relationship Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, uint32_t, + sd_ble_gattc_relationships_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Characteristic Discovery procedure. + * + * @details This function initiates or resumes a Characteristic discovery procedure. If the last Characteristic has not been + * reached, this must be called again with an updated handle range to continue the discovery. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_CHAR_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Characteristic Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, uint32_t, + sd_ble_gattc_characteristics_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Characteristic Descriptor Discovery procedure. + * + * @details This function initiates or resumes a Characteristic Descriptor discovery procedure. If the last Descriptor has not + * been reached, this must be called again with an updated handle range to continue the discovery. See also @ref + * ble_gattc_opt_uuid_disc_t. + * + * @events + * @event{@ref BLE_GATTC_EVT_DESC_DISC_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_DESC_DISC_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range A pointer to the range of handles of the Characteristic to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Descriptor Discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t, + sd_ble_gattc_descriptors_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Read using Characteristic UUID procedure. + * + * @details This function initiates or resumes a Read using Characteristic UUID procedure. If the last Characteristic has not been + * reached, this must be called again with an updated handle range to continue the discovery. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_READ_UUID_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_uuid Pointer to a Characteristic value UUID to read. + * @param[in] p_handle_range A pointer to the range of handles to perform this procedure on. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Read using Characteristic UUID procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, uint32_t, + sd_ble_gattc_char_value_by_uuid_read(uint16_t conn_handle, ble_uuid_t const *p_uuid, + ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Initiate or continue a GATT Read (Long) Characteristic or Descriptor procedure. + * + * @details This function initiates or resumes a GATT Read (Long) Characteristic or Descriptor procedure. If the Characteristic or + * Descriptor to be read is longer than ATT_MTU - 1, this function must be called multiple times with appropriate offset to read + * the complete value. + * + * @events + * @event{@ref BLE_GATTC_EVT_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_VALUE_READ_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] handle The handle of the attribute to be read. + * @param[in] offset Offset into the attribute value to be read. + * + * @retval ::NRF_SUCCESS Successfully started or resumed the Read (Long) procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_READ, uint32_t, sd_ble_gattc_read(uint16_t conn_handle, uint16_t handle, uint16_t offset)); + +/**@brief Initiate a GATT Read Multiple Characteristic Values procedure. + * + * @details This function initiates a GATT Read Multiple Characteristic Values procedure. + * + * @events + * @event{@ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_READ_MULT_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handles A pointer to the handle(s) of the attribute(s) to be read. + * @param[in] handle_count The number of handles in p_handles. + * + * @retval ::NRF_SUCCESS Successfully started the Read Multiple Characteristic Values procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t, + sd_ble_gattc_char_values_read(uint16_t conn_handle, uint16_t const *p_handles, uint16_t handle_count)); + +/**@brief Perform a Write (Characteristic Value or Descriptor, with or without response, signed or not, long or reliable) + * procedure. + * + * @details This function can perform all write procedures described in GATT. + * + * @note Only one write with response procedure can be ongoing per connection at a time. + * If the application tries to write with response while another write with response procedure is ongoing, + * the function call will return @ref NRF_ERROR_BUSY. + * A @ref BLE_GATTC_EVT_WRITE_RSP event will be issued as soon as the write response arrives from the peer. + * + * @note The number of Write without Response that can be queued is configured by @ref + * ble_gattc_conn_cfg_t::write_cmd_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. + * A @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event will be issued as soon as the transmission of the write without + * response is complete. + * + * @note The application can keep track of the available queue element count for writes without responses by following the + * procedure below: + * - Store initial queue element count in a variable. + * - Decrement the variable, which stores the currently available queue element count, by one when a call to this + * function returns @ref NRF_SUCCESS. + * - Increment the variable, which stores the current available queue element count, by the count variable in @ref + * BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event. + * + * @events + * @event{@ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE, Write without response transmission complete.} + * @event{@ref BLE_GATTC_EVT_WRITE_RSP, Write response received from the peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_VALUE_WRITE_WITHOUT_RESP_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_WRITE_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_LONG_WRITE_MSC} + * @mmsc{@ref BLE_GATTC_VALUE_RELIABLE_WRITE_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_write_params A pointer to a write parameters structure. + * + * @retval ::NRF_SUCCESS Successfully started the Write procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_BUSY For write with response, procedure already in progress. Wait for a @ref BLE_GATTC_EVT_WRITE_RSP event + * and retry. + * @retval ::NRF_ERROR_RESOURCES Too many writes without responses queued. + * Wait for a @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event and retry. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_WRITE, uint32_t, sd_ble_gattc_write(uint16_t conn_handle, ble_gattc_write_params_t const *p_write_params)); + +/**@brief Send a Handle Value Confirmation to the GATT Server. + * + * @mscs + * @mmsc{@ref BLE_GATTC_HVI_MSC} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] handle The handle of the attribute in the indication. + * + * @retval ::NRF_SUCCESS Successfully queued the Handle Value Confirmation for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no Indication pending to be confirmed. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_HV_CONFIRM, uint32_t, sd_ble_gattc_hv_confirm(uint16_t conn_handle, uint16_t handle)); + +/**@brief Discovers information about a range of attributes on a GATT server. + * + * @events + * @event{@ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, Generated when information about a range of attributes has been received.} + * @endevents + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] p_handle_range The range of handles to request information about. + * + * @retval ::NRF_SUCCESS Successfully started an attribute information discovery procedure. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t, + sd_ble_gattc_attr_info_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); + +/**@brief Start an ATT_MTU exchange by sending an Exchange MTU Request to the server. + * + * @details The SoftDevice sets ATT_MTU to the minimum of: + * - The Client RX MTU value, and + * - The Server RX MTU value from @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. + * + * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. + * + * @events + * @event{@ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] client_rx_mtu Client RX MTU size. + * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration + used for this connection. + * - The value must be equal to Server RX MTU size given in @ref sd_ble_gatts_exchange_mtu_reply + * if an ATT_MTU exchange has already been performed in the other direction. + * + * @retval ::NRF_SUCCESS Successfully sent request to the server. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state or an ATT_MTU exchange was already requested once. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid Client RX MTU size supplied. + * @retval ::NRF_ERROR_BUSY Client procedure already in progress. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + reestablishing the connection. + */ +SVCALL(SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, uint32_t, + sd_ble_gattc_exchange_mtu_request(uint16_t conn_handle, uint16_t client_rx_mtu)); + +/**@brief Iterate through Handle-Value(s) list in @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. + * + * @param[in] p_gattc_evt Pointer to event buffer containing @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. + * @note If the buffer contains different event, behavior is undefined. + * @param[in,out] p_iter Iterator, points to @ref ble_gattc_handle_value_t structure that will be filled in with + * the next Handle-Value pair in each iteration. If the function returns other than + * @ref NRF_SUCCESS, it will not be changed. + * - To start iteration, initialize the structure to zero. + * - To continue, pass the value from previous iteration. + * + * \code + * ble_gattc_handle_value_t iter; + * memset(&iter, 0, sizeof(ble_gattc_handle_value_t)); + * while (sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(&ble_evt.evt.gattc_evt, &iter) == NRF_SUCCESS) + * { + * app_handle = iter.handle; + * memcpy(app_value, iter.p_value, ble_evt.evt.gattc_evt.params.char_val_by_uuid_read_rsp.value_len); + * } + * \endcode + * + * @retval ::NRF_SUCCESS Successfully retrieved the next Handle-Value pair. + * @retval ::NRF_ERROR_NOT_FOUND No more Handle-Value pairs available in the list. + */ +__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, + ble_gattc_handle_value_t *p_iter); + +/** @} */ + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION + +__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, + ble_gattc_handle_value_t *p_iter) +{ + uint32_t value_len = p_gattc_evt->params.char_val_by_uuid_read_rsp.value_len; + uint8_t *p_first = p_gattc_evt->params.char_val_by_uuid_read_rsp.handle_value; + uint8_t *p_next = p_iter->p_value ? p_iter->p_value + value_len : p_first; + + if ((p_next - p_first) / (sizeof(uint16_t) + value_len) < p_gattc_evt->params.char_val_by_uuid_read_rsp.count) { + p_iter->handle = (uint16_t)p_next[1] << 8 | p_next[0]; + p_iter->p_value = p_next + sizeof(uint16_t); + return NRF_SUCCESS; + } else { + return NRF_ERROR_NOT_FOUND; + } +} + +#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ + +#ifdef __cplusplus +} +#endif +#endif /* BLE_GATTC_H__ */ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gatts.h b/variants/wio-tracker-wm1110/softdevice/ble_gatts.h new file mode 100644 index 0000000000..dc94957cd1 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_gatts.h @@ -0,0 +1,904 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_GATTS Generic Attribute Profile (GATT) Server + @{ + @brief Definitions and prototypes for the GATTS interface. + */ + +#ifndef BLE_GATTS_H__ +#define BLE_GATTS_H__ + +#include "ble_err.h" +#include "ble_gap.h" +#include "ble_gatt.h" +#include "ble_hci.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_GATTS_ENUMERATIONS Enumerations + * @{ */ + +/** + * @brief GATTS API SVC numbers. + */ +enum BLE_GATTS_SVCS { + SD_BLE_GATTS_SERVICE_ADD = BLE_GATTS_SVC_BASE, /**< Add a service. */ + SD_BLE_GATTS_INCLUDE_ADD, /**< Add an included service. */ + SD_BLE_GATTS_CHARACTERISTIC_ADD, /**< Add a characteristic. */ + SD_BLE_GATTS_DESCRIPTOR_ADD, /**< Add a generic attribute. */ + SD_BLE_GATTS_VALUE_SET, /**< Set an attribute value. */ + SD_BLE_GATTS_VALUE_GET, /**< Get an attribute value. */ + SD_BLE_GATTS_HVX, /**< Handle Value Notification or Indication. */ + SD_BLE_GATTS_SERVICE_CHANGED, /**< Perform a Service Changed Indication to one or more peers. */ + SD_BLE_GATTS_RW_AUTHORIZE_REPLY, /**< Reply to an authorization request for a read or write operation on one or more + attributes. */ + SD_BLE_GATTS_SYS_ATTR_SET, /**< Set the persistent system attributes for a connection. */ + SD_BLE_GATTS_SYS_ATTR_GET, /**< Retrieve the persistent system attributes. */ + SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, /**< Retrieve the first valid user handle. */ + SD_BLE_GATTS_ATTR_GET, /**< Retrieve the UUID and/or metadata of an attribute. */ + SD_BLE_GATTS_EXCHANGE_MTU_REPLY /**< Reply to Exchange MTU Request. */ +}; + +/** + * @brief GATT Server Event IDs. + */ +enum BLE_GATTS_EVTS { + BLE_GATTS_EVT_WRITE = BLE_GATTS_EVT_BASE, /**< Write operation performed. \n See + @ref ble_gatts_evt_write_t. */ + BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST, /**< Read/Write Authorization request. \n Reply with + @ref sd_ble_gatts_rw_authorize_reply. \n See @ref ble_gatts_evt_rw_authorize_request_t. + */ + BLE_GATTS_EVT_SYS_ATTR_MISSING, /**< A persistent system attribute access is pending. \n Respond with @ref + sd_ble_gatts_sys_attr_set. \n See @ref ble_gatts_evt_sys_attr_missing_t. */ + BLE_GATTS_EVT_HVC, /**< Handle Value Confirmation. \n See @ref ble_gatts_evt_hvc_t. + */ + BLE_GATTS_EVT_SC_CONFIRM, /**< Service Changed Confirmation. \n No additional event + structure applies. */ + BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. \n Reply with + @ref sd_ble_gatts_exchange_mtu_reply. \n See @ref ble_gatts_evt_exchange_mtu_request_t. + */ + BLE_GATTS_EVT_TIMEOUT, /**< Peer failed to respond to an ATT request in time. \n See @ref + ble_gatts_evt_timeout_t. */ + BLE_GATTS_EVT_HVN_TX_COMPLETE /**< Handle Value Notification transmission complete. \n See @ref + ble_gatts_evt_hvn_tx_complete_t. */ +}; + +/**@brief GATTS Configuration IDs. + * + * IDs that uniquely identify a GATTS configuration. + */ +enum BLE_GATTS_CFGS { + BLE_GATTS_CFG_SERVICE_CHANGED = BLE_GATTS_CFG_BASE, /**< Service changed configuration. */ + BLE_GATTS_CFG_ATTR_TAB_SIZE, /**< Attribute table size configuration. */ + BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM, /**< Service changed CCCD permission configuration. */ +}; + +/** @} */ + +/** @addtogroup BLE_GATTS_DEFINES Defines + * @{ */ + +/** @defgroup BLE_ERRORS_GATTS SVC return values specific to GATTS + * @{ */ +#define BLE_ERROR_GATTS_INVALID_ATTR_TYPE (NRF_GATTS_ERR_BASE + 0x000) /**< Invalid attribute type. */ +#define BLE_ERROR_GATTS_SYS_ATTR_MISSING (NRF_GATTS_ERR_BASE + 0x001) /**< System Attributes missing. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_LENS_MAX Maximum attribute lengths + * @{ */ +#define BLE_GATTS_FIX_ATTR_LEN_MAX (510) /**< Maximum length for fixed length Attribute Values. */ +#define BLE_GATTS_VAR_ATTR_LEN_MAX (512) /**< Maximum length for variable length Attribute Values. */ +/** @} */ + +/** @defgroup BLE_GATTS_SRVC_TYPES GATT Server Service Types + * @{ */ +#define BLE_GATTS_SRVC_TYPE_INVALID 0x00 /**< Invalid Service Type. */ +#define BLE_GATTS_SRVC_TYPE_PRIMARY 0x01 /**< Primary Service. */ +#define BLE_GATTS_SRVC_TYPE_SECONDARY 0x02 /**< Secondary Type. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_TYPES GATT Server Attribute Types + * @{ */ +#define BLE_GATTS_ATTR_TYPE_INVALID 0x00 /**< Invalid Attribute Type. */ +#define BLE_GATTS_ATTR_TYPE_PRIM_SRVC_DECL 0x01 /**< Primary Service Declaration. */ +#define BLE_GATTS_ATTR_TYPE_SEC_SRVC_DECL 0x02 /**< Secondary Service Declaration. */ +#define BLE_GATTS_ATTR_TYPE_INC_DECL 0x03 /**< Include Declaration. */ +#define BLE_GATTS_ATTR_TYPE_CHAR_DECL 0x04 /**< Characteristic Declaration. */ +#define BLE_GATTS_ATTR_TYPE_CHAR_VAL 0x05 /**< Characteristic Value. */ +#define BLE_GATTS_ATTR_TYPE_DESC 0x06 /**< Descriptor. */ +#define BLE_GATTS_ATTR_TYPE_OTHER 0x07 /**< Other, non-GATT specific type. */ +/** @} */ + +/** @defgroup BLE_GATTS_OPS GATT Server Operations + * @{ */ +#define BLE_GATTS_OP_INVALID 0x00 /**< Invalid Operation. */ +#define BLE_GATTS_OP_WRITE_REQ 0x01 /**< Write Request. */ +#define BLE_GATTS_OP_WRITE_CMD 0x02 /**< Write Command. */ +#define BLE_GATTS_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ +#define BLE_GATTS_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ +#define BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL 0x05 /**< Execute Write Request: Cancel all prepared writes. */ +#define BLE_GATTS_OP_EXEC_WRITE_REQ_NOW 0x06 /**< Execute Write Request: Immediately execute all prepared writes. */ +/** @} */ + +/** @defgroup BLE_GATTS_VLOCS GATT Value Locations + * @{ */ +#define BLE_GATTS_VLOC_INVALID 0x00 /**< Invalid Location. */ +#define BLE_GATTS_VLOC_STACK 0x01 /**< Attribute Value is located in stack memory, no user memory is required. */ +#define BLE_GATTS_VLOC_USER \ + 0x02 /**< Attribute Value is located in user memory. This requires the user to maintain a valid buffer through the lifetime \ + of the attribute, since the stack will read and write directly to the memory using the pointer provided in the APIs. \ + There are no alignment requirements for the buffer. */ +/** @} */ + +/** @defgroup BLE_GATTS_AUTHORIZE_TYPES GATT Server Authorization Types + * @{ */ +#define BLE_GATTS_AUTHORIZE_TYPE_INVALID 0x00 /**< Invalid Type. */ +#define BLE_GATTS_AUTHORIZE_TYPE_READ 0x01 /**< Authorize a Read Operation. */ +#define BLE_GATTS_AUTHORIZE_TYPE_WRITE 0x02 /**< Authorize a Write Request Operation. */ +/** @} */ + +/** @defgroup BLE_GATTS_SYS_ATTR_FLAGS System Attribute Flags + * @{ */ +#define BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS (1 << 0) /**< Restrict system attributes to system services only. */ +#define BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS (1 << 1) /**< Restrict system attributes to user services only. */ +/** @} */ + +/** @defgroup BLE_GATTS_SERVICE_CHANGED Service Changed Inclusion Values + * @{ + */ +#define BLE_GATTS_SERVICE_CHANGED_DEFAULT \ + (1) /**< Default is to include the Service Changed characteristic in the Attribute Table. */ +/** @} */ + +/** @defgroup BLE_GATTS_ATTR_TAB_SIZE Attribute Table size + * @{ + */ +#define BLE_GATTS_ATTR_TAB_SIZE_MIN (248) /**< Minimum Attribute Table size */ +#define BLE_GATTS_ATTR_TAB_SIZE_DEFAULT (1408) /**< Default Attribute Table size. */ +/** @} */ + +/** @defgroup BLE_GATTS_DEFAULTS GATT Server defaults + * @{ + */ +#define BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT \ + 1 /**< Default number of Handle Value Notifications that can be queued for transmission. */ +/** @} */ + +/** @} */ + +/** @addtogroup BLE_GATTS_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE GATTS connection configuration parameters, set with @ref sd_ble_cfg_set. + */ +typedef struct { + uint8_t hvn_tx_queue_size; /**< Minimum guaranteed number of Handle Value Notifications that can be queued for transmission. + The default value is @ref BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT */ +} ble_gatts_conn_cfg_t; + +/**@brief Attribute metadata. */ +typedef struct { + ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */ + ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ + uint8_t vlen : 1; /**< Variable length attribute. */ + uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ + uint8_t rd_auth : 1; /**< Read authorization and value will be requested from the application on every read operation. */ + uint8_t wr_auth : 1; /**< Write authorization will be requested from the application on every Write Request operation (but not + Write Command). */ +} ble_gatts_attr_md_t; + +/**@brief GATT Attribute. */ +typedef struct { + ble_uuid_t const *p_uuid; /**< Pointer to the attribute UUID. */ + ble_gatts_attr_md_t const *p_attr_md; /**< Pointer to the attribute metadata structure. */ + uint16_t init_len; /**< Initial attribute value length in bytes. */ + uint16_t init_offs; /**< Initial attribute value offset in bytes. If different from zero, the first init_offs bytes of the + attribute value will be left uninitialized. */ + uint16_t max_len; /**< Maximum attribute value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */ + uint8_t *p_value; /**< Pointer to the attribute data. Please note that if the @ref BLE_GATTS_VLOC_USER value location is + selected in the attribute metadata, this will have to point to a buffer that remains valid through the + lifetime of the attribute. This excludes usage of automatic variables that may go out of scope or any + other temporary location. The stack may access that memory directly without the application's + knowledge. For writable characteristics, this value must not be a location in flash memory.*/ +} ble_gatts_attr_t; + +/**@brief GATT Attribute Value. */ +typedef struct { + uint16_t len; /**< Length in bytes to be written or read. Length in bytes written or read after successful return.*/ + uint16_t offset; /**< Attribute value offset. */ + uint8_t *p_value; /**< Pointer to where value is stored or will be stored. + If value is stored in user memory, only the attribute length is updated when p_value == NULL. + Set to NULL when reading to obtain the complete length of the attribute value */ +} ble_gatts_value_t; + +/**@brief GATT Characteristic Presentation Format. */ +typedef struct { + uint8_t format; /**< Format of the value, see @ref BLE_GATT_CPF_FORMATS. */ + int8_t exponent; /**< Exponent for integer data types. */ + uint16_t unit; /**< Unit from Bluetooth Assigned Numbers. */ + uint8_t name_space; /**< Namespace from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ + uint16_t desc; /**< Namespace description from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ +} ble_gatts_char_pf_t; + +/**@brief GATT Characteristic metadata. */ +typedef struct { + ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ + ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic Extended Properties. */ + uint8_t const * + p_char_user_desc; /**< Pointer to a UTF-8 encoded string (non-NULL terminated), NULL if the descriptor is not required. */ + uint16_t char_user_desc_max_size; /**< The maximum size in bytes of the user description descriptor. */ + uint16_t char_user_desc_size; /**< The size of the user description, must be smaller or equal to char_user_desc_max_size. */ + ble_gatts_char_pf_t const + *p_char_pf; /**< Pointer to a presentation format structure or NULL if the CPF descriptor is not required. */ + ble_gatts_attr_md_t const + *p_user_desc_md; /**< Attribute metadata for the User Description descriptor, or NULL for default values. */ + ble_gatts_attr_md_t const + *p_cccd_md; /**< Attribute metadata for the Client Characteristic Configuration Descriptor, or NULL for default values. */ + ble_gatts_attr_md_t const + *p_sccd_md; /**< Attribute metadata for the Server Characteristic Configuration Descriptor, or NULL for default values. */ +} ble_gatts_char_md_t; + +/**@brief GATT Characteristic Definition Handles. */ +typedef struct { + uint16_t value_handle; /**< Handle to the characteristic value. */ + uint16_t user_desc_handle; /**< Handle to the User Description descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */ + uint16_t cccd_handle; /**< Handle to the Client Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if + not present. */ + uint16_t sccd_handle; /**< Handle to the Server Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if + not present. */ +} ble_gatts_char_handles_t; + +/**@brief GATT HVx parameters. */ +typedef struct { + uint16_t handle; /**< Characteristic Value Handle. */ + uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ + uint16_t offset; /**< Offset within the attribute value. */ + uint16_t *p_len; /**< Length in bytes to be written, length in bytes written after return. */ + uint8_t const *p_data; /**< Actual data content, use NULL to use the current attribute value. */ +} ble_gatts_hvx_params_t; + +/**@brief GATT Authorization parameters. */ +typedef struct { + uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ + uint8_t update : 1; /**< If set, data supplied in p_data will be used to update the attribute value. + Please note that for @ref BLE_GATTS_AUTHORIZE_TYPE_WRITE operations this bit must always be set, + as the data to be written needs to be stored and later provided by the application. */ + uint16_t offset; /**< Offset of the attribute value being updated. */ + uint16_t len; /**< Length in bytes of the value in p_data pointer, see @ref BLE_GATTS_ATTR_LENS_MAX. */ + uint8_t const *p_data; /**< Pointer to new value used to update the attribute value. */ +} ble_gatts_authorize_params_t; + +/**@brief GATT Read or Write Authorize Reply parameters. */ +typedef struct { + uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ + union { + ble_gatts_authorize_params_t read; /**< Read authorization parameters. */ + ble_gatts_authorize_params_t write; /**< Write authorization parameters. */ + } params; /**< Reply Parameters. */ +} ble_gatts_rw_authorize_reply_params_t; + +/**@brief Service Changed Inclusion configuration parameters, set with @ref sd_ble_cfg_set. */ +typedef struct { + uint8_t service_changed : 1; /**< If 1, include the Service Changed characteristic in the Attribute Table. Default is @ref + BLE_GATTS_SERVICE_CHANGED_DEFAULT. */ +} ble_gatts_cfg_service_changed_t; + +/**@brief Service Changed CCCD permission configuration parameters, set with @ref sd_ble_cfg_set. + * + * @note @ref ble_gatts_attr_md_t::vlen is ignored and should be set to 0. + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - @ref ble_gatts_attr_md_t::write_perm is out of range. + * - @ref ble_gatts_attr_md_t::write_perm is @ref BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS, that is + * not allowed by the Bluetooth Specification. + * - wrong @ref ble_gatts_attr_md_t::read_perm, only @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN is + * allowed by the Bluetooth Specification. + * - wrong @ref ble_gatts_attr_md_t::vloc, only @ref BLE_GATTS_VLOC_STACK is allowed. + * @retval ::NRF_ERROR_NOT_SUPPORTED Security Mode 2 not supported + */ +typedef struct { + ble_gatts_attr_md_t + perm; /**< Permission for Service Changed CCCD. Default is @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN, no authorization. */ +} ble_gatts_cfg_service_changed_cccd_perm_t; + +/**@brief Attribute table size configuration parameters, set with @ref sd_ble_cfg_set. + * + * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: + * - The specified Attribute Table size is too small. + * The minimum acceptable size is defined by @ref BLE_GATTS_ATTR_TAB_SIZE_MIN. + * - The specified Attribute Table size is not a multiple of 4. + */ +typedef struct { + uint32_t attr_tab_size; /**< Attribute table size. Default is @ref BLE_GATTS_ATTR_TAB_SIZE_DEFAULT, minimum is @ref + BLE_GATTS_ATTR_TAB_SIZE_MIN. */ +} ble_gatts_cfg_attr_tab_size_t; + +/**@brief Config structure for GATTS configurations. */ +typedef union { + ble_gatts_cfg_service_changed_t + service_changed; /**< Include service changed characteristic, cfg_id is @ref BLE_GATTS_CFG_SERVICE_CHANGED. */ + ble_gatts_cfg_service_changed_cccd_perm_t service_changed_cccd_perm; /**< Service changed CCCD permission, cfg_id is @ref + BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM. */ + ble_gatts_cfg_attr_tab_size_t attr_tab_size; /**< Attribute table size, cfg_id is @ref BLE_GATTS_CFG_ATTR_TAB_SIZE. */ +} ble_gatts_cfg_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_WRITE. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + ble_uuid_t uuid; /**< Attribute UUID. */ + uint8_t op; /**< Type of write operation, see @ref BLE_GATTS_OPS. */ + uint8_t auth_required; /**< Writing operation deferred due to authorization requirement. Application may use @ref + sd_ble_gatts_value_set to finalize the writing operation. */ + uint16_t offset; /**< Offset for the write operation. */ + uint16_t len; /**< Length of the received data. */ + uint8_t data[1]; /**< Received data. @note This is a variable length array. The size of 1 indicated is only a placeholder for + compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable + length array members. */ +} ble_gatts_evt_write_t; + +/**@brief Event substructure for authorized read requests, see @ref ble_gatts_evt_rw_authorize_request_t. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ + ble_uuid_t uuid; /**< Attribute UUID. */ + uint16_t offset; /**< Offset for the read operation. */ +} ble_gatts_evt_read_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST. */ +typedef struct { + uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ + union { + ble_gatts_evt_read_t read; /**< Attribute Read Parameters. */ + ble_gatts_evt_write_t write; /**< Attribute Write Parameters. */ + } request; /**< Request Parameters. */ +} ble_gatts_evt_rw_authorize_request_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. */ +typedef struct { + uint8_t hint; /**< Hint (currently unused). */ +} ble_gatts_evt_sys_attr_missing_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_HVC. */ +typedef struct { + uint16_t handle; /**< Attribute Handle. */ +} ble_gatts_evt_hvc_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST. */ +typedef struct { + uint16_t client_rx_mtu; /**< Client RX MTU size. */ +} ble_gatts_evt_exchange_mtu_request_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_TIMEOUT. */ +typedef struct { + uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ +} ble_gatts_evt_timeout_t; + +/**@brief Event structure for @ref BLE_GATTS_EVT_HVN_TX_COMPLETE. */ +typedef struct { + uint8_t count; /**< Number of notification transmissions completed. */ +} ble_gatts_evt_hvn_tx_complete_t; + +/**@brief GATTS event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which the event occurred. */ + union { + ble_gatts_evt_write_t write; /**< Write Event Parameters. */ + ble_gatts_evt_rw_authorize_request_t authorize_request; /**< Read or Write Authorize Request Parameters. */ + ble_gatts_evt_sys_attr_missing_t sys_attr_missing; /**< System attributes missing. */ + ble_gatts_evt_hvc_t hvc; /**< Handle Value Confirmation Event Parameters. */ + ble_gatts_evt_exchange_mtu_request_t exchange_mtu_request; /**< Exchange MTU Request Event Parameters. */ + ble_gatts_evt_timeout_t timeout; /**< Timeout Event. */ + ble_gatts_evt_hvn_tx_complete_t hvn_tx_complete; /**< Handle Value Notification transmission complete Event Parameters. */ + } params; /**< Event Parameters. */ +} ble_gatts_evt_t; + +/** @} */ + +/** @addtogroup BLE_GATTS_FUNCTIONS Functions + * @{ */ + +/**@brief Add a service declaration to the Attribute Table. + * + * @note Secondary Services are only relevant in the context of the entity that references them, it is therefore forbidden to + * add a secondary service declaration that is not referenced by another service later in the Attribute Table. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] type Toggles between primary and secondary services, see @ref BLE_GATTS_SRVC_TYPES. + * @param[in] p_uuid Pointer to service UUID. + * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a service declaration. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, Vendor Specific UUIDs need to be present in the table. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type, ble_uuid_t const *p_uuid, uint16_t *p_handle)); + +/**@brief Add an include declaration to the Attribute Table. + * + * @note It is currently only possible to add an include declaration to the last added service (i.e. only sequential population is + * supported at this time). + * + * @note The included service must already be present in the Attribute Table prior to this call. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] service_handle Handle of the service where the included service is to be placed, if @ref BLE_GATT_HANDLE_INVALID + * is used, it will be placed sequentially. + * @param[in] inc_srvc_handle Handle of the included service. + * @param[out] p_include_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added an include declaration. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, handle values need to match previously added services. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. + * @retval ::NRF_ERROR_NOT_SUPPORTED Feature is not supported, service_handle must be that of the last added service. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, self inclusions are not allowed. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + */ +SVCALL(SD_BLE_GATTS_INCLUDE_ADD, uint32_t, + sd_ble_gatts_include_add(uint16_t service_handle, uint16_t inc_srvc_handle, uint16_t *p_include_handle)); + +/**@brief Add a characteristic declaration, a characteristic value declaration and optional characteristic descriptor declarations + * to the Attribute Table. + * + * @note It is currently only possible to add a characteristic to the last added service (i.e. only sequential population is + * supported at this time). + * + * @note Several restrictions apply to the parameters, such as matching permissions between the user description descriptor and + * the writable auxiliaries bits, readable (no security) and writable (selectable) CCCDs and SCCDs and valid presentation format + * values. + * + * @note If no metadata is provided for the optional descriptors, their permissions will be derived from the characteristic + * permissions. + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] service_handle Handle of the service where the characteristic is to be placed, if @ref BLE_GATT_HANDLE_INVALID is + * used, it will be placed sequentially. + * @param[in] p_char_md Characteristic metadata. + * @param[in] p_attr_char_value Pointer to the attribute structure corresponding to the characteristic value. + * @param[out] p_handles Pointer to the structure where the assigned handles will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a characteristic. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, service handle, Vendor Specific UUIDs, lengths, and + * permissions need to adhere to the constraints. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + */ +SVCALL(SD_BLE_GATTS_CHARACTERISTIC_ADD, uint32_t, + sd_ble_gatts_characteristic_add(uint16_t service_handle, ble_gatts_char_md_t const *p_char_md, + ble_gatts_attr_t const *p_attr_char_value, ble_gatts_char_handles_t *p_handles)); + +/**@brief Add a descriptor to the Attribute Table. + * + * @note It is currently only possible to add a descriptor to the last added characteristic (i.e. only sequential population is + * supported at this time). + * + * @mscs + * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} + * @endmscs + * + * @param[in] char_handle Handle of the characteristic where the descriptor is to be placed, if @ref BLE_GATT_HANDLE_INVALID is + * used, it will be placed sequentially. + * @param[in] p_attr Pointer to the attribute structure. + * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully added a descriptor. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, characteristic handle, Vendor Specific UUIDs, lengths, and + * permissions need to adhere to the constraints. + * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a characteristic context is required. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + */ +SVCALL(SD_BLE_GATTS_DESCRIPTOR_ADD, uint32_t, + sd_ble_gatts_descriptor_add(uint16_t char_handle, ble_gatts_attr_t const *p_attr, uint16_t *p_handle)); + +/**@brief Set the value of a given attribute. + * + * @note Values other than system attributes can be set at any time, regardless of whether any active connections exist. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. + * @param[in] handle Attribute handle. + * @param[in,out] p_value Attribute value information. + * + * @retval ::NRF_SUCCESS Successfully set the value of the attribute. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_FORBIDDEN Forbidden handle supplied, certain attributes are not modifiable by the application. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. + */ +SVCALL(SD_BLE_GATTS_VALUE_SET, uint32_t, + sd_ble_gatts_value_set(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); + +/**@brief Get the value of a given attribute. + * + * @note If the attribute value is longer than the size of the supplied buffer, + * @ref ble_gatts_value_t::len will return the total attribute value length (excluding offset), + * and not the number of bytes actually returned in @ref ble_gatts_value_t::p_value. + * The application may use this information to allocate a suitable buffer size. + * + * @note When retrieving system attribute values with this function, the connection handle + * may refer to an already disconnected connection. Refer to the documentation of + * @ref sd_ble_gatts_sys_attr_get for further information. + * + * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. + * @param[in] handle Attribute handle. + * @param[in,out] p_value Attribute value information. + * + * @retval ::NRF_SUCCESS Successfully retrieved the value of the attribute. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid attribute offset supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + */ +SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, + sd_ble_gatts_value_get(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); + +/**@brief Notify or Indicate an attribute value. + * + * @details This function checks for the relevant Client Characteristic Configuration descriptor value to verify that the relevant + * operation (notification or indication) has been enabled by the client. It is also able to update the attribute value before + * issuing the PDU, so that the application can atomically perform a value update and a server initiated transaction with a single + * API call. + * + * @note The local attribute value may be updated even if an outgoing packet is not sent to the peer due to an error during + * execution. The Attribute Table has been updated if one of the following error codes is returned: @ref NRF_ERROR_INVALID_STATE, + * @ref NRF_ERROR_BUSY, + * @ref NRF_ERROR_FORBIDDEN, @ref BLE_ERROR_GATTS_SYS_ATTR_MISSING and @ref NRF_ERROR_RESOURCES. + * The caller can check whether the value has been updated by looking at the contents of *(@ref + * ble_gatts_hvx_params_t::p_len). + * + * @note Only one indication procedure can be ongoing per connection at a time. + * If the application tries to indicate an attribute value while another indication procedure is ongoing, + * the function call will return @ref NRF_ERROR_BUSY. + * A @ref BLE_GATTS_EVT_HVC event will be issued as soon as the confirmation arrives from the peer. + * + * @note The number of Handle Value Notifications that can be queued is configured by @ref + * ble_gatts_conn_cfg_t::hvn_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. A @ref + * BLE_GATTS_EVT_HVN_TX_COMPLETE event will be issued as soon as the transmission of the notification is complete. + * + * @note The application can keep track of the available queue element count for notifications by following the procedure + * below: + * - Store initial queue element count in a variable. + * - Decrement the variable, which stores the currently available queue element count, by one when a call to this + * function returns @ref NRF_SUCCESS. + * - Increment the variable, which stores the current available queue element count, by the count variable in @ref + * BLE_GATTS_EVT_HVN_TX_COMPLETE event. + * + * @events + * @event{@ref BLE_GATTS_EVT_HVN_TX_COMPLETE, Notification transmission complete.} + * @event{@ref BLE_GATTS_EVT_HVC, Confirmation received from the peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} + * @mmsc{@ref BLE_GATTS_HVN_MSC} + * @mmsc{@ref BLE_GATTS_HVI_MSC} + * @mmsc{@ref BLE_GATTS_HVX_DISABLED_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in,out] p_hvx_params Pointer to an HVx parameters structure. If @ref ble_gatts_hvx_params_t::p_data + * contains a non-NULL pointer the attribute value will be updated with the contents + * pointed by it before sending the notification or indication. If the attribute value + * is updated, @ref ble_gatts_hvx_params_t::p_len is updated by the SoftDevice to + * contain the number of actual bytes written, else it will be set to 0. + * + * @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute + * value. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: + * - Invalid Connection State + * - Notifications and/or indications not enabled in the CCCD + * - An ATT_MTU exchange is ongoing + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application + * are available to notify and indicate. + * @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and + * indicated. + * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. + * @retval ::NRF_ERROR_FORBIDDEN The connection's current security level is lower than the one required by the write permissions + * of the CCCD associated with this characteristic. + * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. + * @retval ::NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC + * event and retry. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + * @retval ::NRF_ERROR_RESOURCES Too many notifications queued. + * Wait for a @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event and retry. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_gatts_hvx_params_t const *p_hvx_params)); + +/**@brief Indicate the Service Changed attribute value. + * + * @details This call will send a Handle Value Indication to one or more peers connected to inform them that the Attribute + * Table layout has changed. As soon as the peer has confirmed the indication, a @ref BLE_GATTS_EVT_SC_CONFIRM event will + * be issued. + * + * @note Some of the restrictions and limitations that apply to @ref sd_ble_gatts_hvx also apply here. + * + * @events + * @event{@ref BLE_GATTS_EVT_SC_CONFIRM, Confirmation of attribute table change received from peer.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_GATTS_SC_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] start_handle Start of affected attribute handle range. + * @param[in] end_handle End of affected attribute handle range. + * + * @retval ::NRF_SUCCESS Successfully queued the Service Changed indication for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_NOT_SUPPORTED Service Changed not enabled at initialization. See @ref + * sd_ble_cfg_set and @ref ble_gatts_cfg_service_changed_t. + * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: + * - Invalid Connection State + * - Notifications and/or indications not enabled in the CCCD + * - An ATT_MTU exchange is ongoing + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied, handles must be in the range populated by the + * application. + * @retval ::NRF_ERROR_BUSY Procedure already in progress. + * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known + * value. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t, + sd_ble_gatts_service_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle)); + +/**@brief Respond to a Read/Write authorization request. + * + * @note This call should only be used as a response to a @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event issued to the application. + * + * @mscs + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} + * @mmsc{@ref BLE_GATTS_READ_REQ_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_WRITE_REQ_AUTH_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} + * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_rw_authorize_reply_params Pointer to a structure with the attribute provided by the application. + * + * @note @ref ble_gatts_authorize_params_t::p_data is ignored when this function is used to respond + * to a @ref BLE_GATTS_AUTHORIZE_TYPE_READ event if @ref ble_gatts_authorize_params_t::update + * is set to 0. + * + * @retval ::NRF_SUCCESS Successfully queued a response to the peer, and in the case of a write operation, Attribute + * Table updated. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no authorization request pending. + * @retval ::NRF_ERROR_INVALID_PARAM Authorization op invalid, + * handle supplied does not match requested handle, + * or invalid data to be written provided by the application. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_RW_AUTHORIZE_REPLY, uint32_t, + sd_ble_gatts_rw_authorize_reply(uint16_t conn_handle, + ble_gatts_rw_authorize_reply_params_t const *p_rw_authorize_reply_params)); + +/**@brief Update persistent system attribute information. + * + * @details Supply information about persistent system attributes to the stack, + * previously obtained using @ref sd_ble_gatts_sys_attr_get. + * This call is only allowed for active connections, and is usually + * made immediately after a connection is established with an known bonded device, + * often as a response to a @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. + * + * p_sysattrs may point directly to the application's stored copy of the system attributes + * obtained using @ref sd_ble_gatts_sys_attr_get. + * If the pointer is NULL, the system attribute info is initialized, assuming that + * the application does not have any previously saved system attribute data for this device. + * + * @note The state of persistent system attributes is reset upon connection establishment and then remembered for its duration. + * + * @note If this call returns with an error code different from @ref NRF_SUCCESS, the storage of persistent system attributes may + * have been completed only partially. This means that the state of the attribute table is undefined, and the application should + * either provide a new set of attributes using this same call or reset the SoftDevice to return to a known state. + * + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system + * services will be modified. + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user + * services will be modified. + * + * @mscs + * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_UNK_PEER_MSC} + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle. + * @param[in] p_sys_attr_data Pointer to a saved copy of system attributes supplied to the stack, or NULL. + * @param[in] len Size of data pointed by p_sys_attr_data, in octets. + * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS + * + * @retval ::NRF_SUCCESS Successfully set the system attribute information. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. + * @retval ::NRF_ERROR_INVALID_DATA Invalid data supplied, the data should be exactly the same as retrieved with @ref + * sd_ble_gatts_sys_attr_get. + * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. + */ +SVCALL(SD_BLE_GATTS_SYS_ATTR_SET, uint32_t, + sd_ble_gatts_sys_attr_set(uint16_t conn_handle, uint8_t const *p_sys_attr_data, uint16_t len, uint32_t flags)); + +/**@brief Retrieve persistent system attribute information from the stack. + * + * @details This call is used to retrieve information about values to be stored persistently by the application + * during the lifetime of a connection or after it has been terminated. When a new connection is established with the + * same bonded device, the system attribute information retrieved with this function should be restored using using @ref + * sd_ble_gatts_sys_attr_set. If retrieved after disconnection, the data should be read before a new connection established. The + * connection handle for the previous, now disconnected, connection will remain valid until a new one is created to allow this API + * call to refer to it. Connection handles belonging to active connections can be used as well, but care should be taken since the + * system attributes may be written to at any time by the peer during a connection's lifetime. + * + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system + * services will be returned. + * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user + * services will be returned. + * + * @mscs + * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} + * @endmscs + * + * @param[in] conn_handle Connection handle of the recently terminated connection. + * @param[out] p_sys_attr_data Pointer to a buffer where updated information about system attributes will be filled in. The + * format of the data is described in @ref BLE_GATTS_SYS_ATTRS_FORMAT. NULL can be provided to obtain the length of the data. + * @param[in,out] p_len Size of application buffer if p_sys_attr_data is not NULL. Unconditionally updated to actual + * length of system attribute data. + * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS + * + * @retval ::NRF_SUCCESS Successfully retrieved the system attribute information. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. + * @retval ::NRF_ERROR_DATA_SIZE The system attribute information did not fit into the provided buffer. + * @retval ::NRF_ERROR_NOT_FOUND No system attributes found. + */ +SVCALL(SD_BLE_GATTS_SYS_ATTR_GET, uint32_t, + sd_ble_gatts_sys_attr_get(uint16_t conn_handle, uint8_t *p_sys_attr_data, uint16_t *p_len, uint32_t flags)); + +/**@brief Retrieve the first valid user attribute handle. + * + * @param[out] p_handle Pointer to an integer where the handle will be stored. + * + * @retval ::NRF_SUCCESS Successfully retrieved the handle. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + */ +SVCALL(SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, uint32_t, sd_ble_gatts_initial_user_handle_get(uint16_t *p_handle)); + +/**@brief Retrieve the attribute UUID and/or metadata. + * + * @param[in] handle Attribute handle + * @param[out] p_uuid UUID of the attribute. Use NULL to omit this field. + * @param[out] p_md Metadata of the attribute. Use NULL to omit this field. + * + * @retval ::NRF_SUCCESS Successfully retrieved the attribute metadata, + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. Returned when both @c p_uuid and @c p_md are NULL. + * @retval ::NRF_ERROR_NOT_FOUND Attribute was not found. + */ +SVCALL(SD_BLE_GATTS_ATTR_GET, uint32_t, sd_ble_gatts_attr_get(uint16_t handle, ble_uuid_t *p_uuid, ble_gatts_attr_md_t *p_md)); + +/**@brief Reply to an ATT_MTU exchange request by sending an Exchange MTU Response to the client. + * + * @details This function is only used to reply to a @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event. + * + * @details The SoftDevice sets ATT_MTU to the minimum of: + * - The Client RX MTU value from @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, and + * - The Server RX MTU value. + * + * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. + * + * @mscs + * @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} + * @endmscs + * + * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. + * @param[in] server_rx_mtu Server RX MTU size. + * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. + * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration + * used for this connection. + * - The value must be equal to Client RX MTU size given in @ref sd_ble_gattc_exchange_mtu_request + * if an ATT_MTU exchange has already been performed in the other direction. + * + * @retval ::NRF_SUCCESS Successfully sent response to the client. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no ATT_MTU exchange request pending. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid Server RX MTU size supplied. + * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without + * reestablishing the connection. + */ +SVCALL(SD_BLE_GATTS_EXCHANGE_MTU_REPLY, uint32_t, sd_ble_gatts_exchange_mtu_reply(uint16_t conn_handle, uint16_t server_rx_mtu)); +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_GATTS_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_hci.h b/variants/wio-tracker-wm1110/softdevice/ble_hci.h new file mode 100644 index 0000000000..27f85d52ea --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_hci.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ +*/ + +#ifndef BLE_HCI_H__ +#define BLE_HCI_H__ +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup BLE_HCI_STATUS_CODES Bluetooth status codes + * @{ */ + +#define BLE_HCI_STATUS_CODE_SUCCESS 0x00 /**< Success. */ +#define BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND 0x01 /**< Unknown BLE Command. */ +#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02 /**< Unknown Connection Identifier. */ +/*0x03 Hardware Failure +0x04 Page Timeout +*/ +#define BLE_HCI_AUTHENTICATION_FAILURE 0x05 /**< Authentication Failure. */ +#define BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING 0x06 /**< Pin or Key missing. */ +#define BLE_HCI_MEMORY_CAPACITY_EXCEEDED 0x07 /**< Memory Capacity Exceeded. */ +#define BLE_HCI_CONNECTION_TIMEOUT 0x08 /**< Connection Timeout. */ +/*0x09 Connection Limit Exceeded +0x0A Synchronous Connection Limit To A Device Exceeded +0x0B ACL Connection Already Exists*/ +#define BLE_HCI_STATUS_CODE_COMMAND_DISALLOWED 0x0C /**< Command Disallowed. */ +/*0x0D Connection Rejected due to Limited Resources +0x0E Connection Rejected Due To Security Reasons +0x0F Connection Rejected due to Unacceptable BD_ADDR +0x10 Connection Accept Timeout Exceeded +0x11 Unsupported Feature or Parameter Value*/ +#define BLE_HCI_STATUS_CODE_INVALID_BTLE_COMMAND_PARAMETERS 0x12 /**< Invalid BLE Command Parameters. */ +#define BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION 0x13 /**< Remote User Terminated Connection. */ +#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES \ + 0x14 /**< Remote Device Terminated Connection due to low \ + resources.*/ +#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF 0x15 /**< Remote Device Terminated Connection due to power off. */ +#define BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION 0x16 /**< Local Host Terminated Connection. */ +/* +0x17 Repeated Attempts +0x18 Pairing Not Allowed +0x19 Unknown LMP PDU +*/ +#define BLE_HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A /**< Unsupported Remote Feature. */ +/* +0x1B SCO Offset Rejected +0x1C SCO Interval Rejected +0x1D SCO Air Mode Rejected*/ +#define BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS 0x1E /**< Invalid LMP Parameters. */ +#define BLE_HCI_STATUS_CODE_UNSPECIFIED_ERROR 0x1F /**< Unspecified Error. */ +/*0x20 Unsupported LMP Parameter Value +0x21 Role Change Not Allowed +*/ +#define BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT 0x22 /**< LMP Response Timeout. */ +#define BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION 0x23 /**< LMP Error Transaction Collision/LL Procedure Collision. */ +#define BLE_HCI_STATUS_CODE_LMP_PDU_NOT_ALLOWED 0x24 /**< LMP PDU Not Allowed. */ +/*0x25 Encryption Mode Not Acceptable +0x26 Link Key Can Not be Changed +0x27 Requested QoS Not Supported +*/ +#define BLE_HCI_INSTANT_PASSED 0x28 /**< Instant Passed. */ +#define BLE_HCI_PAIRING_WITH_UNIT_KEY_UNSUPPORTED 0x29 /**< Pairing with Unit Key Unsupported. */ +#define BLE_HCI_DIFFERENT_TRANSACTION_COLLISION 0x2A /**< Different Transaction Collision. */ +/* +0x2B Reserved +0x2C QoS Unacceptable Parameter +0x2D QoS Rejected +0x2E Channel Classification Not Supported +0x2F Insufficient Security +*/ +#define BLE_HCI_PARAMETER_OUT_OF_MANDATORY_RANGE 0x30 /**< Parameter Out Of Mandatory Range. */ +/* +0x31 Reserved +0x32 Role Switch Pending +0x33 Reserved +0x34 Reserved Slot Violation +0x35 Role Switch Failed +0x36 Extended Inquiry Response Too Large +0x37 Secure Simple Pairing Not Supported By Host. +0x38 Host Busy - Pairing +0x39 Connection Rejected due to No Suitable Channel Found*/ +#define BLE_HCI_CONTROLLER_BUSY 0x3A /**< Controller Busy. */ +#define BLE_HCI_CONN_INTERVAL_UNACCEPTABLE 0x3B /**< Connection Interval Unacceptable. */ +#define BLE_HCI_DIRECTED_ADVERTISER_TIMEOUT 0x3C /**< Directed Advertisement Timeout. */ +#define BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE 0x3D /**< Connection Terminated due to MIC Failure. */ +#define BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED 0x3E /**< Connection Failed to be Established. */ + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_HCI_H__ + +/** @} */ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h b/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h new file mode 100644 index 0000000000..5f4bd277d3 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h @@ -0,0 +1,495 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_L2CAP Logical Link Control and Adaptation Protocol (L2CAP) + @{ + @brief Definitions and prototypes for the L2CAP interface. + */ + +#ifndef BLE_L2CAP_H__ +#define BLE_L2CAP_H__ + +#include "ble_err.h" +#include "ble_ranges.h" +#include "ble_types.h" +#include "nrf_error.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup BLE_L2CAP_TERMINOLOGY Terminology + * @{ + * @details + * + * L2CAP SDU + * - A data unit that the application can send/receive to/from a peer. + * + * L2CAP PDU + * - A data unit that is exchanged between local and remote L2CAP entities. + * It consists of L2CAP protocol control information and payload fields. + * The payload field can contain an L2CAP SDU or a part of an L2CAP SDU. + * + * L2CAP MTU + * - The maximum length of an L2CAP SDU. + * + * L2CAP MPS + * - The maximum length of an L2CAP PDU payload field. + * + * Credits + * - A value indicating the number of L2CAP PDUs that the receiver of the credit can send to the peer. + * @} */ + +/**@addtogroup BLE_L2CAP_ENUMERATIONS Enumerations + * @{ */ + +/**@brief L2CAP API SVC numbers. */ +enum BLE_L2CAP_SVCS { + SD_BLE_L2CAP_CH_SETUP = BLE_L2CAP_SVC_BASE + 0, /**< Set up an L2CAP channel. */ + SD_BLE_L2CAP_CH_RELEASE = BLE_L2CAP_SVC_BASE + 1, /**< Release an L2CAP channel. */ + SD_BLE_L2CAP_CH_RX = BLE_L2CAP_SVC_BASE + 2, /**< Receive an SDU on an L2CAP channel. */ + SD_BLE_L2CAP_CH_TX = BLE_L2CAP_SVC_BASE + 3, /**< Transmit an SDU on an L2CAP channel. */ + SD_BLE_L2CAP_CH_FLOW_CONTROL = BLE_L2CAP_SVC_BASE + 4, /**< Advanced SDU reception flow control. */ +}; + +/**@brief L2CAP Event IDs. */ +enum BLE_L2CAP_EVTS { + BLE_L2CAP_EVT_CH_SETUP_REQUEST = BLE_L2CAP_EVT_BASE + 0, /**< L2CAP Channel Setup Request event. + \n Reply with @ref sd_ble_l2cap_ch_setup. + \n See @ref ble_l2cap_evt_ch_setup_request_t. */ + BLE_L2CAP_EVT_CH_SETUP_REFUSED = BLE_L2CAP_EVT_BASE + 1, /**< L2CAP Channel Setup Refused event. + \n See @ref ble_l2cap_evt_ch_setup_refused_t. */ + BLE_L2CAP_EVT_CH_SETUP = BLE_L2CAP_EVT_BASE + 2, /**< L2CAP Channel Setup Completed event. + \n See @ref ble_l2cap_evt_ch_setup_t. */ + BLE_L2CAP_EVT_CH_RELEASED = BLE_L2CAP_EVT_BASE + 3, /**< L2CAP Channel Released event. + \n No additional event structure applies. */ + BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED = BLE_L2CAP_EVT_BASE + 4, /**< L2CAP Channel SDU data buffer released event. + \n See @ref ble_l2cap_evt_ch_sdu_buf_released_t. */ + BLE_L2CAP_EVT_CH_CREDIT = BLE_L2CAP_EVT_BASE + 5, /**< L2CAP Channel Credit received. + \n See @ref ble_l2cap_evt_ch_credit_t. */ + BLE_L2CAP_EVT_CH_RX = BLE_L2CAP_EVT_BASE + 6, /**< L2CAP Channel SDU received. + \n See @ref ble_l2cap_evt_ch_rx_t. */ + BLE_L2CAP_EVT_CH_TX = BLE_L2CAP_EVT_BASE + 7, /**< L2CAP Channel SDU transmitted. + \n See @ref ble_l2cap_evt_ch_tx_t. */ +}; + +/** @} */ + +/**@addtogroup BLE_L2CAP_DEFINES Defines + * @{ */ + +/**@brief Maximum number of L2CAP channels per connection. */ +#define BLE_L2CAP_CH_COUNT_MAX (64) + +/**@brief Minimum L2CAP MTU, in bytes. */ +#define BLE_L2CAP_MTU_MIN (23) + +/**@brief Minimum L2CAP MPS, in bytes. */ +#define BLE_L2CAP_MPS_MIN (23) + +/**@brief Invalid CID. */ +#define BLE_L2CAP_CID_INVALID (0x0000) + +/**@brief Default number of credits for @ref sd_ble_l2cap_ch_flow_control. */ +#define BLE_L2CAP_CREDITS_DEFAULT (1) + +/**@defgroup BLE_L2CAP_CH_SETUP_REFUSED_SRCS L2CAP channel setup refused sources + * @{ */ +#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_LOCAL (0x01) /**< Local. */ +#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_REMOTE (0x02) /**< Remote. */ + /** @} */ + +/** @defgroup BLE_L2CAP_CH_STATUS_CODES L2CAP channel status codes + * @{ */ +#define BLE_L2CAP_CH_STATUS_CODE_SUCCESS (0x0000) /**< Success. */ +#define BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED (0x0002) /**< LE_PSM not supported. */ +#define BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES (0x0004) /**< No resources available. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHENTICATION (0x0005) /**< Insufficient authentication. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHORIZATION (0x0006) /**< Insufficient authorization. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC_KEY_SIZE (0x0007) /**< Insufficient encryption key size. */ +#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC (0x0008) /**< Insufficient encryption. */ +#define BLE_L2CAP_CH_STATUS_CODE_INVALID_SCID (0x0009) /**< Invalid Source CID. */ +#define BLE_L2CAP_CH_STATUS_CODE_SCID_ALLOCATED (0x000A) /**< Source CID already allocated. */ +#define BLE_L2CAP_CH_STATUS_CODE_UNACCEPTABLE_PARAMS (0x000B) /**< Unacceptable parameters. */ +#define BLE_L2CAP_CH_STATUS_CODE_NOT_UNDERSTOOD \ + (0x8000) /**< Command Reject received instead of LE Credit Based Connection Response. */ +#define BLE_L2CAP_CH_STATUS_CODE_TIMEOUT (0xC000) /**< Operation timed out. */ +/** @} */ + +/** @} */ + +/**@addtogroup BLE_L2CAP_STRUCTURES Structures + * @{ */ + +/** + * @brief BLE L2CAP connection configuration parameters, set with @ref sd_ble_cfg_set. + * + * @note These parameters are set per connection, so all L2CAP channels created on this connection + * will have the same parameters. + * + * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: + * - rx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. + * - tx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. + * - ch_count is greater than @ref BLE_L2CAP_CH_COUNT_MAX. + * @retval ::NRF_ERROR_NO_MEM rx_mps or tx_mps is set too high. + */ +typedef struct { + uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall + be able to receive on L2CAP channels on connections with this + configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ + uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall + be able to transmit on L2CAP channels on connections with this + configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ + uint8_t rx_queue_size; /**< Number of SDU data buffers that can be queued for reception per + L2CAP channel. The minimum value is one. */ + uint8_t tx_queue_size; /**< Number of SDU data buffers that can be queued for transmission + per L2CAP channel. The minimum value is one. */ + uint8_t ch_count; /**< Number of L2CAP channels the application can create per connection + with this configuration. The default value is zero, the maximum + value is @ref BLE_L2CAP_CH_COUNT_MAX. + @note if this parameter is set to zero, all other parameters in + @ref ble_l2cap_conn_cfg_t are ignored. */ +} ble_l2cap_conn_cfg_t; + +/**@brief L2CAP channel RX parameters. */ +typedef struct { + uint16_t rx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP shall be able to + receive on this L2CAP channel. + - Must be equal to or greater than @ref BLE_L2CAP_MTU_MIN. */ + uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall be + able to receive on this L2CAP channel. + - Must be equal to or greater than @ref BLE_L2CAP_MPS_MIN. + - Must be equal to or less than @ref ble_l2cap_conn_cfg_t::rx_mps. */ + ble_data_t sdu_buf; /**< SDU data buffer for reception. + - If @ref ble_data_t::p_data is non-NULL, initial credits are + issued to the peer. + - If @ref ble_data_t::p_data is NULL, no initial credits are + issued to the peer. */ +} ble_l2cap_ch_rx_params_t; + +/**@brief L2CAP channel setup parameters. */ +typedef struct { + ble_l2cap_ch_rx_params_t rx_params; /**< L2CAP channel RX parameters. */ + uint16_t le_psm; /**< LE Protocol/Service Multiplexer. Used when requesting + setup of an L2CAP channel, ignored otherwise. */ + uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES. + Used when replying to a setup request of an L2CAP + channel, ignored otherwise. */ +} ble_l2cap_ch_setup_params_t; + +/**@brief L2CAP channel TX parameters. */ +typedef struct { + uint16_t tx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP is able to + transmit on this L2CAP channel. */ + uint16_t peer_mps; /**< The maximum L2CAP PDU payload size, in bytes, that the peer is + able to receive on this L2CAP channel. */ + uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP is able + to transmit on this L2CAP channel. This is effective tx_mps, + selected by the SoftDevice as + MIN( @ref ble_l2cap_ch_tx_params_t::peer_mps, @ref ble_l2cap_conn_cfg_t::tx_mps ) */ + uint16_t credits; /**< Initial credits given by the peer. */ +} ble_l2cap_ch_tx_params_t; + +/**@brief L2CAP Channel Setup Request event. */ +typedef struct { + ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ + uint16_t le_psm; /**< LE Protocol/Service Multiplexer. */ +} ble_l2cap_evt_ch_setup_request_t; + +/**@brief L2CAP Channel Setup Refused event. */ +typedef struct { + uint8_t source; /**< Source, see @ref BLE_L2CAP_CH_SETUP_REFUSED_SRCS */ + uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES */ +} ble_l2cap_evt_ch_setup_refused_t; + +/**@brief L2CAP Channel Setup Completed event. */ +typedef struct { + ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ +} ble_l2cap_evt_ch_setup_t; + +/**@brief L2CAP Channel SDU Data Buffer Released event. */ +typedef struct { + ble_data_t sdu_buf; /**< Returned reception or transmission SDU data buffer. The SoftDevice + returns SDU data buffers supplied by the application, which have + not yet been returned previously via a @ref BLE_L2CAP_EVT_CH_RX or + @ref BLE_L2CAP_EVT_CH_TX event. */ +} ble_l2cap_evt_ch_sdu_buf_released_t; + +/**@brief L2CAP Channel Credit received event. */ +typedef struct { + uint16_t credits; /**< Additional credits given by the peer. */ +} ble_l2cap_evt_ch_credit_t; + +/**@brief L2CAP Channel received SDU event. */ +typedef struct { + uint16_t sdu_len; /**< Total SDU length, in bytes. */ + ble_data_t sdu_buf; /**< SDU data buffer. + @note If there is not enough space in the buffer + (sdu_buf.len < sdu_len) then the rest of the SDU will be + silently discarded by the SoftDevice. */ +} ble_l2cap_evt_ch_rx_t; + +/**@brief L2CAP Channel transmitted SDU event. */ +typedef struct { + ble_data_t sdu_buf; /**< SDU data buffer. */ +} ble_l2cap_evt_ch_tx_t; + +/**@brief L2CAP event structure. */ +typedef struct { + uint16_t conn_handle; /**< Connection Handle on which the event occured. */ + uint16_t local_cid; /**< Local Channel ID of the L2CAP channel, or + @ref BLE_L2CAP_CID_INVALID if not present. */ + union { + ble_l2cap_evt_ch_setup_request_t ch_setup_request; /**< L2CAP Channel Setup Request Event Parameters. */ + ble_l2cap_evt_ch_setup_refused_t ch_setup_refused; /**< L2CAP Channel Setup Refused Event Parameters. */ + ble_l2cap_evt_ch_setup_t ch_setup; /**< L2CAP Channel Setup Completed Event Parameters. */ + ble_l2cap_evt_ch_sdu_buf_released_t ch_sdu_buf_released; /**< L2CAP Channel SDU Data Buffer Released Event Parameters. */ + ble_l2cap_evt_ch_credit_t credit; /**< L2CAP Channel Credit Received Event Parameters. */ + ble_l2cap_evt_ch_rx_t rx; /**< L2CAP Channel SDU Received Event Parameters. */ + ble_l2cap_evt_ch_tx_t tx; /**< L2CAP Channel SDU Transmitted Event Parameters. */ + } params; /**< Event Parameters. */ +} ble_l2cap_evt_t; + +/** @} */ + +/**@addtogroup BLE_L2CAP_FUNCTIONS Functions + * @{ */ + +/**@brief Set up an L2CAP channel. + * + * @details This function is used to: + * - Request setup of an L2CAP channel: sends an LE Credit Based Connection Request packet to a peer. + * - Reply to a setup request of an L2CAP channel (if called in response to a + * @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST event): sends an LE Credit Based Connection + * Response packet to a peer. + * + * @note A call to this function will require the application to keep the SDU data buffer alive + * until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX or + * @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_SETUP, Setup successful.} + * @event{@ref BLE_L2CAP_EVT_CH_SETUP_REFUSED, Setup failed.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_SETUP_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in,out] p_local_cid Pointer to a uint16_t containing Local Channel ID of the L2CAP channel: + * - As input: @ref BLE_L2CAP_CID_INVALID when requesting setup of an L2CAP + * channel or local_cid provided in the @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST + * event when replying to a setup request of an L2CAP channel. + * - As output: local_cid for this channel. + * @param[in] p_params L2CAP channel parameters. + * + * @retval ::NRF_SUCCESS Successfully queued request or response for transmission. + * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. + * @retval ::NRF_ERROR_INVALID_LENGTH Supplied higher rx_mps than has been configured on this link. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (L2CAP channel already set up). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_RESOURCES The limit has been reached for available L2CAP channels, + * see @ref ble_l2cap_conn_cfg_t::ch_count. + */ +SVCALL(SD_BLE_L2CAP_CH_SETUP, uint32_t, + sd_ble_l2cap_ch_setup(uint16_t conn_handle, uint16_t *p_local_cid, ble_l2cap_ch_setup_params_t const *p_params)); + +/**@brief Release an L2CAP channel. + * + * @details This sends a Disconnection Request packet to a peer. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_RELEASED, Release complete.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_RELEASE_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * + * @retval ::NRF_SUCCESS Successfully queued request for transmission. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for the L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + */ +SVCALL(SD_BLE_L2CAP_CH_RELEASE, uint32_t, sd_ble_l2cap_ch_release(uint16_t conn_handle, uint16_t local_cid)); + +/**@brief Receive an SDU on an L2CAP channel. + * + * @details This may issue additional credits to the peer using an LE Flow Control Credit packet. + * + * @note A call to this function will require the application to keep the memory pointed by + * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX + * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::rx_queue_size SDU data buffers + * for reception per L2CAP channel. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_RX, The SDU is received.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_RX_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * @param[in] p_sdu_buf Pointer to the SDU data buffer. + * + * @retval ::NRF_SUCCESS Buffer accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for an L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_RESOURCES Too many SDU data buffers supplied. Wait for a + * @ref BLE_L2CAP_EVT_CH_RX event and retry. + */ +SVCALL(SD_BLE_L2CAP_CH_RX, uint32_t, sd_ble_l2cap_ch_rx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); + +/**@brief Transmit an SDU on an L2CAP channel. + * + * @note A call to this function will require the application to keep the memory pointed by + * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_TX + * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. + * + * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::tx_queue_size SDUs for + * transmission per L2CAP channel. + * + * @note The application can keep track of the available credits for transmission by following + * the procedure below: + * - Store initial credits given by the peer in a variable. + * (Initial credits are provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) + * - Decrement the variable, which stores the currently available credits, by + * ceiling((@ref ble_data_t::len + 2) / tx_mps) when a call to this function returns + * @ref NRF_SUCCESS. (tx_mps is provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) + * - Increment the variable, which stores the currently available credits, by additional + * credits given by the peer in a @ref BLE_L2CAP_EVT_CH_CREDIT event. + * + * @events + * @event{@ref BLE_L2CAP_EVT_CH_TX, The SDU is transmitted.} + * @endevents + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_TX_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel. + * @param[in] p_sdu_buf Pointer to the SDU data buffer. + * + * @retval ::NRF_SUCCESS Successfully queued L2CAP SDU for transmission. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for the L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + * @retval ::NRF_ERROR_DATA_SIZE Invalid SDU length supplied, must not be more than + * @ref ble_l2cap_ch_tx_params_t::tx_mtu provided in + * @ref BLE_L2CAP_EVT_CH_SETUP event. + * @retval ::NRF_ERROR_RESOURCES Too many SDUs queued for transmission. Wait for a + * @ref BLE_L2CAP_EVT_CH_TX event and retry. + */ +SVCALL(SD_BLE_L2CAP_CH_TX, uint32_t, sd_ble_l2cap_ch_tx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); + +/**@brief Advanced SDU reception flow control. + * + * @details Adjust the way the SoftDevice issues credits to the peer. + * This may issue additional credits to the peer using an LE Flow Control Credit packet. + * + * @mscs + * @mmsc{@ref BLE_L2CAP_CH_FLOW_CONTROL_MSC} + * @endmscs + * + * @param[in] conn_handle Connection Handle. + * @param[in] local_cid Local Channel ID of the L2CAP channel or @ref BLE_L2CAP_CID_INVALID to set + * the value that will be used for newly created channels. + * @param[in] credits Number of credits that the SoftDevice will make sure the peer has every + * time it starts using a new reception buffer. + * - @ref BLE_L2CAP_CREDITS_DEFAULT is the default value the SoftDevice will + * use if this function is not called. + * - If set to zero, the SoftDevice will stop issuing credits for new reception + * buffers the application provides or has provided. SDU reception that is + * currently ongoing will be allowed to complete. + * @param[out] p_credits NULL or pointer to a uint16_t. If a valid pointer is provided, it will be + * written by the SoftDevice with the number of credits that is or will be + * available to the peer. If the value written by the SoftDevice is 0 when + * credits parameter was set to 0, the peer will not be able to send more + * data until more credits are provided by calling this function again with + * credits > 0. This parameter is ignored when local_cid is set to + * @ref BLE_L2CAP_CID_INVALID. + * + * @note Application should take care when setting number of credits higher than default value. In + * this case the application must make sure that the SoftDevice always has reception buffers + * available (see @ref sd_ble_l2cap_ch_rx) for that channel. If the SoftDevice does not have + * such buffers available, packets may be NACKed on the Link Layer and all Bluetooth traffic + * on the connection handle may be stalled until the SoftDevice again has an available + * reception buffer. This applies even if the application has used this call to set the + * credits back to default, or zero. + * + * @retval ::NRF_SUCCESS Flow control parameters accepted. + * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. + * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. + * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is + * in progress for an L2CAP channel). + * @retval ::NRF_ERROR_NOT_FOUND CID not found. + */ +SVCALL(SD_BLE_L2CAP_CH_FLOW_CONTROL, uint32_t, + sd_ble_l2cap_ch_flow_control(uint16_t conn_handle, uint16_t local_cid, uint16_t credits, uint16_t *p_credits)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // BLE_L2CAP_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_ranges.h b/variants/wio-tracker-wm1110/softdevice/ble_ranges.h new file mode 100644 index 0000000000..2768e49967 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_ranges.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @defgroup ble_ranges Module specific SVC, event and option number subranges + @{ + + @brief Definition of SVC, event and option number subranges for each API module. + + @note + SVCs, event and option numbers are split into subranges for each API module. + Each module receives its entire allocated range of SVC calls, whether implemented or not, + but return BLE_ERROR_NOT_SUPPORTED for unimplemented or undefined calls in its range. + + Note that the symbols BLE__SVC_LAST is the end of the allocated SVC range, + rather than the last SVC function call actually defined and implemented. + + Specific SVC, event and option values are defined in each module's ble_.h file, + which defines names of each individual SVC code based on the range start value. +*/ + +#ifndef BLE_RANGES_H__ +#define BLE_RANGES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_SVC_BASE 0x60 /**< Common BLE SVC base. */ +#define BLE_SVC_LAST 0x6B /**< Common BLE SVC last. */ + +#define BLE_GAP_SVC_BASE 0x6C /**< GAP BLE SVC base. */ +#define BLE_GAP_SVC_LAST 0x9A /**< GAP BLE SVC last. */ + +#define BLE_GATTC_SVC_BASE 0x9B /**< GATTC BLE SVC base. */ +#define BLE_GATTC_SVC_LAST 0xA7 /**< GATTC BLE SVC last. */ + +#define BLE_GATTS_SVC_BASE 0xA8 /**< GATTS BLE SVC base. */ +#define BLE_GATTS_SVC_LAST 0xB7 /**< GATTS BLE SVC last. */ + +#define BLE_L2CAP_SVC_BASE 0xB8 /**< L2CAP BLE SVC base. */ +#define BLE_L2CAP_SVC_LAST 0xBF /**< L2CAP BLE SVC last. */ + +#define BLE_EVT_INVALID 0x00 /**< Invalid BLE Event. */ + +#define BLE_EVT_BASE 0x01 /**< Common BLE Event base. */ +#define BLE_EVT_LAST 0x0F /**< Common BLE Event last. */ + +#define BLE_GAP_EVT_BASE 0x10 /**< GAP BLE Event base. */ +#define BLE_GAP_EVT_LAST 0x2F /**< GAP BLE Event last. */ + +#define BLE_GATTC_EVT_BASE 0x30 /**< GATTC BLE Event base. */ +#define BLE_GATTC_EVT_LAST 0x4F /**< GATTC BLE Event last. */ + +#define BLE_GATTS_EVT_BASE 0x50 /**< GATTS BLE Event base. */ +#define BLE_GATTS_EVT_LAST 0x6F /**< GATTS BLE Event last. */ + +#define BLE_L2CAP_EVT_BASE 0x70 /**< L2CAP BLE Event base. */ +#define BLE_L2CAP_EVT_LAST 0x8F /**< L2CAP BLE Event last. */ + +#define BLE_OPT_INVALID 0x00 /**< Invalid BLE Option. */ + +#define BLE_OPT_BASE 0x01 /**< Common BLE Option base. */ +#define BLE_OPT_LAST 0x1F /**< Common BLE Option last. */ + +#define BLE_GAP_OPT_BASE 0x20 /**< GAP BLE Option base. */ +#define BLE_GAP_OPT_LAST 0x3F /**< GAP BLE Option last. */ + +#define BLE_GATT_OPT_BASE 0x40 /**< GATT BLE Option base. */ +#define BLE_GATT_OPT_LAST 0x5F /**< GATT BLE Option last. */ + +#define BLE_GATTC_OPT_BASE 0x60 /**< GATTC BLE Option base. */ +#define BLE_GATTC_OPT_LAST 0x7F /**< GATTC BLE Option last. */ + +#define BLE_GATTS_OPT_BASE 0x80 /**< GATTS BLE Option base. */ +#define BLE_GATTS_OPT_LAST 0x9F /**< GATTS BLE Option last. */ + +#define BLE_L2CAP_OPT_BASE 0xA0 /**< L2CAP BLE Option base. */ +#define BLE_L2CAP_OPT_LAST 0xBF /**< L2CAP BLE Option last. */ + +#define BLE_CFG_INVALID 0x00 /**< Invalid BLE configuration. */ + +#define BLE_CFG_BASE 0x01 /**< Common BLE configuration base. */ +#define BLE_CFG_LAST 0x1F /**< Common BLE configuration last. */ + +#define BLE_CONN_CFG_BASE 0x20 /**< BLE connection configuration base. */ +#define BLE_CONN_CFG_LAST 0x3F /**< BLE connection configuration last. */ + +#define BLE_GAP_CFG_BASE 0x40 /**< GAP BLE configuration base. */ +#define BLE_GAP_CFG_LAST 0x5F /**< GAP BLE configuration last. */ + +#define BLE_GATT_CFG_BASE 0x60 /**< GATT BLE configuration base. */ +#define BLE_GATT_CFG_LAST 0x7F /**< GATT BLE configuration last. */ + +#define BLE_GATTC_CFG_BASE 0x80 /**< GATTC BLE configuration base. */ +#define BLE_GATTC_CFG_LAST 0x9F /**< GATTC BLE configuration last. */ + +#define BLE_GATTS_CFG_BASE 0xA0 /**< GATTS BLE configuration base. */ +#define BLE_GATTS_CFG_LAST 0xBF /**< GATTS BLE configuration last. */ + +#define BLE_L2CAP_CFG_BASE 0xC0 /**< L2CAP BLE configuration base. */ +#define BLE_L2CAP_CFG_LAST 0xDF /**< L2CAP BLE configuration last. */ + +#ifdef __cplusplus +} +#endif +#endif /* BLE_RANGES_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_types.h b/variants/wio-tracker-wm1110/softdevice/ble_types.h new file mode 100644 index 0000000000..db3656cfdd --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/ble_types.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup BLE_COMMON + @{ + @defgroup ble_types Common types and macro definitions + @{ + + @brief Common types and macro definitions for the BLE SoftDevice. + */ + +#ifndef BLE_TYPES_H__ +#define BLE_TYPES_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup BLE_TYPES_DEFINES Defines + * @{ */ + +/** @defgroup BLE_CONN_HANDLES BLE Connection Handles + * @{ */ +#define BLE_CONN_HANDLE_INVALID 0xFFFF /**< Invalid Connection Handle. */ +#define BLE_CONN_HANDLE_ALL 0xFFFE /**< Applies to all Connection Handles. */ +/** @} */ + +/** @defgroup BLE_UUID_VALUES Assigned Values for BLE UUIDs + * @{ */ +/* Generic UUIDs, applicable to all services */ +#define BLE_UUID_UNKNOWN 0x0000 /**< Reserved UUID. */ +#define BLE_UUID_SERVICE_PRIMARY 0x2800 /**< Primary Service. */ +#define BLE_UUID_SERVICE_SECONDARY 0x2801 /**< Secondary Service. */ +#define BLE_UUID_SERVICE_INCLUDE 0x2802 /**< Include. */ +#define BLE_UUID_CHARACTERISTIC 0x2803 /**< Characteristic. */ +#define BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP 0x2900 /**< Characteristic Extended Properties Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_USER_DESC 0x2901 /**< Characteristic User Description Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG 0x2902 /**< Client Characteristic Configuration Descriptor. */ +#define BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG 0x2903 /**< Server Characteristic Configuration Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT 0x2904 /**< Characteristic Presentation Format Descriptor. */ +#define BLE_UUID_DESCRIPTOR_CHAR_AGGREGATE_FORMAT 0x2905 /**< Characteristic Aggregate Format Descriptor. */ +/* GATT specific UUIDs */ +#define BLE_UUID_GATT 0x1801 /**< Generic Attribute Profile. */ +#define BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED 0x2A05 /**< Service Changed Characteristic. */ +/* GAP specific UUIDs */ +#define BLE_UUID_GAP 0x1800 /**< Generic Access Profile. */ +#define BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME 0x2A00 /**< Device Name Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_APPEARANCE 0x2A01 /**< Appearance Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_RECONN_ADDR 0x2A03 /**< Reconnection Address Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_PPCP 0x2A04 /**< Peripheral Preferred Connection Parameters Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_CAR 0x2AA6 /**< Central Address Resolution Characteristic. */ +#define BLE_UUID_GAP_CHARACTERISTIC_RPA_ONLY 0x2AC9 /**< Resolvable Private Address Only Characteristic. */ +/** @} */ + +/** @defgroup BLE_UUID_TYPES Types of UUID + * @{ */ +#define BLE_UUID_TYPE_UNKNOWN 0x00 /**< Invalid UUID type. */ +#define BLE_UUID_TYPE_BLE 0x01 /**< Bluetooth SIG UUID (16-bit). */ +#define BLE_UUID_TYPE_VENDOR_BEGIN 0x02 /**< Vendor UUID types start at this index (128-bit). */ +/** @} */ + +/** @defgroup BLE_APPEARANCES Bluetooth Appearance values + * @note Retrieved from + * http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml + * @{ */ +#define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */ +#define BLE_APPEARANCE_GENERIC_PHONE 64 /**< Generic Phone. */ +#define BLE_APPEARANCE_GENERIC_COMPUTER 128 /**< Generic Computer. */ +#define BLE_APPEARANCE_GENERIC_WATCH 192 /**< Generic Watch. */ +#define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /**< Watch: Sports Watch. */ +#define BLE_APPEARANCE_GENERIC_CLOCK 256 /**< Generic Clock. */ +#define BLE_APPEARANCE_GENERIC_DISPLAY 320 /**< Generic Display. */ +#define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /**< Generic Remote Control. */ +#define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /**< Generic Eye-glasses. */ +#define BLE_APPEARANCE_GENERIC_TAG 512 /**< Generic Tag. */ +#define BLE_APPEARANCE_GENERIC_KEYRING 576 /**< Generic Keyring. */ +#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /**< Generic Media Player. */ +#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /**< Generic Barcode Scanner. */ +#define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /**< Generic Thermometer. */ +#define BLE_APPEARANCE_THERMOMETER_EAR 769 /**< Thermometer: Ear. */ +#define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /**< Generic Heart rate Sensor. */ +#define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /**< Heart Rate Sensor: Heart Rate Belt. */ +#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /**< Generic Blood Pressure. */ +#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /**< Blood Pressure: Arm. */ +#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /**< Blood Pressure: Wrist. */ +#define BLE_APPEARANCE_GENERIC_HID 960 /**< Human Interface Device (HID). */ +#define BLE_APPEARANCE_HID_KEYBOARD 961 /**< Keyboard (HID Subtype). */ +#define BLE_APPEARANCE_HID_MOUSE 962 /**< Mouse (HID Subtype). */ +#define BLE_APPEARANCE_HID_JOYSTICK 963 /**< Joystick (HID Subtype). */ +#define BLE_APPEARANCE_HID_GAMEPAD 964 /**< Gamepad (HID Subtype). */ +#define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /**< Digitizer Tablet (HID Subtype). */ +#define BLE_APPEARANCE_HID_CARD_READER 966 /**< Card Reader (HID Subtype). */ +#define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /**< Digital Pen (HID Subtype). */ +#define BLE_APPEARANCE_HID_BARCODE 968 /**< Barcode Scanner (HID Subtype). */ +#define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /**< Generic Glucose Meter. */ +#define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /**< Generic Running Walking Sensor. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /**< Running Walking Sensor: In-Shoe. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /**< Running Walking Sensor: On-Shoe. */ +#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /**< Running Walking Sensor: On-Hip. */ +#define BLE_APPEARANCE_GENERIC_CYCLING 1152 /**< Generic Cycling. */ +#define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /**< Cycling: Cycling Computer. */ +#define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /**< Cycling: Speed Sensor. */ +#define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /**< Cycling: Cadence Sensor. */ +#define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /**< Cycling: Power Sensor. */ +#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /**< Cycling: Speed and Cadence Sensor. */ +#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /**< Generic Pulse Oximeter. */ +#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /**< Fingertip (Pulse Oximeter subtype). */ +#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /**< Wrist Worn(Pulse Oximeter subtype). */ +#define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /**< Generic Weight Scale. */ +#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /**< Generic Outdoor Sports Activity. */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /**< Location Display Device (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP \ + 5186 /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /**< Location Pod (Outdoor Sports Activity subtype). */ +#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD \ + 5188 /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */ +/** @} */ + +/** @brief Set .type and .uuid fields of ble_uuid_struct to specified UUID value. */ +#define BLE_UUID_BLE_ASSIGN(instance, value) \ + do { \ + instance.type = BLE_UUID_TYPE_BLE; \ + instance.uuid = value; \ + } while (0) + +/** @brief Copy type and uuid members from src to dst ble_uuid_t pointer. Both pointers must be valid/non-null. */ +#define BLE_UUID_COPY_PTR(dst, src) \ + do { \ + (dst)->type = (src)->type; \ + (dst)->uuid = (src)->uuid; \ + } while (0) + +/** @brief Copy type and uuid members from src to dst ble_uuid_t struct. */ +#define BLE_UUID_COPY_INST(dst, src) \ + do { \ + (dst).type = (src).type; \ + (dst).uuid = (src).uuid; \ + } while (0) + +/** @brief Compare for equality both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ +#define BLE_UUID_EQ(p_uuid1, p_uuid2) (((p_uuid1)->type == (p_uuid2)->type) && ((p_uuid1)->uuid == (p_uuid2)->uuid)) + +/** @brief Compare for difference both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ +#define BLE_UUID_NEQ(p_uuid1, p_uuid2) (((p_uuid1)->type != (p_uuid2)->type) || ((p_uuid1)->uuid != (p_uuid2)->uuid)) + +/** @} */ + +/** @addtogroup BLE_TYPES_STRUCTURES Structures + * @{ */ + +/** @brief 128 bit UUID values. */ +typedef struct { + uint8_t uuid128[16]; /**< Little-Endian UUID bytes. */ +} ble_uuid128_t; + +/** @brief Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */ +typedef struct { + uint16_t uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */ + uint8_t + type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is @ref BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */ +} ble_uuid_t; + +/**@brief Data structure. */ +typedef struct { + uint8_t *p_data; /**< Pointer to the data buffer provided to/from the application. */ + uint16_t len; /**< Length of the data buffer, in bytes. */ +} ble_data_t; + +/** @} */ +#ifdef __cplusplus +} +#endif + +#endif /* BLE_TYPES_H__ */ + +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h b/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h new file mode 100644 index 0000000000..4e0bd752ab --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2014 - 2017, Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_mbr_api Master Boot Record API + @{ + + @brief APIs for updating SoftDevice and BootLoader + +*/ + +#ifndef NRF_MBR_H__ +#define NRF_MBR_H__ + +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup NRF_MBR_DEFINES Defines + * @{ */ + +/**@brief MBR SVC Base number. */ +#define MBR_SVC_BASE (0x18) + +/**@brief Page size in words. */ +#define MBR_PAGE_SIZE_IN_WORDS (1024) + +/** @brief The size that must be reserved for the MBR when a SoftDevice is written to flash. +This is the offset where the first byte of the SoftDevice hex file is written. */ +#define MBR_SIZE (0x1000) + +/** @brief Location (in the flash memory) of the bootloader address. */ +#define MBR_BOOTLOADER_ADDR (0xFF8) + +/** @brief Location (in UICR) of the bootloader address. */ +#define MBR_UICR_BOOTLOADER_ADDR (&(NRF_UICR->NRFFW[0])) + +/** @brief Location (in the flash memory) of the address of the MBR parameter page. */ +#define MBR_PARAM_PAGE_ADDR (0xFFC) + +/** @brief Location (in UICR) of the address of the MBR parameter page. */ +#define MBR_UICR_PARAM_PAGE_ADDR (&(NRF_UICR->NRFFW[1])) + +/** @} */ + +/** @addtogroup NRF_MBR_ENUMS Enumerations + * @{ */ + +/**@brief nRF Master Boot Record API SVC numbers. */ +enum NRF_MBR_SVCS { + SD_MBR_COMMAND = MBR_SVC_BASE, /**< ::sd_mbr_command */ +}; + +/**@brief Possible values for ::sd_mbr_command_t.command */ +enum NRF_MBR_COMMANDS { + SD_MBR_COMMAND_COPY_BL, /**< Copy a new BootLoader. @see ::sd_mbr_command_copy_bl_t*/ + SD_MBR_COMMAND_COPY_SD, /**< Copy a new SoftDevice. @see ::sd_mbr_command_copy_sd_t*/ + SD_MBR_COMMAND_INIT_SD, /**< Initialize forwarding interrupts to SD, and run reset function in SD. Does not require any + parameters in ::sd_mbr_command_t params.*/ + SD_MBR_COMMAND_COMPARE, /**< This command works like memcmp. @see ::sd_mbr_command_compare_t*/ + SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET, /**< Change the address the MBR starts after a reset. @see + ::sd_mbr_command_vector_table_base_set_t*/ + SD_MBR_COMMAND_RESERVED, + SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET, /**< Start forwarding all interrupts to this address. @see + ::sd_mbr_command_irq_forward_address_set_t*/ +}; + +/** @} */ + +/** @addtogroup NRF_MBR_TYPES Types + * @{ */ + +/**@brief This command copies part of a new SoftDevice + * + * The destination area is erased before copying. + * If dst is in the middle of a flash page, that whole flash page will be erased. + * If (dst+len) is in the middle of a flash page, that whole flash page will be erased. + * + * The user of this function is responsible for setting the BPROT registers. + * + * @retval ::NRF_SUCCESS indicates that the contents of the memory blocks where copied correctly. + * @retval ::NRF_ERROR_INTERNAL indicates that the contents of the memory blocks where not verified correctly after copying. + */ +typedef struct { + uint32_t *src; /**< Pointer to the source of data to be copied.*/ + uint32_t *dst; /**< Pointer to the destination where the content is to be copied.*/ + uint32_t len; /**< Number of 32 bit words to copy. Must be a multiple of @ref MBR_PAGE_SIZE_IN_WORDS words.*/ +} sd_mbr_command_copy_sd_t; + +/**@brief This command works like memcmp, but takes the length in words. + * + * @retval ::NRF_SUCCESS indicates that the contents of both memory blocks are equal. + * @retval ::NRF_ERROR_NULL indicates that the contents of the memory blocks are not equal. + */ +typedef struct { + uint32_t *ptr1; /**< Pointer to block of memory. */ + uint32_t *ptr2; /**< Pointer to block of memory. */ + uint32_t len; /**< Number of 32 bit words to compare.*/ +} sd_mbr_command_compare_t; + +/**@brief This command copies a new BootLoader. + * + * The MBR assumes that either @ref MBR_BOOTLOADER_ADDR or @ref MBR_UICR_BOOTLOADER_ADDR is set to + * the address where the bootloader will be copied. If both addresses are set, the MBR will prioritize + * @ref MBR_BOOTLOADER_ADDR. + * + * The bootloader destination is erased by this function. + * If (destination+bl_len) is in the middle of a flash page, that whole flash page will be erased. + * + * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, + * see @ref sd_mbr_command. + * + * This command will use the flash protect peripheral (BPROT or ACL) to protect the flash that is + * not intended to be written. + * + * On success, this function will not return. It will start the new bootloader from reset-vector as normal. + * + * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. + * @retval ::NRF_ERROR_FORBIDDEN if the bootloader address is not set. + * @retval ::NRF_ERROR_INVALID_LENGTH if parameters attempts to read or write outside flash area. + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. + */ +typedef struct { + uint32_t *bl_src; /**< Pointer to the source of the bootloader to be be copied.*/ + uint32_t bl_len; /**< Number of 32 bit words to copy for BootLoader. */ +} sd_mbr_command_copy_bl_t; + +/**@brief Change the address the MBR starts after a reset + * + * Once this function has been called, this address is where the MBR will start to forward + * interrupts to after a reset. + * + * To restore default forwarding, this function should be called with @ref address set to 0. If a + * bootloader is present, interrupts will be forwarded to the bootloader. If not, interrupts will + * be forwarded to the SoftDevice. + * + * The location of a bootloader can be specified in @ref MBR_BOOTLOADER_ADDR or + * @ref MBR_UICR_BOOTLOADER_ADDR. If both addresses are set, the MBR will prioritize + * @ref MBR_BOOTLOADER_ADDR. + * + * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, + * see @ref sd_mbr_command. + * + * On success, this function will not return. It will reset the device. + * + * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. + * @retval ::NRF_ERROR_INVALID_ADDR if parameter address is outside of the flash size. + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. + */ +typedef struct { + uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ +} sd_mbr_command_vector_table_base_set_t; + +/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the MBR + * + * Unlike sd_mbr_command_vector_table_base_set_t, this function does not reset, and it does not + * change where the MBR starts after reset. + * + * @retval ::NRF_SUCCESS + */ +typedef struct { + uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ +} sd_mbr_command_irq_forward_address_set_t; + +/**@brief Input structure containing data used when calling ::sd_mbr_command + * + * Depending on what command value that is set, the corresponding params value type must also be + * set. See @ref NRF_MBR_COMMANDS for command types and corresponding params value type. If command + * @ref SD_MBR_COMMAND_INIT_SD is set, it is not necessary to set any values under params. + */ +typedef struct { + uint32_t command; /**< Type of command to be issued. See @ref NRF_MBR_COMMANDS. */ + union { + sd_mbr_command_copy_sd_t copy_sd; /**< Parameters for copy SoftDevice.*/ + sd_mbr_command_compare_t compare; /**< Parameters for verify.*/ + sd_mbr_command_copy_bl_t copy_bl; /**< Parameters for copy BootLoader. Requires parameter page. */ + sd_mbr_command_vector_table_base_set_t base_set; /**< Parameters for vector table base set. Requires parameter page.*/ + sd_mbr_command_irq_forward_address_set_t irq_forward_address_set; /**< Parameters for irq forward address set*/ + } params; /**< Command parameters. */ +} sd_mbr_command_t; + +/** @} */ + +/** @addtogroup NRF_MBR_FUNCTIONS Functions + * @{ */ + +/**@brief Issue Master Boot Record commands + * + * Commands used when updating a SoftDevice and bootloader. + * + * The @ref SD_MBR_COMMAND_COPY_BL and @ref SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET requires + * parameters to be retained by the MBR when resetting the IC. This is done in a separate flash + * page. The location of the flash page should be provided by the application in either + * @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR. If both addresses are set, the MBR + * will prioritize @ref MBR_PARAM_PAGE_ADDR. This page will be cleared by the MBR and is used to + * store the command before reset. When an address is specified, the page it refers to must not be + * used by the application. If no address is provided by the application, i.e. both + * @ref MBR_PARAM_PAGE_ADDR and @ref MBR_UICR_PARAM_PAGE_ADDR is 0xFFFFFFFF, MBR commands which use + * flash will be unavailable and return @ref NRF_ERROR_NO_MEM. + * + * @param[in] param Pointer to a struct describing the command. + * + * @note For a complete set of return values, see ::sd_mbr_command_copy_sd_t, + * ::sd_mbr_command_copy_bl_t, ::sd_mbr_command_compare_t, + * ::sd_mbr_command_vector_table_base_set_t, ::sd_mbr_command_irq_forward_address_set_t + * + * @retval ::NRF_ERROR_NO_MEM No MBR parameter page provided + * @retval ::NRF_ERROR_INVALID_PARAM if an invalid command is given. + */ +SVCALL(SD_MBR_COMMAND, uint32_t, sd_mbr_command(sd_mbr_command_t *param)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_MBR_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error.h b/variants/wio-tracker-wm1110/softdevice/nrf_error.h new file mode 100644 index 0000000000..fb2831e191 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_error.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_error SoftDevice Global Error Codes + @{ + + @brief Global Error definitions +*/ + +/* Header guard */ +#ifndef NRF_ERROR_H__ +#define NRF_ERROR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup NRF_ERRORS_BASE Error Codes Base number definitions + * @{ */ +#define NRF_ERROR_BASE_NUM (0x0) ///< Global error base +#define NRF_ERROR_SDM_BASE_NUM (0x1000) ///< SDM error base +#define NRF_ERROR_SOC_BASE_NUM (0x2000) ///< SoC error base +#define NRF_ERROR_STK_BASE_NUM (0x3000) ///< STK error base +/** @} */ + +#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command +#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing +#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled +#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error +#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation +#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found +#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported +#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter +#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state +#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length +#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags +#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data +#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Invalid Data size +#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out +#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer +#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation +#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address +#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy +#define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded. +#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h b/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h new file mode 100644 index 0000000000..2fd6210576 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup nrf_sdm_api + @{ + @defgroup nrf_sdm_error SoftDevice Manager Error Codes + @{ + + @brief Error definitions for the SDM API +*/ + +/* Header guard */ +#ifndef NRF_ERROR_SDM_H__ +#define NRF_ERROR_SDM_H__ + +#include "nrf_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN (NRF_ERROR_SDM_BASE_NUM + 0) ///< Unknown LFCLK source. +#define NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION \ + (NRF_ERROR_SDM_BASE_NUM + 1) ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having + ///< enabled SoftDevice interrupts). +#define NRF_ERROR_SDM_INCORRECT_CLENR0 \ + (NRF_ERROR_SDM_BASE_NUM + 2) ///< Incorrect CLENR0 (can be caused by erroneous SoftDevice flashing). + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_SDM_H__ + +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h b/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h new file mode 100644 index 0000000000..cbd0ba8ac4 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @addtogroup nrf_soc_api + @{ + @defgroup nrf_soc_error SoC Library Error Codes + @{ + + @brief Error definitions for the SoC library + +*/ + +/* Header guard */ +#ifndef NRF_ERROR_SOC_H__ +#define NRF_ERROR_SOC_H__ + +#include "nrf_error.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* Mutex Errors */ +#define NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN (NRF_ERROR_SOC_BASE_NUM + 0) ///< Mutex already taken + +/* NVIC errors */ +#define NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE (NRF_ERROR_SOC_BASE_NUM + 1) ///< NVIC interrupt not available +#define NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED (NRF_ERROR_SOC_BASE_NUM + 2) ///< NVIC interrupt priority not allowed +#define NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 3) ///< NVIC should not return + +/* Power errors */ +#define NRF_ERROR_SOC_POWER_MODE_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 4) ///< Power mode unknown +#define NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 5) ///< Power POF threshold unknown +#define NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 6) ///< Power off should not return + +/* Rand errors */ +#define NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES (NRF_ERROR_SOC_BASE_NUM + 7) ///< RAND not enough values + +/* PPI errors */ +#define NRF_ERROR_SOC_PPI_INVALID_CHANNEL (NRF_ERROR_SOC_BASE_NUM + 8) ///< Invalid PPI Channel +#define NRF_ERROR_SOC_PPI_INVALID_GROUP (NRF_ERROR_SOC_BASE_NUM + 9) ///< Invalid PPI Group + +#ifdef __cplusplus +} +#endif +#endif // NRF_ERROR_SOC_H__ +/** + @} + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h b/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h new file mode 100644 index 0000000000..d4ab204d96 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h @@ -0,0 +1,449 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup nrf_nvic_api SoftDevice NVIC API + * @{ + * + * @note In order to use this module, the following code has to be added to a .c file: + * \code + * nrf_nvic_state_t nrf_nvic_state = {0}; + * \endcode + * + * @note Definitions and declarations starting with __ (double underscore) in this header file are + * not intended for direct use by the application. + * + * @brief APIs for the accessing NVIC when using a SoftDevice. + * + */ + +#ifndef NRF_NVIC_H__ +#define NRF_NVIC_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup NRF_NVIC_DEFINES Defines + * @{ */ + +/**@defgroup NRF_NVIC_ISER_DEFINES SoftDevice NVIC internal definitions + * @{ */ + +#define __NRF_NVIC_NVMC_IRQn \ + (30) /**< The peripheral ID of the NVMC. IRQ numbers are used to identify peripherals, but the NVMC doesn't have an IRQ \ + number in the MDK. */ + +#define __NRF_NVIC_ISER_COUNT (2) /**< The number of ISER/ICER registers in the NVIC that are used. */ + +/**@brief Interrupt priority levels used by the SoftDevice. */ +#define __NRF_NVIC_SD_IRQ_PRIOS \ + ((uint8_t)((1U << 0) /**< Priority level high .*/ \ + | (1U << 1) /**< Priority level medium. */ \ + | (1U << 4) /**< Priority level low. */ \ + )) + +/**@brief Interrupt priority levels available to the application. */ +#define __NRF_NVIC_APP_IRQ_PRIOS ((uint8_t)~__NRF_NVIC_SD_IRQ_PRIOS) + +/**@brief Interrupts used by the SoftDevice, with IRQn in the range 0-31. */ +#define __NRF_NVIC_SD_IRQS_0 \ + ((uint32_t)((1U << POWER_CLOCK_IRQn) | (1U << RADIO_IRQn) | (1U << RTC0_IRQn) | (1U << TIMER0_IRQn) | (1U << RNG_IRQn) | \ + (1U << ECB_IRQn) | (1U << CCM_AAR_IRQn) | (1U << TEMP_IRQn) | (1U << __NRF_NVIC_NVMC_IRQn) | \ + (1U << (uint32_t)SWI5_IRQn))) + +/**@brief Interrupts used by the SoftDevice, with IRQn in the range 32-63. */ +#define __NRF_NVIC_SD_IRQS_1 ((uint32_t)0) + +/**@brief Interrupts available for to application, with IRQn in the range 0-31. */ +#define __NRF_NVIC_APP_IRQS_0 (~__NRF_NVIC_SD_IRQS_0) + +/**@brief Interrupts available for to application, with IRQn in the range 32-63. */ +#define __NRF_NVIC_APP_IRQS_1 (~__NRF_NVIC_SD_IRQS_1) + +/**@} */ + +/**@} */ + +/**@addtogroup NRF_NVIC_VARIABLES Variables + * @{ */ + +/**@brief Type representing the state struct for the SoftDevice NVIC module. */ +typedef struct { + uint32_t volatile __irq_masks[__NRF_NVIC_ISER_COUNT]; /**< IRQs enabled by the application in the NVIC. */ + uint32_t volatile __cr_flag; /**< Non-zero if already in a critical region */ +} nrf_nvic_state_t; + +/**@brief Variable keeping the state for the SoftDevice NVIC module. This must be declared in an + * application source file. */ +extern nrf_nvic_state_t nrf_nvic_state; + +/**@} */ + +/**@addtogroup NRF_NVIC_INTERNAL_FUNCTIONS SoftDevice NVIC internal functions + * @{ */ + +/**@brief Disables IRQ interrupts globally, including the SoftDevice's interrupts. + * + * @retval The value of PRIMASK prior to disabling the interrupts. + */ +__STATIC_INLINE int __sd_nvic_irq_disable(void); + +/**@brief Enables IRQ interrupts globally, including the SoftDevice's interrupts. + */ +__STATIC_INLINE void __sd_nvic_irq_enable(void); + +/**@brief Checks if IRQn is available to application + * @param[in] IRQn IRQ to check + * + * @retval 1 (true) if the IRQ to check is available to the application + */ +__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn); + +/**@brief Checks if priority is available to application + * @param[in] priority priority to check + * + * @retval 1 (true) if the priority to check is available to the application + */ +__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority); + +/**@} */ + +/**@addtogroup NRF_NVIC_FUNCTIONS SoftDevice NVIC public functions + * @{ */ + +/**@brief Enable External Interrupt. + * @note Corresponds to NVIC_EnableIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_EnableIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt was enabled. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt has a priority not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn); + +/**@brief Disable External Interrupt. + * @note Corresponds to NVIC_DisableIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_DisableIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt was disabled. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn); + +/**@brief Get Pending Interrupt. + * @note Corresponds to NVIC_GetPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_GetPendingIRQ documentation in CMSIS. + * @param[out] p_pending_irq Return value from NVIC_GetPendingIRQ. + * + * @retval ::NRF_SUCCESS The interrupt is available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq); + +/**@brief Set Pending Interrupt. + * @note Corresponds to NVIC_SetPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_SetPendingIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt is set pending. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn); + +/**@brief Clear Pending Interrupt. + * @note Corresponds to NVIC_ClearPendingIRQ in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_ClearPendingIRQ documentation in CMSIS. + * + * @retval ::NRF_SUCCESS The interrupt pending flag is cleared. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn); + +/**@brief Set Interrupt Priority. + * @note Corresponds to NVIC_SetPriority in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * @pre Priority is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_SetPriority documentation in CMSIS. + * @param[in] priority A valid IRQ priority for use by the application. + * + * @retval ::NRF_SUCCESS The interrupt and priority level is available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt priority is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority); + +/**@brief Get Interrupt Priority. + * @note Corresponds to NVIC_GetPriority in CMSIS. + * + * @pre IRQn is valid and not reserved by the stack. + * + * @param[in] IRQn See the NVIC_GetPriority documentation in CMSIS. + * @param[out] p_priority Return value from NVIC_GetPriority. + * + * @retval ::NRF_SUCCESS The interrupt priority is returned in p_priority. + * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE - IRQn is not available for the application. + */ +__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority); + +/**@brief System Reset. + * @note Corresponds to NVIC_SystemReset in CMSIS. + * + * @retval ::NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN + */ +__STATIC_INLINE uint32_t sd_nvic_SystemReset(void); + +/**@brief Enter critical region. + * + * @post Application interrupts will be disabled. + * @note sd_nvic_critical_region_enter() and ::sd_nvic_critical_region_exit() must be called in matching pairs inside each + * execution context + * @sa sd_nvic_critical_region_exit + * + * @param[out] p_is_nested_critical_region If 1, the application is now in a nested critical region. + * + * @retval ::NRF_SUCCESS + */ +__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region); + +/**@brief Exit critical region. + * + * @pre Application has entered a critical region using ::sd_nvic_critical_region_enter. + * @post If not in a nested critical region, the application interrupts will restored to the state before + * ::sd_nvic_critical_region_enter was called. + * + * @param[in] is_nested_critical_region If this is set to 1, the critical region won't be exited. @sa + * sd_nvic_critical_region_enter. + * + * @retval ::NRF_SUCCESS + */ +__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region); + +/**@} */ + +#ifndef SUPPRESS_INLINE_IMPLEMENTATION + +__STATIC_INLINE int __sd_nvic_irq_disable(void) +{ + int pm = __get_PRIMASK(); + __disable_irq(); + return pm; +} + +__STATIC_INLINE void __sd_nvic_irq_enable(void) +{ + __enable_irq(); +} + +__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn) +{ + if (IRQn < 32) { + return ((1UL << IRQn) & __NRF_NVIC_APP_IRQS_0) != 0; + } else if (IRQn < 64) { + return ((1UL << (IRQn - 32)) & __NRF_NVIC_APP_IRQS_1) != 0; + } else { + return 1; + } +} + +__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority) +{ + if ((priority >= (1 << __NVIC_PRIO_BITS)) || (((1 << priority) & __NRF_NVIC_APP_IRQ_PRIOS) == 0)) { + return 0; + } + return 1; +} + +__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + if (!__sd_nvic_is_app_accessible_priority(NVIC_GetPriority(IRQn))) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; + } + + if (nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] |= + (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F)); + } else { + NVIC_EnableIRQ(IRQn); + } + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + + if (nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] &= ~(1UL << ((uint32_t)(IRQn)&0x1F)); + } else { + NVIC_DisableIRQ(IRQn); + } + + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + *p_pending_irq = NVIC_GetPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + NVIC_SetPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + NVIC_ClearPendingIRQ(IRQn); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if (!__sd_nvic_app_accessible_irq(IRQn)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } + + if (!__sd_nvic_is_app_accessible_priority(priority)) { + return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; + } + + NVIC_SetPriority(IRQn, (uint32_t)priority); + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority) +{ + if (__sd_nvic_app_accessible_irq(IRQn)) { + *p_priority = (NVIC_GetPriority(IRQn) & 0xFF); + return NRF_SUCCESS; + } else { + return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; + } +} + +__STATIC_INLINE uint32_t sd_nvic_SystemReset(void) +{ + NVIC_SystemReset(); + return NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN; +} + +__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region) +{ + int was_masked = __sd_nvic_irq_disable(); + if (!nrf_nvic_state.__cr_flag) { + nrf_nvic_state.__cr_flag = 1; + nrf_nvic_state.__irq_masks[0] = (NVIC->ICER[0] & __NRF_NVIC_APP_IRQS_0); + NVIC->ICER[0] = __NRF_NVIC_APP_IRQS_0; + nrf_nvic_state.__irq_masks[1] = (NVIC->ICER[1] & __NRF_NVIC_APP_IRQS_1); + NVIC->ICER[1] = __NRF_NVIC_APP_IRQS_1; + *p_is_nested_critical_region = 0; + } else { + *p_is_nested_critical_region = 1; + } + if (!was_masked) { + __sd_nvic_irq_enable(); + } + return NRF_SUCCESS; +} + +__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region) +{ + if (nrf_nvic_state.__cr_flag && (is_nested_critical_region == 0)) { + int was_masked = __sd_nvic_irq_disable(); + NVIC->ISER[0] = nrf_nvic_state.__irq_masks[0]; + NVIC->ISER[1] = nrf_nvic_state.__irq_masks[1]; + nrf_nvic_state.__cr_flag = 0; + if (!was_masked) { + __sd_nvic_irq_enable(); + } + } + + return NRF_SUCCESS; +} + +#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ + +#ifdef __cplusplus +} +#endif + +#endif // NRF_NVIC_H__ + +/**@} */ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h b/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h new file mode 100644 index 0000000000..2786a86a45 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h @@ -0,0 +1,380 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + @defgroup nrf_sdm_api SoftDevice Manager API + @{ + + @brief APIs for SoftDevice management. + +*/ + +#ifndef NRF_SDM_H__ +#define NRF_SDM_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_sdm.h" +#include "nrf_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @addtogroup NRF_SDM_DEFINES Defines + * @{ */ +#ifdef NRFSOC_DOXYGEN +/// Declared in nrf_mbr.h +#define MBR_SIZE 0 +#warning test +#endif + +/** @brief The major version for the SoftDevice binary distributed with this header file. */ +#define SD_MAJOR_VERSION (7) + +/** @brief The minor version for the SoftDevice binary distributed with this header file. */ +#define SD_MINOR_VERSION (3) + +/** @brief The bugfix version for the SoftDevice binary distributed with this header file. */ +#define SD_BUGFIX_VERSION (0) + +/** @brief The SoftDevice variant of this firmware. */ +#define SD_VARIANT_ID 140 + +/** @brief The full version number for the SoftDevice binary this header file was distributed + * with, as a decimal number in the form Mmmmbbb, where: + * - M is major version (one or more digits) + * - mmm is minor version (three digits) + * - bbb is bugfix version (three digits). */ +#define SD_VERSION (SD_MAJOR_VERSION * 1000000 + SD_MINOR_VERSION * 1000 + SD_BUGFIX_VERSION) + +/** @brief SoftDevice Manager SVC Base number. */ +#define SDM_SVC_BASE 0x10 + +/** @brief SoftDevice unique string size in bytes. */ +#define SD_UNIQUE_STR_SIZE 20 + +/** @brief Invalid info field. Returned when an info field does not exist. */ +#define SDM_INFO_FIELD_INVALID (0) + +/** @brief Defines the SoftDevice Information Structure location (address) as an offset from +the start of the SoftDevice (without MBR)*/ +#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000) + +/** @brief Defines the absolute SoftDevice Information Structure location (address) when the + * SoftDevice is installed just above the MBR (the usual case). */ +#define SOFTDEVICE_INFO_STRUCT_ADDRESS (SOFTDEVICE_INFO_STRUCT_OFFSET + MBR_SIZE) + +/** @brief Defines the offset for the SoftDevice Information Structure size value relative to the + * SoftDevice base address. The size value is of type uint8_t. */ +#define SD_INFO_STRUCT_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET) + +/** @brief Defines the offset for the SoftDevice size value relative to the SoftDevice base address. + * The size value is of type uint32_t. */ +#define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08) + +/** @brief Defines the offset for FWID value relative to the SoftDevice base address. The FWID value + * is of type uint16_t. */ +#define SD_FWID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x0C) + +/** @brief Defines the offset for the SoftDevice ID relative to the SoftDevice base address. The ID + * is of type uint32_t. */ +#define SD_ID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x10) + +/** @brief Defines the offset for the SoftDevice version relative to the SoftDevice base address in + * the same format as @ref SD_VERSION, stored as an uint32_t. */ +#define SD_VERSION_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x14) + +/** @brief Defines the offset for the SoftDevice unique string relative to the SoftDevice base address. + * The SD_UNIQUE_STR is stored as an array of uint8_t. The size of array is @ref SD_UNIQUE_STR_SIZE. + */ +#define SD_UNIQUE_STR_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x18) + +/** @brief Defines a macro for retrieving the actual SoftDevice Information Structure size value + * from a given base address. Use @ref MBR_SIZE as the argument when the SoftDevice is + * installed just above the MBR (the usual case). */ +#define SD_INFO_STRUCT_SIZE_GET(baseaddr) (*((uint8_t *)((baseaddr) + SD_INFO_STRUCT_SIZE_OFFSET))) + +/** @brief Defines a macro for retrieving the actual SoftDevice size value from a given base + * address. Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above + * the MBR (the usual case). */ +#define SD_SIZE_GET(baseaddr) (*((uint32_t *)((baseaddr) + SD_SIZE_OFFSET))) + +/** @brief Defines the amount of flash that is used by the SoftDevice. + * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed + * just above the MBR (the usual case). + */ +#define SD_FLASH_SIZE 0x26000 + +/** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use + * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual + * case). */ +#define SD_FWID_GET(baseaddr) (*((uint16_t *)((baseaddr) + SD_FWID_OFFSET))) + +/** @brief Defines a macro for retrieving the actual SoftDevice ID from a given base address. Use + * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the + * usual case). */ +#define SD_ID_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_ID_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (*((uint32_t *)((baseaddr) + SD_ID_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/** @brief Defines a macro for retrieving the actual SoftDevice version from a given base address. + * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR + * (the usual case). */ +#define SD_VERSION_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_VERSION_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (*((uint32_t *)((baseaddr) + SD_VERSION_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/** @brief Defines a macro for retrieving the address of SoftDevice unique str based on a given base address. + * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR + * (the usual case). */ +#define SD_UNIQUE_STR_ADDR_GET(baseaddr) \ + ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_UNIQUE_STR_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ + ? (((uint8_t *)((baseaddr) + SD_UNIQUE_STR_OFFSET))) \ + : SDM_INFO_FIELD_INVALID) + +/**@defgroup NRF_FAULT_ID_RANGES Fault ID ranges + * @{ */ +#define NRF_FAULT_ID_SD_RANGE_START 0x00000000 /**< SoftDevice ID range start. */ +#define NRF_FAULT_ID_APP_RANGE_START 0x00001000 /**< Application ID range start. */ +/**@} */ + +/**@defgroup NRF_FAULT_IDS Fault ID types + * @{ */ +#define NRF_FAULT_ID_SD_ASSERT \ + (NRF_FAULT_ID_SD_RANGE_START + 1) /**< SoftDevice assertion. The info parameter is reserved for future used. */ +#define NRF_FAULT_ID_APP_MEMACC \ + (NRF_FAULT_ID_APP_RANGE_START + 1) /**< Application invalid memory access. The info parameter will contain 0x00000000, \ + in case of SoftDevice RAM access violation. In case of SoftDevice peripheral \ + register violation the info parameter will contain the sub-region number of \ + PREGION[0], on whose address range the disallowed write access caused the \ + memory access fault. */ +/**@} */ + +/** @} */ + +/** @addtogroup NRF_SDM_ENUMS Enumerations + * @{ */ + +/**@brief nRF SoftDevice Manager API SVC numbers. */ +enum NRF_SD_SVCS { + SD_SOFTDEVICE_ENABLE = SDM_SVC_BASE, /**< ::sd_softdevice_enable */ + SD_SOFTDEVICE_DISABLE, /**< ::sd_softdevice_disable */ + SD_SOFTDEVICE_IS_ENABLED, /**< ::sd_softdevice_is_enabled */ + SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, /**< ::sd_softdevice_vector_table_base_set */ + SVC_SDM_LAST /**< Placeholder for last SDM SVC */ +}; + +/** @} */ + +/** @addtogroup NRF_SDM_DEFINES Defines + * @{ */ + +/**@defgroup NRF_CLOCK_LF_ACCURACY Clock accuracy + * @{ */ + +#define NRF_CLOCK_LF_ACCURACY_250_PPM (0) /**< Default: 250 ppm */ +#define NRF_CLOCK_LF_ACCURACY_500_PPM (1) /**< 500 ppm */ +#define NRF_CLOCK_LF_ACCURACY_150_PPM (2) /**< 150 ppm */ +#define NRF_CLOCK_LF_ACCURACY_100_PPM (3) /**< 100 ppm */ +#define NRF_CLOCK_LF_ACCURACY_75_PPM (4) /**< 75 ppm */ +#define NRF_CLOCK_LF_ACCURACY_50_PPM (5) /**< 50 ppm */ +#define NRF_CLOCK_LF_ACCURACY_30_PPM (6) /**< 30 ppm */ +#define NRF_CLOCK_LF_ACCURACY_20_PPM (7) /**< 20 ppm */ +#define NRF_CLOCK_LF_ACCURACY_10_PPM (8) /**< 10 ppm */ +#define NRF_CLOCK_LF_ACCURACY_5_PPM (9) /**< 5 ppm */ +#define NRF_CLOCK_LF_ACCURACY_2_PPM (10) /**< 2 ppm */ +#define NRF_CLOCK_LF_ACCURACY_1_PPM (11) /**< 1 ppm */ + +/** @} */ + +/**@defgroup NRF_CLOCK_LF_SRC Possible LFCLK oscillator sources + * @{ */ + +#define NRF_CLOCK_LF_SRC_RC (0) /**< LFCLK RC oscillator. */ +#define NRF_CLOCK_LF_SRC_XTAL (1) /**< LFCLK crystal oscillator. */ +#define NRF_CLOCK_LF_SRC_SYNTH (2) /**< LFCLK Synthesized from HFCLK. */ + +/** @} */ + +/** @} */ + +/** @addtogroup NRF_SDM_TYPES Types + * @{ */ + +/**@brief Type representing LFCLK oscillator source. */ +typedef struct { + uint8_t source; /**< LF oscillator clock source, see @ref NRF_CLOCK_LF_SRC. */ + uint8_t rc_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: Calibration timer interval in 1/4 second + units (nRF52: 1-32). + @note To avoid excessive clock drift, 0.5 degrees Celsius is the + maximum temperature change allowed in one calibration timer + interval. The interval should be selected to ensure this. + + @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. */ + uint8_t rc_temp_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: How often (in number of calibration + intervals) the RC oscillator shall be calibrated if the temperature + hasn't changed. + 0: Always calibrate even if the temperature hasn't changed. + 1: Only calibrate if the temperature has changed (legacy - nRF51 only). + 2-33: Check the temperature and only calibrate if it has changed, + however calibration will take place every rc_temp_ctiv + intervals in any case. + + @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. + + @note For nRF52, the application must ensure calibration at least once + every 8 seconds to ensure +/-500 ppm clock stability. The + recommended configuration for ::NRF_CLOCK_LF_SRC_RC on nRF52 is + rc_ctiv=16 and rc_temp_ctiv=2. This will ensure calibration at + least once every 8 seconds and for temperature changes of 0.5 + degrees Celsius every 4 seconds. See the Product Specification + for the nRF52 device being used for more information.*/ + uint8_t accuracy; /**< External clock accuracy used in the LL to compute timing + windows, see @ref NRF_CLOCK_LF_ACCURACY.*/ +} nrf_clock_lf_cfg_t; + +/**@brief Fault Handler type. + * + * When certain unrecoverable errors occur within the application or SoftDevice the fault handler will be called back. + * The protocol stack will be in an undefined state when this happens and the only way to recover will be to + * perform a reset, using e.g. CMSIS NVIC_SystemReset(). + * If the application returns from the fault handler the SoftDevice will call NVIC_SystemReset(). + * + * @note It is recommended to either perform a reset in the fault handler or to let the SoftDevice reset the device. + * Otherwise SoC peripherals may behave in an undefined way. For example, the RADIO peripherial may + * continously transmit packets. + * + * @note This callback is executed in HardFault context, thus SVC functions cannot be called from the fault callback. + * + * @param[in] id Fault identifier. See @ref NRF_FAULT_IDS. + * @param[in] pc The program counter of the instruction that triggered the fault. + * @param[in] info Optional additional information regarding the fault. Refer to each Fault identifier for details. + * + * @note When id is set to @ref NRF_FAULT_ID_APP_MEMACC, pc will contain the address of the instruction being executed at the time + * when the fault is detected by the CPU. The CPU program counter may have advanced up to 2 instructions (no branching) after the + * one that triggered the fault. + */ +typedef void (*nrf_fault_handler_t)(uint32_t id, uint32_t pc, uint32_t info); + +/** @} */ + +/** @addtogroup NRF_SDM_FUNCTIONS Functions + * @{ */ + +/**@brief Enables the SoftDevice and by extension the protocol stack. + * + * @note Some care must be taken if a low frequency clock source is already running when calling this function: + * If the LF clock has a different source then the one currently running, it will be stopped. Then, the new + * clock source will be started. + * + * @note This function has no effect when returning with an error. + * + * @post If return code is ::NRF_SUCCESS + * - SoC library and protocol stack APIs are made available. + * - A portion of RAM will be unavailable (see relevant SDS documentation). + * - Some peripherals will be unavailable or available only through the SoC API (see relevant SDS documentation). + * - Interrupts will not arrive from protected peripherals or interrupts. + * - nrf_nvic_ functions must be used instead of CMSIS NVIC_ functions for reliable usage of the SoftDevice. + * - Interrupt latency may be affected by the SoftDevice (see relevant SDS documentation). + * - Chosen low frequency clock source will be running. + * + * @param p_clock_lf_cfg Low frequency clock source and accuracy. + If NULL the clock will be configured as an RC source with rc_ctiv = 16 and .rc_temp_ctiv = 2 + In the case of XTAL source, the PPM accuracy of the chosen clock source must be greater than or equal to + the actual characteristics of your XTAL clock. + * @param fault_handler Callback to be invoked in case of fault, cannot be NULL. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. + * @retval ::NRF_ERROR_INVALID_STATE SoftDevice is already enabled, and the clock source and fault handler cannot be updated. + * @retval ::NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION SoftDevice interrupt is already enabled, or an enabled interrupt has + an illegal priority level. + * @retval ::NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN Unknown low frequency clock source selected. + * @retval ::NRF_ERROR_INVALID_PARAM Invalid clock source configuration supplied in p_clock_lf_cfg. + */ +SVCALL(SD_SOFTDEVICE_ENABLE, uint32_t, + sd_softdevice_enable(nrf_clock_lf_cfg_t const *p_clock_lf_cfg, nrf_fault_handler_t fault_handler)); + +/**@brief Disables the SoftDevice and by extension the protocol stack. + * + * Idempotent function to disable the SoftDevice. + * + * @post SoC library and protocol stack APIs are made unavailable. + * @post All interrupts that was protected by the SoftDevice will be disabled and initialized to priority 0 (highest). + * @post All peripherals used by the SoftDevice will be reset to default values. + * @post All of RAM become available. + * @post All interrupts are forwarded to the application. + * @post LFCLK source chosen in ::sd_softdevice_enable will be left running. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_DISABLE, uint32_t, sd_softdevice_disable(void)); + +/**@brief Check if the SoftDevice is enabled. + * + * @param[out] p_softdevice_enabled If the SoftDevice is enabled: 1 else 0. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_IS_ENABLED, uint32_t, sd_softdevice_is_enabled(uint8_t *p_softdevice_enabled)); + +/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the SoftDevice + * + * This function is only intended to be called when a bootloader is enabled. + * + * @param[in] address The base address of the interrupt vector table for forwarded interrupts. + + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table_base_set(uint32_t address)); + +/** @} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_SDM_H__ + +/** + @} +*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_soc.h b/variants/wio-tracker-wm1110/softdevice/nrf_soc.h new file mode 100644 index 0000000000..c649ca836d --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_soc.h @@ -0,0 +1,1046 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup nrf_soc_api SoC Library API + * @{ + * + * @brief APIs for the SoC library. + * + */ + +#ifndef NRF_SOC_H__ +#define NRF_SOC_H__ + +#include "nrf.h" +#include "nrf_error.h" +#include "nrf_error_soc.h" +#include "nrf_svc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/**@addtogroup NRF_SOC_DEFINES Defines + * @{ */ + +/**@brief The number of the lowest SVC number reserved for the SoC library. */ +#define SOC_SVC_BASE (0x20) /**< Base value for SVCs that are available when the SoftDevice is disabled. */ +#define SOC_SVC_BASE_NOT_AVAILABLE (0x2C) /**< Base value for SVCs that are not available when the SoftDevice is disabled. */ + +/**@brief Guaranteed time for application to process radio inactive notification. */ +#define NRF_RADIO_NOTIFICATION_INACTIVE_GUARANTEED_TIME_US (62) + +/**@brief The minimum allowed timeslot extension time. */ +#define NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US (200) + +/**@brief The maximum processing time to handle a timeslot extension. */ +#define NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US (20) + +/**@brief The latest time before the end of a timeslot the timeslot can be extended. */ +#define NRF_RADIO_MIN_EXTENSION_MARGIN_US (82) + +#define SOC_ECB_KEY_LENGTH (16) /**< ECB key length. */ +#define SOC_ECB_CLEARTEXT_LENGTH (16) /**< ECB cleartext length. */ +#define SOC_ECB_CIPHERTEXT_LENGTH (SOC_ECB_CLEARTEXT_LENGTH) /**< ECB ciphertext length. */ + +#define SD_EVT_IRQn (SWI2_IRQn) /**< SoftDevice Event IRQ number. Used for both protocol events and SoC events. */ +#define SD_EVT_IRQHandler \ + (SWI2_IRQHandler) /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. \ + The default interrupt priority for this handler is set to 6 */ +#define RADIO_NOTIFICATION_IRQn (SWI1_IRQn) /**< The radio notification IRQ number. */ +#define RADIO_NOTIFICATION_IRQHandler \ + (SWI1_IRQHandler) /**< The radio notification IRQ handler. \ + The default interrupt priority for this handler is set to 6 */ +#define NRF_RADIO_LENGTH_MIN_US (100) /**< The shortest allowed radio timeslot, in microseconds. */ +#define NRF_RADIO_LENGTH_MAX_US (100000) /**< The longest allowed radio timeslot, in microseconds. */ + +#define NRF_RADIO_DISTANCE_MAX_US \ + (128000000UL - 1UL) /**< The longest timeslot distance, in microseconds, allowed for the distance parameter (see @ref \ + nrf_radio_request_normal_t) in the request. */ + +#define NRF_RADIO_EARLIEST_TIMEOUT_MAX_US \ + (128000000UL - 1UL) /**< The longest timeout, in microseconds, allowed when requesting the earliest possible timeslot. */ + +#define NRF_RADIO_START_JITTER_US \ + (2) /**< The maximum jitter in @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START relative to the requested start time. */ + +/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is disabled. */ +#define NRF_SOC_SD_PPI_CHANNELS_SD_DISABLED_MSK ((uint32_t)(0)) + +/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is enabled. */ +#define NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK \ + ((uint32_t)((1U << 17) | (1U << 18) | (1U << 19) | (1U << 20) | (1U << 21) | (1U << 22) | (1U << 23) | (1U << 24) | \ + (1U << 25) | (1U << 26) | (1U << 27) | (1U << 28) | (1U << 29) | (1U << 30) | (1U << 31))) + +/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is disabled. */ +#define NRF_SOC_SD_PPI_GROUPS_SD_DISABLED_MSK ((uint32_t)(0)) + +/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is enabled. */ +#define NRF_SOC_SD_PPI_GROUPS_SD_ENABLED_MSK ((uint32_t)((1U << 4) | (1U << 5))) + +/**@} */ + +/**@addtogroup NRF_SOC_ENUMS Enumerations + * @{ */ + +/**@brief The SVC numbers used by the SVC functions in the SoC library. */ +enum NRF_SOC_SVCS { + SD_PPI_CHANNEL_ENABLE_GET = SOC_SVC_BASE, + SD_PPI_CHANNEL_ENABLE_SET = SOC_SVC_BASE + 1, + SD_PPI_CHANNEL_ENABLE_CLR = SOC_SVC_BASE + 2, + SD_PPI_CHANNEL_ASSIGN = SOC_SVC_BASE + 3, + SD_PPI_GROUP_TASK_ENABLE = SOC_SVC_BASE + 4, + SD_PPI_GROUP_TASK_DISABLE = SOC_SVC_BASE + 5, + SD_PPI_GROUP_ASSIGN = SOC_SVC_BASE + 6, + SD_PPI_GROUP_GET = SOC_SVC_BASE + 7, + SD_FLASH_PAGE_ERASE = SOC_SVC_BASE + 8, + SD_FLASH_WRITE = SOC_SVC_BASE + 9, + SD_PROTECTED_REGISTER_WRITE = SOC_SVC_BASE + 11, + SD_MUTEX_NEW = SOC_SVC_BASE_NOT_AVAILABLE, + SD_MUTEX_ACQUIRE = SOC_SVC_BASE_NOT_AVAILABLE + 1, + SD_MUTEX_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 2, + SD_RAND_APPLICATION_POOL_CAPACITY_GET = SOC_SVC_BASE_NOT_AVAILABLE + 3, + SD_RAND_APPLICATION_BYTES_AVAILABLE_GET = SOC_SVC_BASE_NOT_AVAILABLE + 4, + SD_RAND_APPLICATION_VECTOR_GET = SOC_SVC_BASE_NOT_AVAILABLE + 5, + SD_POWER_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 6, + SD_POWER_SYSTEM_OFF = SOC_SVC_BASE_NOT_AVAILABLE + 7, + SD_POWER_RESET_REASON_GET = SOC_SVC_BASE_NOT_AVAILABLE + 8, + SD_POWER_RESET_REASON_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 9, + SD_POWER_POF_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 10, + SD_POWER_POF_THRESHOLD_SET = SOC_SVC_BASE_NOT_AVAILABLE + 11, + SD_POWER_POF_THRESHOLDVDDH_SET = SOC_SVC_BASE_NOT_AVAILABLE + 12, + SD_POWER_RAM_POWER_SET = SOC_SVC_BASE_NOT_AVAILABLE + 13, + SD_POWER_RAM_POWER_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 14, + SD_POWER_RAM_POWER_GET = SOC_SVC_BASE_NOT_AVAILABLE + 15, + SD_POWER_GPREGRET_SET = SOC_SVC_BASE_NOT_AVAILABLE + 16, + SD_POWER_GPREGRET_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 17, + SD_POWER_GPREGRET_GET = SOC_SVC_BASE_NOT_AVAILABLE + 18, + SD_POWER_DCDC_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 19, + SD_POWER_DCDC0_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 20, + SD_APP_EVT_WAIT = SOC_SVC_BASE_NOT_AVAILABLE + 21, + SD_CLOCK_HFCLK_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 22, + SD_CLOCK_HFCLK_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 23, + SD_CLOCK_HFCLK_IS_RUNNING = SOC_SVC_BASE_NOT_AVAILABLE + 24, + SD_RADIO_NOTIFICATION_CFG_SET = SOC_SVC_BASE_NOT_AVAILABLE + 25, + SD_ECB_BLOCK_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 26, + SD_ECB_BLOCKS_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 27, + SD_RADIO_SESSION_OPEN = SOC_SVC_BASE_NOT_AVAILABLE + 28, + SD_RADIO_SESSION_CLOSE = SOC_SVC_BASE_NOT_AVAILABLE + 29, + SD_RADIO_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 30, + SD_EVT_GET = SOC_SVC_BASE_NOT_AVAILABLE + 31, + SD_TEMP_GET = SOC_SVC_BASE_NOT_AVAILABLE + 32, + SD_POWER_USBPWRRDY_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 33, + SD_POWER_USBDETECTED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 34, + SD_POWER_USBREMOVED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 35, + SD_POWER_USBREGSTATUS_GET = SOC_SVC_BASE_NOT_AVAILABLE + 36, + SVC_SOC_LAST = SOC_SVC_BASE_NOT_AVAILABLE + 37 +}; + +/**@brief Possible values of a ::nrf_mutex_t. */ +enum NRF_MUTEX_VALUES { NRF_MUTEX_FREE, NRF_MUTEX_TAKEN }; + +/**@brief Power modes. */ +enum NRF_POWER_MODES { + NRF_POWER_MODE_CONSTLAT, /**< Constant latency mode. See power management in the reference manual. */ + NRF_POWER_MODE_LOWPWR /**< Low power mode. See power management in the reference manual. */ +}; + +/**@brief Power failure thresholds */ +enum NRF_POWER_THRESHOLDS { + NRF_POWER_THRESHOLD_V17 = 4UL, /**< 1.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V18, /**< 1.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V19, /**< 1.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V20, /**< 2.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V21, /**< 2.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V22, /**< 2.2 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V23, /**< 2.3 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V24, /**< 2.4 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V25, /**< 2.5 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V26, /**< 2.6 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V27, /**< 2.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLD_V28 /**< 2.8 Volts power failure threshold. */ +}; + +/**@brief Power failure thresholds for high voltage */ +enum NRF_POWER_THRESHOLDVDDHS { + NRF_POWER_THRESHOLDVDDH_V27, /**< 2.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V28, /**< 2.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V29, /**< 2.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V30, /**< 3.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V31, /**< 3.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V32, /**< 3.2 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V33, /**< 3.3 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V34, /**< 3.4 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V35, /**< 3.5 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V36, /**< 3.6 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V37, /**< 3.7 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V38, /**< 3.8 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V39, /**< 3.9 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V40, /**< 4.0 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V41, /**< 4.1 Volts power failure threshold. */ + NRF_POWER_THRESHOLDVDDH_V42 /**< 4.2 Volts power failure threshold. */ +}; + +/**@brief DC/DC converter modes. */ +enum NRF_POWER_DCDC_MODES { + NRF_POWER_DCDC_DISABLE, /**< The DCDC is disabled. */ + NRF_POWER_DCDC_ENABLE /**< The DCDC is enabled. */ +}; + +/**@brief Radio notification distances. */ +enum NRF_RADIO_NOTIFICATION_DISTANCES { + NRF_RADIO_NOTIFICATION_DISTANCE_NONE = 0, /**< The event does not have a notification. */ + NRF_RADIO_NOTIFICATION_DISTANCE_800US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_1740US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_2680US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_3620US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_4560US, /**< The distance from the active notification to start of radio activity. */ + NRF_RADIO_NOTIFICATION_DISTANCE_5500US /**< The distance from the active notification to start of radio activity. */ +}; + +/**@brief Radio notification types. */ +enum NRF_RADIO_NOTIFICATION_TYPES { + NRF_RADIO_NOTIFICATION_TYPE_NONE = 0, /**< The event does not have a radio notification signal. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, /**< Using interrupt for notification when the radio will be enabled. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, /**< Using interrupt for notification when the radio has been disabled. */ + NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, /**< Using interrupt for notification both when the radio will be enabled and + disabled. */ +}; + +/**@brief The Radio signal callback types. */ +enum NRF_RADIO_CALLBACK_SIGNAL_TYPE { + NRF_RADIO_CALLBACK_SIGNAL_TYPE_START, /**< This signal indicates the start of the radio timeslot. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0, /**< This signal indicates the NRF_TIMER0 interrupt. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO, /**< This signal indicates the NRF_RADIO interrupt. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED, /**< This signal indicates extend action failed. */ + NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED /**< This signal indicates extend action succeeded. */ +}; + +/**@brief The actions requested by the signal callback. + * + * This code gives the SOC instructions about what action to take when the signal callback has + * returned. + */ +enum NRF_RADIO_SIGNAL_CALLBACK_ACTION { + NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE, /**< Return without action. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND, /**< Request an extension of the current + timeslot. Maximum execution time for this action: + @ref NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US. + This action must be started at least + @ref NRF_RADIO_MIN_EXTENSION_MARGIN_US before + the end of the timeslot. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_END, /**< End the current radio timeslot. */ + NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END /**< Request a new radio timeslot and end the current timeslot. */ +}; + +/**@brief Radio timeslot high frequency clock source configuration. */ +enum NRF_RADIO_HFCLK_CFG { + NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED, /**< The SoftDevice will guarantee that the high frequency clock source is the + external crystal for the whole duration of the timeslot. This should be the + preferred option for events that use the radio or require high timing accuracy. + @note The SoftDevice will automatically turn on and off the external crystal, + at the beginning and end of the timeslot, respectively. The crystal may also + intentionally be left running after the timeslot, in cases where it is needed + by the SoftDevice shortly after the end of the timeslot. */ + NRF_RADIO_HFCLK_CFG_NO_GUARANTEE /**< This configuration allows for earlier and tighter scheduling of timeslots. + The RC oscillator may be the clock source in part or for the whole duration of the + timeslot. The RC oscillator's accuracy must therefore be taken into consideration. + @note If the application will use the radio peripheral in timeslots with this + configuration, it must make sure that the crystal is running and stable before + starting the radio. */ +}; + +/**@brief Radio timeslot priorities. */ +enum NRF_RADIO_PRIORITY { + NRF_RADIO_PRIORITY_HIGH, /**< High (equal priority as the normal connection priority of the SoftDevice stack(s)). */ + NRF_RADIO_PRIORITY_NORMAL, /**< Normal (equal priority as the priority of secondary activities of the SoftDevice stack(s)). */ +}; + +/**@brief Radio timeslot request type. */ +enum NRF_RADIO_REQUEST_TYPE { + NRF_RADIO_REQ_TYPE_EARLIEST, /**< Request radio timeslot as early as possible. This should always be used for the first + request in a session. */ + NRF_RADIO_REQ_TYPE_NORMAL /**< Normal radio timeslot request. */ +}; + +/**@brief SoC Events. */ +enum NRF_SOC_EVTS { + NRF_EVT_HFCLKSTARTED, /**< Event indicating that the HFCLK has started. */ + NRF_EVT_POWER_FAILURE_WARNING, /**< Event indicating that a power failure warning has occurred. */ + NRF_EVT_FLASH_OPERATION_SUCCESS, /**< Event indicating that the ongoing flash operation has completed successfully. */ + NRF_EVT_FLASH_OPERATION_ERROR, /**< Event indicating that the ongoing flash operation has timed out with an error. */ + NRF_EVT_RADIO_BLOCKED, /**< Event indicating that a radio timeslot was blocked. */ + NRF_EVT_RADIO_CANCELED, /**< Event indicating that a radio timeslot was canceled by SoftDevice. */ + NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN, /**< Event indicating that a radio timeslot signal callback handler return was + invalid. */ + NRF_EVT_RADIO_SESSION_IDLE, /**< Event indicating that a radio timeslot session is idle. */ + NRF_EVT_RADIO_SESSION_CLOSED, /**< Event indicating that a radio timeslot session is closed. */ + NRF_EVT_POWER_USB_POWER_READY, /**< Event indicating that a USB 3.3 V supply is ready. */ + NRF_EVT_POWER_USB_DETECTED, /**< Event indicating that voltage supply is detected on VBUS. */ + NRF_EVT_POWER_USB_REMOVED, /**< Event indicating that voltage supply is removed from VBUS. */ + NRF_EVT_NUMBER_OF_EVTS +}; + +/**@} */ + +/**@addtogroup NRF_SOC_STRUCTURES Structures + * @{ */ + +/**@brief Represents a mutex for use with the nrf_mutex functions. + * @note Accessing the value directly is not safe, use the mutex functions! + */ +typedef volatile uint8_t nrf_mutex_t; + +/**@brief Parameters for a request for a timeslot as early as possible. */ +typedef struct { + uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ + uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ + uint32_t length_us; /**< The radio timeslot length (in the range 100 to 100,000] microseconds). */ + uint32_t timeout_us; /**< Longest acceptable delay until the start of the requested timeslot (up to @ref + NRF_RADIO_EARLIEST_TIMEOUT_MAX_US microseconds). */ +} nrf_radio_request_earliest_t; + +/**@brief Parameters for a normal radio timeslot request. */ +typedef struct { + uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ + uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ + uint32_t distance_us; /**< Distance from the start of the previous radio timeslot (up to @ref NRF_RADIO_DISTANCE_MAX_US + microseconds). */ + uint32_t length_us; /**< The radio timeslot length (in the range [100..100,000] microseconds). */ +} nrf_radio_request_normal_t; + +/**@brief Radio timeslot request parameters. */ +typedef struct { + uint8_t request_type; /**< Type of request, see @ref NRF_RADIO_REQUEST_TYPE. */ + union { + nrf_radio_request_earliest_t earliest; /**< Parameters for requesting a radio timeslot as early as possible. */ + nrf_radio_request_normal_t normal; /**< Parameters for requesting a normal radio timeslot. */ + } params; /**< Parameter union. */ +} nrf_radio_request_t; + +/**@brief Return parameters of the radio timeslot signal callback. */ +typedef struct { + uint8_t callback_action; /**< The action requested by the application when returning from the signal callback, see @ref + NRF_RADIO_SIGNAL_CALLBACK_ACTION. */ + union { + struct { + nrf_radio_request_t *p_next; /**< The request parameters for the next radio timeslot. */ + } request; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END. */ + struct { + uint32_t length_us; /**< Requested extension of the radio timeslot duration (microseconds) (for minimum time see @ref + NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US). */ + } extend; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND. */ + } params; /**< Parameter union. */ +} nrf_radio_signal_callback_return_param_t; + +/**@brief The radio timeslot signal callback type. + * + * @note In case of invalid return parameters, the radio timeslot will automatically end + * immediately after returning from the signal callback and the + * @ref NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN event will be sent. + * @note The returned struct pointer must remain valid after the signal callback + * function returns. For instance, this means that it must not point to a stack variable. + * + * @param[in] signal_type Type of signal, see @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE. + * + * @return Pointer to structure containing action requested by the application. + */ +typedef nrf_radio_signal_callback_return_param_t *(*nrf_radio_signal_callback_t)(uint8_t signal_type); + +/**@brief AES ECB parameter typedefs */ +typedef uint8_t soc_ecb_key_t[SOC_ECB_KEY_LENGTH]; /**< Encryption key type. */ +typedef uint8_t soc_ecb_cleartext_t[SOC_ECB_CLEARTEXT_LENGTH]; /**< Cleartext data type. */ +typedef uint8_t soc_ecb_ciphertext_t[SOC_ECB_CIPHERTEXT_LENGTH]; /**< Ciphertext data type. */ + +/**@brief AES ECB data structure */ +typedef struct { + soc_ecb_key_t key; /**< Encryption key. */ + soc_ecb_cleartext_t cleartext; /**< Cleartext data. */ + soc_ecb_ciphertext_t ciphertext; /**< Ciphertext data. */ +} nrf_ecb_hal_data_t; + +/**@brief AES ECB block. Used to provide multiple blocks in a single call + to @ref sd_ecb_blocks_encrypt.*/ +typedef struct { + soc_ecb_key_t const *p_key; /**< Pointer to the Encryption key. */ + soc_ecb_cleartext_t const *p_cleartext; /**< Pointer to the Cleartext data. */ + soc_ecb_ciphertext_t *p_ciphertext; /**< Pointer to the Ciphertext data. */ +} nrf_ecb_hal_data_block_t; + +/**@} */ + +/**@addtogroup NRF_SOC_FUNCTIONS Functions + * @{ */ + +/**@brief Initialize a mutex. + * + * @param[in] p_mutex Pointer to the mutex to initialize. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_MUTEX_NEW, uint32_t, sd_mutex_new(nrf_mutex_t *p_mutex)); + +/**@brief Attempt to acquire a mutex. + * + * @param[in] p_mutex Pointer to the mutex to acquire. + * + * @retval ::NRF_SUCCESS The mutex was successfully acquired. + * @retval ::NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN The mutex could not be acquired. + */ +SVCALL(SD_MUTEX_ACQUIRE, uint32_t, sd_mutex_acquire(nrf_mutex_t *p_mutex)); + +/**@brief Release a mutex. + * + * @param[in] p_mutex Pointer to the mutex to release. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_MUTEX_RELEASE, uint32_t, sd_mutex_release(nrf_mutex_t *p_mutex)); + +/**@brief Query the capacity of the application random pool. + * + * @param[out] p_pool_capacity The capacity of the pool. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RAND_APPLICATION_POOL_CAPACITY_GET, uint32_t, sd_rand_application_pool_capacity_get(uint8_t *p_pool_capacity)); + +/**@brief Get number of random bytes available to the application. + * + * @param[out] p_bytes_available The number of bytes currently available in the pool. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RAND_APPLICATION_BYTES_AVAILABLE_GET, uint32_t, sd_rand_application_bytes_available_get(uint8_t *p_bytes_available)); + +/**@brief Get random bytes from the application pool. + * + * @param[out] p_buff Pointer to unit8_t buffer for storing the bytes. + * @param[in] length Number of bytes to take from pool and place in p_buff. + * + * @retval ::NRF_SUCCESS The requested bytes were written to p_buff. + * @retval ::NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES No bytes were written to the buffer, because there were not enough bytes + * available. + */ +SVCALL(SD_RAND_APPLICATION_VECTOR_GET, uint32_t, sd_rand_application_vector_get(uint8_t *p_buff, uint8_t length)); + +/**@brief Gets the reset reason register. + * + * @param[out] p_reset_reason Contents of the NRF_POWER->RESETREAS register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RESET_REASON_GET, uint32_t, sd_power_reset_reason_get(uint32_t *p_reset_reason)); + +/**@brief Clears the bits of the reset reason register. + * + * @param[in] reset_reason_clr_msk Contains the bits to clear from the reset reason register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RESET_REASON_CLR, uint32_t, sd_power_reset_reason_clr(uint32_t reset_reason_clr_msk)); + +/**@brief Sets the power mode when in CPU sleep. + * + * @param[in] power_mode The power mode to use when in CPU sleep, see @ref NRF_POWER_MODES. @sa sd_app_evt_wait + * + * @retval ::NRF_SUCCESS The power mode was set. + * @retval ::NRF_ERROR_SOC_POWER_MODE_UNKNOWN The power mode was unknown. + */ +SVCALL(SD_POWER_MODE_SET, uint32_t, sd_power_mode_set(uint8_t power_mode)); + +/**@brief Puts the chip in System OFF mode. + * + * @retval ::NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN + */ +SVCALL(SD_POWER_SYSTEM_OFF, uint32_t, sd_power_system_off(void)); + +/**@brief Enables or disables the power-fail comparator. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_FAILURE_WARNING) when the power failure warning occurs. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] pof_enable True if the power-fail comparator should be enabled, false if it should be disabled. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_POF_ENABLE, uint32_t, sd_power_pof_enable(uint8_t pof_enable)); + +/**@brief Enables or disables the USB power ready event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_POWER_READY) when a USB 3.3 V supply is ready. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbpwrrdy_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBPWRRDY_ENABLE, uint32_t, sd_power_usbpwrrdy_enable(uint8_t usbpwrrdy_enable)); + +/**@brief Enables or disables the power USB-detected event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_DETECTED) when a voltage supply is detected on VBUS. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbdetected_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBDETECTED_ENABLE, uint32_t, sd_power_usbdetected_enable(uint8_t usbdetected_enable)); + +/**@brief Enables or disables the power USB-removed event. + * + * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_REMOVED) when a voltage supply is removed from VBUS. + * The event can be retrieved with sd_evt_get(); + * + * @param[in] usbremoved_enable True if the power ready event should be enabled, false if it should be disabled. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBREMOVED_ENABLE, uint32_t, sd_power_usbremoved_enable(uint8_t usbremoved_enable)); + +/**@brief Get USB supply status register content. + * + * @param[out] usbregstatus The content of USBREGSTATUS register. + * + * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_USBREGSTATUS_GET, uint32_t, sd_power_usbregstatus_get(uint32_t *usbregstatus)); + +/**@brief Sets the power failure comparator threshold value. + * + * @note: Power failure comparator threshold setting. This setting applies both for normal voltage + * mode (supply connected to both VDD and VDDH) and high voltage mode (supply connected to + * VDDH only). + * + * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDS. + * + * @retval ::NRF_SUCCESS The power failure threshold was set. + * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. + */ +SVCALL(SD_POWER_POF_THRESHOLD_SET, uint32_t, sd_power_pof_threshold_set(uint8_t threshold)); + +/**@brief Sets the power failure comparator threshold value for high voltage. + * + * @note: Power failure comparator threshold setting for high voltage mode (supply connected to + * VDDH only). This setting does not apply for normal voltage mode (supply connected to both + * VDD and VDDH). + * + * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDVDDHS. + * + * @retval ::NRF_SUCCESS The power failure threshold was set. + * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. + */ +SVCALL(SD_POWER_POF_THRESHOLDVDDH_SET, uint32_t, sd_power_pof_thresholdvddh_set(uint8_t threshold)); + +/**@brief Writes the NRF_POWER->RAM[index].POWERSET register. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERSET register to write to. + * @param[in] ram_powerset Contains the word to write to the NRF_POWER->RAM[index].POWERSET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_SET, uint32_t, sd_power_ram_power_set(uint8_t index, uint32_t ram_powerset)); + +/**@brief Writes the NRF_POWER->RAM[index].POWERCLR register. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERCLR register to write to. + * @param[in] ram_powerclr Contains the word to write to the NRF_POWER->RAM[index].POWERCLR register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_CLR, uint32_t, sd_power_ram_power_clr(uint8_t index, uint32_t ram_powerclr)); + +/**@brief Get contents of NRF_POWER->RAM[index].POWER register, indicates power status of RAM[index] blocks. + * + * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWER register to read from. + * @param[out] p_ram_power Content of NRF_POWER->RAM[index].POWER register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_RAM_POWER_GET, uint32_t, sd_power_ram_power_get(uint8_t index, uint32_t *p_ram_power)); + +/**@brief Set bits in the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[in] gpregret_msk Bits to be set in the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_SET, uint32_t, sd_power_gpregret_set(uint32_t gpregret_id, uint32_t gpregret_msk)); + +/**@brief Clear bits in the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[in] gpregret_msk Bits to be clear in the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_CLR, uint32_t, sd_power_gpregret_clr(uint32_t gpregret_id, uint32_t gpregret_msk)); + +/**@brief Get contents of the general purpose retention registers (NRF_POWER->GPREGRET*). + * + * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. + * @param[out] p_gpregret Contents of the GPREGRET register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_POWER_GPREGRET_GET, uint32_t, sd_power_gpregret_get(uint32_t gpregret_id, uint32_t *p_gpregret)); + +/**@brief Enable or disable the DC/DC regulator for the regulator stage 1 (REG1). + * + * @param[in] dcdc_mode The mode of the DCDC, see @ref NRF_POWER_DCDC_MODES. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_PARAM The DCDC mode is invalid. + */ +SVCALL(SD_POWER_DCDC_MODE_SET, uint32_t, sd_power_dcdc_mode_set(uint8_t dcdc_mode)); + +/**@brief Enable or disable the DC/DC regulator for the regulator stage 0 (REG0). + * + * For more details on the REG0 stage, please see product specification. + * + * @param[in] dcdc_mode The mode of the DCDC0, see @ref NRF_POWER_DCDC_MODES. + * + * @retval ::NRF_SUCCESS + * @retval ::NRF_ERROR_INVALID_PARAM The dcdc_mode is invalid. + */ +SVCALL(SD_POWER_DCDC0_MODE_SET, uint32_t, sd_power_dcdc0_mode_set(uint8_t dcdc_mode)); + +/**@brief Request the high frequency crystal oscillator. + * + * Will start the high frequency crystal oscillator, the startup time of the crystal varies + * and the ::sd_clock_hfclk_is_running function can be polled to check if it has started. + * + * @see sd_clock_hfclk_is_running + * @see sd_clock_hfclk_release + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_REQUEST, uint32_t, sd_clock_hfclk_request(void)); + +/**@brief Releases the high frequency crystal oscillator. + * + * Will stop the high frequency crystal oscillator, this happens immediately. + * + * @see sd_clock_hfclk_is_running + * @see sd_clock_hfclk_request + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_RELEASE, uint32_t, sd_clock_hfclk_release(void)); + +/**@brief Checks if the high frequency crystal oscillator is running. + * + * @see sd_clock_hfclk_request + * @see sd_clock_hfclk_release + * + * @param[out] p_is_running 1 if the external crystal oscillator is running, 0 if not. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_CLOCK_HFCLK_IS_RUNNING, uint32_t, sd_clock_hfclk_is_running(uint32_t *p_is_running)); + +/**@brief Waits for an application event. + * + * An application event is either an application interrupt or a pended interrupt when the interrupt + * is disabled. + * + * When the application waits for an application event by calling this function, an interrupt that + * is enabled will be taken immediately on pending since this function will wait in thread mode, + * then the execution will return in the application's main thread. + * + * In order to wake up from disabled interrupts, the SEVONPEND flag has to be set in the Cortex-M + * MCU's System Control Register (SCR), CMSIS_SCB. In that case, when a disabled interrupt gets + * pended, this function will return to the application's main thread. + * + * @note The application must ensure that the pended flag is cleared using ::sd_nvic_ClearPendingIRQ + * in order to sleep using this function. This is only necessary for disabled interrupts, as + * the interrupt handler will clear the pending flag automatically for enabled interrupts. + * + * @note If an application interrupt has happened since the last time sd_app_evt_wait was + * called this function will return immediately and not go to sleep. This is to avoid race + * conditions that can occur when a flag is updated in the interrupt handler and processed + * in the main loop. + * + * @post An application interrupt has happened or a interrupt pending flag is set. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_APP_EVT_WAIT, uint32_t, sd_app_evt_wait(void)); + +/**@brief Get PPI channel enable register contents. + * + * @param[out] p_channel_enable The contents of the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_GET, uint32_t, sd_ppi_channel_enable_get(uint32_t *p_channel_enable)); + +/**@brief Set PPI channel enable register. + * + * @param[in] channel_enable_set_msk Mask containing the bits to set in the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_SET, uint32_t, sd_ppi_channel_enable_set(uint32_t channel_enable_set_msk)); + +/**@brief Clear PPI channel enable register. + * + * @param[in] channel_enable_clr_msk Mask containing the bits to clear in the PPI CHEN register. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ENABLE_CLR, uint32_t, sd_ppi_channel_enable_clr(uint32_t channel_enable_clr_msk)); + +/**@brief Assign endpoints to a PPI channel. + * + * @param[in] channel_num Number of the PPI channel to assign. + * @param[in] evt_endpoint Event endpoint of the PPI channel. + * @param[in] task_endpoint Task endpoint of the PPI channel. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_CHANNEL The channel number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_CHANNEL_ASSIGN, uint32_t, + sd_ppi_channel_assign(uint8_t channel_num, const volatile void *evt_endpoint, const volatile void *task_endpoint)); + +/**@brief Task to enable a channel group. + * + * @param[in] group_num Number of the channel group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_TASK_ENABLE, uint32_t, sd_ppi_group_task_enable(uint8_t group_num)); + +/**@brief Task to disable a channel group. + * + * @param[in] group_num Number of the PPI group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_TASK_DISABLE, uint32_t, sd_ppi_group_task_disable(uint8_t group_num)); + +/**@brief Assign PPI channels to a channel group. + * + * @param[in] group_num Number of the channel group. + * @param[in] channel_msk Mask of the channels to assign to the group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_ASSIGN, uint32_t, sd_ppi_group_assign(uint8_t group_num, uint32_t channel_msk)); + +/**@brief Gets the PPI channels of a channel group. + * + * @param[in] group_num Number of the channel group. + * @param[out] p_channel_msk Mask of the channels assigned to the group. + * + * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_PPI_GROUP_GET, uint32_t, sd_ppi_group_get(uint8_t group_num, uint32_t *p_channel_msk)); + +/**@brief Configures the Radio Notification signal. + * + * @note + * - The notification signal latency depends on the interrupt priority settings of SWI used + * for notification signal. + * - To ensure that the radio notification signal behaves in a consistent way, the radio + * notifications must be configured when there is no protocol stack or other SoftDevice + * activity in progress. It is recommended that the radio notification signal is + * configured directly after the SoftDevice has been enabled. + * - In the period between the ACTIVE signal and the start of the Radio Event, the SoftDevice + * will interrupt the application to do Radio Event preparation. + * - Using the Radio Notification feature may limit the bandwidth, as the SoftDevice may have + * to shorten the connection events to have time for the Radio Notification signals. + * + * @param[in] type Type of notification signal, see @ref NRF_RADIO_NOTIFICATION_TYPES. + * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE shall be used to turn off radio + * notification. Using @ref NRF_RADIO_NOTIFICATION_DISTANCE_NONE is + * recommended (but not required) to be used with + * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE. + * + * @param[in] distance Distance between the notification signal and start of radio activity, see @ref + * NRF_RADIO_NOTIFICATION_DISTANCES. This parameter is ignored when @ref NRF_RADIO_NOTIFICATION_TYPE_NONE or + * @ref NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE is used. + * + * @retval ::NRF_ERROR_INVALID_PARAM The group number is invalid. + * @retval ::NRF_ERROR_INVALID_STATE A protocol stack or other SoftDevice is running. Stop all + * running activities and retry. + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_RADIO_NOTIFICATION_CFG_SET, uint32_t, sd_radio_notification_cfg_set(uint8_t type, uint8_t distance)); + +/**@brief Encrypts a block according to the specified parameters. + * + * 128-bit AES encryption. + * + * @note: + * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while + * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application + * main or low interrupt level. + * + * @param[in, out] p_ecb_data Pointer to the ECB parameters' struct (two input + * parameters and one output parameter). + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_ECB_BLOCK_ENCRYPT, uint32_t, sd_ecb_block_encrypt(nrf_ecb_hal_data_t *p_ecb_data)); + +/**@brief Encrypts multiple data blocks provided as an array of data block structures. + * + * @details: Performs 128-bit AES encryption on multiple data blocks + * + * @note: + * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while + * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application + * main or low interrupt level. + * + * @param[in] block_count Count of blocks in the p_data_blocks array. + * @param[in,out] p_data_blocks Pointer to the first entry in a contiguous array of + * @ref nrf_ecb_hal_data_block_t structures. + * + * @retval ::NRF_SUCCESS + */ +SVCALL(SD_ECB_BLOCKS_ENCRYPT, uint32_t, sd_ecb_blocks_encrypt(uint8_t block_count, nrf_ecb_hal_data_block_t *p_data_blocks)); + +/**@brief Gets any pending events generated by the SoC API. + * + * The application should keep calling this function to get events, until ::NRF_ERROR_NOT_FOUND is returned. + * + * @param[out] p_evt_id Set to one of the values in @ref NRF_SOC_EVTS, if any events are pending. + * + * @retval ::NRF_SUCCESS An event was pending. The event id is written in the p_evt_id parameter. + * @retval ::NRF_ERROR_NOT_FOUND No pending events. + */ +SVCALL(SD_EVT_GET, uint32_t, sd_evt_get(uint32_t *p_evt_id)); + +/**@brief Get the temperature measured on the chip + * + * This function will block until the temperature measurement is done. + * It takes around 50 us from call to return. + * + * @param[out] p_temp Result of temperature measurement. Die temperature in 0.25 degrees Celsius. + * + * @retval ::NRF_SUCCESS A temperature measurement was done, and the temperature was written to temp + */ +SVCALL(SD_TEMP_GET, uint32_t, sd_temp_get(int32_t *p_temp)); + +/**@brief Flash Write + * + * Commands to write a buffer to flash + * + * If the SoftDevice is enabled: + * This call initiates the flash access command, and its completion will be communicated to the + * application with exactly one of the following events: + * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. + * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. + * + * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the + * write has been completed + * + * @note + * - This call takes control over the radio and the CPU during flash erase and write to make sure that + * they will not interfere with the flash access. This means that all interrupts will be blocked + * for a predictable time (depending on the NVMC specification in the device's Product Specification + * and the command parameters). + * - The data in the p_src buffer should not be modified before the @ref NRF_EVT_FLASH_OPERATION_SUCCESS + * or the @ref NRF_EVT_FLASH_OPERATION_ERROR have been received if the SoftDevice is enabled. + * - This call will make the SoftDevice trigger a hardfault when the page is written, if it is + * protected. + * + * + * @param[in] p_dst Pointer to start of flash location to be written. + * @param[in] p_src Pointer to buffer with data to be written. + * @param[in] size Number of 32-bit words to write. Maximum size is the number of words in one + * flash page. See the device's Product Specification for details. + * + * @retval ::NRF_ERROR_INVALID_ADDR Tried to write to a non existing flash address, or p_dst or p_src was unaligned. + * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. + * @retval ::NRF_ERROR_INVALID_LENGTH Size was 0, or higher than the maximum allowed size. + * @retval ::NRF_ERROR_FORBIDDEN Tried to write to an address outside the application flash area. + * @retval ::NRF_SUCCESS The command was accepted. + */ +SVCALL(SD_FLASH_WRITE, uint32_t, sd_flash_write(uint32_t *p_dst, uint32_t const *p_src, uint32_t size)); + +/**@brief Flash Erase page + * + * Commands to erase a flash page + * If the SoftDevice is enabled: + * This call initiates the flash access command, and its completion will be communicated to the + * application with exactly one of the following events: + * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. + * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. + * + * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the + * erase has been completed + * + * @note + * - This call takes control over the radio and the CPU during flash erase and write to make sure that + * they will not interfere with the flash access. This means that all interrupts will be blocked + * for a predictable time (depending on the NVMC specification in the device's Product Specification + * and the command parameters). + * - This call will make the SoftDevice trigger a hardfault when the page is erased, if it is + * protected. + * + * + * @param[in] page_number Page number of the page to erase + * + * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. + * @retval ::NRF_ERROR_INVALID_ADDR Tried to erase to a non existing flash page. + * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. + * @retval ::NRF_ERROR_FORBIDDEN Tried to erase a page outside the application flash area. + * @retval ::NRF_SUCCESS The command was accepted. + */ +SVCALL(SD_FLASH_PAGE_ERASE, uint32_t, sd_flash_page_erase(uint32_t page_number)); + +/**@brief Opens a session for radio timeslot requests. + * + * @note Only one session can be open at a time. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) will be called when the radio timeslot + * starts. From this point the NRF_RADIO and NRF_TIMER0 peripherals can be freely accessed + * by the application. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0) is called whenever the NRF_TIMER0 + * interrupt occurs. + * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO) is called whenever the NRF_RADIO + * interrupt occurs. + * @note p_radio_signal_callback() will be called at ARM interrupt priority level 0. This + * implies that none of the sd_* API calls can be used from p_radio_signal_callback(). + * + * @param[in] p_radio_signal_callback The signal callback. + * + * @retval ::NRF_ERROR_INVALID_ADDR p_radio_signal_callback is an invalid function pointer. + * @retval ::NRF_ERROR_BUSY If session cannot be opened. + * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_SESSION_OPEN, uint32_t, sd_radio_session_open(nrf_radio_signal_callback_t p_radio_signal_callback)); + +/**@brief Closes a session for radio timeslot requests. + * + * @note Any current radio timeslot will be finished before the session is closed. + * @note If a radio timeslot is scheduled when the session is closed, it will be canceled. + * @note The application cannot consider the session closed until the @ref NRF_EVT_RADIO_SESSION_CLOSED + * event is received. + * + * @retval ::NRF_ERROR_FORBIDDEN If session not opened. + * @retval ::NRF_ERROR_BUSY If session is currently being closed. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_SESSION_CLOSE, uint32_t, sd_radio_session_close(void)); + +/**@brief Requests a radio timeslot. + * + * @note The request type is determined by p_request->request_type, and can be one of @ref NRF_RADIO_REQ_TYPE_EARLIEST + * and @ref NRF_RADIO_REQ_TYPE_NORMAL. The first request in a session must always be of type @ref + * NRF_RADIO_REQ_TYPE_EARLIEST. + * @note For a normal request (@ref NRF_RADIO_REQ_TYPE_NORMAL), the start time of a radio timeslot is specified by + * p_request->distance_us and is given relative to the start of the previous timeslot. + * @note A too small p_request->distance_us will lead to a @ref NRF_EVT_RADIO_BLOCKED event. + * @note Timeslots scheduled too close will lead to a @ref NRF_EVT_RADIO_BLOCKED event. + * @note See the SoftDevice Specification for more on radio timeslot scheduling, distances and lengths. + * @note If an opportunity for the first radio timeslot is not found before 100 ms after the call to this + * function, it is not scheduled, and instead a @ref NRF_EVT_RADIO_BLOCKED event is sent. + * The application may then try to schedule the first radio timeslot again. + * @note Successful requests will result in nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START). + * Unsuccessful requests will result in a @ref NRF_EVT_RADIO_BLOCKED event, see @ref NRF_SOC_EVTS. + * @note The jitter in the start time of the radio timeslots is +/- @ref NRF_RADIO_START_JITTER_US us. + * @note The nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) call has a latency relative to the + * specified radio timeslot start, but this does not affect the actual start time of the timeslot. + * @note NRF_TIMER0 is reset at the start of the radio timeslot, and is clocked at 1MHz from the high frequency + * (16 MHz) clock source. If p_request->hfclk_force_xtal is true, the high frequency clock is + * guaranteed to be clocked from the external crystal. + * @note The SoftDevice will neither access the NRF_RADIO peripheral nor the NRF_TIMER0 peripheral + * during the radio timeslot. + * + * @param[in] p_request Pointer to the request parameters. + * + * @retval ::NRF_ERROR_FORBIDDEN Either: + * - The session is not open. + * - The session is not IDLE. + * - This is the first request and its type is not @ref NRF_RADIO_REQ_TYPE_EARLIEST. + * - The request type was set to @ref NRF_RADIO_REQ_TYPE_NORMAL after a + * @ref NRF_RADIO_REQ_TYPE_EARLIEST request was blocked. + * @retval ::NRF_ERROR_INVALID_ADDR If the p_request pointer is invalid. + * @retval ::NRF_ERROR_INVALID_PARAM If the parameters of p_request are not valid. + * @retval ::NRF_SUCCESS Otherwise. + */ +SVCALL(SD_RADIO_REQUEST, uint32_t, sd_radio_request(nrf_radio_request_t const *p_request)); + +/**@brief Write register protected by the SoftDevice + * + * This function writes to a register that is write-protected by the SoftDevice. Please refer to your + * SoftDevice Specification for more details about which registers that are protected by SoftDevice. + * This function can write to the following protected peripheral: + * - ACL + * + * @note Protected registers may be read directly. + * @note Register that are write-once will return @ref NRF_SUCCESS on second set, even the value in + * the register has not changed. See the Product Specification for more details about register + * properties. + * + * @param[in] p_register Pointer to register to be written. + * @param[in] value Value to be written to the register. + * + * @retval ::NRF_ERROR_INVALID_ADDR This function can not write to the reguested register. + * @retval ::NRF_SUCCESS Value successfully written to register. + * + */ +SVCALL(SD_PROTECTED_REGISTER_WRITE, uint32_t, sd_protected_register_write(volatile uint32_t *p_register, uint32_t value)); + +/**@} */ + +#ifdef __cplusplus +} +#endif +#endif // NRF_SOC_H__ + +/**@} */ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_svc.h b/variants/wio-tracker-wm1110/softdevice/nrf_svc.h new file mode 100644 index 0000000000..1de44656f3 --- /dev/null +++ b/variants/wio-tracker-wm1110/softdevice/nrf_svc.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) Nordic Semiconductor ASA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NRF_SVC__ +#define NRF_SVC__ + +#include "stdint.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Supervisor call declaration. + * + * A call to a function marked with @ref SVCALL, will trigger a Supervisor Call (SVC) Exception. + * The SVCs with SVC numbers 0x00-0x0F are forwared to the application. All other SVCs are handled by the SoftDevice. + * + * @param[in] number The SVC number to be used. + * @param[in] return_type The return type of the SVC function. + * @param[in] signature Function signature. The function can have at most four arguments. + */ + +#ifdef SVCALL_AS_NORMAL_FUNCTION +#define SVCALL(number, return_type, signature) return_type signature +#else + +#ifndef SVCALL +#if defined(__CC_ARM) +#define SVCALL(number, return_type, signature) return_type __svc(number) signature +#elif defined(__GNUC__) +#ifdef __cplusplus +#define GCC_CAST_CPP (uint16_t) +#else +#define GCC_CAST_CPP +#endif +#define SVCALL(number, return_type, signature) \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") __attribute__((naked)) \ + __attribute__((unused)) static return_type signature \ + { \ + __asm("svc %0\n" \ + "bx r14" \ + : \ + : "I"(GCC_CAST_CPP number) \ + : "r0"); \ + } \ + _Pragma("GCC diagnostic pop") + +#elif defined(__ICCARM__) +#define PRAGMA(x) _Pragma(#x) +#define SVCALL(number, return_type, signature) \ + PRAGMA(swi_number = (number)) \ + __swi return_type signature; +#else +#define SVCALL(number, return_type, signature) return_type signature +#endif +#endif // SVCALL + +#endif // SVCALL_AS_NORMAL_FUNCTION + +#ifdef __cplusplus +} +#endif +#endif // NRF_SVC__ diff --git a/variants/xiao_ble/platformio.ini b/variants/xiao_ble/platformio.ini index 613fd3599e..6c47780d5f 100644 --- a/variants/xiao_ble/platformio.ini +++ b/variants/xiao_ble/platformio.ini @@ -11,4 +11,4 @@ lib_deps = ${nrf52840_base.lib_deps} debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink \ No newline at end of file +;upload_protocol = jlink diff --git a/version.properties b/version.properties index 268987418b..1cb93ac2bf 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 14 +build = 15 From 2b9848bf1b51ec081d3ed22448aa655a8fd565bc Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 8 Jul 2024 08:16:38 -0500 Subject: [PATCH 131/211] Remove tracker variant specific soft device headers (#4255) --- variants/wio-tracker-wm1110/softdevice/ble.h | 652 ---- .../wio-tracker-wm1110/softdevice/ble_err.h | 92 - .../wio-tracker-wm1110/softdevice/ble_gap.h | 2895 ----------------- .../wio-tracker-wm1110/softdevice/ble_gatt.h | 232 -- .../wio-tracker-wm1110/softdevice/ble_gattc.h | 764 ----- .../wio-tracker-wm1110/softdevice/ble_gatts.h | 904 ----- .../wio-tracker-wm1110/softdevice/ble_hci.h | 135 - .../wio-tracker-wm1110/softdevice/ble_l2cap.h | 495 --- .../softdevice/ble_ranges.h | 149 - .../wio-tracker-wm1110/softdevice/ble_types.h | 217 -- .../softdevice/nrf52/nrf_mbr.h | 259 -- .../wio-tracker-wm1110/softdevice/nrf_error.h | 90 - .../softdevice/nrf_error_sdm.h | 73 - .../softdevice/nrf_error_soc.h | 85 - .../wio-tracker-wm1110/softdevice/nrf_nvic.h | 449 --- .../wio-tracker-wm1110/softdevice/nrf_sdm.h | 380 --- .../wio-tracker-wm1110/softdevice/nrf_soc.h | 1046 ------ .../wio-tracker-wm1110/softdevice/nrf_svc.h | 98 - 18 files changed, 9015 deletions(-) delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_err.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gap.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gatt.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gattc.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gatts.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_hci.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_l2cap.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_ranges.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_types.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_nvic.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_sdm.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_soc.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_svc.h diff --git a/variants/wio-tracker-wm1110/softdevice/ble.h b/variants/wio-tracker-wm1110/softdevice/ble.h deleted file mode 100644 index 177b436ad8..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble.h +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON BLE SoftDevice Common - @{ - @defgroup ble_api Events, type definitions and API calls - @{ - - @brief Module independent events, type definitions and API calls for the BLE SoftDevice. - - */ - -#ifndef BLE_H__ -#define BLE_H__ - -#include "ble_err.h" -#include "ble_gap.h" -#include "ble_gatt.h" -#include "ble_gattc.h" -#include "ble_gatts.h" -#include "ble_l2cap.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_COMMON_ENUMERATIONS Enumerations - * @{ */ - -/** - * @brief Common API SVC numbers. - */ -enum BLE_COMMON_SVCS { - SD_BLE_ENABLE = BLE_SVC_BASE, /**< Enable and initialize the BLE stack */ - SD_BLE_EVT_GET, /**< Get an event from the pending events queue. */ - SD_BLE_UUID_VS_ADD, /**< Add a Vendor Specific base UUID. */ - SD_BLE_UUID_DECODE, /**< Decode UUID bytes. */ - SD_BLE_UUID_ENCODE, /**< Encode UUID bytes. */ - SD_BLE_VERSION_GET, /**< Get the local version information (company ID, Link Layer Version, Link Layer Subversion). */ - SD_BLE_USER_MEM_REPLY, /**< User Memory Reply. */ - SD_BLE_OPT_SET, /**< Set a BLE option. */ - SD_BLE_OPT_GET, /**< Get a BLE option. */ - SD_BLE_CFG_SET, /**< Add a configuration to the BLE stack. */ - SD_BLE_UUID_VS_REMOVE, /**< Remove a Vendor Specific base UUID. */ -}; - -/** - * @brief BLE Module Independent Event IDs. - */ -enum BLE_COMMON_EVTS { - BLE_EVT_USER_MEM_REQUEST = BLE_EVT_BASE + 0, /**< User Memory request. See @ref ble_evt_user_mem_request_t - \n Reply with @ref sd_ble_user_mem_reply. */ - BLE_EVT_USER_MEM_RELEASE = BLE_EVT_BASE + 1, /**< User Memory release. See @ref ble_evt_user_mem_release_t */ -}; - -/**@brief BLE Connection Configuration IDs. - * - * IDs that uniquely identify a connection configuration. - */ -enum BLE_CONN_CFGS { - BLE_CONN_CFG_GAP = BLE_CONN_CFG_BASE + 0, /**< BLE GAP specific connection configuration. */ - BLE_CONN_CFG_GATTC = BLE_CONN_CFG_BASE + 1, /**< BLE GATTC specific connection configuration. */ - BLE_CONN_CFG_GATTS = BLE_CONN_CFG_BASE + 2, /**< BLE GATTS specific connection configuration. */ - BLE_CONN_CFG_GATT = BLE_CONN_CFG_BASE + 3, /**< BLE GATT specific connection configuration. */ - BLE_CONN_CFG_L2CAP = BLE_CONN_CFG_BASE + 4, /**< BLE L2CAP specific connection configuration. */ -}; - -/**@brief BLE Common Configuration IDs. - * - * IDs that uniquely identify a common configuration. - */ -enum BLE_COMMON_CFGS { - BLE_COMMON_CFG_VS_UUID = BLE_CFG_BASE, /**< Vendor specific base UUID configuration */ -}; - -/**@brief Common Option IDs. - * IDs that uniquely identify a common option. - */ -enum BLE_COMMON_OPTS { - BLE_COMMON_OPT_PA_LNA = BLE_OPT_BASE + 0, /**< PA and LNA options */ - BLE_COMMON_OPT_CONN_EVT_EXT = BLE_OPT_BASE + 1, /**< Extended connection events option */ - BLE_COMMON_OPT_EXTENDED_RC_CAL = BLE_OPT_BASE + 2, /**< Extended RC calibration option */ -}; - -/** @} */ - -/** @addtogroup BLE_COMMON_DEFINES Defines - * @{ */ - -/** @brief Required pointer alignment for BLE Events. - */ -#define BLE_EVT_PTR_ALIGNMENT 4 - -/** @brief Leaves the maximum of the two arguments. - */ -#define BLE_MAX(a, b) ((a) < (b) ? (b) : (a)) - -/** @brief Maximum possible length for BLE Events. - * @note The highest value used for @ref ble_gatt_conn_cfg_t::att_mtu in any connection configuration shall be used as a - * parameter. If that value has not been configured for any connections then @ref BLE_GATT_ATT_MTU_DEFAULT must be used instead. - */ -#define BLE_EVT_LEN_MAX(ATT_MTU) \ - (offsetof(ble_evt_t, evt.gattc_evt.params.prim_srvc_disc_rsp.services) + ((ATT_MTU)-1) / 4 * sizeof(ble_gattc_service_t)) - -/** @defgroup BLE_USER_MEM_TYPES User Memory Types - * @{ */ -#define BLE_USER_MEM_TYPE_INVALID 0x00 /**< Invalid User Memory Types. */ -#define BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES 0x01 /**< User Memory for GATTS queued writes. */ -/** @} */ - -/** @defgroup BLE_UUID_VS_COUNTS Vendor Specific base UUID counts - * @{ - */ -#define BLE_UUID_VS_COUNT_DEFAULT 10 /**< Default VS UUID count. */ -#define BLE_UUID_VS_COUNT_MAX 254 /**< Maximum VS UUID count. */ -/** @} */ - -/** @defgroup BLE_COMMON_CFG_DEFAULTS Configuration defaults. - * @{ - */ -#define BLE_CONN_CFG_TAG_DEFAULT 0 /**< Default configuration tag, SoftDevice default connection configuration. */ - -/** @} */ - -/** @} */ - -/** @addtogroup BLE_COMMON_STRUCTURES Structures - * @{ */ - -/**@brief User Memory Block. */ -typedef struct { - uint8_t *p_mem; /**< Pointer to the start of the user memory block. */ - uint16_t len; /**< Length in bytes of the user memory block. */ -} ble_user_mem_block_t; - -/**@brief Event structure for @ref BLE_EVT_USER_MEM_REQUEST. */ -typedef struct { - uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ -} ble_evt_user_mem_request_t; - -/**@brief Event structure for @ref BLE_EVT_USER_MEM_RELEASE. */ -typedef struct { - uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ - ble_user_mem_block_t mem_block; /**< User memory block */ -} ble_evt_user_mem_release_t; - -/**@brief Event structure for events not associated with a specific function module. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which this event occurred. */ - union { - ble_evt_user_mem_request_t user_mem_request; /**< User Memory Request Event Parameters. */ - ble_evt_user_mem_release_t user_mem_release; /**< User Memory Release Event Parameters. */ - } params; /**< Event parameter union. */ -} ble_common_evt_t; - -/**@brief BLE Event header. */ -typedef struct { - uint16_t evt_id; /**< Value from a BLE__EVT series. */ - uint16_t evt_len; /**< Length in octets including this header. */ -} ble_evt_hdr_t; - -/**@brief Common BLE Event type, wrapping the module specific event reports. */ -typedef struct { - ble_evt_hdr_t header; /**< Event header. */ - union { - ble_common_evt_t common_evt; /**< Common Event, evt_id in BLE_EVT_* series. */ - ble_gap_evt_t gap_evt; /**< GAP originated event, evt_id in BLE_GAP_EVT_* series. */ - ble_gattc_evt_t gattc_evt; /**< GATT client originated event, evt_id in BLE_GATTC_EVT* series. */ - ble_gatts_evt_t gatts_evt; /**< GATT server originated event, evt_id in BLE_GATTS_EVT* series. */ - ble_l2cap_evt_t l2cap_evt; /**< L2CAP originated event, evt_id in BLE_L2CAP_EVT* series. */ - } evt; /**< Event union. */ -} ble_evt_t; - -/** - * @brief Version Information. - */ -typedef struct { - uint8_t version_number; /**< Link Layer Version number. See - https://www.bluetooth.org/en-us/specification/assigned-numbers/link-layer for assigned values. */ - uint16_t company_id; /**< Company ID, Nordic Semiconductor's company ID is 89 (0x0059) - (https://www.bluetooth.org/apps/content/Default.aspx?doc_id=49708). */ - uint16_t - subversion_number; /**< Link Layer Sub Version number, corresponds to the SoftDevice Config ID or Firmware ID (FWID). */ -} ble_version_t; - -/** - * @brief Configuration parameters for the PA and LNA. - */ -typedef struct { - uint8_t enable : 1; /**< Enable toggling for this amplifier */ - uint8_t active_high : 1; /**< Set the pin to be active high */ - uint8_t gpio_pin : 6; /**< The GPIO pin to toggle for this amplifier */ -} ble_pa_lna_cfg_t; - -/** - * @brief PA & LNA GPIO toggle configuration - * - * This option configures the SoftDevice to toggle pins when the radio is active for use with a power amplifier and/or - * a low noise amplifier. - * - * Toggling the pins is achieved by using two PPI channels and a GPIOTE channel. The hardware channel IDs are provided - * by the application and should be regarded as reserved as long as any PA/LNA toggling is enabled. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * @note Setting this option while the radio is in use (i.e. any of the roles are active) may have undefined consequences - * and must be avoided by the application. - */ -typedef struct { - ble_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */ - ble_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */ - - uint8_t ppi_ch_id_set; /**< PPI channel used for radio pin setting */ - uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */ - uint8_t gpiote_ch_id; /**< GPIOTE channel used for radio pin toggling */ -} ble_common_opt_pa_lna_t; - -/** - * @brief Configuration of extended BLE connection events. - * - * When enabled the SoftDevice will dynamically extend the connection event when possible. - * - * The connection event length is controlled by the connection configuration as set by @ref ble_gap_conn_cfg_t::event_length. - * The connection event can be extended if there is time to send another packet pair before the start of the next connection - * interval, and if there are no conflicts with other BLE roles requesting radio time. - * - * @note @ref sd_ble_opt_get is not supported for this option. - */ -typedef struct { - uint8_t enable : 1; /**< Enable extended BLE connection events, disabled by default. */ -} ble_common_opt_conn_evt_ext_t; - -/** - * @brief Enable/disable extended RC calibration. - * - * If extended RC calibration is enabled and the internal RC oscillator (@ref NRF_CLOCK_LF_SRC_RC) is used as the SoftDevice - * LFCLK source, the SoftDevice as a peripheral will by default try to increase the receive window if two consecutive packets - * are not received. If it turns out that the packets were not received due to clock drift, the RC calibration is started. - * This calibration comes in addition to the periodic calibration that is configured by @ref sd_softdevice_enable(). When - * using only peripheral connections, the periodic calibration can therefore be configured with a much longer interval as the - * peripheral will be able to detect and adjust automatically to clock drift, and calibrate on demand. - * - * If extended RC calibration is disabled and the internal RC oscillator is used as the SoftDevice LFCLK source, the - * RC oscillator is calibrated periodically as configured by @ref sd_softdevice_enable(). - * - * @note @ref sd_ble_opt_get is not supported for this option. - */ -typedef struct { - uint8_t enable : 1; /**< Enable extended RC calibration, enabled by default. */ -} ble_common_opt_extended_rc_cal_t; - -/**@brief Option structure for common options. */ -typedef union { - ble_common_opt_pa_lna_t pa_lna; /**< Parameters for controlling PA and LNA pin toggling. */ - ble_common_opt_conn_evt_ext_t conn_evt_ext; /**< Parameters for enabling extended connection events. */ - ble_common_opt_extended_rc_cal_t extended_rc_cal; /**< Parameters for enabling extended RC calibration. */ -} ble_common_opt_t; - -/**@brief Common BLE Option type, wrapping the module specific options. */ -typedef union { - ble_common_opt_t common_opt; /**< COMMON options, opt_id in @ref BLE_COMMON_OPTS series. */ - ble_gap_opt_t gap_opt; /**< GAP option, opt_id in @ref BLE_GAP_OPTS series. */ - ble_gattc_opt_t gattc_opt; /**< GATTC option, opt_id in @ref BLE_GATTC_OPTS series. */ -} ble_opt_t; - -/**@brief BLE connection configuration type, wrapping the module specific configurations, set with - * @ref sd_ble_cfg_set. - * - * @note Connection configurations don't have to be set. - * In the case that no configurations has been set, or fewer connection configurations has been set than enabled connections, - * the default connection configuration will be automatically added for the remaining connections. - * When creating connections with the default configuration, @ref BLE_CONN_CFG_TAG_DEFAULT should be used in - * place of @ref ble_conn_cfg_t::conn_cfg_tag. - * - * @sa sd_ble_gap_adv_start() - * @sa sd_ble_gap_connect() - * - * @mscs - * @mmsc{@ref BLE_CONN_CFG} - * @endmscs - - */ -typedef struct { - uint8_t conn_cfg_tag; /**< The application chosen tag it can use with the - @ref sd_ble_gap_adv_start() and @ref sd_ble_gap_connect() calls - to select this configuration when creating a connection. - Must be different for all connection configurations added and not @ref BLE_CONN_CFG_TAG_DEFAULT. */ - union { - ble_gap_conn_cfg_t gap_conn_cfg; /**< GAP connection configuration, cfg_id is @ref BLE_CONN_CFG_GAP. */ - ble_gattc_conn_cfg_t gattc_conn_cfg; /**< GATTC connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTC. */ - ble_gatts_conn_cfg_t gatts_conn_cfg; /**< GATTS connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTS. */ - ble_gatt_conn_cfg_t gatt_conn_cfg; /**< GATT connection configuration, cfg_id is @ref BLE_CONN_CFG_GATT. */ - ble_l2cap_conn_cfg_t l2cap_conn_cfg; /**< L2CAP connection configuration, cfg_id is @ref BLE_CONN_CFG_L2CAP. */ - } params; /**< Connection configuration union. */ -} ble_conn_cfg_t; - -/** - * @brief Configuration of Vendor Specific base UUIDs, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_PARAM Too many UUIDs configured. - */ -typedef struct { - uint8_t vs_uuid_count; /**< Number of 128-bit Vendor Specific base UUID bases to allocate memory for. - Default value is @ref BLE_UUID_VS_COUNT_DEFAULT. Maximum value is - @ref BLE_UUID_VS_COUNT_MAX. */ -} ble_common_cfg_vs_uuid_t; - -/**@brief Common BLE Configuration type, wrapping the common configurations. */ -typedef union { - ble_common_cfg_vs_uuid_t vs_uuid_cfg; /**< Vendor Specific base UUID configuration, cfg_id is @ref BLE_COMMON_CFG_VS_UUID. */ -} ble_common_cfg_t; - -/**@brief BLE Configuration type, wrapping the module specific configurations. */ -typedef union { - ble_conn_cfg_t conn_cfg; /**< Connection specific configurations, cfg_id in @ref BLE_CONN_CFGS series. */ - ble_common_cfg_t common_cfg; /**< Global common configurations, cfg_id in @ref BLE_COMMON_CFGS series. */ - ble_gap_cfg_t gap_cfg; /**< Global GAP configurations, cfg_id in @ref BLE_GAP_CFGS series. */ - ble_gatts_cfg_t gatts_cfg; /**< Global GATTS configuration, cfg_id in @ref BLE_GATTS_CFGS series. */ -} ble_cfg_t; - -/** @} */ - -/** @addtogroup BLE_COMMON_FUNCTIONS Functions - * @{ */ - -/**@brief Enable the BLE stack - * - * @param[in, out] p_app_ram_base Pointer to a variable containing the start address of the - * application RAM region (APP_RAM_BASE). On return, this will - * contain the minimum start address of the application RAM region - * required by the SoftDevice for this configuration. - * @warning After this call, the SoftDevice may generate several events. The list of events provided - * below require the application to initiate a SoftDevice API call. The corresponding API call - * is referenced in the event documentation. - * If the application fails to do so, the BLE connection may timeout, or the SoftDevice may stop - * communicating with the peer device. - * - @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST - * - @ref BLE_GAP_EVT_SEC_INFO_REQUEST - * - @ref BLE_GAP_EVT_SEC_REQUEST - * - @ref BLE_GAP_EVT_AUTH_KEY_REQUEST - * - @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST - * - @ref BLE_EVT_USER_MEM_REQUEST - * - @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST - * - * @note The memory requirement for a specific configuration will not increase between SoftDevices - * with the same major version number. - * - * @note At runtime the IC's RAM is split into 2 regions: The SoftDevice RAM region is located - * between 0x20000000 and APP_RAM_BASE-1 and the application's RAM region is located between - * APP_RAM_BASE and the start of the call stack. - * - * @details This call initializes the BLE stack, no BLE related function other than @ref - * sd_ble_cfg_set can be called before this one. - * - * @mscs - * @mmsc{@ref BLE_COMMON_ENABLE} - * @endmscs - * - * @retval ::NRF_SUCCESS The BLE stack has been initialized successfully. - * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized and cannot be reinitialized. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_NO_MEM One or more of the following is true: - * - The amount of memory assigned to the SoftDevice by *p_app_ram_base is not - * large enough to fit this configuration's memory requirement. Check *p_app_ram_base - * and set the start address of the application RAM region accordingly. - * - Dynamic part of the SoftDevice RAM region is larger then 64 kB which - * is currently not supported. - * @retval ::NRF_ERROR_RESOURCES The total number of L2CAP Channels configured using @ref sd_ble_cfg_set is too large. - */ -SVCALL(SD_BLE_ENABLE, uint32_t, sd_ble_enable(uint32_t *p_app_ram_base)); - -/**@brief Add configurations for the BLE stack - * - * @param[in] cfg_id Config ID, see @ref BLE_CONN_CFGS, @ref BLE_COMMON_CFGS, @ref - * BLE_GAP_CFGS or @ref BLE_GATTS_CFGS. - * @param[in] p_cfg Pointer to a ble_cfg_t structure containing the configuration value. - * @param[in] app_ram_base The start address of the application RAM region (APP_RAM_BASE). - * See @ref sd_ble_enable for details about APP_RAM_BASE. - * - * @note The memory requirement for a specific configuration will not increase between SoftDevices - * with the same major version number. - * - * @note If a configuration is set more than once, the last one set is the one that takes effect on - * @ref sd_ble_enable. - * - * @note Any part of the BLE stack that is NOT configured with @ref sd_ble_cfg_set will have default - * configuration. - * - * @note @ref sd_ble_cfg_set may be called at any time when the SoftDevice is enabled (see @ref - * sd_softdevice_enable) while the BLE part of the SoftDevice is not enabled (see @ref - * sd_ble_enable). - * - * @note Error codes for the configurations are described in the configuration structs. - * - * @mscs - * @mmsc{@ref BLE_COMMON_ENABLE} - * @endmscs - * - * @retval ::NRF_SUCCESS The configuration has been added successfully. - * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid cfg_id supplied. - * @retval ::NRF_ERROR_NO_MEM The amount of memory assigned to the SoftDevice by app_ram_base is not - * large enough to fit this configuration's memory requirement. - */ -SVCALL(SD_BLE_CFG_SET, uint32_t, sd_ble_cfg_set(uint32_t cfg_id, ble_cfg_t const *p_cfg, uint32_t app_ram_base)); - -/**@brief Get an event from the pending events queue. - * - * @param[out] p_dest Pointer to buffer to be filled in with an event, or NULL to retrieve the event length. - * This buffer must be aligned to the extend defined by @ref BLE_EVT_PTR_ALIGNMENT. - * The buffer should be interpreted as a @ref ble_evt_t struct. - * @param[in, out] p_len Pointer the length of the buffer, on return it is filled with the event length. - * - * @details This call allows the application to pull a BLE event from the BLE stack. The application is signaled that - * an event is available from the BLE stack by the triggering of the SD_EVT_IRQn interrupt. - * The application is free to choose whether to call this function from thread mode (main context) or directly from the - * Interrupt Service Routine that maps to SD_EVT_IRQn. In any case however, and because the BLE stack runs at a higher - * priority than the application, this function should be called in a loop (until @ref NRF_ERROR_NOT_FOUND is returned) - * every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the BLE stack. Failure to do so - * could potentially leave events in the internal queue without the application being aware of this fact. - * - * Sizing the p_dest buffer is equally important, since the application needs to provide all the memory necessary for the event to - * be copied into application memory. If the buffer provided is not large enough to fit the entire contents of the event, - * @ref NRF_ERROR_DATA_SIZE will be returned and the application can then call again with a larger buffer size. - * The maximum possible event length is defined by @ref BLE_EVT_LEN_MAX. The application may also "peek" the event length - * by providing p_dest as a NULL pointer and inspecting the value of *p_len upon return: - * - * \code - * uint16_t len; - * errcode = sd_ble_evt_get(NULL, &len); - * \endcode - * - * @mscs - * @mmsc{@ref BLE_COMMON_IRQ_EVT_MSC} - * @mmsc{@ref BLE_COMMON_THREAD_EVT_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Event pulled and stored into the supplied buffer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_NOT_FOUND No events ready to be pulled. - * @retval ::NRF_ERROR_DATA_SIZE Event ready but could not fit into the supplied buffer. - */ -SVCALL(SD_BLE_EVT_GET, uint32_t, sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len)); - -/**@brief Add a Vendor Specific base UUID. - * - * @details This call enables the application to add a Vendor Specific base UUID to the BLE stack's table, for later - * use with all other modules and APIs. This then allows the application to use the shorter, 24-bit @ref ble_uuid_t - * format when dealing with both 16-bit and 128-bit UUIDs without having to check for lengths and having split code - * paths. This is accomplished by extending the grouping mechanism that the Bluetooth SIG standard base UUID uses - * for all other 128-bit UUIDs. The type field in the @ref ble_uuid_t structure is an index (relative to - * @ref BLE_UUID_TYPE_VENDOR_BEGIN) to the table populated by multiple calls to this function, and the UUID field - * in the same structure contains the 2 bytes at indexes 12 and 13. The number of possible 128-bit UUIDs available to - * the application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536, - * although restricted to modifying bytes 12 and 13 for each of the entries in the supplied array. - * - * @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by - * the 16-bit uuid field in @ref ble_uuid_t. - * - * @note If a UUID is already present in the BLE stack's internal table, the corresponding index will be returned in - * p_uuid_type along with an @ref NRF_SUCCESS error code. - * - * @param[in] p_vs_uuid Pointer to a 16-octet (128-bit) little endian Vendor Specific base UUID disregarding - * bytes 12 and 13. - * @param[out] p_uuid_type Pointer to a uint8_t where the type field in @ref ble_uuid_t corresponding to this UUID will be - * stored. - * - * @retval ::NRF_SUCCESS Successfully added the Vendor Specific base UUID. - * @retval ::NRF_ERROR_INVALID_ADDR If p_vs_uuid or p_uuid_type is NULL or invalid. - * @retval ::NRF_ERROR_NO_MEM If there are no more free slots for VS UUIDs. - */ -SVCALL(SD_BLE_UUID_VS_ADD, uint32_t, sd_ble_uuid_vs_add(ble_uuid128_t const *p_vs_uuid, uint8_t *p_uuid_type)); - -/**@brief Remove a Vendor Specific base UUID. - * - * @details This call removes a Vendor Specific base UUID. This function allows - * the application to reuse memory allocated for Vendor Specific base UUIDs. - * - * @note Currently this function can only be called with a p_uuid_type set to @ref BLE_UUID_TYPE_UNKNOWN or the last added UUID - * type. - * - * @param[inout] p_uuid_type Pointer to a uint8_t where its value matches the UUID type in @ref ble_uuid_t::type to be removed. - * If the type is set to @ref BLE_UUID_TYPE_UNKNOWN, or the pointer is NULL, the last Vendor Specific - * base UUID will be removed. If the function returns successfully, the UUID type that was removed will - * be written back to @p p_uuid_type. If function returns with a failure, it contains the last type that - * is in use by the ATT Server. - * - * @retval ::NRF_SUCCESS Successfully removed the Vendor Specific base UUID. - * @retval ::NRF_ERROR_INVALID_ADDR If p_uuid_type is invalid. - * @retval ::NRF_ERROR_INVALID_PARAM If p_uuid_type points to a non-valid UUID type. - * @retval ::NRF_ERROR_FORBIDDEN If the Vendor Specific base UUID is in use by the ATT Server. - */ -SVCALL(SD_BLE_UUID_VS_REMOVE, uint32_t, sd_ble_uuid_vs_remove(uint8_t *p_uuid_type)); - -/** @brief Decode little endian raw UUID bytes (16-bit or 128-bit) into a 24 bit @ref ble_uuid_t structure. - * - * @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared - * to the corresponding ones in each entry of the table of Vendor Specific base UUIDs - * to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index - * relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type. - * - * @note If the UUID length supplied is 2, then the type set by this call will always be @ref BLE_UUID_TYPE_BLE. - * - * @param[in] uuid_le_len Length in bytes of the buffer pointed to by p_uuid_le (must be 2 or 16 bytes). - * @param[in] p_uuid_le Pointer pointing to little endian raw UUID bytes. - * @param[out] p_uuid Pointer to a @ref ble_uuid_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Successfully decoded into the @ref ble_uuid_t structure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid UUID length. - * @retval ::NRF_ERROR_NOT_FOUND For a 128-bit UUID, no match in the populated table of UUIDs. - */ -SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uint8_t const *p_uuid_le, ble_uuid_t *p_uuid)); - -/** @brief Encode a @ref ble_uuid_t structure into little endian raw UUID bytes (16-bit or 128-bit). - * - * @note The pointer to the destination buffer p_uuid_le may be NULL, in which case only the validity and size of p_uuid is - * computed. - * - * @param[in] p_uuid Pointer to a @ref ble_uuid_t structure that will be encoded into bytes. - * @param[out] p_uuid_le_len Pointer to a uint8_t that will be filled with the encoded length (2 or 16 bytes). - * @param[out] p_uuid_le Pointer to a buffer where the little endian raw UUID bytes (2 or 16) will be stored. - * - * @retval ::NRF_SUCCESS Successfully encoded into the buffer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid UUID type. - */ -SVCALL(SD_BLE_UUID_ENCODE, uint32_t, sd_ble_uuid_encode(ble_uuid_t const *p_uuid, uint8_t *p_uuid_le_len, uint8_t *p_uuid_le)); - -/**@brief Get Version Information. - * - * @details This call allows the application to get the BLE stack version information. - * - * @param[out] p_version Pointer to a ble_version_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Version information stored successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy (typically doing a locally-initiated disconnection procedure). - */ -SVCALL(SD_BLE_VERSION_GET, uint32_t, sd_ble_version_get(ble_version_t *p_version)); - -/**@brief Provide a user memory block. - * - * @note This call can only be used as a response to a @ref BLE_EVT_USER_MEM_REQUEST event issued to the application. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_block Pointer to a user memory block structure or NULL if memory is managed by the application. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully queued a response to the peer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid user memory block length supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection state or no user memory request pending. - */ -SVCALL(SD_BLE_USER_MEM_REPLY, uint32_t, sd_ble_user_mem_reply(uint16_t conn_handle, ble_user_mem_block_t const *p_block)); - -/**@brief Set a BLE option. - * - * @details This call allows the application to set the value of an option. - * - * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS, @ref BLE_GAP_OPTS, and @ref BLE_GATTC_OPTS. - * @param[in] p_opt Pointer to a @ref ble_opt_t structure containing the option value. - * - * @retval ::NRF_SUCCESS Option set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Unable to set the parameter at this time. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. - */ -SVCALL(SD_BLE_OPT_SET, uint32_t, sd_ble_opt_set(uint32_t opt_id, ble_opt_t const *p_opt)); - -/**@brief Get a BLE option. - * - * @details This call allows the application to retrieve the value of an option. - * - * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS and @ref BLE_GAP_OPTS. - * @param[out] p_opt Pointer to a ble_opt_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Option retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Unable to retrieve the parameter at this time. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. - * @retval ::NRF_ERROR_NOT_SUPPORTED This option is not supported. - * - */ -SVCALL(SD_BLE_OPT_GET, uint32_t, sd_ble_opt_get(uint32_t opt_id, ble_opt_t *p_opt)); - -/** @} */ -#ifdef __cplusplus -} -#endif -#endif /* BLE_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_err.h b/variants/wio-tracker-wm1110/softdevice/ble_err.h deleted file mode 100644 index d20f6d1416..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_err.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @addtogroup nrf_error - @{ - @ingroup BLE_COMMON - @} - - @defgroup ble_err General error codes - @{ - - @brief General error code definitions for the BLE API. - - @ingroup BLE_COMMON -*/ -#ifndef NRF_BLE_ERR_H__ -#define NRF_BLE_ERR_H__ - -#include "nrf_error.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* @defgroup BLE_ERRORS Error Codes - * @{ */ -#define BLE_ERROR_NOT_ENABLED (NRF_ERROR_STK_BASE_NUM + 0x001) /**< @ref sd_ble_enable has not been called. */ -#define BLE_ERROR_INVALID_CONN_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x002) /**< Invalid connection handle. */ -#define BLE_ERROR_INVALID_ATTR_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x003) /**< Invalid attribute handle. */ -#define BLE_ERROR_INVALID_ADV_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x004) /**< Invalid advertising handle. */ -#define BLE_ERROR_INVALID_ROLE (NRF_ERROR_STK_BASE_NUM + 0x005) /**< Invalid role. */ -#define BLE_ERROR_BLOCKED_BY_OTHER_LINKS \ - (NRF_ERROR_STK_BASE_NUM + 0x006) /**< The attempt to change link settings failed due to the scheduling of other links. */ -/** @} */ - -/** @defgroup BLE_ERROR_SUBRANGES Module specific error code subranges - * @brief Assignment of subranges for module specific error codes. - * @note For specific error codes, see ble_.h or ble_error_.h. - * @{ */ -#define NRF_L2CAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x100) /**< L2CAP specific errors. */ -#define NRF_GAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x200) /**< GAP specific errors. */ -#define NRF_GATTC_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x300) /**< GATT client specific errors. */ -#define NRF_GATTS_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x400) /**< GATT server specific errors. */ -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif - -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gap.h b/variants/wio-tracker-wm1110/softdevice/ble_gap.h deleted file mode 100644 index 8ebdfa82b0..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_gap.h +++ /dev/null @@ -1,2895 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GAP Generic Access Profile (GAP) - @{ - @brief Definitions and prototypes for the GAP interface. - */ - -#ifndef BLE_GAP_H__ -#define BLE_GAP_H__ - -#include "ble_err.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup BLE_GAP_ENUMERATIONS Enumerations - * @{ */ - -/**@brief GAP API SVC numbers. - */ -enum BLE_GAP_SVCS { - SD_BLE_GAP_ADDR_SET = BLE_GAP_SVC_BASE, /**< Set own Bluetooth Address. */ - SD_BLE_GAP_ADDR_GET = BLE_GAP_SVC_BASE + 1, /**< Get own Bluetooth Address. */ - SD_BLE_GAP_WHITELIST_SET = BLE_GAP_SVC_BASE + 2, /**< Set active whitelist. */ - SD_BLE_GAP_DEVICE_IDENTITIES_SET = BLE_GAP_SVC_BASE + 3, /**< Set device identity list. */ - SD_BLE_GAP_PRIVACY_SET = BLE_GAP_SVC_BASE + 4, /**< Set Privacy settings*/ - SD_BLE_GAP_PRIVACY_GET = BLE_GAP_SVC_BASE + 5, /**< Get Privacy settings*/ - SD_BLE_GAP_ADV_SET_CONFIGURE = BLE_GAP_SVC_BASE + 6, /**< Configure an advertising set. */ - SD_BLE_GAP_ADV_START = BLE_GAP_SVC_BASE + 7, /**< Start Advertising. */ - SD_BLE_GAP_ADV_STOP = BLE_GAP_SVC_BASE + 8, /**< Stop Advertising. */ - SD_BLE_GAP_CONN_PARAM_UPDATE = BLE_GAP_SVC_BASE + 9, /**< Connection Parameter Update. */ - SD_BLE_GAP_DISCONNECT = BLE_GAP_SVC_BASE + 10, /**< Disconnect. */ - SD_BLE_GAP_TX_POWER_SET = BLE_GAP_SVC_BASE + 11, /**< Set TX Power. */ - SD_BLE_GAP_APPEARANCE_SET = BLE_GAP_SVC_BASE + 12, /**< Set Appearance. */ - SD_BLE_GAP_APPEARANCE_GET = BLE_GAP_SVC_BASE + 13, /**< Get Appearance. */ - SD_BLE_GAP_PPCP_SET = BLE_GAP_SVC_BASE + 14, /**< Set PPCP. */ - SD_BLE_GAP_PPCP_GET = BLE_GAP_SVC_BASE + 15, /**< Get PPCP. */ - SD_BLE_GAP_DEVICE_NAME_SET = BLE_GAP_SVC_BASE + 16, /**< Set Device Name. */ - SD_BLE_GAP_DEVICE_NAME_GET = BLE_GAP_SVC_BASE + 17, /**< Get Device Name. */ - SD_BLE_GAP_AUTHENTICATE = BLE_GAP_SVC_BASE + 18, /**< Initiate Pairing/Bonding. */ - SD_BLE_GAP_SEC_PARAMS_REPLY = BLE_GAP_SVC_BASE + 19, /**< Reply with Security Parameters. */ - SD_BLE_GAP_AUTH_KEY_REPLY = BLE_GAP_SVC_BASE + 20, /**< Reply with an authentication key. */ - SD_BLE_GAP_LESC_DHKEY_REPLY = BLE_GAP_SVC_BASE + 21, /**< Reply with an LE Secure Connections DHKey. */ - SD_BLE_GAP_KEYPRESS_NOTIFY = BLE_GAP_SVC_BASE + 22, /**< Notify of a keypress during an authentication procedure. */ - SD_BLE_GAP_LESC_OOB_DATA_GET = BLE_GAP_SVC_BASE + 23, /**< Get the local LE Secure Connections OOB data. */ - SD_BLE_GAP_LESC_OOB_DATA_SET = BLE_GAP_SVC_BASE + 24, /**< Set the remote LE Secure Connections OOB data. */ - SD_BLE_GAP_ENCRYPT = BLE_GAP_SVC_BASE + 25, /**< Initiate encryption procedure. */ - SD_BLE_GAP_SEC_INFO_REPLY = BLE_GAP_SVC_BASE + 26, /**< Reply with Security Information. */ - SD_BLE_GAP_CONN_SEC_GET = BLE_GAP_SVC_BASE + 27, /**< Obtain connection security level. */ - SD_BLE_GAP_RSSI_START = BLE_GAP_SVC_BASE + 28, /**< Start reporting of changes in RSSI. */ - SD_BLE_GAP_RSSI_STOP = BLE_GAP_SVC_BASE + 29, /**< Stop reporting of changes in RSSI. */ - SD_BLE_GAP_SCAN_START = BLE_GAP_SVC_BASE + 30, /**< Start Scanning. */ - SD_BLE_GAP_SCAN_STOP = BLE_GAP_SVC_BASE + 31, /**< Stop Scanning. */ - SD_BLE_GAP_CONNECT = BLE_GAP_SVC_BASE + 32, /**< Connect. */ - SD_BLE_GAP_CONNECT_CANCEL = BLE_GAP_SVC_BASE + 33, /**< Cancel ongoing connection procedure. */ - SD_BLE_GAP_RSSI_GET = BLE_GAP_SVC_BASE + 34, /**< Get the last RSSI sample. */ - SD_BLE_GAP_PHY_UPDATE = BLE_GAP_SVC_BASE + 35, /**< Initiate or respond to a PHY Update Procedure. */ - SD_BLE_GAP_DATA_LENGTH_UPDATE = BLE_GAP_SVC_BASE + 36, /**< Initiate or respond to a Data Length Update Procedure. */ - SD_BLE_GAP_QOS_CHANNEL_SURVEY_START = BLE_GAP_SVC_BASE + 37, /**< Start Quality of Service (QoS) channel survey module. */ - SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP = BLE_GAP_SVC_BASE + 38, /**< Stop Quality of Service (QoS) channel survey module. */ - SD_BLE_GAP_ADV_ADDR_GET = BLE_GAP_SVC_BASE + 39, /**< Get the Address used on air while Advertising. */ - SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET = BLE_GAP_SVC_BASE + 40, /**< Get the next connection event counter. */ - SD_BLE_GAP_CONN_EVT_TRIGGER_START = BLE_GAP_SVC_BASE + 41, /** Start triggering a given task on connection event start. */ - SD_BLE_GAP_CONN_EVT_TRIGGER_STOP = - BLE_GAP_SVC_BASE + 42, /** Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. */ -}; - -/**@brief GAP Event IDs. - * IDs that uniquely identify an event coming from the stack to the application. - */ -enum BLE_GAP_EVTS { - BLE_GAP_EVT_CONNECTED = - BLE_GAP_EVT_BASE, /**< Connected to peer. \n See @ref ble_gap_evt_connected_t */ - BLE_GAP_EVT_DISCONNECTED = - BLE_GAP_EVT_BASE + 1, /**< Disconnected from peer. \n See @ref ble_gap_evt_disconnected_t. */ - BLE_GAP_EVT_CONN_PARAM_UPDATE = - BLE_GAP_EVT_BASE + 2, /**< Connection Parameters updated. \n See @ref ble_gap_evt_conn_param_update_t. */ - BLE_GAP_EVT_SEC_PARAMS_REQUEST = - BLE_GAP_EVT_BASE + 3, /**< Request to provide security parameters. \n Reply with @ref sd_ble_gap_sec_params_reply. - \n See @ref ble_gap_evt_sec_params_request_t. */ - BLE_GAP_EVT_SEC_INFO_REQUEST = - BLE_GAP_EVT_BASE + 4, /**< Request to provide security information. \n Reply with @ref sd_ble_gap_sec_info_reply. - \n See @ref ble_gap_evt_sec_info_request_t. */ - BLE_GAP_EVT_PASSKEY_DISPLAY = - BLE_GAP_EVT_BASE + 5, /**< Request to display a passkey to the user. \n In LESC Numeric Comparison, reply with @ref - sd_ble_gap_auth_key_reply. \n See @ref ble_gap_evt_passkey_display_t. */ - BLE_GAP_EVT_KEY_PRESSED = - BLE_GAP_EVT_BASE + 6, /**< Notification of a keypress on the remote device.\n See @ref ble_gap_evt_key_pressed_t */ - BLE_GAP_EVT_AUTH_KEY_REQUEST = - BLE_GAP_EVT_BASE + 7, /**< Request to provide an authentication key. \n Reply with @ref sd_ble_gap_auth_key_reply. - \n See @ref ble_gap_evt_auth_key_request_t. */ - BLE_GAP_EVT_LESC_DHKEY_REQUEST = - BLE_GAP_EVT_BASE + 8, /**< Request to calculate an LE Secure Connections DHKey. \n Reply with @ref - sd_ble_gap_lesc_dhkey_reply. \n See @ref ble_gap_evt_lesc_dhkey_request_t */ - BLE_GAP_EVT_AUTH_STATUS = - BLE_GAP_EVT_BASE + 9, /**< Authentication procedure completed with status. \n See @ref ble_gap_evt_auth_status_t. */ - BLE_GAP_EVT_CONN_SEC_UPDATE = - BLE_GAP_EVT_BASE + 10, /**< Connection security updated. \n See @ref ble_gap_evt_conn_sec_update_t. */ - BLE_GAP_EVT_TIMEOUT = - BLE_GAP_EVT_BASE + 11, /**< Timeout expired. \n See @ref ble_gap_evt_timeout_t. */ - BLE_GAP_EVT_RSSI_CHANGED = - BLE_GAP_EVT_BASE + 12, /**< RSSI report. \n See @ref ble_gap_evt_rssi_changed_t. */ - BLE_GAP_EVT_ADV_REPORT = - BLE_GAP_EVT_BASE + 13, /**< Advertising report. \n See @ref ble_gap_evt_adv_report_t. */ - BLE_GAP_EVT_SEC_REQUEST = - BLE_GAP_EVT_BASE + 14, /**< Security Request. \n Reply with @ref sd_ble_gap_authenticate -\n or with @ref sd_ble_gap_encrypt if required security information is available -. \n See @ref ble_gap_evt_sec_request_t. */ - BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 15, /**< Connection Parameter Update Request. \n Reply with @ref - sd_ble_gap_conn_param_update. \n See @ref ble_gap_evt_conn_param_update_request_t. */ - BLE_GAP_EVT_SCAN_REQ_REPORT = - BLE_GAP_EVT_BASE + 16, /**< Scan request report. \n See @ref ble_gap_evt_scan_req_report_t. */ - BLE_GAP_EVT_PHY_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 17, /**< PHY Update Request. \n Reply with @ref sd_ble_gap_phy_update. \n - See @ref ble_gap_evt_phy_update_request_t. */ - BLE_GAP_EVT_PHY_UPDATE = - BLE_GAP_EVT_BASE + 18, /**< PHY Update Procedure is complete. \n See @ref ble_gap_evt_phy_update_t. */ - BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 19, /**< Data Length Update Request. \n Reply with @ref - sd_ble_gap_data_length_update. \n See @ref ble_gap_evt_data_length_update_request_t. */ - BLE_GAP_EVT_DATA_LENGTH_UPDATE = - BLE_GAP_EVT_BASE + - 20, /**< LL Data Channel PDU payload length updated. \n See @ref ble_gap_evt_data_length_update_t. */ - BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT = - BLE_GAP_EVT_BASE + - 21, /**< Channel survey report. \n See @ref ble_gap_evt_qos_channel_survey_report_t. */ - BLE_GAP_EVT_ADV_SET_TERMINATED = - BLE_GAP_EVT_BASE + - 22, /**< Advertising set terminated. \n See @ref ble_gap_evt_adv_set_terminated_t. */ -}; - -/**@brief GAP Option IDs. - * IDs that uniquely identify a GAP option. - */ -enum BLE_GAP_OPTS { - BLE_GAP_OPT_CH_MAP = BLE_GAP_OPT_BASE, /**< Channel Map. @ref ble_gap_opt_ch_map_t */ - BLE_GAP_OPT_LOCAL_CONN_LATENCY = BLE_GAP_OPT_BASE + 1, /**< Local connection latency. @ref ble_gap_opt_local_conn_latency_t */ - BLE_GAP_OPT_PASSKEY = BLE_GAP_OPT_BASE + 2, /**< Set passkey. @ref ble_gap_opt_passkey_t */ - BLE_GAP_OPT_COMPAT_MODE_1 = BLE_GAP_OPT_BASE + 3, /**< Compatibility mode. @ref ble_gap_opt_compat_mode_1_t */ - BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT = - BLE_GAP_OPT_BASE + 4, /**< Set Authenticated payload timeout. @ref ble_gap_opt_auth_payload_timeout_t */ - BLE_GAP_OPT_SLAVE_LATENCY_DISABLE = - BLE_GAP_OPT_BASE + 5, /**< Disable slave latency. @ref ble_gap_opt_slave_latency_disable_t */ -}; - -/**@brief GAP Configuration IDs. - * - * IDs that uniquely identify a GAP configuration. - */ -enum BLE_GAP_CFGS { - BLE_GAP_CFG_ROLE_COUNT = BLE_GAP_CFG_BASE, /**< Role count configuration. */ - BLE_GAP_CFG_DEVICE_NAME = BLE_GAP_CFG_BASE + 1, /**< Device name configuration. */ - BLE_GAP_CFG_PPCP_INCL_CONFIG = BLE_GAP_CFG_BASE + 2, /**< Peripheral Preferred Connection Parameters characteristic - inclusion configuration. */ - BLE_GAP_CFG_CAR_INCL_CONFIG = BLE_GAP_CFG_BASE + 3, /**< Central Address Resolution characteristic - inclusion configuration. */ -}; - -/**@brief GAP TX Power roles. - */ -enum BLE_GAP_TX_POWER_ROLES { - BLE_GAP_TX_POWER_ROLE_ADV = 1, /**< Advertiser role. */ - BLE_GAP_TX_POWER_ROLE_SCAN_INIT = 2, /**< Scanner and initiator role. */ - BLE_GAP_TX_POWER_ROLE_CONN = 3, /**< Connection role. */ -}; - -/** @} */ - -/**@addtogroup BLE_GAP_DEFINES Defines - * @{ */ - -/**@defgroup BLE_ERRORS_GAP SVC return values specific to GAP - * @{ */ -#define BLE_ERROR_GAP_UUID_LIST_MISMATCH \ - (NRF_GAP_ERR_BASE + 0x000) /**< UUID list does not contain an integral number of UUIDs. */ -#define BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST \ - (NRF_GAP_ERR_BASE + 0x001) /**< Use of Whitelist not permitted with discoverable advertising. */ -#define BLE_ERROR_GAP_INVALID_BLE_ADDR \ - (NRF_GAP_ERR_BASE + 0x002) /**< The upper two bits of the address do not correspond to the specified address type. */ -#define BLE_ERROR_GAP_WHITELIST_IN_USE \ - (NRF_GAP_ERR_BASE + 0x003) /**< Attempt to modify the whitelist while already in use by another operation. */ -#define BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE \ - (NRF_GAP_ERR_BASE + 0x004) /**< Attempt to modify the device identity list while already in use by another operation. */ -#define BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE \ - (NRF_GAP_ERR_BASE + 0x005) /**< The device identity list contains entries with duplicate identity addresses. */ -/**@} */ - -/**@defgroup BLE_GAP_ROLES GAP Roles - * @{ */ -#define BLE_GAP_ROLE_INVALID 0x0 /**< Invalid Role. */ -#define BLE_GAP_ROLE_PERIPH 0x1 /**< Peripheral Role. */ -#define BLE_GAP_ROLE_CENTRAL 0x2 /**< Central Role. */ -/**@} */ - -/**@defgroup BLE_GAP_TIMEOUT_SOURCES GAP Timeout sources - * @{ */ -#define BLE_GAP_TIMEOUT_SRC_SCAN 0x01 /**< Scanning timeout. */ -#define BLE_GAP_TIMEOUT_SRC_CONN 0x02 /**< Connection timeout. */ -#define BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD 0x03 /**< Authenticated payload timeout. */ -/**@} */ - -/**@defgroup BLE_GAP_ADDR_TYPES GAP Address types - * @{ */ -#define BLE_GAP_ADDR_TYPE_PUBLIC 0x00 /**< Public (identity) address.*/ -#define BLE_GAP_ADDR_TYPE_RANDOM_STATIC 0x01 /**< Random static (identity) address. */ -#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE 0x02 /**< Random private resolvable address. */ -#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE 0x03 /**< Random private non-resolvable address. */ -#define BLE_GAP_ADDR_TYPE_ANONYMOUS \ - 0x7F /**< An advertiser may advertise without its address. \ - This type of advertising is called anonymous. */ -/**@} */ - -/**@brief The default interval in seconds at which a private address is refreshed. */ -#define BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S (900) /* 15 minutes. */ -/**@brief The maximum interval in seconds at which a private address can be refreshed. */ -#define BLE_GAP_MAX_PRIVATE_ADDR_CYCLE_INTERVAL_S (41400) /* 11 hours 30 minutes. */ - -/** @brief BLE address length. */ -#define BLE_GAP_ADDR_LEN (6) - -/**@defgroup BLE_GAP_PRIVACY_MODES Privacy modes - * @{ */ -#define BLE_GAP_PRIVACY_MODE_OFF 0x00 /**< Device will send and accept its identity address for its own address. */ -#define BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY 0x01 /**< Device will send and accept only private addresses for its own address. */ -#define BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY \ - 0x02 /**< Device will send and accept only private addresses for its own address, \ - and will not accept a peer using identity address as sender address when \ - the peer IRK is exchanged, non-zero and added to the identity list. */ -/**@} */ - -/** @brief Invalid power level. */ -#define BLE_GAP_POWER_LEVEL_INVALID 127 - -/** @brief Advertising set handle not set. */ -#define BLE_GAP_ADV_SET_HANDLE_NOT_SET (0xFF) - -/** @brief The default number of advertising sets. */ -#define BLE_GAP_ADV_SET_COUNT_DEFAULT (1) - -/** @brief The maximum number of advertising sets supported by this SoftDevice. */ -#define BLE_GAP_ADV_SET_COUNT_MAX (1) - -/**@defgroup BLE_GAP_ADV_SET_DATA_SIZES Advertising data sizes. - * @{ */ -#define BLE_GAP_ADV_SET_DATA_SIZE_MAX \ - (31) /**< Maximum data length for an advertising set. \ - If more advertising data is required, use extended advertising instead. */ -#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED \ - (255) /**< Maximum supported data length for an extended advertising set. */ - -#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED \ - (238) /**< Maximum supported data length for an extended connectable advertising set. */ -/**@}. */ - -/** @brief Set ID not available in advertising report. */ -#define BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE 0xFF - -/**@defgroup BLE_GAP_EVT_ADV_SET_TERMINATED_REASON GAP Advertising Set Terminated reasons - * @{ */ -#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT 0x01 /**< Timeout value reached. */ -#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED 0x02 /**< @ref ble_gap_adv_params_t::max_adv_evts was reached. */ -/**@} */ - -/**@defgroup BLE_GAP_AD_TYPE_DEFINITIONS GAP Advertising and Scan Response Data format - * @note Found at https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm - * @{ */ -#define BLE_GAP_AD_TYPE_FLAGS 0x01 /**< Flags for discoverability. */ -#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 /**< Partial list of 16 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 /**< Complete list of 16 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 /**< Partial list of 32 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 /**< Complete list of 32 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 /**< Partial list of 128 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 /**< Complete list of 128 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 /**< Short local device name. */ -#define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 /**< Complete local device name. */ -#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A /**< Transmit power level. */ -#define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D /**< Class of device. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E /**< Simple Pairing Hash C. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F /**< Simple Pairing Randomizer R. */ -#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 /**< Security Manager TK Value. */ -#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 /**< Security Manager Out Of Band Flags. */ -#define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 /**< Slave Connection Interval Range. */ -#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 /**< List of 16-bit Service Solicitation UUIDs. */ -#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 /**< List of 128-bit Service Solicitation UUIDs. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 /**< Service Data - 16-bit UUID. */ -#define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 /**< Public Target Address. */ -#define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 /**< Random Target Address. */ -#define BLE_GAP_AD_TYPE_APPEARANCE 0x19 /**< Appearance. */ -#define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A /**< Advertising Interval. */ -#define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B /**< LE Bluetooth Device Address. */ -#define BLE_GAP_AD_TYPE_LE_ROLE 0x1C /**< LE Role. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D /**< Simple Pairing Hash C-256. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E /**< Simple Pairing Randomizer R-256. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 /**< Service Data - 32-bit UUID. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 /**< Service Data - 128-bit UUID. */ -#define BLE_GAP_AD_TYPE_LESC_CONFIRMATION_VALUE 0x22 /**< LE Secure Connections Confirmation Value */ -#define BLE_GAP_AD_TYPE_LESC_RANDOM_VALUE 0x23 /**< LE Secure Connections Random Value */ -#define BLE_GAP_AD_TYPE_URI 0x24 /**< URI */ -#define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D /**< 3D Information Data. */ -#define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF /**< Manufacturer Specific Data. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_FLAGS GAP Advertisement Flags - * @{ */ -#define BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE (0x01) /**< LE Limited Discoverable Mode. */ -#define BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) /**< LE General Discoverable Mode. */ -#define BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) /**< BR/EDR not supported. */ -#define BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER (0x08) /**< Simultaneous LE and BR/EDR, Controller. */ -#define BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST (0x10) /**< Simultaneous LE and BR/EDR, Host. */ -#define BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE \ - (BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE | \ - BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE Limited Discoverable Mode, BR/EDR not supported. */ -#define BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE \ - (BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | \ - BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE General Discoverable Mode, BR/EDR not supported. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_INTERVALS GAP Advertising interval max and min - * @{ */ -#define BLE_GAP_ADV_INTERVAL_MIN 0x000020 /**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */ -#define BLE_GAP_ADV_INTERVAL_MAX 0x004000 /**< Maximum Advertising interval in 625 us units, i.e. 10.24 s. */ - /**@} */ - -/**@defgroup BLE_GAP_SCAN_INTERVALS GAP Scan interval max and min - * @{ */ -#define BLE_GAP_SCAN_INTERVAL_MIN 0x0004 /**< Minimum Scan interval in 625 us units, i.e. 2.5 ms. */ -#define BLE_GAP_SCAN_INTERVAL_MAX 0xFFFF /**< Maximum Scan interval in 625 us units, i.e. 40,959.375 s. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_WINDOW GAP Scan window max and min - * @{ */ -#define BLE_GAP_SCAN_WINDOW_MIN 0x0004 /**< Minimum Scan window in 625 us units, i.e. 2.5 ms. */ -#define BLE_GAP_SCAN_WINDOW_MAX 0xFFFF /**< Maximum Scan window in 625 us units, i.e. 40,959.375 s. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_TIMEOUT GAP Scan timeout max and min - * @{ */ -#define BLE_GAP_SCAN_TIMEOUT_MIN 0x0001 /**< Minimum Scan timeout in 10 ms units, i.e 10 ms. */ -#define BLE_GAP_SCAN_TIMEOUT_UNLIMITED 0x0000 /**< Continue to scan forever. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_BUFFER_SIZE GAP Minimum scanner buffer size - * - * Scan buffers are used for storing advertising data received from an advertiser. - * If ble_gap_scan_params_t::extended is set to 0, @ref BLE_GAP_SCAN_BUFFER_MIN is the minimum scan buffer length. - * else the minimum scan buffer size is @ref BLE_GAP_SCAN_BUFFER_EXTENDED_MIN. - * @{ */ -#define BLE_GAP_SCAN_BUFFER_MIN \ - (31) /**< Minimum data length for an \ - advertising set. */ -#define BLE_GAP_SCAN_BUFFER_MAX \ - (31) /**< Maximum data length for an \ - advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MIN \ - (255) /**< Minimum data length for an \ - extended advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX \ - (1650) /**< Maximum data length for an \ - extended advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED \ - (255) /**< Maximum supported data length for \ - an extended advertising set. */ -/** @} */ - -/**@defgroup BLE_GAP_ADV_TYPES GAP Advertising types - * - * Advertising types defined in Bluetooth Core Specification v5.0, Vol 6, Part B, Section 4.4.2. - * - * The maximum advertising data length is defined by @ref BLE_GAP_ADV_SET_DATA_SIZE_MAX. - * The maximum supported data length for an extended advertiser is defined by - * @ref BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED - * Note that some of the advertising types do not support advertising data. Non-scannable types do not support - * scan response data. - * - * @{ */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x01 /**< Connectable and scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE \ - 0x02 /**< Connectable non-scannable directed advertising \ - events. Advertising interval is less that 3.75 ms. \ - Use this type for fast reconnections. \ - @note Advertising data is not supported. */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x03 /**< Connectable non-scannable directed advertising \ - events. \ - @note Advertising data is not supported. */ -#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x04 /**< Non-connectable scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x05 /**< Non-connectable non-scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x06 /**< Connectable non-scannable undirected advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x07 /**< Connectable non-scannable directed advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x08 /**< Non-connectable scannable undirected advertising \ - events using extended advertising PDUs. \ - @note Only scan response data is supported. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED \ - 0x09 /**< Non-connectable scannable directed advertising \ - events using extended advertising PDUs. \ - @note Only scan response data is supported. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x0A /**< Non-connectable non-scannable undirected advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x0B /**< Non-connectable non-scannable directed advertising \ - events using extended advertising PDUs. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_FILTER_POLICIES GAP Advertising filter policies - * @{ */ -#define BLE_GAP_ADV_FP_ANY 0x00 /**< Allow scan requests and connect requests from any device. */ -#define BLE_GAP_ADV_FP_FILTER_SCANREQ 0x01 /**< Filter scan requests with whitelist. */ -#define BLE_GAP_ADV_FP_FILTER_CONNREQ 0x02 /**< Filter connect requests with whitelist. */ -#define BLE_GAP_ADV_FP_FILTER_BOTH 0x03 /**< Filter both scan and connect requests with whitelist. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_DATA_STATUS GAP Advertising data status - * @{ */ -#define BLE_GAP_ADV_DATA_STATUS_COMPLETE 0x00 /**< All data in the advertising event have been received. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA \ - 0x01 /**< More data to be received. \ - @note This value will only be used if \ - @ref ble_gap_scan_params_t::report_incomplete_evts and \ - @ref ble_gap_adv_report_type_t::extended_pdu are set to true. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED \ - 0x02 /**< Incomplete data. Buffer size insufficient to receive more. \ - @note This value will only be used if \ - @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MISSED \ - 0x03 /**< Failed to receive the remaining data. \ - @note This value will only be used if \ - @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ -/**@} */ - -/**@defgroup BLE_GAP_SCAN_FILTER_POLICIES GAP Scanner filter policies - * @{ */ -#define BLE_GAP_SCAN_FP_ACCEPT_ALL \ - 0x00 /**< Accept all advertising packets except directed advertising packets \ - not addressed to this device. */ -#define BLE_GAP_SCAN_FP_WHITELIST \ - 0x01 /**< Accept advertising packets from devices in the whitelist except directed \ - packets not addressed to this device. */ -#define BLE_GAP_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED \ - 0x02 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL. \ - In addition, accept directed advertising packets, where the advertiser's \ - address is a resolvable private address that cannot be resolved. */ -#define BLE_GAP_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED \ - 0x03 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST. \ - In addition, accept directed advertising packets, where the advertiser's \ - address is a resolvable private address that cannot be resolved. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_TIMEOUT_VALUES GAP Advertising timeout values in 10 ms units - * @{ */ -#define BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX \ - (128) /**< Maximum high duty advertising time in 10 ms units. Corresponds to 1.28 s. \ - */ -#define BLE_GAP_ADV_TIMEOUT_LIMITED_MAX \ - (18000) /**< Maximum advertising time in 10 ms units corresponding to TGAP(lim_adv_timeout) = 180 s in limited discoverable \ - mode. */ -#define BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED \ - (0) /**< Unlimited advertising in general discoverable mode. \ - For high duty cycle advertising, this corresponds to @ref BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX. */ -/**@} */ - -/**@defgroup BLE_GAP_DISC_MODES GAP Discovery modes - * @{ */ -#define BLE_GAP_DISC_MODE_NOT_DISCOVERABLE 0x00 /**< Not discoverable discovery Mode. */ -#define BLE_GAP_DISC_MODE_LIMITED 0x01 /**< Limited Discovery Mode. */ -#define BLE_GAP_DISC_MODE_GENERAL 0x02 /**< General Discovery Mode. */ -/**@} */ - -/**@defgroup BLE_GAP_IO_CAPS GAP IO Capabilities - * @{ */ -#define BLE_GAP_IO_CAPS_DISPLAY_ONLY 0x00 /**< Display Only. */ -#define BLE_GAP_IO_CAPS_DISPLAY_YESNO 0x01 /**< Display and Yes/No entry. */ -#define BLE_GAP_IO_CAPS_KEYBOARD_ONLY 0x02 /**< Keyboard Only. */ -#define BLE_GAP_IO_CAPS_NONE 0x03 /**< No I/O capabilities. */ -#define BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY 0x04 /**< Keyboard and Display. */ -/**@} */ - -/**@defgroup BLE_GAP_AUTH_KEY_TYPES GAP Authentication Key Types - * @{ */ -#define BLE_GAP_AUTH_KEY_TYPE_NONE 0x00 /**< No key (may be used to reject). */ -#define BLE_GAP_AUTH_KEY_TYPE_PASSKEY 0x01 /**< 6-digit Passkey. */ -#define BLE_GAP_AUTH_KEY_TYPE_OOB 0x02 /**< Out Of Band data. */ -/**@} */ - -/**@defgroup BLE_GAP_KP_NOT_TYPES GAP Keypress Notification Types - * @{ */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_START 0x00 /**< Passkey entry started. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_IN 0x01 /**< Passkey digit entered. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_OUT 0x02 /**< Passkey digit erased. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_CLEAR 0x03 /**< Passkey cleared. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_END 0x04 /**< Passkey entry completed. */ -/**@} */ - -/**@defgroup BLE_GAP_SEC_STATUS GAP Security status - * @{ */ -#define BLE_GAP_SEC_STATUS_SUCCESS 0x00 /**< Procedure completed with success. */ -#define BLE_GAP_SEC_STATUS_TIMEOUT 0x01 /**< Procedure timed out. */ -#define BLE_GAP_SEC_STATUS_PDU_INVALID 0x02 /**< Invalid PDU received. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE1_BEGIN 0x03 /**< Reserved for Future Use range #1 begin. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE1_END 0x80 /**< Reserved for Future Use range #1 end. */ -#define BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED 0x81 /**< Passkey entry failed (user canceled or other). */ -#define BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE 0x82 /**< Out of Band Key not available. */ -#define BLE_GAP_SEC_STATUS_AUTH_REQ 0x83 /**< Authentication requirements not met. */ -#define BLE_GAP_SEC_STATUS_CONFIRM_VALUE 0x84 /**< Confirm value failed. */ -#define BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP 0x85 /**< Pairing not supported. */ -#define BLE_GAP_SEC_STATUS_ENC_KEY_SIZE 0x86 /**< Encryption key size. */ -#define BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED 0x87 /**< Unsupported SMP command. */ -#define BLE_GAP_SEC_STATUS_UNSPECIFIED 0x88 /**< Unspecified reason. */ -#define BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS 0x89 /**< Too little time elapsed since last attempt. */ -#define BLE_GAP_SEC_STATUS_INVALID_PARAMS 0x8A /**< Invalid parameters. */ -#define BLE_GAP_SEC_STATUS_DHKEY_FAILURE 0x8B /**< DHKey check failure. */ -#define BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE 0x8C /**< Numeric Comparison failure. */ -#define BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG 0x8D /**< BR/EDR pairing in progress. */ -#define BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED 0x8E /**< BR/EDR Link Key cannot be used for LE keys. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE2_BEGIN 0x8F /**< Reserved for Future Use range #2 begin. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE2_END 0xFF /**< Reserved for Future Use range #2 end. */ -/**@} */ - -/**@defgroup BLE_GAP_SEC_STATUS_SOURCES GAP Security status sources - * @{ */ -#define BLE_GAP_SEC_STATUS_SOURCE_LOCAL 0x00 /**< Local failure. */ -#define BLE_GAP_SEC_STATUS_SOURCE_REMOTE 0x01 /**< Remote failure. */ -/**@} */ - -/**@defgroup BLE_GAP_CP_LIMITS GAP Connection Parameters Limits - * @{ */ -#define BLE_GAP_CP_MIN_CONN_INTVL_NONE 0xFFFF /**< No new minimum connection interval specified in connect parameters. */ -#define BLE_GAP_CP_MIN_CONN_INTVL_MIN \ - 0x0006 /**< Lowest minimum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ -#define BLE_GAP_CP_MIN_CONN_INTVL_MAX \ - 0x0C80 /**< Highest minimum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ - */ -#define BLE_GAP_CP_MAX_CONN_INTVL_NONE 0xFFFF /**< No new maximum connection interval specified in connect parameters. */ -#define BLE_GAP_CP_MAX_CONN_INTVL_MIN \ - 0x0006 /**< Lowest maximum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ -#define BLE_GAP_CP_MAX_CONN_INTVL_MAX \ - 0x0C80 /**< Highest maximum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ - */ -#define BLE_GAP_CP_SLAVE_LATENCY_MAX 0x01F3 /**< Highest slave latency permitted, in connection events. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_NONE 0xFFFF /**< No new supervision timeout specified in connect parameters. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN 0x000A /**< Lowest supervision timeout permitted, in units of 10 ms, i.e. 100 ms. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX 0x0C80 /**< Highest supervision timeout permitted, in units of 10 ms, i.e. 32 s. */ -/**@} */ - -/**@defgroup BLE_GAP_DEVNAME GAP device name defines. - * @{ */ -#define BLE_GAP_DEVNAME_DEFAULT "nRF5x" /**< Default device name value. */ -#define BLE_GAP_DEVNAME_DEFAULT_LEN 31 /**< Default number of octets in device name. */ -#define BLE_GAP_DEVNAME_MAX_LEN 248 /**< Maximum number of octets in device name. */ -/**@} */ - -/**@brief Disable RSSI events for connections */ -#define BLE_GAP_RSSI_THRESHOLD_INVALID 0xFF - -/**@defgroup BLE_GAP_PHYS GAP PHYs - * @{ */ -#define BLE_GAP_PHY_AUTO 0x00 /**< Automatic PHY selection. Refer @ref sd_ble_gap_phy_update for more information.*/ -#define BLE_GAP_PHY_1MBPS 0x01 /**< 1 Mbps PHY. */ -#define BLE_GAP_PHY_2MBPS 0x02 /**< 2 Mbps PHY. */ -#define BLE_GAP_PHY_CODED 0x04 /**< Coded PHY. */ -#define BLE_GAP_PHY_NOT_SET 0xFF /**< PHY is not configured. */ - -/**@brief Supported PHYs in connections, for scanning, and for advertising. */ -#define BLE_GAP_PHYS_SUPPORTED (BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_CODED) /**< All PHYs are supported. */ - -/**@} */ - -/**@defgroup BLE_GAP_CONN_SEC_MODE_SET_MACROS GAP attribute security requirement setters - * - * See @ref ble_gap_conn_sec_mode_t. - * @{ */ -/**@brief Set sec_mode pointed to by ptr to have no access rights.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(ptr) \ - do { \ - (ptr)->sm = 0; \ - (ptr)->lv = 0; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require no protection, open link.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_OPEN(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 1; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require encryption, but no MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 2; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require encryption and MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 3; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require LESC encryption and MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 4; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require signing or encryption, no MITM protection needed.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(ptr) \ - do { \ - (ptr)->sm = 2; \ - (ptr)->lv = 1; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require signing or encryption with MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 2; \ - (ptr)->lv = 2; \ - } while (0) -/**@} */ - -/**@brief GAP Security Random Number Length. */ -#define BLE_GAP_SEC_RAND_LEN 8 - -/**@brief GAP Security Key Length. */ -#define BLE_GAP_SEC_KEY_LEN 16 - -/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key Length. */ -#define BLE_GAP_LESC_P256_PK_LEN 64 - -/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman DHKey Length. */ -#define BLE_GAP_LESC_DHKEY_LEN 32 - -/**@brief GAP Passkey Length. */ -#define BLE_GAP_PASSKEY_LEN 6 - -/**@brief Maximum amount of addresses in the whitelist. */ -#define BLE_GAP_WHITELIST_ADDR_MAX_COUNT (8) - -/**@brief Maximum amount of identities in the device identities list. */ -#define BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT (8) - -/**@brief Default connection count for a configuration. */ -#define BLE_GAP_CONN_COUNT_DEFAULT (1) - -/**@defgroup BLE_GAP_EVENT_LENGTH GAP event length defines. - * @{ */ -#define BLE_GAP_EVENT_LENGTH_MIN (2) /**< Minimum event length, in 1.25 ms units. */ -#define BLE_GAP_EVENT_LENGTH_CODED_PHY_MIN (6) /**< The shortest event length in 1.25 ms units supporting LE Coded PHY. */ -#define BLE_GAP_EVENT_LENGTH_DEFAULT (3) /**< Default event length, in 1.25 ms units. */ -/**@} */ - -/**@defgroup BLE_GAP_ROLE_COUNT GAP concurrent connection count defines. - * @{ */ -#define BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT (1) /**< Default maximum number of connections concurrently acting as peripherals. */ -#define BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT (3) /**< Default maximum number of connections concurrently acting as centrals. */ -#define BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT \ - (1) /**< Default number of SMP instances shared between all connections acting as centrals. */ -#define BLE_GAP_ROLE_COUNT_COMBINED_MAX \ - (20) /**< Maximum supported number of concurrent connections in the peripheral and central roles combined. */ - -/**@} */ - -/**@brief Automatic data length parameter. */ -#define BLE_GAP_DATA_LENGTH_AUTO 0 - -/**@defgroup BLE_GAP_AUTH_PAYLOAD_TIMEOUT Authenticated payload timeout defines. - * @{ */ -#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX (48000) /**< Maximum authenticated payload timeout in 10 ms units, i.e. 8 minutes. */ -#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MIN (1) /**< Minimum authenticated payload timeout in 10 ms units, i.e. 10 ms. */ -/**@} */ - -/**@defgroup GAP_SEC_MODES GAP Security Modes - * @{ */ -#define BLE_GAP_SEC_MODE 0x00 /**< No key (may be used to reject). */ -/**@} */ - -/**@brief The total number of channels in Bluetooth Low Energy. */ -#define BLE_GAP_CHANNEL_COUNT (40) - -/**@defgroup BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS Quality of Service (QoS) Channel survey interval defines - * @{ */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS (0) /**< Continuous channel survey. */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MIN_US (7500) /**< Minimum channel survey interval in microseconds (7.5 ms). */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MAX_US (4000000) /**< Maximum channel survey interval in microseconds (4 s). */ - /**@} */ - -/** @} */ - -/** @defgroup BLE_GAP_CHAR_INCL_CONFIG GAP Characteristic inclusion configurations - * @{ - */ -#define BLE_GAP_CHAR_INCL_CONFIG_INCLUDE (0) /**< Include the characteristic in the Attribute Table */ -#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITH_SPACE \ - (1) /**< Do not include the characteristic in the Attribute table. \ - The SoftDevice will reserve the attribute handles \ - which are otherwise used for this characteristic. \ - By reserving the attribute handles it will be possible \ - to upgrade the SoftDevice without changing handle of the \ - Service Changed characteristic. */ -#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITHOUT_SPACE \ - (2) /**< Do not include the characteristic in the Attribute table. \ - The SoftDevice will not reserve the attribute handles \ - which are otherwise used for this characteristic. */ -/**@} */ - -/** @defgroup BLE_GAP_CHAR_INCL_CONFIG_DEFAULTS Characteristic inclusion default values - * @{ */ -#define BLE_GAP_PPCP_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ -#define BLE_GAP_CAR_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ -/**@} */ - -/** @defgroup BLE_GAP_SLAVE_LATENCY Slave latency configuration options - * @{ */ -#define BLE_GAP_SLAVE_LATENCY_ENABLE \ - (0) /**< Slave latency is enabled. When slave latency is enabled, \ - the slave will wake up every time it has data to send, \ - and/or every slave latency number of connection events. */ -#define BLE_GAP_SLAVE_LATENCY_DISABLE \ - (1) /**< Disable slave latency. The slave will wake up every connection event \ - regardless of the requested slave latency. \ - This option consumes the most power. */ -#define BLE_GAP_SLAVE_LATENCY_WAIT_FOR_ACK \ - (2) /**< The slave will wake up every connection event if it has not received \ - an ACK from the master for at least slave latency events. This \ - configuration may increase the power consumption in environments \ - with a lot of radio activity. */ -/**@} */ - -/**@addtogroup BLE_GAP_STRUCTURES Structures - * @{ */ - -/**@brief Advertising event properties. */ -typedef struct { - uint8_t type; /**< Advertising type. See @ref BLE_GAP_ADV_TYPES. */ - uint8_t anonymous : 1; /**< Omit advertiser's address from all PDUs. - @note Anonymous advertising is only available for - @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED and - @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED. */ - uint8_t include_tx_power : 1; /**< This feature is not supported on this SoftDevice. */ -} ble_gap_adv_properties_t; - -/**@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 Advertising Auxiliary Pointer. */ -typedef struct { - uint16_t aux_offset; /**< Time offset from the beginning of advertising packet to the auxiliary packet in 100 us units. */ - uint8_t aux_phy; /**< Indicates the PHY on which the auxiliary advertising packet is sent. See @ref BLE_GAP_PHYS. */ -} ble_gap_aux_pointer_t; - -/**@brief Bluetooth Low Energy address. */ -typedef struct { - uint8_t - addr_id_peer : 1; /**< Only valid for peer addresses. - This bit is set by the SoftDevice to indicate whether the address has been resolved from - a Resolvable Private Address (when the peer is using privacy). - If set to 1, @ref addr and @ref addr_type refer to the identity address of the resolved address. - - This bit is ignored when a variable of type @ref ble_gap_addr_t is used as input to API functions. - */ - uint8_t addr_type : 7; /**< See @ref BLE_GAP_ADDR_TYPES. */ - uint8_t addr[BLE_GAP_ADDR_LEN]; /**< 48-bit address, LSB format. - @ref addr is not used if @ref addr_type is @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. */ -} ble_gap_addr_t; - -/**@brief GAP connection parameters. - * - * @note When ble_conn_params_t is received in an event, both min_conn_interval and - * max_conn_interval will be equal to the connection interval set by the central. - * - * @note If both conn_sup_timeout and max_conn_interval are specified, then the following constraint applies: - * conn_sup_timeout * 4 > (1 + slave_latency) * max_conn_interval - * that corresponds to the following Bluetooth Spec requirement: - * The Supervision_Timeout in milliseconds shall be larger than - * (1 + Conn_Latency) * Conn_Interval_Max * 2, where Conn_Interval_Max is given in milliseconds. - */ -typedef struct { - uint16_t min_conn_interval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t max_conn_interval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t slave_latency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t conn_sup_timeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ -} ble_gap_conn_params_t; - -/**@brief GAP connection security modes. - * - * Security Mode 0 Level 0: No access permissions at all (this level is not defined by the Bluetooth Core specification).\n - * Security Mode 1 Level 1: No security is needed (aka open link).\n - * Security Mode 1 Level 2: Encrypted link required, MITM protection not necessary.\n - * Security Mode 1 Level 3: MITM protected encrypted link required.\n - * Security Mode 1 Level 4: LESC MITM protected encrypted link using a 128-bit strength encryption key required.\n - * Security Mode 2 Level 1: Signing or encryption required, MITM protection not necessary.\n - * Security Mode 2 Level 2: MITM protected signing required, unless link is MITM protected encrypted.\n - */ -typedef struct { - uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ - uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */ - -} ble_gap_conn_sec_mode_t; - -/**@brief GAP connection security status.*/ -typedef struct { - ble_gap_conn_sec_mode_t sec_mode; /**< Currently active security mode for this connection.*/ - uint8_t - encr_key_size; /**< Length of currently active encryption key, 7 to 16 octets (only applicable for bonding procedures). */ -} ble_gap_conn_sec_t; - -/**@brief Identity Resolving Key. */ -typedef struct { - uint8_t irk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing IRK. */ -} ble_gap_irk_t; - -/**@brief Channel mask (40 bits). - * Every channel is represented with a bit positioned as per channel index defined in Bluetooth Core Specification v5.0, - * Vol 6, Part B, Section 1.4.1. The LSB contained in array element 0 represents channel index 0, and bit 39 represents - * channel index 39. If a bit is set to 1, the channel is not used. - */ -typedef uint8_t ble_gap_ch_mask_t[5]; - -/**@brief GAP advertising parameters. */ -typedef struct { - ble_gap_adv_properties_t properties; /**< The properties of the advertising events. */ - ble_gap_addr_t const *p_peer_addr; /**< Address of a known peer. - @note ble_gap_addr_t::addr_type cannot be - @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. - - When privacy is enabled and the local device uses - @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE addresses, - the device identity list is searched for a matching entry. If - the local IRK for that device identity is set, the local IRK - for that device will be used to generate the advertiser address - field in the advertising packet. - - If @ref ble_gap_adv_properties_t::type is directed, this must be - set to the targeted scanner or initiator. If the peer address is - in the device identity list, the peer IRK for that device will be - used to generate @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE - target addresses used in the advertising event PDUs. */ - uint32_t interval; /**< Advertising interval in 625 us units. @sa BLE_GAP_ADV_INTERVALS. - @note If @ref ble_gap_adv_properties_t::type is set to - @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE - advertising, this parameter is ignored. */ - uint16_t duration; /**< Advertising duration in 10 ms units. When timeout is reached, - an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. - @sa BLE_GAP_ADV_TIMEOUT_VALUES. - @note The SoftDevice will always complete at least one advertising - event even if the duration is set too low. */ - uint8_t max_adv_evts; /**< Maximum advertising events that shall be sent prior to disabling - advertising. Setting the value to 0 disables the limitation. When - the count of advertising events specified by this parameter - (if not 0) is reached, advertising will be automatically stopped - and an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised - @note If @ref ble_gap_adv_properties_t::type is set to - @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE, - this parameter is ignored. */ - ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. - At least one of the primary channels, that is channel index 37-39, must be used. - Masking away secondary advertising channels is not supported. */ - uint8_t filter_policy; /**< Filter Policy. @sa BLE_GAP_ADV_FILTER_POLICIES. */ - uint8_t primary_phy; /**< Indicates the PHY on which the primary advertising channel packets - are transmitted. If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS - will be used. - Valid values are @ref BLE_GAP_PHY_1MBPS and @ref BLE_GAP_PHY_CODED. - @note The primary_phy shall indicate @ref BLE_GAP_PHY_1MBPS if - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t secondary_phy; /**< Indicates the PHY on which the secondary advertising channel packets - are transmitted. - If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS will be used. - Valid values are - @ref BLE_GAP_PHY_1MBPS, @ref BLE_GAP_PHY_2MBPS, and @ref BLE_GAP_PHY_CODED. - If @ref ble_gap_adv_properties_t::type is an extended advertising type - and connectable, this is the PHY that will be used to establish a - connection and send AUX_ADV_IND packets on. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t set_id : 4; /**< The advertising set identifier distinguishes this advertising set from other - advertising sets transmitted by this and other devices. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t scan_req_notification : 1; /**< Enable scan request notifications for this advertising set. When a - scan request is received and the scanner address is allowed - by the filter policy, @ref BLE_GAP_EVT_SCAN_REQ_REPORT is raised. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is a non-scannable - advertising type. */ -} ble_gap_adv_params_t; - -/**@brief GAP advertising data buffers. - * - * The application must provide the buffers for advertisement. The memory shall reside in application RAM, and - * shall never be modified while advertising. The data shall be kept alive until either: - * - @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. - * - @ref BLE_GAP_EVT_CONNECTED is raised with @ref ble_gap_evt_connected_t::adv_handle set to the corresponding - * advertising handle. - * - Advertising is stopped. - * - Advertising data is changed. - * To update advertising data while advertising, provide new buffers to @ref sd_ble_gap_adv_set_configure. */ -typedef struct { - ble_data_t adv_data; /**< Advertising data. - @note - Advertising data can only be specified for a @ref ble_gap_adv_properties_t::type - that is allowed to contain advertising data. */ - ble_data_t scan_rsp_data; /**< Scan response data. - @note - Scan response data can only be specified for a @ref ble_gap_adv_properties_t::type - that is scannable. */ -} ble_gap_adv_data_t; - -/**@brief GAP scanning parameters. */ -typedef struct { - uint8_t extended : 1; /**< If 1, the scanner will accept extended advertising packets. - If set to 0, the scanner will not receive advertising packets - on secondary advertising channels, and will not be able - to receive long advertising PDUs. */ - uint8_t report_incomplete_evts : 1; /**< If 1, events of type @ref ble_gap_evt_adv_report_t may have - @ref ble_gap_adv_report_type_t::status set to - @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. - This parameter is ignored when used with @ref sd_ble_gap_connect - @note This may be used to abort receiving more packets from an extended - advertising event, and is only available for extended - scanning, see @ref sd_ble_gap_scan_start. - @note This feature is not supported by this SoftDevice. */ - uint8_t active : 1; /**< If 1, perform active scanning by sending scan requests. - This parameter is ignored when used with @ref sd_ble_gap_connect. */ - uint8_t filter_policy : 2; /**< Scanning filter policy. @sa BLE_GAP_SCAN_FILTER_POLICIES. - @note Only @ref BLE_GAP_SCAN_FP_ACCEPT_ALL and - @ref BLE_GAP_SCAN_FP_WHITELIST are valid when used with - @ref sd_ble_gap_connect */ - uint8_t scan_phys; /**< Bitfield of PHYs to scan on. If set to @ref BLE_GAP_PHY_AUTO, - scan_phys will default to @ref BLE_GAP_PHY_1MBPS. - - If @ref ble_gap_scan_params_t::extended is set to 0, the only - supported PHY is @ref BLE_GAP_PHY_1MBPS. - - When used with @ref sd_ble_gap_scan_start, - the bitfield indicates the PHYs the scanner will use for scanning - on primary advertising channels. The scanner will accept - @ref BLE_GAP_PHYS_SUPPORTED as secondary advertising channel PHYs. - - When used with @ref sd_ble_gap_connect, the bitfield indicates - the PHYs the initiator will use for scanning on primary advertising - channels. The initiator will accept connections initiated on either - of the @ref BLE_GAP_PHYS_SUPPORTED PHYs. - If scan_phys contains @ref BLE_GAP_PHY_1MBPS and/or @ref BLE_GAP_PHY_2MBPS, - the primary scan PHY is @ref BLE_GAP_PHY_1MBPS. - If scan_phys also contains @ref BLE_GAP_PHY_CODED, the primary scan - PHY will also contain @ref BLE_GAP_PHY_CODED. If the only scan PHY is - @ref BLE_GAP_PHY_CODED, the primary scan PHY is - @ref BLE_GAP_PHY_CODED only. */ - uint16_t interval; /**< Scan interval in 625 us units. @sa BLE_GAP_SCAN_INTERVALS. */ - uint16_t window; /**< Scan window in 625 us units. @sa BLE_GAP_SCAN_WINDOW. - If scan_phys contains both @ref BLE_GAP_PHY_1MBPS and - @ref BLE_GAP_PHY_CODED interval shall be larger than or - equal to twice the scan window. */ - uint16_t timeout; /**< Scan timeout in 10 ms units. @sa BLE_GAP_SCAN_TIMEOUT. */ - ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. - At least one of the primary channels, that is channel index 37-39, must be - set to 0. - Masking away secondary channels is not supported. */ -} ble_gap_scan_params_t; - -/**@brief Privacy. - * - * The privacy feature provides a way for the device to avoid being tracked over a period of time. - * The privacy feature, when enabled, hides the local device identity and replaces it with a private address - * that is automatically refreshed at a specified interval. - * - * If a device still wants to be recognized by other peers, it needs to share it's Identity Resolving Key (IRK). - * With this key, a device can generate a random private address that can only be recognized by peers in possession of that - * key, and devices can establish connections without revealing their real identities. - * - * Both network privacy (@ref BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY) and device privacy (@ref - * BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY) are supported. - * - * @note If the device IRK is updated, the new IRK becomes the one to be distributed in all - * bonding procedures performed after @ref sd_ble_gap_privacy_set returns. - * The IRK distributed during bonding procedure is the device IRK that is active when @ref sd_ble_gap_sec_params_reply is - * called. - */ -typedef struct { - uint8_t privacy_mode; /**< Privacy mode, see @ref BLE_GAP_PRIVACY_MODES. Default is @ref BLE_GAP_PRIVACY_MODE_OFF. */ - uint8_t private_addr_type; /**< The private address type must be either @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE or - @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE. */ - uint16_t private_addr_cycle_s; /**< Private address cycle interval in seconds. Providing an address cycle value of 0 will use - the default value defined by @ref BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S. */ - ble_gap_irk_t - *p_device_irk; /**< When used as input, pointer to IRK structure that will be used as the default IRK. If NULL, the device - default IRK will be used. When used as output, pointer to IRK structure where the current default IRK - will be written to. If NULL, this argument is ignored. By default, the default IRK is used to generate - random private resolvable addresses for the local device unless instructed otherwise. */ -} ble_gap_privacy_params_t; - -/**@brief PHY preferences for TX and RX - * @note tx_phys and rx_phys are bit fields. Multiple bits can be set in them to indicate multiple preferred PHYs for each - * direction. - * @code - * p_gap_phys->tx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; - * p_gap_phys->rx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; - * @endcode - * - */ -typedef struct { - uint8_t tx_phys; /**< Preferred transmit PHYs, see @ref BLE_GAP_PHYS. */ - uint8_t rx_phys; /**< Preferred receive PHYs, see @ref BLE_GAP_PHYS. */ -} ble_gap_phys_t; - -/** @brief Keys that can be exchanged during a bonding procedure. */ -typedef struct { - uint8_t enc : 1; /**< Long Term Key and Master Identification. */ - uint8_t id : 1; /**< Identity Resolving Key and Identity Address Information. */ - uint8_t sign : 1; /**< Connection Signature Resolving Key. */ - uint8_t link : 1; /**< Derive the Link Key from the LTK. */ -} ble_gap_sec_kdist_t; - -/**@brief GAP security parameters. */ -typedef struct { - uint8_t bond : 1; /**< Perform bonding. */ - uint8_t mitm : 1; /**< Enable Man In The Middle protection. */ - uint8_t lesc : 1; /**< Enable LE Secure Connection pairing. */ - uint8_t keypress : 1; /**< Enable generation of keypress notifications. */ - uint8_t io_caps : 3; /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */ - uint8_t oob : 1; /**< The OOB data flag. - - In LE legacy pairing, this flag is set if a device has out of band authentication data. - The OOB method is used if both of the devices have out of band authentication data. - - In LE Secure Connections pairing, this flag is set if a device has the peer device's out of band - authentication data. The OOB method is used if at least one device has the peer device's OOB data - available. */ - uint8_t - min_key_size; /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */ - uint8_t max_key_size; /**< Maximum encryption key size in octets between min_key_size and 16. */ - ble_gap_sec_kdist_t kdist_own; /**< Key distribution bitmap: keys that the local device will distribute. */ - ble_gap_sec_kdist_t kdist_peer; /**< Key distribution bitmap: keys that the remote device will distribute. */ -} ble_gap_sec_params_t; - -/**@brief GAP Encryption Information. */ -typedef struct { - uint8_t ltk[BLE_GAP_SEC_KEY_LEN]; /**< Long Term Key. */ - uint8_t lesc : 1; /**< Key generated using LE Secure Connections. */ - uint8_t auth : 1; /**< Authenticated Key. */ - uint8_t ltk_len : 6; /**< LTK length in octets. */ -} ble_gap_enc_info_t; - -/**@brief GAP Master Identification. */ -typedef struct { - uint16_t ediv; /**< Encrypted Diversifier. */ - uint8_t rand[BLE_GAP_SEC_RAND_LEN]; /**< Random Number. */ -} ble_gap_master_id_t; - -/**@brief GAP Signing Information. */ -typedef struct { - uint8_t csrk[BLE_GAP_SEC_KEY_LEN]; /**< Connection Signature Resolving Key. */ -} ble_gap_sign_info_t; - -/**@brief GAP LE Secure Connections P-256 Public Key. */ -typedef struct { - uint8_t pk[BLE_GAP_LESC_P256_PK_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key. Stored in the - standard SMP protocol format: {X,Y} both in little-endian. */ -} ble_gap_lesc_p256_pk_t; - -/**@brief GAP LE Secure Connections DHKey. */ -typedef struct { - uint8_t key[BLE_GAP_LESC_DHKEY_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman Key. Stored in little-endian. */ -} ble_gap_lesc_dhkey_t; - -/**@brief GAP LE Secure Connections OOB data. */ -typedef struct { - ble_gap_addr_t addr; /**< Bluetooth address of the device. */ - uint8_t r[BLE_GAP_SEC_KEY_LEN]; /**< Random Number. */ - uint8_t c[BLE_GAP_SEC_KEY_LEN]; /**< Confirm Value. */ -} ble_gap_lesc_oob_data_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONNECTED. */ -typedef struct { - ble_gap_addr_t - peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref - ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ - uint8_t role; /**< BLE role for this connection, see @ref BLE_GAP_ROLES */ - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ - uint8_t adv_handle; /**< Advertising handle in which advertising has ended. - This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ - ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated - advertising set. The advertising buffers provided in - @ref sd_ble_gap_adv_set_configure are now released. - This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ -} ble_gap_evt_connected_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DISCONNECTED. */ -typedef struct { - uint8_t reason; /**< HCI error code, see @ref BLE_HCI_STATUS_CODES. */ -} ble_gap_evt_disconnected_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE. */ -typedef struct { - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ -} ble_gap_evt_conn_param_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST. */ -typedef struct { - ble_gap_phys_t peer_preferred_phys; /**< The PHYs the peer prefers to use. */ -} ble_gap_evt_phy_update_request_t; - -/**@brief Event Structure for @ref BLE_GAP_EVT_PHY_UPDATE. */ -typedef struct { - uint8_t status; /**< Status of the procedure, see @ref BLE_HCI_STATUS_CODES.*/ - uint8_t tx_phy; /**< TX PHY for this connection, see @ref BLE_GAP_PHYS. */ - uint8_t rx_phy; /**< RX PHY for this connection, see @ref BLE_GAP_PHYS. */ -} ble_gap_evt_phy_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. */ -typedef struct { - ble_gap_sec_params_t peer_params; /**< Initiator Security Parameters. */ -} ble_gap_evt_sec_params_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_INFO_REQUEST. */ -typedef struct { - ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. */ - ble_gap_master_id_t master_id; /**< Master Identification for LTK lookup. */ - uint8_t enc_info : 1; /**< If 1, Encryption Information required. */ - uint8_t id_info : 1; /**< If 1, Identity Information required. */ - uint8_t sign_info : 1; /**< If 1, Signing Information required. */ -} ble_gap_evt_sec_info_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_PASSKEY_DISPLAY. */ -typedef struct { - uint8_t passkey[BLE_GAP_PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */ - uint8_t match_request : 1; /**< If 1 requires the application to report the match using @ref sd_ble_gap_auth_key_reply - with either @ref BLE_GAP_AUTH_KEY_TYPE_NONE if there is no match or - @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY if there is a match. */ -} ble_gap_evt_passkey_display_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_KEY_PRESSED. */ -typedef struct { - uint8_t kp_not; /**< Keypress notification type, see @ref BLE_GAP_KP_NOT_TYPES. */ -} ble_gap_evt_key_pressed_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_KEY_REQUEST. */ -typedef struct { - uint8_t key_type; /**< See @ref BLE_GAP_AUTH_KEY_TYPES. */ -} ble_gap_evt_auth_key_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST. */ -typedef struct { - ble_gap_lesc_p256_pk_t - *p_pk_peer; /**< LE Secure Connections remote P-256 Public Key. This will point to the application-supplied memory - inside the keyset during the call to @ref sd_ble_gap_sec_params_reply. */ - uint8_t oobd_req : 1; /**< LESC OOB data required. A call to @ref sd_ble_gap_lesc_oob_data_set is required to complete the - procedure. */ -} ble_gap_evt_lesc_dhkey_request_t; - -/**@brief Security levels supported. - * @note See Bluetooth Specification Version 4.2 Volume 3, Part C, Chapter 10, Section 10.2.1. - */ -typedef struct { - uint8_t lv1 : 1; /**< If 1: Level 1 is supported. */ - uint8_t lv2 : 1; /**< If 1: Level 2 is supported. */ - uint8_t lv3 : 1; /**< If 1: Level 3 is supported. */ - uint8_t lv4 : 1; /**< If 1: Level 4 is supported. */ -} ble_gap_sec_levels_t; - -/**@brief Encryption Key. */ -typedef struct { - ble_gap_enc_info_t enc_info; /**< Encryption Information. */ - ble_gap_master_id_t master_id; /**< Master Identification. */ -} ble_gap_enc_key_t; - -/**@brief Identity Key. */ -typedef struct { - ble_gap_irk_t id_info; /**< Identity Resolving Key. */ - ble_gap_addr_t id_addr_info; /**< Identity Address. */ -} ble_gap_id_key_t; - -/**@brief Security Keys. */ -typedef struct { - ble_gap_enc_key_t *p_enc_key; /**< Encryption Key, or NULL. */ - ble_gap_id_key_t *p_id_key; /**< Identity Key, or NULL. */ - ble_gap_sign_info_t *p_sign_key; /**< Signing Key, or NULL. */ - ble_gap_lesc_p256_pk_t *p_pk; /**< LE Secure Connections P-256 Public Key. When in debug mode the application must use the - value defined in the Core Bluetooth Specification v4.2 Vol.3, Part H, Section 2.3.5.6.1 */ -} ble_gap_sec_keys_t; - -/**@brief Security key set for both local and peer keys. */ -typedef struct { - ble_gap_sec_keys_t keys_own; /**< Keys distributed by the local device. For LE Secure Connections the encryption key will be - generated locally and will always be stored if bonding. */ - ble_gap_sec_keys_t - keys_peer; /**< Keys distributed by the remote device. For LE Secure Connections, p_enc_key must always be NULL. */ -} ble_gap_sec_keyset_t; - -/**@brief Data Length Update Procedure parameters. */ -typedef struct { - uint16_t max_tx_octets; /**< Maximum number of payload octets that a Controller supports for transmission of a single Link - Layer Data Channel PDU. */ - uint16_t max_rx_octets; /**< Maximum number of payload octets that a Controller supports for reception of a single Link Layer - Data Channel PDU. */ - uint16_t max_tx_time_us; /**< Maximum time, in microseconds, that a Controller supports for transmission of a single Link - Layer Data Channel PDU. */ - uint16_t max_rx_time_us; /**< Maximum time, in microseconds, that a Controller supports for reception of a single Link Layer - Data Channel PDU. */ -} ble_gap_data_length_params_t; - -/**@brief Data Length Update Procedure local limitation. */ -typedef struct { - uint16_t tx_payload_limited_octets; /**< If > 0, the requested TX packet length is too long by this many octets. */ - uint16_t rx_payload_limited_octets; /**< If > 0, the requested RX packet length is too long by this many octets. */ - uint16_t tx_rx_time_limited_us; /**< If > 0, the requested combination of TX and RX packet lengths is too long by this many - microseconds. */ -} ble_gap_data_length_limitation_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_STATUS. */ -typedef struct { - uint8_t auth_status; /**< Authentication status, see @ref BLE_GAP_SEC_STATUS. */ - uint8_t error_src : 2; /**< On error, source that caused the failure, see @ref BLE_GAP_SEC_STATUS_SOURCES. */ - uint8_t bonded : 1; /**< Procedure resulted in a bond. */ - uint8_t lesc : 1; /**< Procedure resulted in a LE Secure Connection. */ - ble_gap_sec_levels_t sm1_levels; /**< Levels supported in Security Mode 1. */ - ble_gap_sec_levels_t sm2_levels; /**< Levels supported in Security Mode 2. */ - ble_gap_sec_kdist_t kdist_own; /**< Bitmap stating which keys were exchanged (distributed) by the local device. If bonding - with LE Secure Connections, the enc bit will be always set. */ - ble_gap_sec_kdist_t kdist_peer; /**< Bitmap stating which keys were exchanged (distributed) by the remote device. If bonding - with LE Secure Connections, the enc bit will never be set. */ -} ble_gap_evt_auth_status_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_SEC_UPDATE. */ -typedef struct { - ble_gap_conn_sec_t conn_sec; /**< Connection security level. */ -} ble_gap_evt_conn_sec_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Source of timeout event, see @ref BLE_GAP_TIMEOUT_SOURCES. */ - union { - ble_data_t adv_report_buffer; /**< If source is set to @ref BLE_GAP_TIMEOUT_SRC_SCAN, the released - scan buffer is contained in this field. */ - } params; /**< Event Parameters. */ -} ble_gap_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_RSSI_CHANGED. */ -typedef struct { - int8_t rssi; /**< Received Signal Strength Indication in dBm. - @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature - measurement. */ - uint8_t ch_index; /**< Data Channel Index on which the Signal Strength is measured (0-36). */ -} ble_gap_evt_rssi_changed_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_ADV_SET_TERMINATED */ -typedef struct { - uint8_t reason; /**< Reason for why the advertising set terminated. See - @ref BLE_GAP_EVT_ADV_SET_TERMINATED_REASON. */ - uint8_t adv_handle; /**< Advertising handle in which advertising has ended. */ - uint8_t num_completed_adv_events; /**< If @ref ble_gap_adv_params_t::max_adv_evts was not set to 0, - this field indicates the number of completed advertising events. */ - ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated - advertising set. The advertising buffers provided in - @ref sd_ble_gap_adv_set_configure are now released. */ -} ble_gap_evt_adv_set_terminated_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; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_REQUEST. */ -typedef struct { - uint8_t bond : 1; /**< Perform bonding. */ - uint8_t mitm : 1; /**< Man In The Middle protection requested. */ - uint8_t lesc : 1; /**< LE Secure Connections requested. */ - uint8_t keypress : 1; /**< Generation of keypress notifications requested. */ -} ble_gap_evt_sec_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST. */ -typedef struct { - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ -} ble_gap_evt_conn_param_update_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SCAN_REQ_REPORT. */ -typedef struct { - uint8_t adv_handle; /**< Advertising handle for the advertising set which received the Scan Request */ - int8_t rssi; /**< Received Signal Strength Indication in dBm. - @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature - measurement. */ - ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref - ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ -} ble_gap_evt_scan_req_report_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST. */ -typedef struct { - ble_gap_data_length_params_t peer_params; /**< Peer data length parameters. */ -} ble_gap_evt_data_length_update_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE. - * - * @note This event may also be raised after a PHY Update procedure. - */ -typedef struct { - ble_gap_data_length_params_t effective_params; /**< The effective data length parameters. */ -} ble_gap_evt_data_length_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT. */ -typedef struct { - int8_t - channel_energy[BLE_GAP_CHANNEL_COUNT]; /**< The measured energy on the Bluetooth Low Energy - channels, in dBm, indexed by Channel Index. - If no measurement is available for the given channel, channel_energy is set to - @ref BLE_GAP_POWER_LEVEL_INVALID. */ -} ble_gap_evt_qos_channel_survey_report_t; - -/**@brief GAP event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which event occurred. */ - union /**< union alternative identified by evt_id in enclosing struct. */ - { - ble_gap_evt_connected_t connected; /**< Connected Event Parameters. */ - ble_gap_evt_disconnected_t disconnected; /**< Disconnected Event Parameters. */ - ble_gap_evt_conn_param_update_t conn_param_update; /**< Connection Parameter Update Parameters. */ - ble_gap_evt_sec_params_request_t sec_params_request; /**< Security Parameters Request Event Parameters. */ - ble_gap_evt_sec_info_request_t sec_info_request; /**< Security Information Request Event Parameters. */ - ble_gap_evt_passkey_display_t passkey_display; /**< Passkey Display Event Parameters. */ - ble_gap_evt_key_pressed_t key_pressed; /**< Key Pressed Event Parameters. */ - ble_gap_evt_auth_key_request_t auth_key_request; /**< Authentication Key Request Event Parameters. */ - ble_gap_evt_lesc_dhkey_request_t lesc_dhkey_request; /**< LE Secure Connections DHKey calculation request. */ - ble_gap_evt_auth_status_t auth_status; /**< Authentication Status Event Parameters. */ - ble_gap_evt_conn_sec_update_t conn_sec_update; /**< Connection Security Update Event Parameters. */ - ble_gap_evt_timeout_t timeout; /**< Timeout Event Parameters. */ - ble_gap_evt_rssi_changed_t rssi_changed; /**< RSSI Event Parameters. */ - ble_gap_evt_adv_report_t adv_report; /**< Advertising Report Event Parameters. */ - ble_gap_evt_adv_set_terminated_t adv_set_terminated; /**< Advertising Set Terminated Event Parameters. */ - ble_gap_evt_sec_request_t sec_request; /**< Security Request Event Parameters. */ - ble_gap_evt_conn_param_update_request_t conn_param_update_request; /**< Connection Parameter Update Parameters. */ - ble_gap_evt_scan_req_report_t scan_req_report; /**< Scan Request Report Parameters. */ - ble_gap_evt_phy_update_request_t phy_update_request; /**< PHY Update Request Event Parameters. */ - ble_gap_evt_phy_update_t phy_update; /**< PHY Update Parameters. */ - ble_gap_evt_data_length_update_request_t data_length_update_request; /**< Data Length Update Request Event Parameters. */ - ble_gap_evt_data_length_update_t data_length_update; /**< Data Length Update Event Parameters. */ - ble_gap_evt_qos_channel_survey_report_t - qos_channel_survey_report; /**< Quality of Service (QoS) Channel Survey Report Parameters. */ - } params; /**< Event Parameters. */ -} ble_gap_evt_t; - -/** - * @brief BLE GAP connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_CONN_COUNT The connection count for the connection configurations is zero. - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - The sum of conn_count for all connection configurations combined exceeds UINT8_MAX. - * - The event length is smaller than @ref BLE_GAP_EVENT_LENGTH_MIN. - */ -typedef struct { - uint8_t conn_count; /**< The number of concurrent connections the application can create with this configuration. - The default and minimum value is @ref BLE_GAP_CONN_COUNT_DEFAULT. */ - uint16_t event_length; /**< The time set aside for this connection on every connection interval in 1.25 ms units. - The default value is @ref BLE_GAP_EVENT_LENGTH_DEFAULT, the minimum value is @ref - BLE_GAP_EVENT_LENGTH_MIN. The event length and the connection interval are the primary parameters - for setting the throughput of a connection. - See the SoftDevice Specification for details on throughput. */ -} ble_gap_conn_cfg_t; - -/** - * @brief Configuration of maximum concurrent connections in the different connected roles, set with - * @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_CONN_COUNT The sum of periph_role_count and central_role_count is too - * large. The maximum supported sum of concurrent connections is - * @ref BLE_GAP_ROLE_COUNT_COMBINED_MAX. - * @retval ::NRF_ERROR_INVALID_PARAM central_sec_count is larger than central_role_count. - * @retval ::NRF_ERROR_RESOURCES The adv_set_count is too large. The maximum - * supported advertising handles is - * @ref BLE_GAP_ADV_SET_COUNT_MAX. - */ -typedef struct { - uint8_t adv_set_count; /**< Maximum number of advertising sets. Default value is @ref BLE_GAP_ADV_SET_COUNT_DEFAULT. */ - uint8_t periph_role_count; /**< Maximum number of connections concurrently acting as a peripheral. Default value is @ref - BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT. */ - uint8_t central_role_count; /**< Maximum number of connections concurrently acting as a central. Default value is @ref - BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT. */ - uint8_t central_sec_count; /**< Number of SMP instances shared between all connections acting as a central. Default value is - @ref BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT. */ - uint8_t qos_channel_survey_role_available : 1; /**< If set, the Quality of Service (QoS) channel survey module is available to - the application using @ref sd_ble_gap_qos_channel_survey_start. */ -} ble_gap_cfg_role_count_t; - -/** - * @brief Device name and its properties, set with @ref sd_ble_cfg_set. - * - * @note If the device name is not configured, the default device name will be - * @ref BLE_GAP_DEVNAME_DEFAULT, the maximum device name length will be - * @ref BLE_GAP_DEVNAME_DEFAULT_LEN, vloc will be set to @ref BLE_GATTS_VLOC_STACK and the device name - * will have no write access. - * - * @note If @ref max_len is more than @ref BLE_GAP_DEVNAME_DEFAULT_LEN and vloc is set to @ref BLE_GATTS_VLOC_STACK, - * the attribute table size must be increased to have room for the longer device name (see - * @ref sd_ble_cfg_set and @ref ble_gatts_cfg_attr_tab_size_t). - * - * @note If vloc is @ref BLE_GATTS_VLOC_STACK : - * - p_value must point to non-volatile memory (flash) or be NULL. - * - If p_value is NULL, the device name will initially be empty. - * - * @note If vloc is @ref BLE_GATTS_VLOC_USER : - * - p_value cannot be NULL. - * - If the device name is writable, p_value must point to volatile memory (RAM). - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - Invalid device name location (vloc). - * - Invalid device name security mode. - * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: - * - The device name length is invalid (must be between 0 and @ref BLE_GAP_DEVNAME_MAX_LEN). - * - The device name length is too long for the given Attribute Table. - * @retval ::NRF_ERROR_NOT_SUPPORTED Device name security mode is not supported. - */ -typedef struct { - ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ - uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ - uint8_t *p_value; /**< Pointer to where the value (device name) is stored or will be stored. */ - uint16_t current_len; /**< Current length in bytes of the memory pointed to by p_value.*/ - uint16_t max_len; /**< Maximum length in bytes of the memory pointed to by p_value.*/ -} ble_gap_cfg_device_name_t; - -/**@brief Peripheral Preferred Connection Parameters include configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t include_cfg; /**< Inclusion configuration of the Peripheral Preferred Connection Parameters characteristic. - See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_PPCP_INCL_CONFIG_DEFAULT. */ -} ble_gap_cfg_ppcp_incl_cfg_t; - -/**@brief Central Address Resolution include configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t include_cfg; /**< Inclusion configuration of the Central Address Resolution characteristic. - See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_CAR_INCL_CONFIG_DEFAULT. */ -} ble_gap_cfg_car_incl_cfg_t; - -/**@brief Configuration structure for GAP configurations. */ -typedef union { - ble_gap_cfg_role_count_t role_count_cfg; /**< Role count configuration, cfg_id is @ref BLE_GAP_CFG_ROLE_COUNT. */ - ble_gap_cfg_device_name_t device_name_cfg; /**< Device name configuration, cfg_id is @ref BLE_GAP_CFG_DEVICE_NAME. */ - ble_gap_cfg_ppcp_incl_cfg_t ppcp_include_cfg; /**< Peripheral Preferred Connection Parameters characteristic include - configuration, cfg_id is @ref BLE_GAP_CFG_PPCP_INCL_CONFIG. */ - ble_gap_cfg_car_incl_cfg_t car_include_cfg; /**< Central Address Resolution characteristic include configuration, - cfg_id is @ref BLE_GAP_CFG_CAR_INCL_CONFIG. */ -} ble_gap_cfg_t; - -/**@brief Channel Map option. - * - * @details Used with @ref sd_ble_opt_get to get the current channel map - * or @ref sd_ble_opt_set to set a new channel map. When setting the - * channel map, it applies to all current and future connections. When getting the - * current channel map, it applies to a single connection and the connection handle - * must be supplied. - * - * @note Setting the channel map may take some time, depending on connection parameters. - * The time taken may be different for each connection and the get operation will - * return the previous channel map until the new one has taken effect. - * - * @note After setting the channel map, by spec it can not be set again until at least 1 s has passed. - * See Bluetooth Specification Version 4.1 Volume 2, Part E, Section 7.3.46. - * - * @retval ::NRF_SUCCESS Get or set successful. - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - Less then two bits in @ref ch_map are set. - * - Bits for primary advertising channels (37-39) are set. - * @retval ::NRF_ERROR_BUSY Channel map was set again before enough time had passed. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied for get. - * - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle (only applicable for get) */ - uint8_t ch_map[5]; /**< Channel Map (37-bit). */ -} ble_gap_opt_ch_map_t; - -/**@brief Local connection latency option. - * - * @details Local connection latency is a feature which enables the slave to improve - * current consumption by ignoring the slave latency set by the peer. The - * local connection latency can only be set to a multiple of the slave latency, - * and cannot be longer than half of the supervision timeout. - * - * @details Used with @ref sd_ble_opt_set to set the local connection latency. The - * @ref sd_ble_opt_get is not supported for this option, but the actual - * local connection latency (unless set to NULL) is set as a return parameter - * when setting the option. - * - * @note The latency set will be truncated down to the closest slave latency event - * multiple, or the nearest multiple before half of the supervision timeout. - * - * @note The local connection latency is disabled by default, and needs to be enabled for new - * connections and whenever the connection is updated. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint16_t requested_latency; /**< Requested local connection latency. */ - uint16_t *p_actual_latency; /**< Pointer to storage for the actual local connection latency (can be set to NULL to skip return - value). */ -} ble_gap_opt_local_conn_latency_t; - -/**@brief Disable slave latency - * - * @details Used with @ref sd_ble_opt_set to temporarily disable slave latency of a peripheral connection - * (see @ref ble_gap_conn_params_t::slave_latency). And to re-enable it again. When disabled, the - * peripheral will ignore the slave_latency set by the central. - * - * @note Shall only be called on peripheral links. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint8_t disable; /**< For allowed values see @ref BLE_GAP_SLAVE_LATENCY */ -} ble_gap_opt_slave_latency_disable_t; - -/**@brief Passkey Option. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} - * @endmscs - * - * @details Structure containing the passkey to be used during pairing. This can be used with @ref - * sd_ble_opt_set to make the SoftDevice use a preprogrammed passkey for authentication - * instead of generating a random one. - * - * @note Repeated pairing attempts using the same preprogrammed passkey makes pairing vulnerable to MITM attacks. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * - */ -typedef struct { - uint8_t const *p_passkey; /**< Pointer to 6-digit ASCII string (digit 0..9 only, no NULL termination) passkey to be used - during pairing. If this is NULL, the SoftDevice will generate a random passkey if required.*/ -} ble_gap_opt_passkey_t; - -/**@brief Compatibility mode 1 option. - * - * @details This can be used with @ref sd_ble_opt_set to enable and disable - * compatibility mode 1. Compatibility mode 1 is disabled by default. - * - * @note Compatibility mode 1 enables interoperability with devices that do not support a value of - * 0 for the WinOffset parameter in the Link Layer CONNECT_IND packet. This applies to a - * limited set of legacy peripheral devices from another vendor. Enabling this compatibility - * mode will only have an effect if the local device will act as a central device and - * initiate a connection to a peripheral device. In that case it may lead to the connection - * creation taking up to one connection interval longer to complete for all connections. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_INVALID_STATE When connection creation is ongoing while mode 1 is set. - */ -typedef struct { - uint8_t enable : 1; /**< Enable compatibility mode 1.*/ -} ble_gap_opt_compat_mode_1_t; - -/**@brief Authenticated payload timeout option. - * - * @details This can be used with @ref sd_ble_opt_set to change the Authenticated payload timeout to a value other - * than the default of @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX. - * - * @note The authenticated payload timeout event ::BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD will be generated - * if auth_payload_timeout time has elapsed without receiving a packet with a valid MIC on an encrypted - * link. - * - * @note The LE ping procedure will be initiated before the timer expires to give the peer a chance - * to reset the timer. In addition the stack will try to prioritize running of LE ping over other - * activities to increase chances of finishing LE ping before timer expires. To avoid side-effects - * on other activities, it is recommended to use high timeout values. - * Recommended timeout > 2*(connInterval * (6 + connSlaveLatency)). - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. auth_payload_timeout was outside of allowed range. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint16_t auth_payload_timeout; /**< Requested timeout in 10 ms unit, see @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT. */ -} ble_gap_opt_auth_payload_timeout_t; - -/**@brief Option structure for GAP options. */ -typedef union { - ble_gap_opt_ch_map_t ch_map; /**< Parameters for the Channel Map option. */ - ble_gap_opt_local_conn_latency_t local_conn_latency; /**< Parameters for the Local connection latency option */ - ble_gap_opt_passkey_t passkey; /**< Parameters for the Passkey option.*/ - ble_gap_opt_compat_mode_1_t compat_mode_1; /**< Parameters for the compatibility mode 1 option.*/ - ble_gap_opt_auth_payload_timeout_t auth_payload_timeout; /**< Parameters for the authenticated payload timeout option.*/ - ble_gap_opt_slave_latency_disable_t slave_latency_disable; /**< Parameters for the Disable slave latency option */ -} ble_gap_opt_t; - -/**@brief Connection event triggering parameters. */ -typedef struct { - uint8_t ppi_ch_id; /**< PPI channel to use. This channel should be regarded as reserved until - connection event PPI task triggering is stopped. - The PPI channel ID can not be one of the PPI channels reserved by - the SoftDevice. See @ref NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK. */ - uint32_t task_endpoint; /**< Task Endpoint to trigger. */ - uint16_t conn_evt_counter_start; /**< The connection event on which the task triggering should start. */ - uint16_t period_in_events; /**< Trigger period. Valid range is [1, 32767]. - If the device is in slave role and slave latency is enabled, - this parameter should be set to a multiple of (slave latency + 1) - to ensure low power operation. */ -} ble_gap_conn_event_trigger_t; -/**@} */ - -/**@addtogroup BLE_GAP_FUNCTIONS Functions - * @{ */ - -/**@brief Set the local Bluetooth identity address. - * - * The local Bluetooth identity address is the address that identifies this device to other peers. - * The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. - * - * @note The identity address cannot be changed while advertising, scanning or creating a connection. - * - * @note This address will be distributed to the peer during bonding. - * If the address changes, the address stored in the peer device will not be valid and the ability to - * reconnect using the old address will be lost. - * - * @note By default the SoftDevice will set an address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC upon being - * enabled. The address is a random number populated during the IC manufacturing process and remains unchanged - * for the lifetime of each IC. - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @endmscs - * - * @param[in] p_addr Pointer to address structure. - * - * @retval ::NRF_SUCCESS Address successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_STATE The identity address cannot be changed while advertising, - * scanning or creating a connection. - */ -SVCALL(SD_BLE_GAP_ADDR_SET, uint32_t, sd_ble_gap_addr_set(ble_gap_addr_t const *p_addr)); - -/**@brief Get local Bluetooth identity address. - * - * @note This will always return the identity address irrespective of the privacy settings, - * i.e. the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. - * - * @param[out] p_addr Pointer to address structure to be filled in. - * - * @retval ::NRF_SUCCESS Address successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - */ -SVCALL(SD_BLE_GAP_ADDR_GET, uint32_t, sd_ble_gap_addr_get(ble_gap_addr_t *p_addr)); - -/**@brief Get the Bluetooth device address used by the advertiser. - * - * @note This function will return the local Bluetooth address used in advertising PDUs. When - * using privacy, the SoftDevice will generate a new private address every - * @ref ble_gap_privacy_params_t::private_addr_cycle_s configured using - * @ref sd_ble_gap_privacy_set. Hence depending on when the application calls this API, the - * address returned may not be the latest address that is used in the advertising PDUs. - * - * @param[in] adv_handle The advertising handle to get the address from. - * @param[out] p_addr Pointer to address structure to be filled in. - * - * @retval ::NRF_SUCCESS Address successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. - * @retval ::NRF_ERROR_INVALID_STATE The advertising set is currently not advertising. - */ -SVCALL(SD_BLE_GAP_ADV_ADDR_GET, uint32_t, sd_ble_gap_adv_addr_get(uint8_t adv_handle, ble_gap_addr_t *p_addr)); - -/**@brief Set the active whitelist in the SoftDevice. - * - * @note Only one whitelist can be used at a time and the whitelist is shared between the BLE roles. - * The whitelist cannot be set if a BLE role is using the whitelist. - * - * @note If an address is resolved using the information in the device identity list, then the whitelist - * filter policy applies to the peer identity address and not the resolvable address sent on air. - * - * @mscs - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} - * @endmscs - * - * @param[in] pp_wl_addrs Pointer to a whitelist of peer addresses, if NULL the whitelist will be cleared. - * @param[in] len Length of the whitelist, maximum @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT. - * - * @retval ::NRF_SUCCESS The whitelist is successfully set/cleared. - * @retval ::NRF_ERROR_INVALID_ADDR The whitelist (or one of its entries) provided is invalid. - * @retval ::BLE_ERROR_GAP_WHITELIST_IN_USE The whitelist is in use by a BLE role and cannot be set or cleared. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_DATA_SIZE The given whitelist size is invalid (zero or too large); this can only return when - * pp_wl_addrs is not NULL. - */ -SVCALL(SD_BLE_GAP_WHITELIST_SET, uint32_t, sd_ble_gap_whitelist_set(ble_gap_addr_t const *const *pp_wl_addrs, uint8_t len)); - -/**@brief Set device identity list. - * - * @note Only one device identity list can be used at a time and the list is shared between the BLE roles. - * The device identity list cannot be set if a BLE role is using the list. - * - * @param[in] pp_id_keys Pointer to an array of peer identity addresses and peer IRKs, if NULL the device identity list will - * be cleared. - * @param[in] pp_local_irks Pointer to an array of local IRKs. Each entry in the array maps to the entry in pp_id_keys at the - * same index. To fill in the list with the currently set device IRK for all peers, set to NULL. - * @param[in] len Length of the device identity list, maximum @ref BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT. - * - * @mscs - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS The device identity list successfully set/cleared. - * @retval ::NRF_ERROR_INVALID_ADDR The device identity list (or one of its entries) provided is invalid. - * This code may be returned if the local IRK list also has an invalid entry. - * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE The device identity list is in use and cannot be set or cleared. - * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE The device identity list contains multiple entries with the same identity - * address. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_DATA_SIZE The given device identity list size invalid (zero or too large); this can - * only return when pp_id_keys is not NULL. - */ -SVCALL(SD_BLE_GAP_DEVICE_IDENTITIES_SET, uint32_t, - sd_ble_gap_device_identities_set(ble_gap_id_key_t const *const *pp_id_keys, ble_gap_irk_t const *const *pp_local_irks, - uint8_t len)); - -/**@brief Set privacy settings. - * - * @note Privacy settings cannot be changed while advertising, scanning or creating a connection. - * - * @param[in] p_privacy_params Privacy settings. - * - * @mscs - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_INVALID_ADDR The pointer to privacy settings is NULL or invalid. - * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. - * @retval ::NRF_ERROR_INVALID_PARAM Out of range parameters are provided. - * @retval ::NRF_ERROR_NOT_SUPPORTED The SoftDevice does not support privacy if the Central Address Resolution - characteristic is not configured to be included and the SoftDevice is configured - to support central roles. - See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - * @retval ::NRF_ERROR_INVALID_STATE Privacy settings cannot be changed while advertising, scanning - * or creating a connection. - */ -SVCALL(SD_BLE_GAP_PRIVACY_SET, uint32_t, sd_ble_gap_privacy_set(ble_gap_privacy_params_t const *p_privacy_params)); - -/**@brief Get privacy settings. - * - * @note ::ble_gap_privacy_params_t::p_device_irk must be initialized to NULL or a valid address before this function is called. - * If it is initialized to a valid address, the address pointed to will contain the current device IRK on return. - * - * @param[in,out] p_privacy_params Privacy settings. - * - * @retval ::NRF_SUCCESS Privacy settings read. - * @retval ::NRF_ERROR_INVALID_ADDR The pointer given for returning the privacy settings may be NULL or invalid. - * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. - */ -SVCALL(SD_BLE_GAP_PRIVACY_GET, uint32_t, sd_ble_gap_privacy_get(ble_gap_privacy_params_t *p_privacy_params)); - -/**@brief Configure an advertising set. Set, clear or update advertising and scan response data. - * - * @note The format of the advertising data will be checked by this call to ensure interoperability. - * Limitations imposed by this API call to the data provided include having a flags data type in the scan response data and - * duplicating the local name in the advertising data and scan response data. - * - * @note In order to update advertising data while advertising, new advertising buffers must be provided. - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in,out] p_adv_handle Provide a pointer to a handle containing @ref - * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising set. On success, a new handle is then returned through the - * pointer. Provide a pointer to an existing advertising handle to configure an existing advertising set. - * @param[in] p_adv_data Advertising data. If set to NULL, no advertising data will be used. See - * @ref ble_gap_adv_data_t. - * @param[in] p_adv_params Advertising parameters. When this function is used to update advertising - * data while advertising, this parameter must be NULL. See @ref ble_gap_adv_params_t. - * - * @retval ::NRF_SUCCESS Advertising set successfully configured. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: - * - Invalid advertising data configuration specified. See @ref - * ble_gap_adv_data_t. - * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. - * - Use of whitelist requested but whitelist has not been set, - * see @ref sd_ble_gap_whitelist_set. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR ble_gap_adv_params_t::p_peer_addr is invalid. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - It is invalid to provide non-NULL advertising set parameters while - * advertising. - * - It is invalid to provide the same data buffers while advertising. To - * update advertising data, provide new advertising buffers. - * @retval ::BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST Discoverable mode and whitelist incompatible. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. Use @ref - * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_FLAGS Invalid combination of advertising flags supplied. - * @retval ::NRF_ERROR_INVALID_DATA Invalid data type(s) supplied. Check the advertising data format - * specification given in Bluetooth Specification Version 5.0, Volume 3, Part C, Chapter 11. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid data length(s) supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported data length or advertising parameter configuration. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to configure a new advertising handle. Update an - * existing advertising handle instead. - * @retval ::BLE_ERROR_GAP_UUID_LIST_MISMATCH Invalid UUID list supplied. - */ -SVCALL(SD_BLE_GAP_ADV_SET_CONFIGURE, uint32_t, - sd_ble_gap_adv_set_configure(uint8_t *p_adv_handle, ble_gap_adv_data_t const *p_adv_data, - ble_gap_adv_params_t const *p_adv_params)); - -/**@brief Start advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). - * - * @note Only one advertiser may be active at any time. - * - * @note If privacy is enabled, the advertiser's private address will be refreshed when this function is called. - * See @ref sd_ble_gap_privacy_set(). - * - * @events - * @event{@ref BLE_GAP_EVT_CONNECTED, Generated after connection has been established through connectable advertising.} - * @event{@ref BLE_GAP_EVT_ADV_SET_TERMINATED, Advertising set has terminated.} - * @event{@ref BLE_GAP_EVT_SCAN_REQ_REPORT, A scan request was received.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] adv_handle Advertising handle to advertise on, received from @ref sd_ble_gap_adv_set_configure. - * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or - * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. For non-connectable - * advertising, this is ignored. - * - * @retval ::NRF_SUCCESS The BLE stack has started advertising. - * @retval ::NRF_ERROR_INVALID_STATE adv_handle is not configured or already advertising. - * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration - * tag has been reached; connectable advertiser cannot be started. - * To increase the number of available connections, - * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. Configure a new adveriting handle with @ref - sd_ble_gap_adv_set_configure. - * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: - * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. - * - Use of whitelist requested but whitelist has not been set, see @ref - sd_ble_gap_whitelist_set. - * @retval ::NRF_ERROR_RESOURCES Either: - * - adv_handle is configured with connectable advertising, but the event_length parameter - * associated with conn_cfg_tag is too small to be able to establish a connection on - * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. - * - Not enough BLE role slots available. - Stop one or more currently active roles (Central, Peripheral, Broadcaster or Observer) - and try again. - * - p_adv_params is configured with connectable advertising, but the event_length - parameter - * associated with conn_cfg_tag is too small to be able to establish a connection on - * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. - */ -SVCALL(SD_BLE_GAP_ADV_START, uint32_t, sd_ble_gap_adv_start(uint8_t adv_handle, uint8_t conn_cfg_tag)); - -/**@brief Stop advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] adv_handle The advertising handle that should stop advertising. - * - * @retval ::NRF_SUCCESS The BLE stack has stopped advertising. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Invalid advertising handle. - * @retval ::NRF_ERROR_INVALID_STATE The advertising handle is not advertising. - */ -SVCALL(SD_BLE_GAP_ADV_STOP, uint32_t, sd_ble_gap_adv_stop(uint8_t adv_handle)); - -/**@brief Update connection parameters. - * - * @details In the central role this will initiate a Link Layer connection parameter update procedure, - * otherwise in the peripheral role, this will send the corresponding L2CAP request and wait for - * the central to perform the procedure. In both cases, and regardless of success or failure, the application - * will be informed of the result with a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE event. - * - * @details This function can be used as a central both to reply to a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST or to start the - * procedure unrequested. - * - * @events - * @event{@ref BLE_GAP_EVT_CONN_PARAM_UPDATE, Result of the connection parameter update procedure.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CPU_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CPU_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CPU_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_conn_params Pointer to desired connection parameters. If NULL is provided on a peripheral role, - * the parameters in the PPCP characteristic of the GAP service will be used instead. - * If NULL is provided on a central role and in response to a @ref - * BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST, the peripheral request will be rejected - * - * @retval ::NRF_SUCCESS The Connection Update procedure has been started successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. - * @retval ::NRF_ERROR_BUSY Procedure already in progress, wait for pending procedures to complete and retry. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GAP_CONN_PARAM_UPDATE, uint32_t, - sd_ble_gap_conn_param_update(uint16_t conn_handle, ble_gap_conn_params_t const *p_conn_params)); - -/**@brief Disconnect (GAP Link Termination). - * - * @details This call initiates the disconnection procedure, and its completion will be communicated to the application - * with a @ref BLE_GAP_EVT_DISCONNECTED event. - * - * @events - * @event{@ref BLE_GAP_EVT_DISCONNECTED, Generated when disconnection procedure is complete.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CONN_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] hci_status_code HCI status code, see @ref BLE_HCI_STATUS_CODES (accepted values are @ref - * BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION and @ref BLE_HCI_CONN_INTERVAL_UNACCEPTABLE). - * - * @retval ::NRF_SUCCESS The disconnection procedure has been started successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. - */ -SVCALL(SD_BLE_GAP_DISCONNECT, uint32_t, sd_ble_gap_disconnect(uint16_t conn_handle, uint8_t hci_status_code)); - -/**@brief Set the radio's transmit power. - * - * @param[in] role The role to set the transmit power for, see @ref BLE_GAP_TX_POWER_ROLES for - * possible roles. - * @param[in] handle The handle parameter is interpreted depending on role: - * - If role is @ref BLE_GAP_TX_POWER_ROLE_CONN, this value is the specific connection handle. - * - If role is @ref BLE_GAP_TX_POWER_ROLE_ADV, the advertising set identified with the advertising handle, - * will use the specified transmit power, and include it in the advertising packet headers if - * @ref ble_gap_adv_properties_t::include_tx_power set. - * - For all other roles handle is ignored. - * @param[in] tx_power Radio transmit power in dBm (see note for accepted values). - * - * @note Supported tx_power values: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm and +4dBm. - * In addition, on some chips following values are supported: +2dBm, +5dBm, +6dBm, +7dBm and +8dBm. - * Setting these values on a chip that does not support them will result in undefined behaviour. - * @note The initiator will have the same transmit power as the scanner. - * @note When a connection is created it will inherit the transmit power from the initiator or - * advertiser leading to the connection. - * - * @retval ::NRF_SUCCESS Successfully changed the transmit power. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_TX_POWER_SET, uint32_t, sd_ble_gap_tx_power_set(uint8_t role, uint16_t handle, int8_t tx_power)); - -/**@brief Set GAP Appearance value. - * - * @param[in] appearance Appearance (16-bit), see @ref BLE_APPEARANCES. - * - * @retval ::NRF_SUCCESS Appearance value set successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - */ -SVCALL(SD_BLE_GAP_APPEARANCE_SET, uint32_t, sd_ble_gap_appearance_set(uint16_t appearance)); - -/**@brief Get GAP Appearance value. - * - * @param[out] p_appearance Pointer to appearance (16-bit) to be filled in, see @ref BLE_APPEARANCES. - * - * @retval ::NRF_SUCCESS Appearance value retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GAP_APPEARANCE_GET, uint32_t, sd_ble_gap_appearance_get(uint16_t *p_appearance)); - -/**@brief Set GAP Peripheral Preferred Connection Parameters. - * - * @param[in] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure with the desired parameters. - * - * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, - see @ref ble_gap_cfg_ppcp_incl_cfg_t. - */ -SVCALL(SD_BLE_GAP_PPCP_SET, uint32_t, sd_ble_gap_ppcp_set(ble_gap_conn_params_t const *p_conn_params)); - -/**@brief Get GAP Peripheral Preferred Connection Parameters. - * - * @param[out] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure where the parameters will be stored. - * - * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, - see @ref ble_gap_cfg_ppcp_incl_cfg_t. - */ -SVCALL(SD_BLE_GAP_PPCP_GET, uint32_t, sd_ble_gap_ppcp_get(ble_gap_conn_params_t *p_conn_params)); - -/**@brief Set GAP device name. - * - * @note If the device name is located in application flash memory (see @ref ble_gap_cfg_device_name_t), - * it cannot be changed. Then @ref NRF_ERROR_FORBIDDEN will be returned. - * - * @param[in] p_write_perm Write permissions for the Device Name characteristic, see @ref ble_gap_conn_sec_mode_t. - * @param[in] p_dev_name Pointer to a UTF-8 encoded, non NULL-terminated string. - * @param[in] len Length of the UTF-8, non NULL-terminated string pointed to by p_dev_name in octets (must be smaller or - * equal than @ref BLE_GAP_DEVNAME_MAX_LEN). - * - * @retval ::NRF_SUCCESS GAP device name and permissions set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_FORBIDDEN Device name is not writable. - */ -SVCALL(SD_BLE_GAP_DEVICE_NAME_SET, uint32_t, - sd_ble_gap_device_name_set(ble_gap_conn_sec_mode_t const *p_write_perm, uint8_t const *p_dev_name, uint16_t len)); - -/**@brief Get GAP device name. - * - * @note If the device name is longer than the size of the supplied buffer, - * p_len will return the complete device name length, - * and not the number of bytes actually returned in p_dev_name. - * The application may use this information to allocate a suitable buffer size. - * - * @param[out] p_dev_name Pointer to an empty buffer where the UTF-8 non NULL-terminated string will be placed. Set to - * NULL to obtain the complete device name length. - * @param[in,out] p_len Length of the buffer pointed by p_dev_name, complete device name length on output. - * - * @retval ::NRF_SUCCESS GAP device name retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - */ -SVCALL(SD_BLE_GAP_DEVICE_NAME_GET, uint32_t, sd_ble_gap_device_name_get(uint8_t *p_dev_name, uint16_t *p_len)); - -/**@brief Initiate the GAP Authentication procedure. - * - * @details In the central role, this function will send an SMP Pairing Request (or an SMP Pairing Failed if rejected), - * otherwise in the peripheral role, an SMP Security Request will be sent. - * - * @events - * @event{Depending on the security parameters set and the packet exchanges with the peer\, the following events may be - * generated:} - * @event{@ref BLE_GAP_EVT_SEC_PARAMS_REQUEST} - * @event{@ref BLE_GAP_EVT_SEC_INFO_REQUEST} - * @event{@ref BLE_GAP_EVT_PASSKEY_DISPLAY} - * @event{@ref BLE_GAP_EVT_KEY_PRESSED} - * @event{@ref BLE_GAP_EVT_AUTH_KEY_REQUEST} - * @event{@ref BLE_GAP_EVT_LESC_DHKEY_REQUEST} - * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE} - * @event{@ref BLE_GAP_EVT_AUTH_STATUS} - * @event{@ref BLE_GAP_EVT_TIMEOUT} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_SEC_REQ_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_sec_params Pointer to the @ref ble_gap_sec_params_t structure with the security parameters to be used during the - * pairing or bonding procedure. In the peripheral role, only the bond, mitm, lesc and keypress fields of this structure are used. - * In the central role, this pointer may be NULL to reject a Security Request. - * - * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - No link has been established. - * - An encryption is already executing or queued. - * @retval ::NRF_ERROR_NO_MEM The maximum number of authentication procedures that can run in parallel for the given role is - * reached. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. - * Distribution of own Identity Information is only supported if the Central - * Address Resolution characteristic is configured to be included or - * the Softdevice is configured to support peripheral roles only. - * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - * @retval ::NRF_ERROR_TIMEOUT A SMP timeout has occurred, and further SMP operations on this link is prohibited. - */ -SVCALL(SD_BLE_GAP_AUTHENTICATE, uint32_t, - sd_ble_gap_authenticate(uint16_t conn_handle, ble_gap_sec_params_t const *p_sec_params)); - -/**@brief Reply with GAP security parameters. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST, calling it at other times will result in - * an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_CONFIRM_FAIL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_KS_TOO_SMALL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_APP_ERROR_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_REMOTE_PAIRING_FAIL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_TIMEOUT_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] sec_status Security status, see @ref BLE_GAP_SEC_STATUS. - * @param[in] p_sec_params Pointer to a @ref ble_gap_sec_params_t security parameters structure. In the central role this must be - * set to NULL, as the parameters have already been provided during a previous call to @ref sd_ble_gap_authenticate. - * @param[in,out] p_sec_keyset Pointer to a @ref ble_gap_sec_keyset_t security keyset structure. Any keys generated and/or - * distributed as a result of the ongoing security procedure will be stored into the memory referenced by the pointers inside this - * structure. The keys will be stored and available to the application upon reception of a @ref BLE_GAP_EVT_AUTH_STATUS event. - * Note that the SoftDevice expects the application to provide memory for storing the - * peer's keys. So it must be ensured that the relevant pointers inside this structure are not NULL. The - * pointers to the local key can, however, be NULL, in which case, the local key data will not be available to the application - * upon reception of the - * @ref BLE_GAP_EVT_AUTH_STATUS event. - * - * @retval ::NRF_SUCCESS Successfully accepted security parameter from the application. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Security parameters has not been requested. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. - * Distribution of own Identity Information is only supported if the Central - * Address Resolution characteristic is configured to be included or - * the Softdevice is configured to support peripheral roles only. - * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - */ -SVCALL(SD_BLE_GAP_SEC_PARAMS_REPLY, uint32_t, - sd_ble_gap_sec_params_reply(uint16_t conn_handle, uint8_t sec_status, ble_gap_sec_params_t const *p_sec_params, - ble_gap_sec_keyset_t const *p_sec_keyset)); - -/**@brief Reply with an authentication key. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_AUTH_KEY_REQUEST or a @ref BLE_GAP_EVT_PASSKEY_DISPLAY, - * calling it at other times will result in an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] key_type See @ref BLE_GAP_AUTH_KEY_TYPES. - * @param[in] p_key If key type is @ref BLE_GAP_AUTH_KEY_TYPE_NONE, then NULL. - * If key type is @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY, then a 6-byte ASCII string (digit 0..9 only, no NULL - * termination) or NULL when confirming LE Secure Connections Numeric Comparison. If key type is @ref BLE_GAP_AUTH_KEY_TYPE_OOB, - * then a 16-byte OOB key value in little-endian format. - * - * @retval ::NRF_SUCCESS Authentication key successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Authentication key has not been requested. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_AUTH_KEY_REPLY, uint32_t, - sd_ble_gap_auth_key_reply(uint16_t conn_handle, uint8_t key_type, uint8_t const *p_key)); - -/**@brief Reply with an LE Secure connections DHKey. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST, calling it at other times will result in - * an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_dhkey LE Secure Connections DHKey. - * - * @retval ::NRF_SUCCESS DHKey successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - The peer is not authenticated. - * - The application has not pulled a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_DHKEY_REPLY, uint32_t, - sd_ble_gap_lesc_dhkey_reply(uint16_t conn_handle, ble_gap_lesc_dhkey_t const *p_dhkey)); - -/**@brief Notify the peer of a local keypress. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] kp_not See @ref BLE_GAP_KP_NOT_TYPES. - * - * @retval ::NRF_SUCCESS Keypress notification successfully queued for transmission. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Authentication key not requested. - * - Passkey has not been entered. - * - Keypresses have not been enabled by both peers. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy. Retry at later time. - */ -SVCALL(SD_BLE_GAP_KEYPRESS_NOTIFY, uint32_t, sd_ble_gap_keypress_notify(uint16_t conn_handle, uint8_t kp_not)); - -/**@brief Generate a set of OOB data to send to a peer out of band. - * - * @note The @ref ble_gap_addr_t included in the OOB data returned will be the currently active one (or, if a connection has - * already been established, the one used during connection setup). The application may manually overwrite it with an updated - * value. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. Can be @ref BLE_CONN_HANDLE_INVALID if a BLE connection has not been established yet. - * @param[in] p_pk_own LE Secure Connections local P-256 Public Key. - * @param[out] p_oobd_own The OOB data to be sent out of band to a peer. - * - * @retval ::NRF_SUCCESS OOB data successfully generated. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_OOB_DATA_GET, uint32_t, - sd_ble_gap_lesc_oob_data_get(uint16_t conn_handle, ble_gap_lesc_p256_pk_t const *p_pk_own, - ble_gap_lesc_oob_data_t *p_oobd_own)); - -/**@brief Provide the OOB data sent/received out of band. - * - * @note An authentication procedure with OOB selected as an algorithm must be in progress when calling this function. - * @note A @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event with the oobd_req set to 1 must have been received prior to calling this - * function. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_oobd_own The OOB data sent out of band to a peer or NULL if the peer has not received OOB data. - * Must correspond to @ref ble_gap_sec_params_t::oob flag in @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. - * @param[in] p_oobd_peer The OOB data received out of band from a peer or NULL if none received. - * Must correspond to @ref ble_gap_sec_params_t::oob flag - * in @ref sd_ble_gap_authenticate in the central role or - * in @ref sd_ble_gap_sec_params_reply in the peripheral role. - * - * @retval ::NRF_SUCCESS OOB data accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Authentication key not requested - * - Not expecting LESC OOB data - * - Have not actually exchanged passkeys. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_OOB_DATA_SET, uint32_t, - sd_ble_gap_lesc_oob_data_set(uint16_t conn_handle, ble_gap_lesc_oob_data_t const *p_oobd_own, - ble_gap_lesc_oob_data_t const *p_oobd_peer)); - -/**@brief Initiate GAP Encryption procedure. - * - * @details In the central role, this function will initiate the encryption procedure using the encryption information provided. - * - * @events - * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE, The connection security has been updated.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_master_id Pointer to a @ref ble_gap_master_id_t master identification structure. - * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. - * - * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::BLE_ERROR_INVALID_ROLE Operation is not supported in the Peripheral role. - * @retval ::NRF_ERROR_BUSY Procedure already in progress or not allowed at this time, wait for pending procedures to complete and - * retry. - */ -SVCALL(SD_BLE_GAP_ENCRYPT, uint32_t, - sd_ble_gap_encrypt(uint16_t conn_handle, ble_gap_master_id_t const *p_master_id, ble_gap_enc_info_t const *p_enc_info)); - -/**@brief Reply with GAP security information. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_INFO_REQUEST, calling it at other times will result in - * @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * @note Data signing is not yet supported, and p_sign_info must therefore be NULL. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_ENC_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. May be NULL to signal none is - * available. - * @param[in] p_id_info Pointer to a @ref ble_gap_irk_t identity information structure. May be NULL to signal none is available. - * @param[in] p_sign_info Pointer to a @ref ble_gap_sign_info_t signing information structure. May be NULL to signal none is - * available. - * - * @retval ::NRF_SUCCESS Successfully accepted security information. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - No link has been established. - * - No @ref BLE_GAP_EVT_SEC_INFO_REQUEST pending. - * - Encryption information provided by the app without being requested. See @ref - * ble_gap_evt_sec_info_request_t::enc_info. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_SEC_INFO_REPLY, uint32_t, - sd_ble_gap_sec_info_reply(uint16_t conn_handle, ble_gap_enc_info_t const *p_enc_info, ble_gap_irk_t const *p_id_info, - ble_gap_sign_info_t const *p_sign_info)); - -/**@brief Get the current connection security. - * - * @param[in] conn_handle Connection handle. - * @param[out] p_conn_sec Pointer to a @ref ble_gap_conn_sec_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Current connection security successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_CONN_SEC_GET, uint32_t, sd_ble_gap_conn_sec_get(uint16_t conn_handle, ble_gap_conn_sec_t *p_conn_sec)); - -/**@brief Start reporting the received signal strength to the application. - * - * A new event is reported whenever the RSSI value changes, until @ref sd_ble_gap_rssi_stop is called. - * - * @events - * @event{@ref BLE_GAP_EVT_RSSI_CHANGED, New RSSI data available. How often the event is generated is - * dependent on the settings of the threshold_dbm - * and skip_count input parameters.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] threshold_dbm Minimum change in dBm before triggering the @ref BLE_GAP_EVT_RSSI_CHANGED event. Events are - * disabled if threshold_dbm equals @ref BLE_GAP_RSSI_THRESHOLD_INVALID. - * @param[in] skip_count Number of RSSI samples with a change of threshold_dbm or more before sending a new @ref - * BLE_GAP_EVT_RSSI_CHANGED event. - * - * @retval ::NRF_SUCCESS Successfully activated RSSI reporting. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is already ongoing. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_RSSI_START, uint32_t, sd_ble_gap_rssi_start(uint16_t conn_handle, uint8_t threshold_dbm, uint8_t skip_count)); - -/**@brief Stop reporting the received signal strength. - * - * @note An RSSI change detected before the call but not yet received by the application - * may be reported after @ref sd_ble_gap_rssi_stop has been called. - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * - * @retval ::NRF_SUCCESS Successfully deactivated RSSI reporting. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_RSSI_STOP, uint32_t, sd_ble_gap_rssi_stop(uint16_t conn_handle)); - -/**@brief Get the received signal strength for the last connection event. - * - * @ref sd_ble_gap_rssi_start must be called to start reporting RSSI before using this function. @ref NRF_ERROR_NOT_FOUND - * will be returned until RSSI was sampled for the first time after calling @ref sd_ble_gap_rssi_start. - * @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature measurement. - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[out] p_rssi Pointer to the location where the RSSI measurement shall be stored. - * @param[out] p_ch_index Pointer to the location where Channel Index for the RSSI measurement shall be stored. - * - * @retval ::NRF_SUCCESS Successfully read the RSSI. - * @retval ::NRF_ERROR_NOT_FOUND No sample is available. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. - */ -SVCALL(SD_BLE_GAP_RSSI_GET, uint32_t, sd_ble_gap_rssi_get(uint16_t conn_handle, int8_t *p_rssi, uint8_t *p_ch_index)); - -/**@brief Start or continue scanning (GAP Discovery procedure, Observer Procedure). - * - * @note A call to this function will require the application to keep the memory pointed by - * p_adv_report_buffer alive until the buffer is released. The buffer is released when the scanner is stopped - * or when this function is called with another buffer. - * - * @note The scanner will automatically stop in the following cases: - * - @ref sd_ble_gap_scan_stop is called. - * - @ref sd_ble_gap_connect is called. - * - A @ref BLE_GAP_EVT_TIMEOUT with source set to @ref BLE_GAP_TIMEOUT_SRC_SCAN is received. - * - When a @ref BLE_GAP_EVT_ADV_REPORT event is received and @ref ble_gap_adv_report_type_t::status is not set to - * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. In this case scanning is only paused to let the application - * access received data. The application must call this function to continue scanning, or call @ref - * sd_ble_gap_scan_stop to stop scanning. - * - * @note If a @ref BLE_GAP_EVT_ADV_REPORT event is received with @ref ble_gap_adv_report_type_t::status set to - * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the scanner will continue scanning, and the application will - * receive more reports from this advertising event. The following reports will include the old and new received data. - * - * @events - * @event{@ref BLE_GAP_EVT_ADV_REPORT, An advertising or scan response packet has been received.} - * @event{@ref BLE_GAP_EVT_TIMEOUT, Scanner has timed out.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_SCAN_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] p_scan_params Pointer to scan parameters structure. When this function is used to continue - * scanning, this parameter must be NULL. - * @param[in] p_adv_report_buffer Pointer to buffer used to store incoming advertising data. - * The memory pointed to should be kept alive until the scanning is stopped. - * See @ref BLE_GAP_SCAN_BUFFER_SIZE for minimum and maximum buffer size. - * If the scanner receives advertising data larger than can be stored in the buffer, - * a @ref BLE_GAP_EVT_ADV_REPORT will be raised with @ref ble_gap_adv_report_type_t::status - * set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED. - * - * @retval ::NRF_SUCCESS Successfully initiated scanning procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Scanning is already ongoing and p_scan_params was not NULL - * - Scanning is not running and p_scan_params was NULL. - * - The scanner has timed out when this function is called to continue scanning. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. See @ref ble_gap_scan_params_t. - * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported parameters supplied. See @ref ble_gap_scan_params_t. - * @retval ::NRF_ERROR_INVALID_LENGTH The provided buffer length is invalid. See @ref BLE_GAP_SCAN_BUFFER_MIN. - * @retval ::NRF_ERROR_RESOURCES Not enough BLE role slots available. - * Stop one or more currently active roles (Central, Peripheral or Broadcaster) and try again - */ -SVCALL(SD_BLE_GAP_SCAN_START, uint32_t, - sd_ble_gap_scan_start(ble_gap_scan_params_t const *p_scan_params, ble_data_t const *p_adv_report_buffer)); - -/**@brief Stop scanning (GAP Discovery procedure, Observer Procedure). - * - * @note The buffer provided in @ref sd_ble_gap_scan_start is released. - * - * @mscs - * @mmsc{@ref BLE_GAP_SCAN_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully stopped scanning procedure. - * @retval ::NRF_ERROR_INVALID_STATE Not in the scanning state. - */ -SVCALL(SD_BLE_GAP_SCAN_STOP, uint32_t, sd_ble_gap_scan_stop(void)); - -/**@brief Create a connection (GAP Link Establishment). - * - * @note If a scanning procedure is currently in progress it will be automatically stopped when calling this function. - * The scanning procedure will be stopped even if the function returns an error. - * - * @events - * @event{@ref BLE_GAP_EVT_CONNECTED, A connection was established.} - * @event{@ref BLE_GAP_EVT_TIMEOUT, Failed to establish a connection.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} - * @endmscs - * - * @param[in] p_peer_addr Pointer to peer identity address. If @ref ble_gap_scan_params_t::filter_policy is set to use - * whitelist, then p_peer_addr is ignored. - * @param[in] p_scan_params Pointer to scan parameters structure. - * @param[in] p_conn_params Pointer to desired connection parameters. - * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or - * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. - * - * @retval ::NRF_SUCCESS Successfully initiated connection procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid parameter(s) pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * - Invalid parameter(s) in p_scan_params or p_conn_params. - * - Use of whitelist requested but whitelist has not been set, see @ref - * sd_ble_gap_whitelist_set. - * - Peer address was not present in the device identity list, see @ref - * sd_ble_gap_device_identities_set. - * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. - * @retval ::NRF_ERROR_INVALID_STATE The SoftDevice is in an invalid state to perform this operation. This may be due to an - * existing locally initiated connect procedure, which must complete before initiating again. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid Peer address. - * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration tag has been reached. - * To increase the number of available connections, - * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. - * @retval ::NRF_ERROR_RESOURCES Either: - * - Not enough BLE role slots available. - * Stop one or more currently active roles (Central, Peripheral or Observer) and try again. - * - The event_length parameter associated with conn_cfg_tag is too small to be able to - * establish a connection on the selected @ref ble_gap_scan_params_t::scan_phys. - * Use @ref sd_ble_cfg_set to increase the event length. - */ -SVCALL(SD_BLE_GAP_CONNECT, uint32_t, - sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params, - ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag)); - -/**@brief Cancel a connection establishment. - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully canceled an ongoing connection procedure. - * @retval ::NRF_ERROR_INVALID_STATE No locally initiated connect procedure started or connection - * completed occurred. - */ -SVCALL(SD_BLE_GAP_CONNECT_CANCEL, uint32_t, sd_ble_gap_connect_cancel(void)); - -/**@brief Initiate or respond to a PHY Update Procedure - * - * @details This function is used to initiate or respond to a PHY Update Procedure. It will always - * generate a @ref BLE_GAP_EVT_PHY_UPDATE event if successfully executed. - * If this function is used to initiate a PHY Update procedure and the only option - * provided in @ref ble_gap_phys_t::tx_phys and @ref ble_gap_phys_t::rx_phys is the - * currently active PHYs in the respective directions, the SoftDevice will generate a - * @ref BLE_GAP_EVT_PHY_UPDATE with the current PHYs set and will not initiate the - * procedure in the Link Layer. - * - * If @ref ble_gap_phys_t::tx_phys or @ref ble_gap_phys_t::rx_phys is @ref BLE_GAP_PHY_AUTO, - * then the stack will select PHYs based on the peer's PHY preferences and the local link - * configuration. The PHY Update procedure will for this case result in a PHY combination - * that respects the time constraints configured with @ref sd_ble_cfg_set and the current - * link layer data length. - * - * When acting as a central, the SoftDevice will select the fastest common PHY in each direction. - * - * If the peer does not support the PHY Update Procedure, then the resulting - * @ref BLE_GAP_EVT_PHY_UPDATE event will have a status set to - * @ref BLE_HCI_UNSUPPORTED_REMOTE_FEATURE. - * - * If the PHY Update procedure was rejected by the peer due to a procedure collision, the status - * will be @ref BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION or - * @ref BLE_HCI_DIFFERENT_TRANSACTION_COLLISION. - * If the peer responds to the PHY Update procedure with invalid parameters, the status - * will be @ref BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS. - * If the PHY Update procedure was rejected by the peer for a different reason, the status will - * contain the reason as specified by the peer. - * - * @events - * @event{@ref BLE_GAP_EVT_PHY_UPDATE, Result of the PHY Update Procedure.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_PHY_UPDATE} - * @mmsc{@ref BLE_GAP_PERIPHERAL_PHY_UPDATE} - * @endmscs - * - * @param[in] conn_handle Connection handle to indicate the connection for which the PHY Update is requested. - * @param[in] p_gap_phys Pointer to PHY structure. - * - * @retval ::NRF_SUCCESS Successfully requested a PHY Update. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the combination of - * @ref ble_gap_phys_t::tx_phys, @ref ble_gap_phys_t::rx_phys, and @ref - * ble_gap_data_length_params_t. The connection event length is configured with @ref BLE_CONN_CFG_GAP using @ref sd_ble_cfg_set. - * @retval ::NRF_ERROR_BUSY Procedure is already in progress or not allowed at this time. Process pending events and wait for the - * pending procedure to complete and retry. - * - */ -SVCALL(SD_BLE_GAP_PHY_UPDATE, uint32_t, sd_ble_gap_phy_update(uint16_t conn_handle, ble_gap_phys_t const *p_gap_phys)); - -/**@brief Initiate or respond to a Data Length Update Procedure. - * - * @note If the application uses @ref BLE_GAP_DATA_LENGTH_AUTO for one or more members of - * p_dl_params, the SoftDevice will choose the highest value supported in current - * configuration and connection parameters. - * @note If the link PHY is Coded, the SoftDevice will ensure that the MaxTxTime and/or MaxRxTime - * used in the Data Length Update procedure is at least 2704 us. Otherwise, MaxTxTime and - * MaxRxTime will be limited to maximum 2120 us. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_dl_params Pointer to local parameters to be used in Data Length Update - * Procedure. Set any member to @ref BLE_GAP_DATA_LENGTH_AUTO to let - * the SoftDevice automatically decide the value for that member. - * Set to NULL to use automatic values for all members. - * @param[out] p_dl_limitation Pointer to limitation to be written when local device does not - * have enough resources or does not support the requested Data Length - * Update parameters. Ignored if NULL. - * - * @mscs - * @mmsc{@ref BLE_GAP_DATA_LENGTH_UPDATE_PROCEDURE_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully set Data Length Extension initiation/response parameters. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The requested parameters are not supported by the SoftDevice. Inspect - * p_dl_limitation to see which parameter is not supported. - * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the requested - * parameters. Use @ref sd_ble_cfg_set with @ref BLE_CONN_CFG_GAP to increase the connection event length. Inspect p_dl_limitation - * to see where the limitation is. - * @retval ::NRF_ERROR_BUSY Peer has already initiated a Data Length Update Procedure. Process the - * pending @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event to respond. - */ -SVCALL(SD_BLE_GAP_DATA_LENGTH_UPDATE, uint32_t, - sd_ble_gap_data_length_update(uint16_t conn_handle, ble_gap_data_length_params_t const *p_dl_params, - ble_gap_data_length_limitation_t *p_dl_limitation)); - -/**@brief Start the Quality of Service (QoS) channel survey module. - * - * @details The channel survey module provides measurements of the energy levels on - * the Bluetooth Low Energy channels. When the module is enabled, @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT - * events will periodically report the measured energy levels for each channel. - * - * @note The measurements are scheduled with lower priority than other Bluetooth Low Energy roles, - * Radio Timeslot API events and Flash API events. - * - * @note The channel survey module will attempt to do measurements so that the average interval - * between measurements will be interval_us. However due to the channel survey module - * having the lowest priority of all roles and modules, this may not be possible. In that - * case fewer than expected channel survey reports may be given. - * - * @note In order to use the channel survey module, @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available - * must be set. This is done using @ref sd_ble_cfg_set. - * - * @param[in] interval_us Requested average interval for the measurements and reports. See - * @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS for valid ranges. If set - * to @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS, the channel - * survey role will be scheduled at every available opportunity. - * - * @retval ::NRF_SUCCESS The module is successfully started. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. interval_us is out of the - * allowed range. - * @retval ::NRF_ERROR_INVALID_STATE Trying to start the module when already running. - * @retval ::NRF_ERROR_RESOURCES The channel survey module is not available to the application. - * Set @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available using - * @ref sd_ble_cfg_set. - */ -SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_START, uint32_t, sd_ble_gap_qos_channel_survey_start(uint32_t interval_us)); - -/**@brief Stop the Quality of Service (QoS) channel survey module. - * - * @note The SoftDevice may generate one @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT event after this - * function is called. - * - * @retval ::NRF_SUCCESS The module is successfully stopped. - * @retval ::NRF_ERROR_INVALID_STATE Trying to stop the module when it is not running. - */ -SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP, uint32_t, sd_ble_gap_qos_channel_survey_stop(void)); - -/**@brief Obtain the next connection event counter value. - * - * @details The connection event counter is initialized to zero on the first connection event. The value is incremented - * by one for each connection event. For more information see Bluetooth Core Specification v5.0, Vol 6, Part B, - * Section 4.5.1. - * - * @note The connection event counter obtained through this API will be outdated if this API is called - * at the same time as the connection event counter is incremented. - * - * @note This API will always return the last connection event counter + 1. - * The actual connection event may be multiple connection events later if: - * - Slave latency is enabled and there is no data to transmit or receive. - * - Another role is scheduled with a higher priority at the same time as the next connection event. - * - * @param[in] conn_handle Connection handle. - * @param[out] p_counter Pointer to the variable where the next connection event counter will be written. - * - * @retval ::NRF_SUCCESS The connection event counter was successfully retrieved. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET, uint32_t, - sd_ble_gap_next_conn_evt_counter_get(uint16_t conn_handle, uint16_t *p_counter)); - -/**@brief Start triggering a given task on connection event start. - * - * @details When enabled, this feature will trigger a PPI task at the start of connection events. - * The application can configure the SoftDevice to trigger every N connection events starting from - * a given connection event counter. See also @ref ble_gap_conn_event_trigger_t. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_params Connection event trigger parameters. - * - * @retval ::NRF_SUCCESS Success. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. See @ref ble_gap_conn_event_trigger_t. - * @retval ::NRF_ERROR_INVALID_STATE Either: - * - Trying to start connection event triggering when it is already ongoing. - * - @ref ble_gap_conn_event_trigger_t::conn_evt_counter_start is in the past. - * Use @ref sd_ble_gap_next_conn_evt_counter_get to find a new value - to be used as ble_gap_conn_event_trigger_t::conn_evt_counter_start. - */ -SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_START, uint32_t, - sd_ble_gap_conn_evt_trigger_start(uint16_t conn_handle, ble_gap_conn_event_trigger_t const *p_params)); - -/**@brief Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. - * - * @param[in] conn_handle Connection handle. - * - * @retval ::NRF_SUCCESS Success. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE Trying to stop connection event triggering when it is not enabled. - */ -SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_STOP, uint32_t, sd_ble_gap_conn_evt_trigger_stop(uint16_t conn_handle)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GAP_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gatt.h b/variants/wio-tracker-wm1110/softdevice/ble_gatt.h deleted file mode 100644 index df0d728fc8..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_gatt.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATT Generic Attribute Profile (GATT) Common - @{ - @brief Common definitions and prototypes for the GATT interfaces. - */ - -#ifndef BLE_GATT_H__ -#define BLE_GATT_H__ - -#include "ble_err.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATT_DEFINES Defines - * @{ */ - -/** @brief Default ATT MTU, in bytes. */ -#define BLE_GATT_ATT_MTU_DEFAULT 23 - -/**@brief Invalid Attribute Handle. */ -#define BLE_GATT_HANDLE_INVALID 0x0000 - -/**@brief First Attribute Handle. */ -#define BLE_GATT_HANDLE_START 0x0001 - -/**@brief Last Attribute Handle. */ -#define BLE_GATT_HANDLE_END 0xFFFF - -/** @defgroup BLE_GATT_TIMEOUT_SOURCES GATT Timeout sources - * @{ */ -#define BLE_GATT_TIMEOUT_SRC_PROTOCOL 0x00 /**< ATT Protocol timeout. */ -/** @} */ - -/** @defgroup BLE_GATT_WRITE_OPS GATT Write operations - * @{ */ -#define BLE_GATT_OP_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATT_OP_WRITE_REQ 0x01 /**< Write Request. */ -#define BLE_GATT_OP_WRITE_CMD 0x02 /**< Write Command. */ -#define BLE_GATT_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ -#define BLE_GATT_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ -#define BLE_GATT_OP_EXEC_WRITE_REQ 0x05 /**< Execute Write Request. */ -/** @} */ - -/** @defgroup BLE_GATT_EXEC_WRITE_FLAGS GATT Execute Write flags - * @{ */ -#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL 0x00 /**< Cancel prepared write. */ -#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE 0x01 /**< Execute prepared write. */ -/** @} */ - -/** @defgroup BLE_GATT_HVX_TYPES GATT Handle Value operations - * @{ */ -#define BLE_GATT_HVX_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATT_HVX_NOTIFICATION 0x01 /**< Handle Value Notification. */ -#define BLE_GATT_HVX_INDICATION 0x02 /**< Handle Value Indication. */ -/** @} */ - -/** @defgroup BLE_GATT_STATUS_CODES GATT Status Codes - * @{ */ -#define BLE_GATT_STATUS_SUCCESS 0x0000 /**< Success. */ -#define BLE_GATT_STATUS_UNKNOWN 0x0001 /**< Unknown or not applicable status. */ -#define BLE_GATT_STATUS_ATTERR_INVALID 0x0100 /**< ATT Error: Invalid Error Code. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_HANDLE 0x0101 /**< ATT Error: Invalid Attribute Handle. */ -#define BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED 0x0102 /**< ATT Error: Read not permitted. */ -#define BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED 0x0103 /**< ATT Error: Write not permitted. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_PDU 0x0104 /**< ATT Error: Used in ATT as Invalid PDU. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION 0x0105 /**< ATT Error: Authenticated link required. */ -#define BLE_GATT_STATUS_ATTERR_REQUEST_NOT_SUPPORTED 0x0106 /**< ATT Error: Used in ATT as Request Not Supported. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_OFFSET 0x0107 /**< ATT Error: Offset specified was past the end of the attribute. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION 0x0108 /**< ATT Error: Used in ATT as Insufficient Authorization. */ -#define BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL 0x0109 /**< ATT Error: Used in ATT as Prepare Queue Full. */ -#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND 0x010A /**< ATT Error: Used in ATT as Attribute not found. */ -#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_LONG \ - 0x010B /**< ATT Error: Attribute cannot be read or written using read/write blob requests. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_ENC_KEY_SIZE 0x010C /**< ATT Error: Encryption key size used is insufficient. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH 0x010D /**< ATT Error: Invalid value size. */ -#define BLE_GATT_STATUS_ATTERR_UNLIKELY_ERROR 0x010E /**< ATT Error: Very unlikely error. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION 0x010F /**< ATT Error: Encrypted link required. */ -#define BLE_GATT_STATUS_ATTERR_UNSUPPORTED_GROUP_TYPE \ - 0x0110 /**< ATT Error: Attribute type is not a supported grouping attribute. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_RESOURCES 0x0111 /**< ATT Error: Insufficient resources. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_BEGIN 0x0112 /**< ATT Error: Reserved for Future Use range #1 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_END 0x017F /**< ATT Error: Reserved for Future Use range #1 end. */ -#define BLE_GATT_STATUS_ATTERR_APP_BEGIN 0x0180 /**< ATT Error: Application range begin. */ -#define BLE_GATT_STATUS_ATTERR_APP_END 0x019F /**< ATT Error: Application range end. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_BEGIN 0x01A0 /**< ATT Error: Reserved for Future Use range #2 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_END 0x01DF /**< ATT Error: Reserved for Future Use range #2 end. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_BEGIN 0x01E0 /**< ATT Error: Reserved for Future Use range #3 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_END 0x01FC /**< ATT Error: Reserved for Future Use range #3 end. */ -#define BLE_GATT_STATUS_ATTERR_CPS_WRITE_REQ_REJECTED \ - 0x01FC /**< ATT Common Profile and Service Error: Write request rejected. \ - */ -#define BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR \ - 0x01FD /**< ATT Common Profile and Service Error: Client Characteristic Configuration Descriptor improperly configured. */ -#define BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG \ - 0x01FE /**< ATT Common Profile and Service Error: Procedure Already in Progress. */ -#define BLE_GATT_STATUS_ATTERR_CPS_OUT_OF_RANGE 0x01FF /**< ATT Common Profile and Service Error: Out Of Range. */ -/** @} */ - -/** @defgroup BLE_GATT_CPF_FORMATS Characteristic Presentation Formats - * @note Found at - * http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml - * @{ */ -#define BLE_GATT_CPF_FORMAT_RFU 0x00 /**< Reserved For Future Use. */ -#define BLE_GATT_CPF_FORMAT_BOOLEAN 0x01 /**< Boolean. */ -#define BLE_GATT_CPF_FORMAT_2BIT 0x02 /**< Unsigned 2-bit integer. */ -#define BLE_GATT_CPF_FORMAT_NIBBLE 0x03 /**< Unsigned 4-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT8 0x04 /**< Unsigned 8-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT12 0x05 /**< Unsigned 12-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT16 0x06 /**< Unsigned 16-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT24 0x07 /**< Unsigned 24-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT32 0x08 /**< Unsigned 32-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT48 0x09 /**< Unsigned 48-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT64 0x0A /**< Unsigned 64-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT128 0x0B /**< Unsigned 128-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT8 0x0C /**< Signed 2-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT12 0x0D /**< Signed 12-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT16 0x0E /**< Signed 16-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT24 0x0F /**< Signed 24-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT32 0x10 /**< Signed 32-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT48 0x11 /**< Signed 48-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT64 0x12 /**< Signed 64-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT128 0x13 /**< Signed 128-bit integer. */ -#define BLE_GATT_CPF_FORMAT_FLOAT32 0x14 /**< IEEE-754 32-bit floating point. */ -#define BLE_GATT_CPF_FORMAT_FLOAT64 0x15 /**< IEEE-754 64-bit floating point. */ -#define BLE_GATT_CPF_FORMAT_SFLOAT 0x16 /**< IEEE-11073 16-bit SFLOAT. */ -#define BLE_GATT_CPF_FORMAT_FLOAT 0x17 /**< IEEE-11073 32-bit FLOAT. */ -#define BLE_GATT_CPF_FORMAT_DUINT16 0x18 /**< IEEE-20601 format. */ -#define BLE_GATT_CPF_FORMAT_UTF8S 0x19 /**< UTF-8 string. */ -#define BLE_GATT_CPF_FORMAT_UTF16S 0x1A /**< UTF-16 string. */ -#define BLE_GATT_CPF_FORMAT_STRUCT 0x1B /**< Opaque Structure. */ -/** @} */ - -/** @defgroup BLE_GATT_CPF_NAMESPACES GATT Bluetooth Namespaces - * @{ - */ -#define BLE_GATT_CPF_NAMESPACE_BTSIG 0x01 /**< Bluetooth SIG defined Namespace. */ -#define BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN 0x0000 /**< Namespace Description Unknown. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATT_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATT connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_PARAM att_mtu is smaller than @ref BLE_GATT_ATT_MTU_DEFAULT. - */ -typedef struct { - uint16_t att_mtu; /**< Maximum size of ATT packet the SoftDevice can send or receive. - The default and minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - @mscs - @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} - @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} - @endmscs - */ -} ble_gatt_conn_cfg_t; - -/**@brief GATT Characteristic Properties. */ -typedef struct { - /* Standard properties */ - uint8_t broadcast : 1; /**< Broadcasting of the value permitted. */ - uint8_t read : 1; /**< Reading the value permitted. */ - uint8_t write_wo_resp : 1; /**< Writing the value with Write Command permitted. */ - uint8_t write : 1; /**< Writing the value with Write Request permitted. */ - uint8_t notify : 1; /**< Notification of the value permitted. */ - uint8_t indicate : 1; /**< Indications of the value permitted. */ - uint8_t auth_signed_wr : 1; /**< Writing the value with Signed Write Command permitted. */ -} ble_gatt_char_props_t; - -/**@brief GATT Characteristic Extended Properties. */ -typedef struct { - /* Extended properties */ - uint8_t reliable_wr : 1; /**< Writing the value with Queued Write operations permitted. */ - uint8_t wr_aux : 1; /**< Writing the Characteristic User Description descriptor permitted. */ -} ble_gatt_char_ext_props_t; - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GATT_H__ - -/** @} */ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gattc.h b/variants/wio-tracker-wm1110/softdevice/ble_gattc.h deleted file mode 100644 index f1df1782ca..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_gattc.h +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATTC Generic Attribute Profile (GATT) Client - @{ - @brief Definitions and prototypes for the GATT Client interface. - */ - -#ifndef BLE_GATTC_H__ -#define BLE_GATTC_H__ - -#include "ble_err.h" -#include "ble_gatt.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATTC_ENUMERATIONS Enumerations - * @{ */ - -/**@brief GATTC API SVC numbers. */ -enum BLE_GATTC_SVCS { - SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER = BLE_GATTC_SVC_BASE, /**< Primary Service Discovery. */ - SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, /**< Relationship Discovery. */ - SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, /**< Characteristic Discovery. */ - SD_BLE_GATTC_DESCRIPTORS_DISCOVER, /**< Characteristic Descriptor Discovery. */ - SD_BLE_GATTC_ATTR_INFO_DISCOVER, /**< Attribute Information Discovery. */ - SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, /**< Read Characteristic Value by UUID. */ - SD_BLE_GATTC_READ, /**< Generic read. */ - SD_BLE_GATTC_CHAR_VALUES_READ, /**< Read multiple Characteristic Values. */ - SD_BLE_GATTC_WRITE, /**< Generic write. */ - SD_BLE_GATTC_HV_CONFIRM, /**< Handle Value Confirmation. */ - SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. */ -}; - -/** - * @brief GATT Client Event IDs. - */ -enum BLE_GATTC_EVTS { - BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP = BLE_GATTC_EVT_BASE, /**< Primary Service Discovery Response event. \n See @ref - ble_gattc_evt_prim_srvc_disc_rsp_t. */ - BLE_GATTC_EVT_REL_DISC_RSP, /**< Relationship Discovery Response event. \n See @ref ble_gattc_evt_rel_disc_rsp_t. - */ - BLE_GATTC_EVT_CHAR_DISC_RSP, /**< Characteristic Discovery Response event. \n See @ref - ble_gattc_evt_char_disc_rsp_t. */ - BLE_GATTC_EVT_DESC_DISC_RSP, /**< Descriptor Discovery Response event. \n See @ref - ble_gattc_evt_desc_disc_rsp_t. */ - BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, /**< Attribute Information Response event. \n See @ref - ble_gattc_evt_attr_info_disc_rsp_t. */ - BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP, /**< Read By UUID Response event. \n See @ref - ble_gattc_evt_char_val_by_uuid_read_rsp_t. */ - BLE_GATTC_EVT_READ_RSP, /**< Read Response event. \n See @ref ble_gattc_evt_read_rsp_t. */ - BLE_GATTC_EVT_CHAR_VALS_READ_RSP, /**< Read multiple Response event. \n See @ref - ble_gattc_evt_char_vals_read_rsp_t. */ - BLE_GATTC_EVT_WRITE_RSP, /**< Write Response event. \n See @ref ble_gattc_evt_write_rsp_t. */ - BLE_GATTC_EVT_HVX, /**< Handle Value Notification or Indication event. \n Confirm indication with @ref - sd_ble_gattc_hv_confirm. \n See @ref ble_gattc_evt_hvx_t. */ - BLE_GATTC_EVT_EXCHANGE_MTU_RSP, /**< Exchange MTU Response event. \n See @ref - ble_gattc_evt_exchange_mtu_rsp_t. */ - BLE_GATTC_EVT_TIMEOUT, /**< Timeout event. \n See @ref ble_gattc_evt_timeout_t. */ - BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE /**< Write without Response transmission complete. \n See @ref - ble_gattc_evt_write_cmd_tx_complete_t. */ -}; - -/**@brief GATTC Option IDs. - * IDs that uniquely identify a GATTC option. - */ -enum BLE_GATTC_OPTS { - BLE_GATTC_OPT_UUID_DISC = BLE_GATTC_OPT_BASE, /**< UUID discovery. @ref ble_gattc_opt_uuid_disc_t */ -}; - -/** @} */ - -/** @addtogroup BLE_GATTC_DEFINES Defines - * @{ */ - -/** @defgroup BLE_ERRORS_GATTC SVC return values specific to GATTC - * @{ */ -#define BLE_ERROR_GATTC_PROC_NOT_PERMITTED (NRF_GATTC_ERR_BASE + 0x000) /**< Procedure not Permitted. */ -/** @} */ - -/** @defgroup BLE_GATTC_ATTR_INFO_FORMAT Attribute Information Formats - * @{ */ -#define BLE_GATTC_ATTR_INFO_FORMAT_16BIT 1 /**< 16-bit Attribute Information Format. */ -#define BLE_GATTC_ATTR_INFO_FORMAT_128BIT 2 /**< 128-bit Attribute Information Format. */ -/** @} */ - -/** @defgroup BLE_GATTC_DEFAULTS GATT Client defaults - * @{ */ -#define BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT \ - 1 /**< Default number of Write without Response that can be queued for transmission. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATTC_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATTC connection configuration parameters, set with @ref sd_ble_cfg_set. - */ -typedef struct { - uint8_t write_cmd_tx_queue_size; /**< The guaranteed minimum number of Write without Response that can be queued for - transmission. The default value is @ref BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT */ -} ble_gattc_conn_cfg_t; - -/**@brief Operation Handle Range. */ -typedef struct { - uint16_t start_handle; /**< Start Handle. */ - uint16_t end_handle; /**< End Handle. */ -} ble_gattc_handle_range_t; - -/**@brief GATT service. */ -typedef struct { - ble_uuid_t uuid; /**< Service UUID. */ - ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */ -} ble_gattc_service_t; - -/**@brief GATT include. */ -typedef struct { - uint16_t handle; /**< Include Handle. */ - ble_gattc_service_t included_srvc; /**< Handle of the included service. */ -} ble_gattc_include_t; - -/**@brief GATT characteristic. */ -typedef struct { - ble_uuid_t uuid; /**< Characteristic UUID. */ - ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ - uint8_t char_ext_props : 1; /**< Extended properties present. */ - uint16_t handle_decl; /**< Handle of the Characteristic Declaration. */ - uint16_t handle_value; /**< Handle of the Characteristic Value. */ -} ble_gattc_char_t; - -/**@brief GATT descriptor. */ -typedef struct { - uint16_t handle; /**< Descriptor Handle. */ - ble_uuid_t uuid; /**< Descriptor UUID. */ -} ble_gattc_desc_t; - -/**@brief Write Parameters. */ -typedef struct { - uint8_t write_op; /**< Write Operation to be performed, see @ref BLE_GATT_WRITE_OPS. */ - uint8_t flags; /**< Flags, see @ref BLE_GATT_EXEC_WRITE_FLAGS. */ - uint16_t handle; /**< Handle to the attribute to be written. */ - uint16_t offset; /**< Offset in bytes. @note For WRITE_CMD and WRITE_REQ, offset must be 0. */ - uint16_t len; /**< Length of data in bytes. */ - uint8_t const *p_value; /**< Pointer to the value data. */ -} ble_gattc_write_params_t; - -/**@brief Attribute Information for 16-bit Attribute UUID. */ -typedef struct { - uint16_t handle; /**< Attribute handle. */ - ble_uuid_t uuid; /**< 16-bit Attribute UUID. */ -} ble_gattc_attr_info16_t; - -/**@brief Attribute Information for 128-bit Attribute UUID. */ -typedef struct { - uint16_t handle; /**< Attribute handle. */ - ble_uuid128_t uuid; /**< 128-bit Attribute UUID. */ -} ble_gattc_attr_info128_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Service count. */ - ble_gattc_service_t services[1]; /**< Service data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use - event structures with variable length array members. */ -} ble_gattc_evt_prim_srvc_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_REL_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Include count. */ - ble_gattc_include_t includes[1]; /**< Include data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use - event structures with variable length array members. */ -} ble_gattc_evt_rel_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Characteristic count. */ - ble_gattc_char_t chars[1]; /**< Characteristic data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event - structures with variable length array members. */ -} ble_gattc_evt_char_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_DESC_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Descriptor count. */ - ble_gattc_desc_t descs[1]; /**< Descriptor data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event - structures with variable length array members. */ -} ble_gattc_evt_desc_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Attribute count. */ - uint8_t format; /**< Attribute information format, see @ref BLE_GATTC_ATTR_INFO_FORMAT. */ - union { - ble_gattc_attr_info16_t attr_info16[1]; /**< Attribute information for 16-bit Attribute UUID. - @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on - how to use event structures with variable length array members. */ - ble_gattc_attr_info128_t attr_info128[1]; /**< Attribute information for 128-bit Attribute UUID. - @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on - how to use event structures with variable length array members. */ - } info; /**< Attribute information union. */ -} ble_gattc_evt_attr_info_disc_rsp_t; - -/**@brief GATT read by UUID handle value pair. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint8_t *p_value; /**< Pointer to the Attribute Value, length is available in @ref - ble_gattc_evt_char_val_by_uuid_read_rsp_t::value_len. */ -} ble_gattc_handle_value_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP. */ -typedef struct { - uint16_t count; /**< Handle-Value Pair Count. */ - uint16_t value_len; /**< Length of the value in Handle-Value(s) list. */ - uint8_t handle_value[1]; /**< Handle-Value(s) list. To iterate through the list use @ref - sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter. - @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with - variable length array members. */ -} ble_gattc_evt_char_val_by_uuid_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_READ_RSP. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint16_t offset; /**< Offset of the attribute data. */ - uint16_t len; /**< Attribute data length. */ - uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP. */ -typedef struct { - uint16_t len; /**< Concatenated Attribute values length. */ - uint8_t values[1]; /**< Attribute values. @note This is a variable length array. The size of 1 indicated is only a placeholder - for compilation. See @ref sd_ble_evt_get for more information on how to use event structures with - variable length array members. */ -} ble_gattc_evt_char_vals_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_RSP. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint8_t write_op; /**< Type of write operation, see @ref BLE_GATT_WRITE_OPS. */ - uint16_t offset; /**< Data offset. */ - uint16_t len; /**< Data length. */ - uint8_t data[1]; /**< Data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_write_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_HVX. */ -typedef struct { - uint16_t handle; /**< Handle to which the HVx operation applies. */ - uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ - uint16_t len; /**< Attribute data length. */ - uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_hvx_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. */ -typedef struct { - uint16_t server_rx_mtu; /**< Server RX MTU size. */ -} ble_gattc_evt_exchange_mtu_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ -} ble_gattc_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE. */ -typedef struct { - uint8_t count; /**< Number of write without response transmissions completed. */ -} ble_gattc_evt_write_cmd_tx_complete_t; - -/**@brief GATTC event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which event occurred. */ - uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ - uint16_t - error_handle; /**< In case of error: The handle causing the error. In all other cases @ref BLE_GATT_HANDLE_INVALID. */ - union { - ble_gattc_evt_prim_srvc_disc_rsp_t prim_srvc_disc_rsp; /**< Primary Service Discovery Response Event Parameters. */ - ble_gattc_evt_rel_disc_rsp_t rel_disc_rsp; /**< Relationship Discovery Response Event Parameters. */ - ble_gattc_evt_char_disc_rsp_t char_disc_rsp; /**< Characteristic Discovery Response Event Parameters. */ - ble_gattc_evt_desc_disc_rsp_t desc_disc_rsp; /**< Descriptor Discovery Response Event Parameters. */ - ble_gattc_evt_char_val_by_uuid_read_rsp_t - char_val_by_uuid_read_rsp; /**< Characteristic Value Read by UUID Response Event Parameters. */ - ble_gattc_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. */ - ble_gattc_evt_char_vals_read_rsp_t char_vals_read_rsp; /**< Characteristic Values Read Response Event Parameters. */ - ble_gattc_evt_write_rsp_t write_rsp; /**< Write Response Event Parameters. */ - ble_gattc_evt_hvx_t hvx; /**< Handle Value Notification/Indication Event Parameters. */ - ble_gattc_evt_exchange_mtu_rsp_t exchange_mtu_rsp; /**< Exchange MTU Response Event Parameters. */ - ble_gattc_evt_timeout_t timeout; /**< Timeout Event Parameters. */ - ble_gattc_evt_attr_info_disc_rsp_t attr_info_disc_rsp; /**< Attribute Information Discovery Event Parameters. */ - ble_gattc_evt_write_cmd_tx_complete_t - write_cmd_tx_complete; /**< Write without Response transmission complete Event Parameters. */ - } params; /**< Event Parameters. @note Only valid if @ref gatt_status == @ref BLE_GATT_STATUS_SUCCESS. */ -} ble_gattc_evt_t; - -/**@brief UUID discovery option. - * - * @details Used with @ref sd_ble_opt_set to enable and disable automatic insertion of discovered 128-bit UUIDs to the - * Vendor Specific UUID table. Disabled by default. - * - When disabled, if a procedure initiated by - * @ref sd_ble_gattc_primary_services_discover, - * @ref sd_ble_gattc_relationships_discover, - * @ref sd_ble_gattc_characteristics_discover, - * @ref sd_ble_gattc_descriptors_discover - * finds a 128-bit UUID which was not added by @ref sd_ble_uuid_vs_add, @ref ble_uuid_t::type will be set - * to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. - * - When enabled, all found 128-bit UUIDs will be automatically added. The application can use - * @ref sd_ble_uuid_encode to retrieve the 128-bit UUID from @ref ble_uuid_t received in the corresponding - * event. If the total number of Vendor Specific UUIDs exceeds the table capacity, @ref ble_uuid_t::type will - * be set to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. - * See also @ref ble_common_cfg_vs_uuid_t, @ref sd_ble_uuid_vs_remove. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * - * @retval ::NRF_SUCCESS Set successfully. - * - */ -typedef struct { - uint8_t auto_add_vs_enable : 1; /**< Set to 1 to enable (or 0 to disable) automatic insertion of discovered 128-bit UUIDs. */ -} ble_gattc_opt_uuid_disc_t; - -/**@brief Option structure for GATTC options. */ -typedef union { - ble_gattc_opt_uuid_disc_t uuid_disc; /**< Parameters for the UUID discovery option. */ -} ble_gattc_opt_t; - -/** @} */ - -/** @addtogroup BLE_GATTC_FUNCTIONS Functions - * @{ */ - -/**@brief Initiate or continue a GATT Primary Service Discovery procedure. - * - * @details This function initiates or resumes a Primary Service discovery procedure, starting from the supplied handle. - * If the last service has not been reached, this function must be called again with an updated start handle value to - * continue the search. See also @ref ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_PRIM_SRVC_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] start_handle Handle to start searching from. - * @param[in] p_srvc_uuid Pointer to the service UUID to be found. If it is NULL, all primary services will be returned. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Primary Service Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER, uint32_t, - sd_ble_gattc_primary_services_discover(uint16_t conn_handle, uint16_t start_handle, ble_uuid_t const *p_srvc_uuid)); - -/**@brief Initiate or continue a GATT Relationship Discovery procedure. - * - * @details This function initiates or resumes the Find Included Services sub-procedure. If the last included service has not been - * reached, this must be called again with an updated handle range to continue the search. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_REL_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_REL_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Relationship Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, uint32_t, - sd_ble_gattc_relationships_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Characteristic Discovery procedure. - * - * @details This function initiates or resumes a Characteristic discovery procedure. If the last Characteristic has not been - * reached, this must be called again with an updated handle range to continue the discovery. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_CHAR_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Characteristic Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, uint32_t, - sd_ble_gattc_characteristics_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Characteristic Descriptor Discovery procedure. - * - * @details This function initiates or resumes a Characteristic Descriptor discovery procedure. If the last Descriptor has not - * been reached, this must be called again with an updated handle range to continue the discovery. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_DESC_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_DESC_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Characteristic to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Descriptor Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t, - sd_ble_gattc_descriptors_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Read using Characteristic UUID procedure. - * - * @details This function initiates or resumes a Read using Characteristic UUID procedure. If the last Characteristic has not been - * reached, this must be called again with an updated handle range to continue the discovery. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_READ_UUID_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_uuid Pointer to a Characteristic value UUID to read. - * @param[in] p_handle_range A pointer to the range of handles to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Read using Characteristic UUID procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, uint32_t, - sd_ble_gattc_char_value_by_uuid_read(uint16_t conn_handle, ble_uuid_t const *p_uuid, - ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Read (Long) Characteristic or Descriptor procedure. - * - * @details This function initiates or resumes a GATT Read (Long) Characteristic or Descriptor procedure. If the Characteristic or - * Descriptor to be read is longer than ATT_MTU - 1, this function must be called multiple times with appropriate offset to read - * the complete value. - * - * @events - * @event{@ref BLE_GATTC_EVT_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_VALUE_READ_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] handle The handle of the attribute to be read. - * @param[in] offset Offset into the attribute value to be read. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Read (Long) procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_READ, uint32_t, sd_ble_gattc_read(uint16_t conn_handle, uint16_t handle, uint16_t offset)); - -/**@brief Initiate a GATT Read Multiple Characteristic Values procedure. - * - * @details This function initiates a GATT Read Multiple Characteristic Values procedure. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_READ_MULT_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handles A pointer to the handle(s) of the attribute(s) to be read. - * @param[in] handle_count The number of handles in p_handles. - * - * @retval ::NRF_SUCCESS Successfully started the Read Multiple Characteristic Values procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t, - sd_ble_gattc_char_values_read(uint16_t conn_handle, uint16_t const *p_handles, uint16_t handle_count)); - -/**@brief Perform a Write (Characteristic Value or Descriptor, with or without response, signed or not, long or reliable) - * procedure. - * - * @details This function can perform all write procedures described in GATT. - * - * @note Only one write with response procedure can be ongoing per connection at a time. - * If the application tries to write with response while another write with response procedure is ongoing, - * the function call will return @ref NRF_ERROR_BUSY. - * A @ref BLE_GATTC_EVT_WRITE_RSP event will be issued as soon as the write response arrives from the peer. - * - * @note The number of Write without Response that can be queued is configured by @ref - * ble_gattc_conn_cfg_t::write_cmd_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. - * A @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event will be issued as soon as the transmission of the write without - * response is complete. - * - * @note The application can keep track of the available queue element count for writes without responses by following the - * procedure below: - * - Store initial queue element count in a variable. - * - Decrement the variable, which stores the currently available queue element count, by one when a call to this - * function returns @ref NRF_SUCCESS. - * - Increment the variable, which stores the current available queue element count, by the count variable in @ref - * BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event. - * - * @events - * @event{@ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE, Write without response transmission complete.} - * @event{@ref BLE_GATTC_EVT_WRITE_RSP, Write response received from the peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_VALUE_WRITE_WITHOUT_RESP_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_WRITE_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_LONG_WRITE_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_RELIABLE_WRITE_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_write_params A pointer to a write parameters structure. - * - * @retval ::NRF_SUCCESS Successfully started the Write procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_BUSY For write with response, procedure already in progress. Wait for a @ref BLE_GATTC_EVT_WRITE_RSP event - * and retry. - * @retval ::NRF_ERROR_RESOURCES Too many writes without responses queued. - * Wait for a @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event and retry. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_WRITE, uint32_t, sd_ble_gattc_write(uint16_t conn_handle, ble_gattc_write_params_t const *p_write_params)); - -/**@brief Send a Handle Value Confirmation to the GATT Server. - * - * @mscs - * @mmsc{@ref BLE_GATTC_HVI_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] handle The handle of the attribute in the indication. - * - * @retval ::NRF_SUCCESS Successfully queued the Handle Value Confirmation for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no Indication pending to be confirmed. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_HV_CONFIRM, uint32_t, sd_ble_gattc_hv_confirm(uint16_t conn_handle, uint16_t handle)); - -/**@brief Discovers information about a range of attributes on a GATT server. - * - * @events - * @event{@ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, Generated when information about a range of attributes has been received.} - * @endevents - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range The range of handles to request information about. - * - * @retval ::NRF_SUCCESS Successfully started an attribute information discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t, - sd_ble_gattc_attr_info_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Start an ATT_MTU exchange by sending an Exchange MTU Request to the server. - * - * @details The SoftDevice sets ATT_MTU to the minimum of: - * - The Client RX MTU value, and - * - The Server RX MTU value from @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. - * - * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. - * - * @events - * @event{@ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] client_rx_mtu Client RX MTU size. - * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration - used for this connection. - * - The value must be equal to Server RX MTU size given in @ref sd_ble_gatts_exchange_mtu_reply - * if an ATT_MTU exchange has already been performed in the other direction. - * - * @retval ::NRF_SUCCESS Successfully sent request to the server. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state or an ATT_MTU exchange was already requested once. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid Client RX MTU size supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, uint32_t, - sd_ble_gattc_exchange_mtu_request(uint16_t conn_handle, uint16_t client_rx_mtu)); - -/**@brief Iterate through Handle-Value(s) list in @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. - * - * @param[in] p_gattc_evt Pointer to event buffer containing @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. - * @note If the buffer contains different event, behavior is undefined. - * @param[in,out] p_iter Iterator, points to @ref ble_gattc_handle_value_t structure that will be filled in with - * the next Handle-Value pair in each iteration. If the function returns other than - * @ref NRF_SUCCESS, it will not be changed. - * - To start iteration, initialize the structure to zero. - * - To continue, pass the value from previous iteration. - * - * \code - * ble_gattc_handle_value_t iter; - * memset(&iter, 0, sizeof(ble_gattc_handle_value_t)); - * while (sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(&ble_evt.evt.gattc_evt, &iter) == NRF_SUCCESS) - * { - * app_handle = iter.handle; - * memcpy(app_value, iter.p_value, ble_evt.evt.gattc_evt.params.char_val_by_uuid_read_rsp.value_len); - * } - * \endcode - * - * @retval ::NRF_SUCCESS Successfully retrieved the next Handle-Value pair. - * @retval ::NRF_ERROR_NOT_FOUND No more Handle-Value pairs available in the list. - */ -__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, - ble_gattc_handle_value_t *p_iter); - -/** @} */ - -#ifndef SUPPRESS_INLINE_IMPLEMENTATION - -__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, - ble_gattc_handle_value_t *p_iter) -{ - uint32_t value_len = p_gattc_evt->params.char_val_by_uuid_read_rsp.value_len; - uint8_t *p_first = p_gattc_evt->params.char_val_by_uuid_read_rsp.handle_value; - uint8_t *p_next = p_iter->p_value ? p_iter->p_value + value_len : p_first; - - if ((p_next - p_first) / (sizeof(uint16_t) + value_len) < p_gattc_evt->params.char_val_by_uuid_read_rsp.count) { - p_iter->handle = (uint16_t)p_next[1] << 8 | p_next[0]; - p_iter->p_value = p_next + sizeof(uint16_t); - return NRF_SUCCESS; - } else { - return NRF_ERROR_NOT_FOUND; - } -} - -#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ - -#ifdef __cplusplus -} -#endif -#endif /* BLE_GATTC_H__ */ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gatts.h b/variants/wio-tracker-wm1110/softdevice/ble_gatts.h deleted file mode 100644 index dc94957cd1..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_gatts.h +++ /dev/null @@ -1,904 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATTS Generic Attribute Profile (GATT) Server - @{ - @brief Definitions and prototypes for the GATTS interface. - */ - -#ifndef BLE_GATTS_H__ -#define BLE_GATTS_H__ - -#include "ble_err.h" -#include "ble_gap.h" -#include "ble_gatt.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATTS_ENUMERATIONS Enumerations - * @{ */ - -/** - * @brief GATTS API SVC numbers. - */ -enum BLE_GATTS_SVCS { - SD_BLE_GATTS_SERVICE_ADD = BLE_GATTS_SVC_BASE, /**< Add a service. */ - SD_BLE_GATTS_INCLUDE_ADD, /**< Add an included service. */ - SD_BLE_GATTS_CHARACTERISTIC_ADD, /**< Add a characteristic. */ - SD_BLE_GATTS_DESCRIPTOR_ADD, /**< Add a generic attribute. */ - SD_BLE_GATTS_VALUE_SET, /**< Set an attribute value. */ - SD_BLE_GATTS_VALUE_GET, /**< Get an attribute value. */ - SD_BLE_GATTS_HVX, /**< Handle Value Notification or Indication. */ - SD_BLE_GATTS_SERVICE_CHANGED, /**< Perform a Service Changed Indication to one or more peers. */ - SD_BLE_GATTS_RW_AUTHORIZE_REPLY, /**< Reply to an authorization request for a read or write operation on one or more - attributes. */ - SD_BLE_GATTS_SYS_ATTR_SET, /**< Set the persistent system attributes for a connection. */ - SD_BLE_GATTS_SYS_ATTR_GET, /**< Retrieve the persistent system attributes. */ - SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, /**< Retrieve the first valid user handle. */ - SD_BLE_GATTS_ATTR_GET, /**< Retrieve the UUID and/or metadata of an attribute. */ - SD_BLE_GATTS_EXCHANGE_MTU_REPLY /**< Reply to Exchange MTU Request. */ -}; - -/** - * @brief GATT Server Event IDs. - */ -enum BLE_GATTS_EVTS { - BLE_GATTS_EVT_WRITE = BLE_GATTS_EVT_BASE, /**< Write operation performed. \n See - @ref ble_gatts_evt_write_t. */ - BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST, /**< Read/Write Authorization request. \n Reply with - @ref sd_ble_gatts_rw_authorize_reply. \n See @ref ble_gatts_evt_rw_authorize_request_t. - */ - BLE_GATTS_EVT_SYS_ATTR_MISSING, /**< A persistent system attribute access is pending. \n Respond with @ref - sd_ble_gatts_sys_attr_set. \n See @ref ble_gatts_evt_sys_attr_missing_t. */ - BLE_GATTS_EVT_HVC, /**< Handle Value Confirmation. \n See @ref ble_gatts_evt_hvc_t. - */ - BLE_GATTS_EVT_SC_CONFIRM, /**< Service Changed Confirmation. \n No additional event - structure applies. */ - BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. \n Reply with - @ref sd_ble_gatts_exchange_mtu_reply. \n See @ref ble_gatts_evt_exchange_mtu_request_t. - */ - BLE_GATTS_EVT_TIMEOUT, /**< Peer failed to respond to an ATT request in time. \n See @ref - ble_gatts_evt_timeout_t. */ - BLE_GATTS_EVT_HVN_TX_COMPLETE /**< Handle Value Notification transmission complete. \n See @ref - ble_gatts_evt_hvn_tx_complete_t. */ -}; - -/**@brief GATTS Configuration IDs. - * - * IDs that uniquely identify a GATTS configuration. - */ -enum BLE_GATTS_CFGS { - BLE_GATTS_CFG_SERVICE_CHANGED = BLE_GATTS_CFG_BASE, /**< Service changed configuration. */ - BLE_GATTS_CFG_ATTR_TAB_SIZE, /**< Attribute table size configuration. */ - BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM, /**< Service changed CCCD permission configuration. */ -}; - -/** @} */ - -/** @addtogroup BLE_GATTS_DEFINES Defines - * @{ */ - -/** @defgroup BLE_ERRORS_GATTS SVC return values specific to GATTS - * @{ */ -#define BLE_ERROR_GATTS_INVALID_ATTR_TYPE (NRF_GATTS_ERR_BASE + 0x000) /**< Invalid attribute type. */ -#define BLE_ERROR_GATTS_SYS_ATTR_MISSING (NRF_GATTS_ERR_BASE + 0x001) /**< System Attributes missing. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_LENS_MAX Maximum attribute lengths - * @{ */ -#define BLE_GATTS_FIX_ATTR_LEN_MAX (510) /**< Maximum length for fixed length Attribute Values. */ -#define BLE_GATTS_VAR_ATTR_LEN_MAX (512) /**< Maximum length for variable length Attribute Values. */ -/** @} */ - -/** @defgroup BLE_GATTS_SRVC_TYPES GATT Server Service Types - * @{ */ -#define BLE_GATTS_SRVC_TYPE_INVALID 0x00 /**< Invalid Service Type. */ -#define BLE_GATTS_SRVC_TYPE_PRIMARY 0x01 /**< Primary Service. */ -#define BLE_GATTS_SRVC_TYPE_SECONDARY 0x02 /**< Secondary Type. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_TYPES GATT Server Attribute Types - * @{ */ -#define BLE_GATTS_ATTR_TYPE_INVALID 0x00 /**< Invalid Attribute Type. */ -#define BLE_GATTS_ATTR_TYPE_PRIM_SRVC_DECL 0x01 /**< Primary Service Declaration. */ -#define BLE_GATTS_ATTR_TYPE_SEC_SRVC_DECL 0x02 /**< Secondary Service Declaration. */ -#define BLE_GATTS_ATTR_TYPE_INC_DECL 0x03 /**< Include Declaration. */ -#define BLE_GATTS_ATTR_TYPE_CHAR_DECL 0x04 /**< Characteristic Declaration. */ -#define BLE_GATTS_ATTR_TYPE_CHAR_VAL 0x05 /**< Characteristic Value. */ -#define BLE_GATTS_ATTR_TYPE_DESC 0x06 /**< Descriptor. */ -#define BLE_GATTS_ATTR_TYPE_OTHER 0x07 /**< Other, non-GATT specific type. */ -/** @} */ - -/** @defgroup BLE_GATTS_OPS GATT Server Operations - * @{ */ -#define BLE_GATTS_OP_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATTS_OP_WRITE_REQ 0x01 /**< Write Request. */ -#define BLE_GATTS_OP_WRITE_CMD 0x02 /**< Write Command. */ -#define BLE_GATTS_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ -#define BLE_GATTS_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ -#define BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL 0x05 /**< Execute Write Request: Cancel all prepared writes. */ -#define BLE_GATTS_OP_EXEC_WRITE_REQ_NOW 0x06 /**< Execute Write Request: Immediately execute all prepared writes. */ -/** @} */ - -/** @defgroup BLE_GATTS_VLOCS GATT Value Locations - * @{ */ -#define BLE_GATTS_VLOC_INVALID 0x00 /**< Invalid Location. */ -#define BLE_GATTS_VLOC_STACK 0x01 /**< Attribute Value is located in stack memory, no user memory is required. */ -#define BLE_GATTS_VLOC_USER \ - 0x02 /**< Attribute Value is located in user memory. This requires the user to maintain a valid buffer through the lifetime \ - of the attribute, since the stack will read and write directly to the memory using the pointer provided in the APIs. \ - There are no alignment requirements for the buffer. */ -/** @} */ - -/** @defgroup BLE_GATTS_AUTHORIZE_TYPES GATT Server Authorization Types - * @{ */ -#define BLE_GATTS_AUTHORIZE_TYPE_INVALID 0x00 /**< Invalid Type. */ -#define BLE_GATTS_AUTHORIZE_TYPE_READ 0x01 /**< Authorize a Read Operation. */ -#define BLE_GATTS_AUTHORIZE_TYPE_WRITE 0x02 /**< Authorize a Write Request Operation. */ -/** @} */ - -/** @defgroup BLE_GATTS_SYS_ATTR_FLAGS System Attribute Flags - * @{ */ -#define BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS (1 << 0) /**< Restrict system attributes to system services only. */ -#define BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS (1 << 1) /**< Restrict system attributes to user services only. */ -/** @} */ - -/** @defgroup BLE_GATTS_SERVICE_CHANGED Service Changed Inclusion Values - * @{ - */ -#define BLE_GATTS_SERVICE_CHANGED_DEFAULT \ - (1) /**< Default is to include the Service Changed characteristic in the Attribute Table. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_TAB_SIZE Attribute Table size - * @{ - */ -#define BLE_GATTS_ATTR_TAB_SIZE_MIN (248) /**< Minimum Attribute Table size */ -#define BLE_GATTS_ATTR_TAB_SIZE_DEFAULT (1408) /**< Default Attribute Table size. */ -/** @} */ - -/** @defgroup BLE_GATTS_DEFAULTS GATT Server defaults - * @{ - */ -#define BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT \ - 1 /**< Default number of Handle Value Notifications that can be queued for transmission. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATTS_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATTS connection configuration parameters, set with @ref sd_ble_cfg_set. - */ -typedef struct { - uint8_t hvn_tx_queue_size; /**< Minimum guaranteed number of Handle Value Notifications that can be queued for transmission. - The default value is @ref BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT */ -} ble_gatts_conn_cfg_t; - -/**@brief Attribute metadata. */ -typedef struct { - ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */ - ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ - uint8_t vlen : 1; /**< Variable length attribute. */ - uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ - uint8_t rd_auth : 1; /**< Read authorization and value will be requested from the application on every read operation. */ - uint8_t wr_auth : 1; /**< Write authorization will be requested from the application on every Write Request operation (but not - Write Command). */ -} ble_gatts_attr_md_t; - -/**@brief GATT Attribute. */ -typedef struct { - ble_uuid_t const *p_uuid; /**< Pointer to the attribute UUID. */ - ble_gatts_attr_md_t const *p_attr_md; /**< Pointer to the attribute metadata structure. */ - uint16_t init_len; /**< Initial attribute value length in bytes. */ - uint16_t init_offs; /**< Initial attribute value offset in bytes. If different from zero, the first init_offs bytes of the - attribute value will be left uninitialized. */ - uint16_t max_len; /**< Maximum attribute value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */ - uint8_t *p_value; /**< Pointer to the attribute data. Please note that if the @ref BLE_GATTS_VLOC_USER value location is - selected in the attribute metadata, this will have to point to a buffer that remains valid through the - lifetime of the attribute. This excludes usage of automatic variables that may go out of scope or any - other temporary location. The stack may access that memory directly without the application's - knowledge. For writable characteristics, this value must not be a location in flash memory.*/ -} ble_gatts_attr_t; - -/**@brief GATT Attribute Value. */ -typedef struct { - uint16_t len; /**< Length in bytes to be written or read. Length in bytes written or read after successful return.*/ - uint16_t offset; /**< Attribute value offset. */ - uint8_t *p_value; /**< Pointer to where value is stored or will be stored. - If value is stored in user memory, only the attribute length is updated when p_value == NULL. - Set to NULL when reading to obtain the complete length of the attribute value */ -} ble_gatts_value_t; - -/**@brief GATT Characteristic Presentation Format. */ -typedef struct { - uint8_t format; /**< Format of the value, see @ref BLE_GATT_CPF_FORMATS. */ - int8_t exponent; /**< Exponent for integer data types. */ - uint16_t unit; /**< Unit from Bluetooth Assigned Numbers. */ - uint8_t name_space; /**< Namespace from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ - uint16_t desc; /**< Namespace description from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ -} ble_gatts_char_pf_t; - -/**@brief GATT Characteristic metadata. */ -typedef struct { - ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ - ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic Extended Properties. */ - uint8_t const * - p_char_user_desc; /**< Pointer to a UTF-8 encoded string (non-NULL terminated), NULL if the descriptor is not required. */ - uint16_t char_user_desc_max_size; /**< The maximum size in bytes of the user description descriptor. */ - uint16_t char_user_desc_size; /**< The size of the user description, must be smaller or equal to char_user_desc_max_size. */ - ble_gatts_char_pf_t const - *p_char_pf; /**< Pointer to a presentation format structure or NULL if the CPF descriptor is not required. */ - ble_gatts_attr_md_t const - *p_user_desc_md; /**< Attribute metadata for the User Description descriptor, or NULL for default values. */ - ble_gatts_attr_md_t const - *p_cccd_md; /**< Attribute metadata for the Client Characteristic Configuration Descriptor, or NULL for default values. */ - ble_gatts_attr_md_t const - *p_sccd_md; /**< Attribute metadata for the Server Characteristic Configuration Descriptor, or NULL for default values. */ -} ble_gatts_char_md_t; - -/**@brief GATT Characteristic Definition Handles. */ -typedef struct { - uint16_t value_handle; /**< Handle to the characteristic value. */ - uint16_t user_desc_handle; /**< Handle to the User Description descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */ - uint16_t cccd_handle; /**< Handle to the Client Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if - not present. */ - uint16_t sccd_handle; /**< Handle to the Server Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if - not present. */ -} ble_gatts_char_handles_t; - -/**@brief GATT HVx parameters. */ -typedef struct { - uint16_t handle; /**< Characteristic Value Handle. */ - uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ - uint16_t offset; /**< Offset within the attribute value. */ - uint16_t *p_len; /**< Length in bytes to be written, length in bytes written after return. */ - uint8_t const *p_data; /**< Actual data content, use NULL to use the current attribute value. */ -} ble_gatts_hvx_params_t; - -/**@brief GATT Authorization parameters. */ -typedef struct { - uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ - uint8_t update : 1; /**< If set, data supplied in p_data will be used to update the attribute value. - Please note that for @ref BLE_GATTS_AUTHORIZE_TYPE_WRITE operations this bit must always be set, - as the data to be written needs to be stored and later provided by the application. */ - uint16_t offset; /**< Offset of the attribute value being updated. */ - uint16_t len; /**< Length in bytes of the value in p_data pointer, see @ref BLE_GATTS_ATTR_LENS_MAX. */ - uint8_t const *p_data; /**< Pointer to new value used to update the attribute value. */ -} ble_gatts_authorize_params_t; - -/**@brief GATT Read or Write Authorize Reply parameters. */ -typedef struct { - uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ - union { - ble_gatts_authorize_params_t read; /**< Read authorization parameters. */ - ble_gatts_authorize_params_t write; /**< Write authorization parameters. */ - } params; /**< Reply Parameters. */ -} ble_gatts_rw_authorize_reply_params_t; - -/**@brief Service Changed Inclusion configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t service_changed : 1; /**< If 1, include the Service Changed characteristic in the Attribute Table. Default is @ref - BLE_GATTS_SERVICE_CHANGED_DEFAULT. */ -} ble_gatts_cfg_service_changed_t; - -/**@brief Service Changed CCCD permission configuration parameters, set with @ref sd_ble_cfg_set. - * - * @note @ref ble_gatts_attr_md_t::vlen is ignored and should be set to 0. - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - @ref ble_gatts_attr_md_t::write_perm is out of range. - * - @ref ble_gatts_attr_md_t::write_perm is @ref BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS, that is - * not allowed by the Bluetooth Specification. - * - wrong @ref ble_gatts_attr_md_t::read_perm, only @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN is - * allowed by the Bluetooth Specification. - * - wrong @ref ble_gatts_attr_md_t::vloc, only @ref BLE_GATTS_VLOC_STACK is allowed. - * @retval ::NRF_ERROR_NOT_SUPPORTED Security Mode 2 not supported - */ -typedef struct { - ble_gatts_attr_md_t - perm; /**< Permission for Service Changed CCCD. Default is @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN, no authorization. */ -} ble_gatts_cfg_service_changed_cccd_perm_t; - -/**@brief Attribute table size configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: - * - The specified Attribute Table size is too small. - * The minimum acceptable size is defined by @ref BLE_GATTS_ATTR_TAB_SIZE_MIN. - * - The specified Attribute Table size is not a multiple of 4. - */ -typedef struct { - uint32_t attr_tab_size; /**< Attribute table size. Default is @ref BLE_GATTS_ATTR_TAB_SIZE_DEFAULT, minimum is @ref - BLE_GATTS_ATTR_TAB_SIZE_MIN. */ -} ble_gatts_cfg_attr_tab_size_t; - -/**@brief Config structure for GATTS configurations. */ -typedef union { - ble_gatts_cfg_service_changed_t - service_changed; /**< Include service changed characteristic, cfg_id is @ref BLE_GATTS_CFG_SERVICE_CHANGED. */ - ble_gatts_cfg_service_changed_cccd_perm_t service_changed_cccd_perm; /**< Service changed CCCD permission, cfg_id is @ref - BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM. */ - ble_gatts_cfg_attr_tab_size_t attr_tab_size; /**< Attribute table size, cfg_id is @ref BLE_GATTS_CFG_ATTR_TAB_SIZE. */ -} ble_gatts_cfg_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_WRITE. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - ble_uuid_t uuid; /**< Attribute UUID. */ - uint8_t op; /**< Type of write operation, see @ref BLE_GATTS_OPS. */ - uint8_t auth_required; /**< Writing operation deferred due to authorization requirement. Application may use @ref - sd_ble_gatts_value_set to finalize the writing operation. */ - uint16_t offset; /**< Offset for the write operation. */ - uint16_t len; /**< Length of the received data. */ - uint8_t data[1]; /**< Received data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gatts_evt_write_t; - -/**@brief Event substructure for authorized read requests, see @ref ble_gatts_evt_rw_authorize_request_t. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - ble_uuid_t uuid; /**< Attribute UUID. */ - uint16_t offset; /**< Offset for the read operation. */ -} ble_gatts_evt_read_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST. */ -typedef struct { - uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ - union { - ble_gatts_evt_read_t read; /**< Attribute Read Parameters. */ - ble_gatts_evt_write_t write; /**< Attribute Write Parameters. */ - } request; /**< Request Parameters. */ -} ble_gatts_evt_rw_authorize_request_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. */ -typedef struct { - uint8_t hint; /**< Hint (currently unused). */ -} ble_gatts_evt_sys_attr_missing_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_HVC. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ -} ble_gatts_evt_hvc_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST. */ -typedef struct { - uint16_t client_rx_mtu; /**< Client RX MTU size. */ -} ble_gatts_evt_exchange_mtu_request_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ -} ble_gatts_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_HVN_TX_COMPLETE. */ -typedef struct { - uint8_t count; /**< Number of notification transmissions completed. */ -} ble_gatts_evt_hvn_tx_complete_t; - -/**@brief GATTS event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which the event occurred. */ - union { - ble_gatts_evt_write_t write; /**< Write Event Parameters. */ - ble_gatts_evt_rw_authorize_request_t authorize_request; /**< Read or Write Authorize Request Parameters. */ - ble_gatts_evt_sys_attr_missing_t sys_attr_missing; /**< System attributes missing. */ - ble_gatts_evt_hvc_t hvc; /**< Handle Value Confirmation Event Parameters. */ - ble_gatts_evt_exchange_mtu_request_t exchange_mtu_request; /**< Exchange MTU Request Event Parameters. */ - ble_gatts_evt_timeout_t timeout; /**< Timeout Event. */ - ble_gatts_evt_hvn_tx_complete_t hvn_tx_complete; /**< Handle Value Notification transmission complete Event Parameters. */ - } params; /**< Event Parameters. */ -} ble_gatts_evt_t; - -/** @} */ - -/** @addtogroup BLE_GATTS_FUNCTIONS Functions - * @{ */ - -/**@brief Add a service declaration to the Attribute Table. - * - * @note Secondary Services are only relevant in the context of the entity that references them, it is therefore forbidden to - * add a secondary service declaration that is not referenced by another service later in the Attribute Table. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] type Toggles between primary and secondary services, see @ref BLE_GATTS_SRVC_TYPES. - * @param[in] p_uuid Pointer to service UUID. - * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a service declaration. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, Vendor Specific UUIDs need to be present in the table. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type, ble_uuid_t const *p_uuid, uint16_t *p_handle)); - -/**@brief Add an include declaration to the Attribute Table. - * - * @note It is currently only possible to add an include declaration to the last added service (i.e. only sequential population is - * supported at this time). - * - * @note The included service must already be present in the Attribute Table prior to this call. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] service_handle Handle of the service where the included service is to be placed, if @ref BLE_GATT_HANDLE_INVALID - * is used, it will be placed sequentially. - * @param[in] inc_srvc_handle Handle of the included service. - * @param[out] p_include_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added an include declaration. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, handle values need to match previously added services. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. - * @retval ::NRF_ERROR_NOT_SUPPORTED Feature is not supported, service_handle must be that of the last added service. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, self inclusions are not allowed. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - */ -SVCALL(SD_BLE_GATTS_INCLUDE_ADD, uint32_t, - sd_ble_gatts_include_add(uint16_t service_handle, uint16_t inc_srvc_handle, uint16_t *p_include_handle)); - -/**@brief Add a characteristic declaration, a characteristic value declaration and optional characteristic descriptor declarations - * to the Attribute Table. - * - * @note It is currently only possible to add a characteristic to the last added service (i.e. only sequential population is - * supported at this time). - * - * @note Several restrictions apply to the parameters, such as matching permissions between the user description descriptor and - * the writable auxiliaries bits, readable (no security) and writable (selectable) CCCDs and SCCDs and valid presentation format - * values. - * - * @note If no metadata is provided for the optional descriptors, their permissions will be derived from the characteristic - * permissions. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] service_handle Handle of the service where the characteristic is to be placed, if @ref BLE_GATT_HANDLE_INVALID is - * used, it will be placed sequentially. - * @param[in] p_char_md Characteristic metadata. - * @param[in] p_attr_char_value Pointer to the attribute structure corresponding to the characteristic value. - * @param[out] p_handles Pointer to the structure where the assigned handles will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a characteristic. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, service handle, Vendor Specific UUIDs, lengths, and - * permissions need to adhere to the constraints. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - */ -SVCALL(SD_BLE_GATTS_CHARACTERISTIC_ADD, uint32_t, - sd_ble_gatts_characteristic_add(uint16_t service_handle, ble_gatts_char_md_t const *p_char_md, - ble_gatts_attr_t const *p_attr_char_value, ble_gatts_char_handles_t *p_handles)); - -/**@brief Add a descriptor to the Attribute Table. - * - * @note It is currently only possible to add a descriptor to the last added characteristic (i.e. only sequential population is - * supported at this time). - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] char_handle Handle of the characteristic where the descriptor is to be placed, if @ref BLE_GATT_HANDLE_INVALID is - * used, it will be placed sequentially. - * @param[in] p_attr Pointer to the attribute structure. - * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a descriptor. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, characteristic handle, Vendor Specific UUIDs, lengths, and - * permissions need to adhere to the constraints. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a characteristic context is required. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - */ -SVCALL(SD_BLE_GATTS_DESCRIPTOR_ADD, uint32_t, - sd_ble_gatts_descriptor_add(uint16_t char_handle, ble_gatts_attr_t const *p_attr, uint16_t *p_handle)); - -/**@brief Set the value of a given attribute. - * - * @note Values other than system attributes can be set at any time, regardless of whether any active connections exist. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. - * @param[in] handle Attribute handle. - * @param[in,out] p_value Attribute value information. - * - * @retval ::NRF_SUCCESS Successfully set the value of the attribute. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden handle supplied, certain attributes are not modifiable by the application. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. - */ -SVCALL(SD_BLE_GATTS_VALUE_SET, uint32_t, - sd_ble_gatts_value_set(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); - -/**@brief Get the value of a given attribute. - * - * @note If the attribute value is longer than the size of the supplied buffer, - * @ref ble_gatts_value_t::len will return the total attribute value length (excluding offset), - * and not the number of bytes actually returned in @ref ble_gatts_value_t::p_value. - * The application may use this information to allocate a suitable buffer size. - * - * @note When retrieving system attribute values with this function, the connection handle - * may refer to an already disconnected connection. Refer to the documentation of - * @ref sd_ble_gatts_sys_attr_get for further information. - * - * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. - * @param[in] handle Attribute handle. - * @param[in,out] p_value Attribute value information. - * - * @retval ::NRF_SUCCESS Successfully retrieved the value of the attribute. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid attribute offset supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - */ -SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, - sd_ble_gatts_value_get(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); - -/**@brief Notify or Indicate an attribute value. - * - * @details This function checks for the relevant Client Characteristic Configuration descriptor value to verify that the relevant - * operation (notification or indication) has been enabled by the client. It is also able to update the attribute value before - * issuing the PDU, so that the application can atomically perform a value update and a server initiated transaction with a single - * API call. - * - * @note The local attribute value may be updated even if an outgoing packet is not sent to the peer due to an error during - * execution. The Attribute Table has been updated if one of the following error codes is returned: @ref NRF_ERROR_INVALID_STATE, - * @ref NRF_ERROR_BUSY, - * @ref NRF_ERROR_FORBIDDEN, @ref BLE_ERROR_GATTS_SYS_ATTR_MISSING and @ref NRF_ERROR_RESOURCES. - * The caller can check whether the value has been updated by looking at the contents of *(@ref - * ble_gatts_hvx_params_t::p_len). - * - * @note Only one indication procedure can be ongoing per connection at a time. - * If the application tries to indicate an attribute value while another indication procedure is ongoing, - * the function call will return @ref NRF_ERROR_BUSY. - * A @ref BLE_GATTS_EVT_HVC event will be issued as soon as the confirmation arrives from the peer. - * - * @note The number of Handle Value Notifications that can be queued is configured by @ref - * ble_gatts_conn_cfg_t::hvn_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. A @ref - * BLE_GATTS_EVT_HVN_TX_COMPLETE event will be issued as soon as the transmission of the notification is complete. - * - * @note The application can keep track of the available queue element count for notifications by following the procedure - * below: - * - Store initial queue element count in a variable. - * - Decrement the variable, which stores the currently available queue element count, by one when a call to this - * function returns @ref NRF_SUCCESS. - * - Increment the variable, which stores the current available queue element count, by the count variable in @ref - * BLE_GATTS_EVT_HVN_TX_COMPLETE event. - * - * @events - * @event{@ref BLE_GATTS_EVT_HVN_TX_COMPLETE, Notification transmission complete.} - * @event{@ref BLE_GATTS_EVT_HVC, Confirmation received from the peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} - * @mmsc{@ref BLE_GATTS_HVN_MSC} - * @mmsc{@ref BLE_GATTS_HVI_MSC} - * @mmsc{@ref BLE_GATTS_HVX_DISABLED_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in,out] p_hvx_params Pointer to an HVx parameters structure. If @ref ble_gatts_hvx_params_t::p_data - * contains a non-NULL pointer the attribute value will be updated with the contents - * pointed by it before sending the notification or indication. If the attribute value - * is updated, @ref ble_gatts_hvx_params_t::p_len is updated by the SoftDevice to - * contain the number of actual bytes written, else it will be set to 0. - * - * @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute - * value. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: - * - Invalid Connection State - * - Notifications and/or indications not enabled in the CCCD - * - An ATT_MTU exchange is ongoing - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application - * are available to notify and indicate. - * @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and - * indicated. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_FORBIDDEN The connection's current security level is lower than the one required by the write permissions - * of the CCCD associated with this characteristic. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC - * event and retry. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - * @retval ::NRF_ERROR_RESOURCES Too many notifications queued. - * Wait for a @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event and retry. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_gatts_hvx_params_t const *p_hvx_params)); - -/**@brief Indicate the Service Changed attribute value. - * - * @details This call will send a Handle Value Indication to one or more peers connected to inform them that the Attribute - * Table layout has changed. As soon as the peer has confirmed the indication, a @ref BLE_GATTS_EVT_SC_CONFIRM event will - * be issued. - * - * @note Some of the restrictions and limitations that apply to @ref sd_ble_gatts_hvx also apply here. - * - * @events - * @event{@ref BLE_GATTS_EVT_SC_CONFIRM, Confirmation of attribute table change received from peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTS_SC_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] start_handle Start of affected attribute handle range. - * @param[in] end_handle End of affected attribute handle range. - * - * @retval ::NRF_SUCCESS Successfully queued the Service Changed indication for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_NOT_SUPPORTED Service Changed not enabled at initialization. See @ref - * sd_ble_cfg_set and @ref ble_gatts_cfg_service_changed_t. - * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: - * - Invalid Connection State - * - Notifications and/or indications not enabled in the CCCD - * - An ATT_MTU exchange is ongoing - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied, handles must be in the range populated by the - * application. - * @retval ::NRF_ERROR_BUSY Procedure already in progress. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t, - sd_ble_gatts_service_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle)); - -/**@brief Respond to a Read/Write authorization request. - * - * @note This call should only be used as a response to a @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event issued to the application. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_READ_REQ_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_WRITE_REQ_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_rw_authorize_reply_params Pointer to a structure with the attribute provided by the application. - * - * @note @ref ble_gatts_authorize_params_t::p_data is ignored when this function is used to respond - * to a @ref BLE_GATTS_AUTHORIZE_TYPE_READ event if @ref ble_gatts_authorize_params_t::update - * is set to 0. - * - * @retval ::NRF_SUCCESS Successfully queued a response to the peer, and in the case of a write operation, Attribute - * Table updated. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no authorization request pending. - * @retval ::NRF_ERROR_INVALID_PARAM Authorization op invalid, - * handle supplied does not match requested handle, - * or invalid data to be written provided by the application. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_RW_AUTHORIZE_REPLY, uint32_t, - sd_ble_gatts_rw_authorize_reply(uint16_t conn_handle, - ble_gatts_rw_authorize_reply_params_t const *p_rw_authorize_reply_params)); - -/**@brief Update persistent system attribute information. - * - * @details Supply information about persistent system attributes to the stack, - * previously obtained using @ref sd_ble_gatts_sys_attr_get. - * This call is only allowed for active connections, and is usually - * made immediately after a connection is established with an known bonded device, - * often as a response to a @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. - * - * p_sysattrs may point directly to the application's stored copy of the system attributes - * obtained using @ref sd_ble_gatts_sys_attr_get. - * If the pointer is NULL, the system attribute info is initialized, assuming that - * the application does not have any previously saved system attribute data for this device. - * - * @note The state of persistent system attributes is reset upon connection establishment and then remembered for its duration. - * - * @note If this call returns with an error code different from @ref NRF_SUCCESS, the storage of persistent system attributes may - * have been completed only partially. This means that the state of the attribute table is undefined, and the application should - * either provide a new set of attributes using this same call or reset the SoftDevice to return to a known state. - * - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system - * services will be modified. - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user - * services will be modified. - * - * @mscs - * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_UNK_PEER_MSC} - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_sys_attr_data Pointer to a saved copy of system attributes supplied to the stack, or NULL. - * @param[in] len Size of data pointed by p_sys_attr_data, in octets. - * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS - * - * @retval ::NRF_SUCCESS Successfully set the system attribute information. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. - * @retval ::NRF_ERROR_INVALID_DATA Invalid data supplied, the data should be exactly the same as retrieved with @ref - * sd_ble_gatts_sys_attr_get. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GATTS_SYS_ATTR_SET, uint32_t, - sd_ble_gatts_sys_attr_set(uint16_t conn_handle, uint8_t const *p_sys_attr_data, uint16_t len, uint32_t flags)); - -/**@brief Retrieve persistent system attribute information from the stack. - * - * @details This call is used to retrieve information about values to be stored persistently by the application - * during the lifetime of a connection or after it has been terminated. When a new connection is established with the - * same bonded device, the system attribute information retrieved with this function should be restored using using @ref - * sd_ble_gatts_sys_attr_set. If retrieved after disconnection, the data should be read before a new connection established. The - * connection handle for the previous, now disconnected, connection will remain valid until a new one is created to allow this API - * call to refer to it. Connection handles belonging to active connections can be used as well, but care should be taken since the - * system attributes may be written to at any time by the peer during a connection's lifetime. - * - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system - * services will be returned. - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user - * services will be returned. - * - * @mscs - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle of the recently terminated connection. - * @param[out] p_sys_attr_data Pointer to a buffer where updated information about system attributes will be filled in. The - * format of the data is described in @ref BLE_GATTS_SYS_ATTRS_FORMAT. NULL can be provided to obtain the length of the data. - * @param[in,out] p_len Size of application buffer if p_sys_attr_data is not NULL. Unconditionally updated to actual - * length of system attribute data. - * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS - * - * @retval ::NRF_SUCCESS Successfully retrieved the system attribute information. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. - * @retval ::NRF_ERROR_DATA_SIZE The system attribute information did not fit into the provided buffer. - * @retval ::NRF_ERROR_NOT_FOUND No system attributes found. - */ -SVCALL(SD_BLE_GATTS_SYS_ATTR_GET, uint32_t, - sd_ble_gatts_sys_attr_get(uint16_t conn_handle, uint8_t *p_sys_attr_data, uint16_t *p_len, uint32_t flags)); - -/**@brief Retrieve the first valid user attribute handle. - * - * @param[out] p_handle Pointer to an integer where the handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully retrieved the handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, uint32_t, sd_ble_gatts_initial_user_handle_get(uint16_t *p_handle)); - -/**@brief Retrieve the attribute UUID and/or metadata. - * - * @param[in] handle Attribute handle - * @param[out] p_uuid UUID of the attribute. Use NULL to omit this field. - * @param[out] p_md Metadata of the attribute. Use NULL to omit this field. - * - * @retval ::NRF_SUCCESS Successfully retrieved the attribute metadata, - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. Returned when both @c p_uuid and @c p_md are NULL. - * @retval ::NRF_ERROR_NOT_FOUND Attribute was not found. - */ -SVCALL(SD_BLE_GATTS_ATTR_GET, uint32_t, sd_ble_gatts_attr_get(uint16_t handle, ble_uuid_t *p_uuid, ble_gatts_attr_md_t *p_md)); - -/**@brief Reply to an ATT_MTU exchange request by sending an Exchange MTU Response to the client. - * - * @details This function is only used to reply to a @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event. - * - * @details The SoftDevice sets ATT_MTU to the minimum of: - * - The Client RX MTU value from @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, and - * - The Server RX MTU value. - * - * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. - * - * @mscs - * @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] server_rx_mtu Server RX MTU size. - * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration - * used for this connection. - * - The value must be equal to Client RX MTU size given in @ref sd_ble_gattc_exchange_mtu_request - * if an ATT_MTU exchange has already been performed in the other direction. - * - * @retval ::NRF_SUCCESS Successfully sent response to the client. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no ATT_MTU exchange request pending. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid Server RX MTU size supplied. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_EXCHANGE_MTU_REPLY, uint32_t, sd_ble_gatts_exchange_mtu_reply(uint16_t conn_handle, uint16_t server_rx_mtu)); -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GATTS_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_hci.h b/variants/wio-tracker-wm1110/softdevice/ble_hci.h deleted file mode 100644 index 27f85d52ea..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_hci.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ -*/ - -#ifndef BLE_HCI_H__ -#define BLE_HCI_H__ -#ifdef __cplusplus -extern "C" { -#endif - -/** @defgroup BLE_HCI_STATUS_CODES Bluetooth status codes - * @{ */ - -#define BLE_HCI_STATUS_CODE_SUCCESS 0x00 /**< Success. */ -#define BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND 0x01 /**< Unknown BLE Command. */ -#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02 /**< Unknown Connection Identifier. */ -/*0x03 Hardware Failure -0x04 Page Timeout -*/ -#define BLE_HCI_AUTHENTICATION_FAILURE 0x05 /**< Authentication Failure. */ -#define BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING 0x06 /**< Pin or Key missing. */ -#define BLE_HCI_MEMORY_CAPACITY_EXCEEDED 0x07 /**< Memory Capacity Exceeded. */ -#define BLE_HCI_CONNECTION_TIMEOUT 0x08 /**< Connection Timeout. */ -/*0x09 Connection Limit Exceeded -0x0A Synchronous Connection Limit To A Device Exceeded -0x0B ACL Connection Already Exists*/ -#define BLE_HCI_STATUS_CODE_COMMAND_DISALLOWED 0x0C /**< Command Disallowed. */ -/*0x0D Connection Rejected due to Limited Resources -0x0E Connection Rejected Due To Security Reasons -0x0F Connection Rejected due to Unacceptable BD_ADDR -0x10 Connection Accept Timeout Exceeded -0x11 Unsupported Feature or Parameter Value*/ -#define BLE_HCI_STATUS_CODE_INVALID_BTLE_COMMAND_PARAMETERS 0x12 /**< Invalid BLE Command Parameters. */ -#define BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION 0x13 /**< Remote User Terminated Connection. */ -#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES \ - 0x14 /**< Remote Device Terminated Connection due to low \ - resources.*/ -#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF 0x15 /**< Remote Device Terminated Connection due to power off. */ -#define BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION 0x16 /**< Local Host Terminated Connection. */ -/* -0x17 Repeated Attempts -0x18 Pairing Not Allowed -0x19 Unknown LMP PDU -*/ -#define BLE_HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A /**< Unsupported Remote Feature. */ -/* -0x1B SCO Offset Rejected -0x1C SCO Interval Rejected -0x1D SCO Air Mode Rejected*/ -#define BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS 0x1E /**< Invalid LMP Parameters. */ -#define BLE_HCI_STATUS_CODE_UNSPECIFIED_ERROR 0x1F /**< Unspecified Error. */ -/*0x20 Unsupported LMP Parameter Value -0x21 Role Change Not Allowed -*/ -#define BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT 0x22 /**< LMP Response Timeout. */ -#define BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION 0x23 /**< LMP Error Transaction Collision/LL Procedure Collision. */ -#define BLE_HCI_STATUS_CODE_LMP_PDU_NOT_ALLOWED 0x24 /**< LMP PDU Not Allowed. */ -/*0x25 Encryption Mode Not Acceptable -0x26 Link Key Can Not be Changed -0x27 Requested QoS Not Supported -*/ -#define BLE_HCI_INSTANT_PASSED 0x28 /**< Instant Passed. */ -#define BLE_HCI_PAIRING_WITH_UNIT_KEY_UNSUPPORTED 0x29 /**< Pairing with Unit Key Unsupported. */ -#define BLE_HCI_DIFFERENT_TRANSACTION_COLLISION 0x2A /**< Different Transaction Collision. */ -/* -0x2B Reserved -0x2C QoS Unacceptable Parameter -0x2D QoS Rejected -0x2E Channel Classification Not Supported -0x2F Insufficient Security -*/ -#define BLE_HCI_PARAMETER_OUT_OF_MANDATORY_RANGE 0x30 /**< Parameter Out Of Mandatory Range. */ -/* -0x31 Reserved -0x32 Role Switch Pending -0x33 Reserved -0x34 Reserved Slot Violation -0x35 Role Switch Failed -0x36 Extended Inquiry Response Too Large -0x37 Secure Simple Pairing Not Supported By Host. -0x38 Host Busy - Pairing -0x39 Connection Rejected due to No Suitable Channel Found*/ -#define BLE_HCI_CONTROLLER_BUSY 0x3A /**< Controller Busy. */ -#define BLE_HCI_CONN_INTERVAL_UNACCEPTABLE 0x3B /**< Connection Interval Unacceptable. */ -#define BLE_HCI_DIRECTED_ADVERTISER_TIMEOUT 0x3C /**< Directed Advertisement Timeout. */ -#define BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE 0x3D /**< Connection Terminated due to MIC Failure. */ -#define BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED 0x3E /**< Connection Failed to be Established. */ - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_HCI_H__ - -/** @} */ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h b/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h deleted file mode 100644 index 5f4bd277d3..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_L2CAP Logical Link Control and Adaptation Protocol (L2CAP) - @{ - @brief Definitions and prototypes for the L2CAP interface. - */ - -#ifndef BLE_L2CAP_H__ -#define BLE_L2CAP_H__ - -#include "ble_err.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup BLE_L2CAP_TERMINOLOGY Terminology - * @{ - * @details - * - * L2CAP SDU - * - A data unit that the application can send/receive to/from a peer. - * - * L2CAP PDU - * - A data unit that is exchanged between local and remote L2CAP entities. - * It consists of L2CAP protocol control information and payload fields. - * The payload field can contain an L2CAP SDU or a part of an L2CAP SDU. - * - * L2CAP MTU - * - The maximum length of an L2CAP SDU. - * - * L2CAP MPS - * - The maximum length of an L2CAP PDU payload field. - * - * Credits - * - A value indicating the number of L2CAP PDUs that the receiver of the credit can send to the peer. - * @} */ - -/**@addtogroup BLE_L2CAP_ENUMERATIONS Enumerations - * @{ */ - -/**@brief L2CAP API SVC numbers. */ -enum BLE_L2CAP_SVCS { - SD_BLE_L2CAP_CH_SETUP = BLE_L2CAP_SVC_BASE + 0, /**< Set up an L2CAP channel. */ - SD_BLE_L2CAP_CH_RELEASE = BLE_L2CAP_SVC_BASE + 1, /**< Release an L2CAP channel. */ - SD_BLE_L2CAP_CH_RX = BLE_L2CAP_SVC_BASE + 2, /**< Receive an SDU on an L2CAP channel. */ - SD_BLE_L2CAP_CH_TX = BLE_L2CAP_SVC_BASE + 3, /**< Transmit an SDU on an L2CAP channel. */ - SD_BLE_L2CAP_CH_FLOW_CONTROL = BLE_L2CAP_SVC_BASE + 4, /**< Advanced SDU reception flow control. */ -}; - -/**@brief L2CAP Event IDs. */ -enum BLE_L2CAP_EVTS { - BLE_L2CAP_EVT_CH_SETUP_REQUEST = BLE_L2CAP_EVT_BASE + 0, /**< L2CAP Channel Setup Request event. - \n Reply with @ref sd_ble_l2cap_ch_setup. - \n See @ref ble_l2cap_evt_ch_setup_request_t. */ - BLE_L2CAP_EVT_CH_SETUP_REFUSED = BLE_L2CAP_EVT_BASE + 1, /**< L2CAP Channel Setup Refused event. - \n See @ref ble_l2cap_evt_ch_setup_refused_t. */ - BLE_L2CAP_EVT_CH_SETUP = BLE_L2CAP_EVT_BASE + 2, /**< L2CAP Channel Setup Completed event. - \n See @ref ble_l2cap_evt_ch_setup_t. */ - BLE_L2CAP_EVT_CH_RELEASED = BLE_L2CAP_EVT_BASE + 3, /**< L2CAP Channel Released event. - \n No additional event structure applies. */ - BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED = BLE_L2CAP_EVT_BASE + 4, /**< L2CAP Channel SDU data buffer released event. - \n See @ref ble_l2cap_evt_ch_sdu_buf_released_t. */ - BLE_L2CAP_EVT_CH_CREDIT = BLE_L2CAP_EVT_BASE + 5, /**< L2CAP Channel Credit received. - \n See @ref ble_l2cap_evt_ch_credit_t. */ - BLE_L2CAP_EVT_CH_RX = BLE_L2CAP_EVT_BASE + 6, /**< L2CAP Channel SDU received. - \n See @ref ble_l2cap_evt_ch_rx_t. */ - BLE_L2CAP_EVT_CH_TX = BLE_L2CAP_EVT_BASE + 7, /**< L2CAP Channel SDU transmitted. - \n See @ref ble_l2cap_evt_ch_tx_t. */ -}; - -/** @} */ - -/**@addtogroup BLE_L2CAP_DEFINES Defines - * @{ */ - -/**@brief Maximum number of L2CAP channels per connection. */ -#define BLE_L2CAP_CH_COUNT_MAX (64) - -/**@brief Minimum L2CAP MTU, in bytes. */ -#define BLE_L2CAP_MTU_MIN (23) - -/**@brief Minimum L2CAP MPS, in bytes. */ -#define BLE_L2CAP_MPS_MIN (23) - -/**@brief Invalid CID. */ -#define BLE_L2CAP_CID_INVALID (0x0000) - -/**@brief Default number of credits for @ref sd_ble_l2cap_ch_flow_control. */ -#define BLE_L2CAP_CREDITS_DEFAULT (1) - -/**@defgroup BLE_L2CAP_CH_SETUP_REFUSED_SRCS L2CAP channel setup refused sources - * @{ */ -#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_LOCAL (0x01) /**< Local. */ -#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_REMOTE (0x02) /**< Remote. */ - /** @} */ - -/** @defgroup BLE_L2CAP_CH_STATUS_CODES L2CAP channel status codes - * @{ */ -#define BLE_L2CAP_CH_STATUS_CODE_SUCCESS (0x0000) /**< Success. */ -#define BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED (0x0002) /**< LE_PSM not supported. */ -#define BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES (0x0004) /**< No resources available. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHENTICATION (0x0005) /**< Insufficient authentication. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHORIZATION (0x0006) /**< Insufficient authorization. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC_KEY_SIZE (0x0007) /**< Insufficient encryption key size. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC (0x0008) /**< Insufficient encryption. */ -#define BLE_L2CAP_CH_STATUS_CODE_INVALID_SCID (0x0009) /**< Invalid Source CID. */ -#define BLE_L2CAP_CH_STATUS_CODE_SCID_ALLOCATED (0x000A) /**< Source CID already allocated. */ -#define BLE_L2CAP_CH_STATUS_CODE_UNACCEPTABLE_PARAMS (0x000B) /**< Unacceptable parameters. */ -#define BLE_L2CAP_CH_STATUS_CODE_NOT_UNDERSTOOD \ - (0x8000) /**< Command Reject received instead of LE Credit Based Connection Response. */ -#define BLE_L2CAP_CH_STATUS_CODE_TIMEOUT (0xC000) /**< Operation timed out. */ -/** @} */ - -/** @} */ - -/**@addtogroup BLE_L2CAP_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE L2CAP connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @note These parameters are set per connection, so all L2CAP channels created on this connection - * will have the same parameters. - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - rx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. - * - tx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. - * - ch_count is greater than @ref BLE_L2CAP_CH_COUNT_MAX. - * @retval ::NRF_ERROR_NO_MEM rx_mps or tx_mps is set too high. - */ -typedef struct { - uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall - be able to receive on L2CAP channels on connections with this - configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ - uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall - be able to transmit on L2CAP channels on connections with this - configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ - uint8_t rx_queue_size; /**< Number of SDU data buffers that can be queued for reception per - L2CAP channel. The minimum value is one. */ - uint8_t tx_queue_size; /**< Number of SDU data buffers that can be queued for transmission - per L2CAP channel. The minimum value is one. */ - uint8_t ch_count; /**< Number of L2CAP channels the application can create per connection - with this configuration. The default value is zero, the maximum - value is @ref BLE_L2CAP_CH_COUNT_MAX. - @note if this parameter is set to zero, all other parameters in - @ref ble_l2cap_conn_cfg_t are ignored. */ -} ble_l2cap_conn_cfg_t; - -/**@brief L2CAP channel RX parameters. */ -typedef struct { - uint16_t rx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP shall be able to - receive on this L2CAP channel. - - Must be equal to or greater than @ref BLE_L2CAP_MTU_MIN. */ - uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall be - able to receive on this L2CAP channel. - - Must be equal to or greater than @ref BLE_L2CAP_MPS_MIN. - - Must be equal to or less than @ref ble_l2cap_conn_cfg_t::rx_mps. */ - ble_data_t sdu_buf; /**< SDU data buffer for reception. - - If @ref ble_data_t::p_data is non-NULL, initial credits are - issued to the peer. - - If @ref ble_data_t::p_data is NULL, no initial credits are - issued to the peer. */ -} ble_l2cap_ch_rx_params_t; - -/**@brief L2CAP channel setup parameters. */ -typedef struct { - ble_l2cap_ch_rx_params_t rx_params; /**< L2CAP channel RX parameters. */ - uint16_t le_psm; /**< LE Protocol/Service Multiplexer. Used when requesting - setup of an L2CAP channel, ignored otherwise. */ - uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES. - Used when replying to a setup request of an L2CAP - channel, ignored otherwise. */ -} ble_l2cap_ch_setup_params_t; - -/**@brief L2CAP channel TX parameters. */ -typedef struct { - uint16_t tx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP is able to - transmit on this L2CAP channel. */ - uint16_t peer_mps; /**< The maximum L2CAP PDU payload size, in bytes, that the peer is - able to receive on this L2CAP channel. */ - uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP is able - to transmit on this L2CAP channel. This is effective tx_mps, - selected by the SoftDevice as - MIN( @ref ble_l2cap_ch_tx_params_t::peer_mps, @ref ble_l2cap_conn_cfg_t::tx_mps ) */ - uint16_t credits; /**< Initial credits given by the peer. */ -} ble_l2cap_ch_tx_params_t; - -/**@brief L2CAP Channel Setup Request event. */ -typedef struct { - ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ - uint16_t le_psm; /**< LE Protocol/Service Multiplexer. */ -} ble_l2cap_evt_ch_setup_request_t; - -/**@brief L2CAP Channel Setup Refused event. */ -typedef struct { - uint8_t source; /**< Source, see @ref BLE_L2CAP_CH_SETUP_REFUSED_SRCS */ - uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES */ -} ble_l2cap_evt_ch_setup_refused_t; - -/**@brief L2CAP Channel Setup Completed event. */ -typedef struct { - ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ -} ble_l2cap_evt_ch_setup_t; - -/**@brief L2CAP Channel SDU Data Buffer Released event. */ -typedef struct { - ble_data_t sdu_buf; /**< Returned reception or transmission SDU data buffer. The SoftDevice - returns SDU data buffers supplied by the application, which have - not yet been returned previously via a @ref BLE_L2CAP_EVT_CH_RX or - @ref BLE_L2CAP_EVT_CH_TX event. */ -} ble_l2cap_evt_ch_sdu_buf_released_t; - -/**@brief L2CAP Channel Credit received event. */ -typedef struct { - uint16_t credits; /**< Additional credits given by the peer. */ -} ble_l2cap_evt_ch_credit_t; - -/**@brief L2CAP Channel received SDU event. */ -typedef struct { - uint16_t sdu_len; /**< Total SDU length, in bytes. */ - ble_data_t sdu_buf; /**< SDU data buffer. - @note If there is not enough space in the buffer - (sdu_buf.len < sdu_len) then the rest of the SDU will be - silently discarded by the SoftDevice. */ -} ble_l2cap_evt_ch_rx_t; - -/**@brief L2CAP Channel transmitted SDU event. */ -typedef struct { - ble_data_t sdu_buf; /**< SDU data buffer. */ -} ble_l2cap_evt_ch_tx_t; - -/**@brief L2CAP event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which the event occured. */ - uint16_t local_cid; /**< Local Channel ID of the L2CAP channel, or - @ref BLE_L2CAP_CID_INVALID if not present. */ - union { - ble_l2cap_evt_ch_setup_request_t ch_setup_request; /**< L2CAP Channel Setup Request Event Parameters. */ - ble_l2cap_evt_ch_setup_refused_t ch_setup_refused; /**< L2CAP Channel Setup Refused Event Parameters. */ - ble_l2cap_evt_ch_setup_t ch_setup; /**< L2CAP Channel Setup Completed Event Parameters. */ - ble_l2cap_evt_ch_sdu_buf_released_t ch_sdu_buf_released; /**< L2CAP Channel SDU Data Buffer Released Event Parameters. */ - ble_l2cap_evt_ch_credit_t credit; /**< L2CAP Channel Credit Received Event Parameters. */ - ble_l2cap_evt_ch_rx_t rx; /**< L2CAP Channel SDU Received Event Parameters. */ - ble_l2cap_evt_ch_tx_t tx; /**< L2CAP Channel SDU Transmitted Event Parameters. */ - } params; /**< Event Parameters. */ -} ble_l2cap_evt_t; - -/** @} */ - -/**@addtogroup BLE_L2CAP_FUNCTIONS Functions - * @{ */ - -/**@brief Set up an L2CAP channel. - * - * @details This function is used to: - * - Request setup of an L2CAP channel: sends an LE Credit Based Connection Request packet to a peer. - * - Reply to a setup request of an L2CAP channel (if called in response to a - * @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST event): sends an LE Credit Based Connection - * Response packet to a peer. - * - * @note A call to this function will require the application to keep the SDU data buffer alive - * until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX or - * @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_SETUP, Setup successful.} - * @event{@ref BLE_L2CAP_EVT_CH_SETUP_REFUSED, Setup failed.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_SETUP_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in,out] p_local_cid Pointer to a uint16_t containing Local Channel ID of the L2CAP channel: - * - As input: @ref BLE_L2CAP_CID_INVALID when requesting setup of an L2CAP - * channel or local_cid provided in the @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST - * event when replying to a setup request of an L2CAP channel. - * - As output: local_cid for this channel. - * @param[in] p_params L2CAP channel parameters. - * - * @retval ::NRF_SUCCESS Successfully queued request or response for transmission. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_LENGTH Supplied higher rx_mps than has been configured on this link. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (L2CAP channel already set up). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_RESOURCES The limit has been reached for available L2CAP channels, - * see @ref ble_l2cap_conn_cfg_t::ch_count. - */ -SVCALL(SD_BLE_L2CAP_CH_SETUP, uint32_t, - sd_ble_l2cap_ch_setup(uint16_t conn_handle, uint16_t *p_local_cid, ble_l2cap_ch_setup_params_t const *p_params)); - -/**@brief Release an L2CAP channel. - * - * @details This sends a Disconnection Request packet to a peer. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_RELEASED, Release complete.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_RELEASE_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * - * @retval ::NRF_SUCCESS Successfully queued request for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for the L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - */ -SVCALL(SD_BLE_L2CAP_CH_RELEASE, uint32_t, sd_ble_l2cap_ch_release(uint16_t conn_handle, uint16_t local_cid)); - -/**@brief Receive an SDU on an L2CAP channel. - * - * @details This may issue additional credits to the peer using an LE Flow Control Credit packet. - * - * @note A call to this function will require the application to keep the memory pointed by - * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX - * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::rx_queue_size SDU data buffers - * for reception per L2CAP channel. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_RX, The SDU is received.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_RX_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * @param[in] p_sdu_buf Pointer to the SDU data buffer. - * - * @retval ::NRF_SUCCESS Buffer accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for an L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_RESOURCES Too many SDU data buffers supplied. Wait for a - * @ref BLE_L2CAP_EVT_CH_RX event and retry. - */ -SVCALL(SD_BLE_L2CAP_CH_RX, uint32_t, sd_ble_l2cap_ch_rx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); - -/**@brief Transmit an SDU on an L2CAP channel. - * - * @note A call to this function will require the application to keep the memory pointed by - * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_TX - * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::tx_queue_size SDUs for - * transmission per L2CAP channel. - * - * @note The application can keep track of the available credits for transmission by following - * the procedure below: - * - Store initial credits given by the peer in a variable. - * (Initial credits are provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) - * - Decrement the variable, which stores the currently available credits, by - * ceiling((@ref ble_data_t::len + 2) / tx_mps) when a call to this function returns - * @ref NRF_SUCCESS. (tx_mps is provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) - * - Increment the variable, which stores the currently available credits, by additional - * credits given by the peer in a @ref BLE_L2CAP_EVT_CH_CREDIT event. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_TX, The SDU is transmitted.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_TX_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * @param[in] p_sdu_buf Pointer to the SDU data buffer. - * - * @retval ::NRF_SUCCESS Successfully queued L2CAP SDU for transmission. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for the L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_DATA_SIZE Invalid SDU length supplied, must not be more than - * @ref ble_l2cap_ch_tx_params_t::tx_mtu provided in - * @ref BLE_L2CAP_EVT_CH_SETUP event. - * @retval ::NRF_ERROR_RESOURCES Too many SDUs queued for transmission. Wait for a - * @ref BLE_L2CAP_EVT_CH_TX event and retry. - */ -SVCALL(SD_BLE_L2CAP_CH_TX, uint32_t, sd_ble_l2cap_ch_tx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); - -/**@brief Advanced SDU reception flow control. - * - * @details Adjust the way the SoftDevice issues credits to the peer. - * This may issue additional credits to the peer using an LE Flow Control Credit packet. - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_FLOW_CONTROL_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel or @ref BLE_L2CAP_CID_INVALID to set - * the value that will be used for newly created channels. - * @param[in] credits Number of credits that the SoftDevice will make sure the peer has every - * time it starts using a new reception buffer. - * - @ref BLE_L2CAP_CREDITS_DEFAULT is the default value the SoftDevice will - * use if this function is not called. - * - If set to zero, the SoftDevice will stop issuing credits for new reception - * buffers the application provides or has provided. SDU reception that is - * currently ongoing will be allowed to complete. - * @param[out] p_credits NULL or pointer to a uint16_t. If a valid pointer is provided, it will be - * written by the SoftDevice with the number of credits that is or will be - * available to the peer. If the value written by the SoftDevice is 0 when - * credits parameter was set to 0, the peer will not be able to send more - * data until more credits are provided by calling this function again with - * credits > 0. This parameter is ignored when local_cid is set to - * @ref BLE_L2CAP_CID_INVALID. - * - * @note Application should take care when setting number of credits higher than default value. In - * this case the application must make sure that the SoftDevice always has reception buffers - * available (see @ref sd_ble_l2cap_ch_rx) for that channel. If the SoftDevice does not have - * such buffers available, packets may be NACKed on the Link Layer and all Bluetooth traffic - * on the connection handle may be stalled until the SoftDevice again has an available - * reception buffer. This applies even if the application has used this call to set the - * credits back to default, or zero. - * - * @retval ::NRF_SUCCESS Flow control parameters accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for an L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - */ -SVCALL(SD_BLE_L2CAP_CH_FLOW_CONTROL, uint32_t, - sd_ble_l2cap_ch_flow_control(uint16_t conn_handle, uint16_t local_cid, uint16_t credits, uint16_t *p_credits)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_L2CAP_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_ranges.h b/variants/wio-tracker-wm1110/softdevice/ble_ranges.h deleted file mode 100644 index 2768e49967..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_ranges.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @defgroup ble_ranges Module specific SVC, event and option number subranges - @{ - - @brief Definition of SVC, event and option number subranges for each API module. - - @note - SVCs, event and option numbers are split into subranges for each API module. - Each module receives its entire allocated range of SVC calls, whether implemented or not, - but return BLE_ERROR_NOT_SUPPORTED for unimplemented or undefined calls in its range. - - Note that the symbols BLE__SVC_LAST is the end of the allocated SVC range, - rather than the last SVC function call actually defined and implemented. - - Specific SVC, event and option values are defined in each module's ble_.h file, - which defines names of each individual SVC code based on the range start value. -*/ - -#ifndef BLE_RANGES_H__ -#define BLE_RANGES_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#define BLE_SVC_BASE 0x60 /**< Common BLE SVC base. */ -#define BLE_SVC_LAST 0x6B /**< Common BLE SVC last. */ - -#define BLE_GAP_SVC_BASE 0x6C /**< GAP BLE SVC base. */ -#define BLE_GAP_SVC_LAST 0x9A /**< GAP BLE SVC last. */ - -#define BLE_GATTC_SVC_BASE 0x9B /**< GATTC BLE SVC base. */ -#define BLE_GATTC_SVC_LAST 0xA7 /**< GATTC BLE SVC last. */ - -#define BLE_GATTS_SVC_BASE 0xA8 /**< GATTS BLE SVC base. */ -#define BLE_GATTS_SVC_LAST 0xB7 /**< GATTS BLE SVC last. */ - -#define BLE_L2CAP_SVC_BASE 0xB8 /**< L2CAP BLE SVC base. */ -#define BLE_L2CAP_SVC_LAST 0xBF /**< L2CAP BLE SVC last. */ - -#define BLE_EVT_INVALID 0x00 /**< Invalid BLE Event. */ - -#define BLE_EVT_BASE 0x01 /**< Common BLE Event base. */ -#define BLE_EVT_LAST 0x0F /**< Common BLE Event last. */ - -#define BLE_GAP_EVT_BASE 0x10 /**< GAP BLE Event base. */ -#define BLE_GAP_EVT_LAST 0x2F /**< GAP BLE Event last. */ - -#define BLE_GATTC_EVT_BASE 0x30 /**< GATTC BLE Event base. */ -#define BLE_GATTC_EVT_LAST 0x4F /**< GATTC BLE Event last. */ - -#define BLE_GATTS_EVT_BASE 0x50 /**< GATTS BLE Event base. */ -#define BLE_GATTS_EVT_LAST 0x6F /**< GATTS BLE Event last. */ - -#define BLE_L2CAP_EVT_BASE 0x70 /**< L2CAP BLE Event base. */ -#define BLE_L2CAP_EVT_LAST 0x8F /**< L2CAP BLE Event last. */ - -#define BLE_OPT_INVALID 0x00 /**< Invalid BLE Option. */ - -#define BLE_OPT_BASE 0x01 /**< Common BLE Option base. */ -#define BLE_OPT_LAST 0x1F /**< Common BLE Option last. */ - -#define BLE_GAP_OPT_BASE 0x20 /**< GAP BLE Option base. */ -#define BLE_GAP_OPT_LAST 0x3F /**< GAP BLE Option last. */ - -#define BLE_GATT_OPT_BASE 0x40 /**< GATT BLE Option base. */ -#define BLE_GATT_OPT_LAST 0x5F /**< GATT BLE Option last. */ - -#define BLE_GATTC_OPT_BASE 0x60 /**< GATTC BLE Option base. */ -#define BLE_GATTC_OPT_LAST 0x7F /**< GATTC BLE Option last. */ - -#define BLE_GATTS_OPT_BASE 0x80 /**< GATTS BLE Option base. */ -#define BLE_GATTS_OPT_LAST 0x9F /**< GATTS BLE Option last. */ - -#define BLE_L2CAP_OPT_BASE 0xA0 /**< L2CAP BLE Option base. */ -#define BLE_L2CAP_OPT_LAST 0xBF /**< L2CAP BLE Option last. */ - -#define BLE_CFG_INVALID 0x00 /**< Invalid BLE configuration. */ - -#define BLE_CFG_BASE 0x01 /**< Common BLE configuration base. */ -#define BLE_CFG_LAST 0x1F /**< Common BLE configuration last. */ - -#define BLE_CONN_CFG_BASE 0x20 /**< BLE connection configuration base. */ -#define BLE_CONN_CFG_LAST 0x3F /**< BLE connection configuration last. */ - -#define BLE_GAP_CFG_BASE 0x40 /**< GAP BLE configuration base. */ -#define BLE_GAP_CFG_LAST 0x5F /**< GAP BLE configuration last. */ - -#define BLE_GATT_CFG_BASE 0x60 /**< GATT BLE configuration base. */ -#define BLE_GATT_CFG_LAST 0x7F /**< GATT BLE configuration last. */ - -#define BLE_GATTC_CFG_BASE 0x80 /**< GATTC BLE configuration base. */ -#define BLE_GATTC_CFG_LAST 0x9F /**< GATTC BLE configuration last. */ - -#define BLE_GATTS_CFG_BASE 0xA0 /**< GATTS BLE configuration base. */ -#define BLE_GATTS_CFG_LAST 0xBF /**< GATTS BLE configuration last. */ - -#define BLE_L2CAP_CFG_BASE 0xC0 /**< L2CAP BLE configuration base. */ -#define BLE_L2CAP_CFG_LAST 0xDF /**< L2CAP BLE configuration last. */ - -#ifdef __cplusplus -} -#endif -#endif /* BLE_RANGES_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_types.h b/variants/wio-tracker-wm1110/softdevice/ble_types.h deleted file mode 100644 index db3656cfdd..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_types.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @defgroup ble_types Common types and macro definitions - @{ - - @brief Common types and macro definitions for the BLE SoftDevice. - */ - -#ifndef BLE_TYPES_H__ -#define BLE_TYPES_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_TYPES_DEFINES Defines - * @{ */ - -/** @defgroup BLE_CONN_HANDLES BLE Connection Handles - * @{ */ -#define BLE_CONN_HANDLE_INVALID 0xFFFF /**< Invalid Connection Handle. */ -#define BLE_CONN_HANDLE_ALL 0xFFFE /**< Applies to all Connection Handles. */ -/** @} */ - -/** @defgroup BLE_UUID_VALUES Assigned Values for BLE UUIDs - * @{ */ -/* Generic UUIDs, applicable to all services */ -#define BLE_UUID_UNKNOWN 0x0000 /**< Reserved UUID. */ -#define BLE_UUID_SERVICE_PRIMARY 0x2800 /**< Primary Service. */ -#define BLE_UUID_SERVICE_SECONDARY 0x2801 /**< Secondary Service. */ -#define BLE_UUID_SERVICE_INCLUDE 0x2802 /**< Include. */ -#define BLE_UUID_CHARACTERISTIC 0x2803 /**< Characteristic. */ -#define BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP 0x2900 /**< Characteristic Extended Properties Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_USER_DESC 0x2901 /**< Characteristic User Description Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG 0x2902 /**< Client Characteristic Configuration Descriptor. */ -#define BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG 0x2903 /**< Server Characteristic Configuration Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT 0x2904 /**< Characteristic Presentation Format Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_AGGREGATE_FORMAT 0x2905 /**< Characteristic Aggregate Format Descriptor. */ -/* GATT specific UUIDs */ -#define BLE_UUID_GATT 0x1801 /**< Generic Attribute Profile. */ -#define BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED 0x2A05 /**< Service Changed Characteristic. */ -/* GAP specific UUIDs */ -#define BLE_UUID_GAP 0x1800 /**< Generic Access Profile. */ -#define BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME 0x2A00 /**< Device Name Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_APPEARANCE 0x2A01 /**< Appearance Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_RECONN_ADDR 0x2A03 /**< Reconnection Address Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_PPCP 0x2A04 /**< Peripheral Preferred Connection Parameters Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_CAR 0x2AA6 /**< Central Address Resolution Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_RPA_ONLY 0x2AC9 /**< Resolvable Private Address Only Characteristic. */ -/** @} */ - -/** @defgroup BLE_UUID_TYPES Types of UUID - * @{ */ -#define BLE_UUID_TYPE_UNKNOWN 0x00 /**< Invalid UUID type. */ -#define BLE_UUID_TYPE_BLE 0x01 /**< Bluetooth SIG UUID (16-bit). */ -#define BLE_UUID_TYPE_VENDOR_BEGIN 0x02 /**< Vendor UUID types start at this index (128-bit). */ -/** @} */ - -/** @defgroup BLE_APPEARANCES Bluetooth Appearance values - * @note Retrieved from - * http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml - * @{ */ -#define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */ -#define BLE_APPEARANCE_GENERIC_PHONE 64 /**< Generic Phone. */ -#define BLE_APPEARANCE_GENERIC_COMPUTER 128 /**< Generic Computer. */ -#define BLE_APPEARANCE_GENERIC_WATCH 192 /**< Generic Watch. */ -#define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /**< Watch: Sports Watch. */ -#define BLE_APPEARANCE_GENERIC_CLOCK 256 /**< Generic Clock. */ -#define BLE_APPEARANCE_GENERIC_DISPLAY 320 /**< Generic Display. */ -#define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /**< Generic Remote Control. */ -#define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /**< Generic Eye-glasses. */ -#define BLE_APPEARANCE_GENERIC_TAG 512 /**< Generic Tag. */ -#define BLE_APPEARANCE_GENERIC_KEYRING 576 /**< Generic Keyring. */ -#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /**< Generic Media Player. */ -#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /**< Generic Barcode Scanner. */ -#define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /**< Generic Thermometer. */ -#define BLE_APPEARANCE_THERMOMETER_EAR 769 /**< Thermometer: Ear. */ -#define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /**< Generic Heart rate Sensor. */ -#define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /**< Heart Rate Sensor: Heart Rate Belt. */ -#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /**< Generic Blood Pressure. */ -#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /**< Blood Pressure: Arm. */ -#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /**< Blood Pressure: Wrist. */ -#define BLE_APPEARANCE_GENERIC_HID 960 /**< Human Interface Device (HID). */ -#define BLE_APPEARANCE_HID_KEYBOARD 961 /**< Keyboard (HID Subtype). */ -#define BLE_APPEARANCE_HID_MOUSE 962 /**< Mouse (HID Subtype). */ -#define BLE_APPEARANCE_HID_JOYSTICK 963 /**< Joystick (HID Subtype). */ -#define BLE_APPEARANCE_HID_GAMEPAD 964 /**< Gamepad (HID Subtype). */ -#define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /**< Digitizer Tablet (HID Subtype). */ -#define BLE_APPEARANCE_HID_CARD_READER 966 /**< Card Reader (HID Subtype). */ -#define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /**< Digital Pen (HID Subtype). */ -#define BLE_APPEARANCE_HID_BARCODE 968 /**< Barcode Scanner (HID Subtype). */ -#define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /**< Generic Glucose Meter. */ -#define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /**< Generic Running Walking Sensor. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /**< Running Walking Sensor: In-Shoe. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /**< Running Walking Sensor: On-Shoe. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /**< Running Walking Sensor: On-Hip. */ -#define BLE_APPEARANCE_GENERIC_CYCLING 1152 /**< Generic Cycling. */ -#define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /**< Cycling: Cycling Computer. */ -#define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /**< Cycling: Speed Sensor. */ -#define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /**< Cycling: Cadence Sensor. */ -#define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /**< Cycling: Power Sensor. */ -#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /**< Cycling: Speed and Cadence Sensor. */ -#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /**< Generic Pulse Oximeter. */ -#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /**< Fingertip (Pulse Oximeter subtype). */ -#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /**< Wrist Worn(Pulse Oximeter subtype). */ -#define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /**< Generic Weight Scale. */ -#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /**< Generic Outdoor Sports Activity. */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /**< Location Display Device (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP \ - 5186 /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /**< Location Pod (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD \ - 5188 /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */ -/** @} */ - -/** @brief Set .type and .uuid fields of ble_uuid_struct to specified UUID value. */ -#define BLE_UUID_BLE_ASSIGN(instance, value) \ - do { \ - instance.type = BLE_UUID_TYPE_BLE; \ - instance.uuid = value; \ - } while (0) - -/** @brief Copy type and uuid members from src to dst ble_uuid_t pointer. Both pointers must be valid/non-null. */ -#define BLE_UUID_COPY_PTR(dst, src) \ - do { \ - (dst)->type = (src)->type; \ - (dst)->uuid = (src)->uuid; \ - } while (0) - -/** @brief Copy type and uuid members from src to dst ble_uuid_t struct. */ -#define BLE_UUID_COPY_INST(dst, src) \ - do { \ - (dst).type = (src).type; \ - (dst).uuid = (src).uuid; \ - } while (0) - -/** @brief Compare for equality both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ -#define BLE_UUID_EQ(p_uuid1, p_uuid2) (((p_uuid1)->type == (p_uuid2)->type) && ((p_uuid1)->uuid == (p_uuid2)->uuid)) - -/** @brief Compare for difference both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ -#define BLE_UUID_NEQ(p_uuid1, p_uuid2) (((p_uuid1)->type != (p_uuid2)->type) || ((p_uuid1)->uuid != (p_uuid2)->uuid)) - -/** @} */ - -/** @addtogroup BLE_TYPES_STRUCTURES Structures - * @{ */ - -/** @brief 128 bit UUID values. */ -typedef struct { - uint8_t uuid128[16]; /**< Little-Endian UUID bytes. */ -} ble_uuid128_t; - -/** @brief Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */ -typedef struct { - uint16_t uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */ - uint8_t - type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is @ref BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */ -} ble_uuid_t; - -/**@brief Data structure. */ -typedef struct { - uint8_t *p_data; /**< Pointer to the data buffer provided to/from the application. */ - uint16_t len; /**< Length of the data buffer, in bytes. */ -} ble_data_t; - -/** @} */ -#ifdef __cplusplus -} -#endif - -#endif /* BLE_TYPES_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h b/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h deleted file mode 100644 index 4e0bd752ab..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2014 - 2017, Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_mbr_api Master Boot Record API - @{ - - @brief APIs for updating SoftDevice and BootLoader - -*/ - -#ifndef NRF_MBR_H__ -#define NRF_MBR_H__ - -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup NRF_MBR_DEFINES Defines - * @{ */ - -/**@brief MBR SVC Base number. */ -#define MBR_SVC_BASE (0x18) - -/**@brief Page size in words. */ -#define MBR_PAGE_SIZE_IN_WORDS (1024) - -/** @brief The size that must be reserved for the MBR when a SoftDevice is written to flash. -This is the offset where the first byte of the SoftDevice hex file is written. */ -#define MBR_SIZE (0x1000) - -/** @brief Location (in the flash memory) of the bootloader address. */ -#define MBR_BOOTLOADER_ADDR (0xFF8) - -/** @brief Location (in UICR) of the bootloader address. */ -#define MBR_UICR_BOOTLOADER_ADDR (&(NRF_UICR->NRFFW[0])) - -/** @brief Location (in the flash memory) of the address of the MBR parameter page. */ -#define MBR_PARAM_PAGE_ADDR (0xFFC) - -/** @brief Location (in UICR) of the address of the MBR parameter page. */ -#define MBR_UICR_PARAM_PAGE_ADDR (&(NRF_UICR->NRFFW[1])) - -/** @} */ - -/** @addtogroup NRF_MBR_ENUMS Enumerations - * @{ */ - -/**@brief nRF Master Boot Record API SVC numbers. */ -enum NRF_MBR_SVCS { - SD_MBR_COMMAND = MBR_SVC_BASE, /**< ::sd_mbr_command */ -}; - -/**@brief Possible values for ::sd_mbr_command_t.command */ -enum NRF_MBR_COMMANDS { - SD_MBR_COMMAND_COPY_BL, /**< Copy a new BootLoader. @see ::sd_mbr_command_copy_bl_t*/ - SD_MBR_COMMAND_COPY_SD, /**< Copy a new SoftDevice. @see ::sd_mbr_command_copy_sd_t*/ - SD_MBR_COMMAND_INIT_SD, /**< Initialize forwarding interrupts to SD, and run reset function in SD. Does not require any - parameters in ::sd_mbr_command_t params.*/ - SD_MBR_COMMAND_COMPARE, /**< This command works like memcmp. @see ::sd_mbr_command_compare_t*/ - SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET, /**< Change the address the MBR starts after a reset. @see - ::sd_mbr_command_vector_table_base_set_t*/ - SD_MBR_COMMAND_RESERVED, - SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET, /**< Start forwarding all interrupts to this address. @see - ::sd_mbr_command_irq_forward_address_set_t*/ -}; - -/** @} */ - -/** @addtogroup NRF_MBR_TYPES Types - * @{ */ - -/**@brief This command copies part of a new SoftDevice - * - * The destination area is erased before copying. - * If dst is in the middle of a flash page, that whole flash page will be erased. - * If (dst+len) is in the middle of a flash page, that whole flash page will be erased. - * - * The user of this function is responsible for setting the BPROT registers. - * - * @retval ::NRF_SUCCESS indicates that the contents of the memory blocks where copied correctly. - * @retval ::NRF_ERROR_INTERNAL indicates that the contents of the memory blocks where not verified correctly after copying. - */ -typedef struct { - uint32_t *src; /**< Pointer to the source of data to be copied.*/ - uint32_t *dst; /**< Pointer to the destination where the content is to be copied.*/ - uint32_t len; /**< Number of 32 bit words to copy. Must be a multiple of @ref MBR_PAGE_SIZE_IN_WORDS words.*/ -} sd_mbr_command_copy_sd_t; - -/**@brief This command works like memcmp, but takes the length in words. - * - * @retval ::NRF_SUCCESS indicates that the contents of both memory blocks are equal. - * @retval ::NRF_ERROR_NULL indicates that the contents of the memory blocks are not equal. - */ -typedef struct { - uint32_t *ptr1; /**< Pointer to block of memory. */ - uint32_t *ptr2; /**< Pointer to block of memory. */ - uint32_t len; /**< Number of 32 bit words to compare.*/ -} sd_mbr_command_compare_t; - -/**@brief This command copies a new BootLoader. - * - * The MBR assumes that either @ref MBR_BOOTLOADER_ADDR or @ref MBR_UICR_BOOTLOADER_ADDR is set to - * the address where the bootloader will be copied. If both addresses are set, the MBR will prioritize - * @ref MBR_BOOTLOADER_ADDR. - * - * The bootloader destination is erased by this function. - * If (destination+bl_len) is in the middle of a flash page, that whole flash page will be erased. - * - * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, - * see @ref sd_mbr_command. - * - * This command will use the flash protect peripheral (BPROT or ACL) to protect the flash that is - * not intended to be written. - * - * On success, this function will not return. It will start the new bootloader from reset-vector as normal. - * - * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. - * @retval ::NRF_ERROR_FORBIDDEN if the bootloader address is not set. - * @retval ::NRF_ERROR_INVALID_LENGTH if parameters attempts to read or write outside flash area. - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. - */ -typedef struct { - uint32_t *bl_src; /**< Pointer to the source of the bootloader to be be copied.*/ - uint32_t bl_len; /**< Number of 32 bit words to copy for BootLoader. */ -} sd_mbr_command_copy_bl_t; - -/**@brief Change the address the MBR starts after a reset - * - * Once this function has been called, this address is where the MBR will start to forward - * interrupts to after a reset. - * - * To restore default forwarding, this function should be called with @ref address set to 0. If a - * bootloader is present, interrupts will be forwarded to the bootloader. If not, interrupts will - * be forwarded to the SoftDevice. - * - * The location of a bootloader can be specified in @ref MBR_BOOTLOADER_ADDR or - * @ref MBR_UICR_BOOTLOADER_ADDR. If both addresses are set, the MBR will prioritize - * @ref MBR_BOOTLOADER_ADDR. - * - * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, - * see @ref sd_mbr_command. - * - * On success, this function will not return. It will reset the device. - * - * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. - * @retval ::NRF_ERROR_INVALID_ADDR if parameter address is outside of the flash size. - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. - */ -typedef struct { - uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ -} sd_mbr_command_vector_table_base_set_t; - -/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the MBR - * - * Unlike sd_mbr_command_vector_table_base_set_t, this function does not reset, and it does not - * change where the MBR starts after reset. - * - * @retval ::NRF_SUCCESS - */ -typedef struct { - uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ -} sd_mbr_command_irq_forward_address_set_t; - -/**@brief Input structure containing data used when calling ::sd_mbr_command - * - * Depending on what command value that is set, the corresponding params value type must also be - * set. See @ref NRF_MBR_COMMANDS for command types and corresponding params value type. If command - * @ref SD_MBR_COMMAND_INIT_SD is set, it is not necessary to set any values under params. - */ -typedef struct { - uint32_t command; /**< Type of command to be issued. See @ref NRF_MBR_COMMANDS. */ - union { - sd_mbr_command_copy_sd_t copy_sd; /**< Parameters for copy SoftDevice.*/ - sd_mbr_command_compare_t compare; /**< Parameters for verify.*/ - sd_mbr_command_copy_bl_t copy_bl; /**< Parameters for copy BootLoader. Requires parameter page. */ - sd_mbr_command_vector_table_base_set_t base_set; /**< Parameters for vector table base set. Requires parameter page.*/ - sd_mbr_command_irq_forward_address_set_t irq_forward_address_set; /**< Parameters for irq forward address set*/ - } params; /**< Command parameters. */ -} sd_mbr_command_t; - -/** @} */ - -/** @addtogroup NRF_MBR_FUNCTIONS Functions - * @{ */ - -/**@brief Issue Master Boot Record commands - * - * Commands used when updating a SoftDevice and bootloader. - * - * The @ref SD_MBR_COMMAND_COPY_BL and @ref SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET requires - * parameters to be retained by the MBR when resetting the IC. This is done in a separate flash - * page. The location of the flash page should be provided by the application in either - * @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR. If both addresses are set, the MBR - * will prioritize @ref MBR_PARAM_PAGE_ADDR. This page will be cleared by the MBR and is used to - * store the command before reset. When an address is specified, the page it refers to must not be - * used by the application. If no address is provided by the application, i.e. both - * @ref MBR_PARAM_PAGE_ADDR and @ref MBR_UICR_PARAM_PAGE_ADDR is 0xFFFFFFFF, MBR commands which use - * flash will be unavailable and return @ref NRF_ERROR_NO_MEM. - * - * @param[in] param Pointer to a struct describing the command. - * - * @note For a complete set of return values, see ::sd_mbr_command_copy_sd_t, - * ::sd_mbr_command_copy_bl_t, ::sd_mbr_command_compare_t, - * ::sd_mbr_command_vector_table_base_set_t, ::sd_mbr_command_irq_forward_address_set_t - * - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page provided - * @retval ::NRF_ERROR_INVALID_PARAM if an invalid command is given. - */ -SVCALL(SD_MBR_COMMAND, uint32_t, sd_mbr_command(sd_mbr_command_t *param)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_MBR_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error.h b/variants/wio-tracker-wm1110/softdevice/nrf_error.h deleted file mode 100644 index fb2831e191..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_error.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_error SoftDevice Global Error Codes - @{ - - @brief Global Error definitions -*/ - -/* Header guard */ -#ifndef NRF_ERROR_H__ -#define NRF_ERROR_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** @defgroup NRF_ERRORS_BASE Error Codes Base number definitions - * @{ */ -#define NRF_ERROR_BASE_NUM (0x0) ///< Global error base -#define NRF_ERROR_SDM_BASE_NUM (0x1000) ///< SDM error base -#define NRF_ERROR_SOC_BASE_NUM (0x2000) ///< SoC error base -#define NRF_ERROR_STK_BASE_NUM (0x3000) ///< STK error base -/** @} */ - -#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command -#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing -#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled -#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error -#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation -#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found -#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported -#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter -#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state -#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length -#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags -#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data -#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Invalid Data size -#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out -#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer -#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation -#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address -#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy -#define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded. -#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h b/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h deleted file mode 100644 index 2fd6210576..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup nrf_sdm_api - @{ - @defgroup nrf_sdm_error SoftDevice Manager Error Codes - @{ - - @brief Error definitions for the SDM API -*/ - -/* Header guard */ -#ifndef NRF_ERROR_SDM_H__ -#define NRF_ERROR_SDM_H__ - -#include "nrf_error.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN (NRF_ERROR_SDM_BASE_NUM + 0) ///< Unknown LFCLK source. -#define NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION \ - (NRF_ERROR_SDM_BASE_NUM + 1) ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having - ///< enabled SoftDevice interrupts). -#define NRF_ERROR_SDM_INCORRECT_CLENR0 \ - (NRF_ERROR_SDM_BASE_NUM + 2) ///< Incorrect CLENR0 (can be caused by erroneous SoftDevice flashing). - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_SDM_H__ - -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h b/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h deleted file mode 100644 index cbd0ba8ac4..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup nrf_soc_api - @{ - @defgroup nrf_soc_error SoC Library Error Codes - @{ - - @brief Error definitions for the SoC library - -*/ - -/* Header guard */ -#ifndef NRF_ERROR_SOC_H__ -#define NRF_ERROR_SOC_H__ - -#include "nrf_error.h" -#ifdef __cplusplus -extern "C" { -#endif - -/* Mutex Errors */ -#define NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN (NRF_ERROR_SOC_BASE_NUM + 0) ///< Mutex already taken - -/* NVIC errors */ -#define NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE (NRF_ERROR_SOC_BASE_NUM + 1) ///< NVIC interrupt not available -#define NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED (NRF_ERROR_SOC_BASE_NUM + 2) ///< NVIC interrupt priority not allowed -#define NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 3) ///< NVIC should not return - -/* Power errors */ -#define NRF_ERROR_SOC_POWER_MODE_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 4) ///< Power mode unknown -#define NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 5) ///< Power POF threshold unknown -#define NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 6) ///< Power off should not return - -/* Rand errors */ -#define NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES (NRF_ERROR_SOC_BASE_NUM + 7) ///< RAND not enough values - -/* PPI errors */ -#define NRF_ERROR_SOC_PPI_INVALID_CHANNEL (NRF_ERROR_SOC_BASE_NUM + 8) ///< Invalid PPI Channel -#define NRF_ERROR_SOC_PPI_INVALID_GROUP (NRF_ERROR_SOC_BASE_NUM + 9) ///< Invalid PPI Group - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_SOC_H__ -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h b/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h deleted file mode 100644 index d4ab204d96..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @defgroup nrf_nvic_api SoftDevice NVIC API - * @{ - * - * @note In order to use this module, the following code has to be added to a .c file: - * \code - * nrf_nvic_state_t nrf_nvic_state = {0}; - * \endcode - * - * @note Definitions and declarations starting with __ (double underscore) in this header file are - * not intended for direct use by the application. - * - * @brief APIs for the accessing NVIC when using a SoftDevice. - * - */ - -#ifndef NRF_NVIC_H__ -#define NRF_NVIC_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup NRF_NVIC_DEFINES Defines - * @{ */ - -/**@defgroup NRF_NVIC_ISER_DEFINES SoftDevice NVIC internal definitions - * @{ */ - -#define __NRF_NVIC_NVMC_IRQn \ - (30) /**< The peripheral ID of the NVMC. IRQ numbers are used to identify peripherals, but the NVMC doesn't have an IRQ \ - number in the MDK. */ - -#define __NRF_NVIC_ISER_COUNT (2) /**< The number of ISER/ICER registers in the NVIC that are used. */ - -/**@brief Interrupt priority levels used by the SoftDevice. */ -#define __NRF_NVIC_SD_IRQ_PRIOS \ - ((uint8_t)((1U << 0) /**< Priority level high .*/ \ - | (1U << 1) /**< Priority level medium. */ \ - | (1U << 4) /**< Priority level low. */ \ - )) - -/**@brief Interrupt priority levels available to the application. */ -#define __NRF_NVIC_APP_IRQ_PRIOS ((uint8_t)~__NRF_NVIC_SD_IRQ_PRIOS) - -/**@brief Interrupts used by the SoftDevice, with IRQn in the range 0-31. */ -#define __NRF_NVIC_SD_IRQS_0 \ - ((uint32_t)((1U << POWER_CLOCK_IRQn) | (1U << RADIO_IRQn) | (1U << RTC0_IRQn) | (1U << TIMER0_IRQn) | (1U << RNG_IRQn) | \ - (1U << ECB_IRQn) | (1U << CCM_AAR_IRQn) | (1U << TEMP_IRQn) | (1U << __NRF_NVIC_NVMC_IRQn) | \ - (1U << (uint32_t)SWI5_IRQn))) - -/**@brief Interrupts used by the SoftDevice, with IRQn in the range 32-63. */ -#define __NRF_NVIC_SD_IRQS_1 ((uint32_t)0) - -/**@brief Interrupts available for to application, with IRQn in the range 0-31. */ -#define __NRF_NVIC_APP_IRQS_0 (~__NRF_NVIC_SD_IRQS_0) - -/**@brief Interrupts available for to application, with IRQn in the range 32-63. */ -#define __NRF_NVIC_APP_IRQS_1 (~__NRF_NVIC_SD_IRQS_1) - -/**@} */ - -/**@} */ - -/**@addtogroup NRF_NVIC_VARIABLES Variables - * @{ */ - -/**@brief Type representing the state struct for the SoftDevice NVIC module. */ -typedef struct { - uint32_t volatile __irq_masks[__NRF_NVIC_ISER_COUNT]; /**< IRQs enabled by the application in the NVIC. */ - uint32_t volatile __cr_flag; /**< Non-zero if already in a critical region */ -} nrf_nvic_state_t; - -/**@brief Variable keeping the state for the SoftDevice NVIC module. This must be declared in an - * application source file. */ -extern nrf_nvic_state_t nrf_nvic_state; - -/**@} */ - -/**@addtogroup NRF_NVIC_INTERNAL_FUNCTIONS SoftDevice NVIC internal functions - * @{ */ - -/**@brief Disables IRQ interrupts globally, including the SoftDevice's interrupts. - * - * @retval The value of PRIMASK prior to disabling the interrupts. - */ -__STATIC_INLINE int __sd_nvic_irq_disable(void); - -/**@brief Enables IRQ interrupts globally, including the SoftDevice's interrupts. - */ -__STATIC_INLINE void __sd_nvic_irq_enable(void); - -/**@brief Checks if IRQn is available to application - * @param[in] IRQn IRQ to check - * - * @retval 1 (true) if the IRQ to check is available to the application - */ -__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn); - -/**@brief Checks if priority is available to application - * @param[in] priority priority to check - * - * @retval 1 (true) if the priority to check is available to the application - */ -__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority); - -/**@} */ - -/**@addtogroup NRF_NVIC_FUNCTIONS SoftDevice NVIC public functions - * @{ */ - -/**@brief Enable External Interrupt. - * @note Corresponds to NVIC_EnableIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_EnableIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt was enabled. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt has a priority not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn); - -/**@brief Disable External Interrupt. - * @note Corresponds to NVIC_DisableIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_DisableIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt was disabled. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn); - -/**@brief Get Pending Interrupt. - * @note Corresponds to NVIC_GetPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_GetPendingIRQ documentation in CMSIS. - * @param[out] p_pending_irq Return value from NVIC_GetPendingIRQ. - * - * @retval ::NRF_SUCCESS The interrupt is available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq); - -/**@brief Set Pending Interrupt. - * @note Corresponds to NVIC_SetPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_SetPendingIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt is set pending. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn); - -/**@brief Clear Pending Interrupt. - * @note Corresponds to NVIC_ClearPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_ClearPendingIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt pending flag is cleared. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn); - -/**@brief Set Interrupt Priority. - * @note Corresponds to NVIC_SetPriority in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * @pre Priority is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_SetPriority documentation in CMSIS. - * @param[in] priority A valid IRQ priority for use by the application. - * - * @retval ::NRF_SUCCESS The interrupt and priority level is available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt priority is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority); - -/**@brief Get Interrupt Priority. - * @note Corresponds to NVIC_GetPriority in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_GetPriority documentation in CMSIS. - * @param[out] p_priority Return value from NVIC_GetPriority. - * - * @retval ::NRF_SUCCESS The interrupt priority is returned in p_priority. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE - IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority); - -/**@brief System Reset. - * @note Corresponds to NVIC_SystemReset in CMSIS. - * - * @retval ::NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN - */ -__STATIC_INLINE uint32_t sd_nvic_SystemReset(void); - -/**@brief Enter critical region. - * - * @post Application interrupts will be disabled. - * @note sd_nvic_critical_region_enter() and ::sd_nvic_critical_region_exit() must be called in matching pairs inside each - * execution context - * @sa sd_nvic_critical_region_exit - * - * @param[out] p_is_nested_critical_region If 1, the application is now in a nested critical region. - * - * @retval ::NRF_SUCCESS - */ -__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region); - -/**@brief Exit critical region. - * - * @pre Application has entered a critical region using ::sd_nvic_critical_region_enter. - * @post If not in a nested critical region, the application interrupts will restored to the state before - * ::sd_nvic_critical_region_enter was called. - * - * @param[in] is_nested_critical_region If this is set to 1, the critical region won't be exited. @sa - * sd_nvic_critical_region_enter. - * - * @retval ::NRF_SUCCESS - */ -__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region); - -/**@} */ - -#ifndef SUPPRESS_INLINE_IMPLEMENTATION - -__STATIC_INLINE int __sd_nvic_irq_disable(void) -{ - int pm = __get_PRIMASK(); - __disable_irq(); - return pm; -} - -__STATIC_INLINE void __sd_nvic_irq_enable(void) -{ - __enable_irq(); -} - -__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn) -{ - if (IRQn < 32) { - return ((1UL << IRQn) & __NRF_NVIC_APP_IRQS_0) != 0; - } else if (IRQn < 64) { - return ((1UL << (IRQn - 32)) & __NRF_NVIC_APP_IRQS_1) != 0; - } else { - return 1; - } -} - -__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority) -{ - if ((priority >= (1 << __NVIC_PRIO_BITS)) || (((1 << priority) & __NRF_NVIC_APP_IRQ_PRIOS) == 0)) { - return 0; - } - return 1; -} - -__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - if (!__sd_nvic_is_app_accessible_priority(NVIC_GetPriority(IRQn))) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; - } - - if (nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] |= - (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F)); - } else { - NVIC_EnableIRQ(IRQn); - } - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - - if (nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] &= ~(1UL << ((uint32_t)(IRQn)&0x1F)); - } else { - NVIC_DisableIRQ(IRQn); - } - - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - *p_pending_irq = NVIC_GetPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - NVIC_SetPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - NVIC_ClearPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - - if (!__sd_nvic_is_app_accessible_priority(priority)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; - } - - NVIC_SetPriority(IRQn, (uint32_t)priority); - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - *p_priority = (NVIC_GetPriority(IRQn) & 0xFF); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SystemReset(void) -{ - NVIC_SystemReset(); - return NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN; -} - -__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region) -{ - int was_masked = __sd_nvic_irq_disable(); - if (!nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__cr_flag = 1; - nrf_nvic_state.__irq_masks[0] = (NVIC->ICER[0] & __NRF_NVIC_APP_IRQS_0); - NVIC->ICER[0] = __NRF_NVIC_APP_IRQS_0; - nrf_nvic_state.__irq_masks[1] = (NVIC->ICER[1] & __NRF_NVIC_APP_IRQS_1); - NVIC->ICER[1] = __NRF_NVIC_APP_IRQS_1; - *p_is_nested_critical_region = 0; - } else { - *p_is_nested_critical_region = 1; - } - if (!was_masked) { - __sd_nvic_irq_enable(); - } - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region) -{ - if (nrf_nvic_state.__cr_flag && (is_nested_critical_region == 0)) { - int was_masked = __sd_nvic_irq_disable(); - NVIC->ISER[0] = nrf_nvic_state.__irq_masks[0]; - NVIC->ISER[1] = nrf_nvic_state.__irq_masks[1]; - nrf_nvic_state.__cr_flag = 0; - if (!was_masked) { - __sd_nvic_irq_enable(); - } - } - - return NRF_SUCCESS; -} - -#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ - -#ifdef __cplusplus -} -#endif - -#endif // NRF_NVIC_H__ - -/**@} */ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h b/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h deleted file mode 100644 index 2786a86a45..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_sdm_api SoftDevice Manager API - @{ - - @brief APIs for SoftDevice management. - -*/ - -#ifndef NRF_SDM_H__ -#define NRF_SDM_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_sdm.h" -#include "nrf_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup NRF_SDM_DEFINES Defines - * @{ */ -#ifdef NRFSOC_DOXYGEN -/// Declared in nrf_mbr.h -#define MBR_SIZE 0 -#warning test -#endif - -/** @brief The major version for the SoftDevice binary distributed with this header file. */ -#define SD_MAJOR_VERSION (7) - -/** @brief The minor version for the SoftDevice binary distributed with this header file. */ -#define SD_MINOR_VERSION (3) - -/** @brief The bugfix version for the SoftDevice binary distributed with this header file. */ -#define SD_BUGFIX_VERSION (0) - -/** @brief The SoftDevice variant of this firmware. */ -#define SD_VARIANT_ID 140 - -/** @brief The full version number for the SoftDevice binary this header file was distributed - * with, as a decimal number in the form Mmmmbbb, where: - * - M is major version (one or more digits) - * - mmm is minor version (three digits) - * - bbb is bugfix version (three digits). */ -#define SD_VERSION (SD_MAJOR_VERSION * 1000000 + SD_MINOR_VERSION * 1000 + SD_BUGFIX_VERSION) - -/** @brief SoftDevice Manager SVC Base number. */ -#define SDM_SVC_BASE 0x10 - -/** @brief SoftDevice unique string size in bytes. */ -#define SD_UNIQUE_STR_SIZE 20 - -/** @brief Invalid info field. Returned when an info field does not exist. */ -#define SDM_INFO_FIELD_INVALID (0) - -/** @brief Defines the SoftDevice Information Structure location (address) as an offset from -the start of the SoftDevice (without MBR)*/ -#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000) - -/** @brief Defines the absolute SoftDevice Information Structure location (address) when the - * SoftDevice is installed just above the MBR (the usual case). */ -#define SOFTDEVICE_INFO_STRUCT_ADDRESS (SOFTDEVICE_INFO_STRUCT_OFFSET + MBR_SIZE) - -/** @brief Defines the offset for the SoftDevice Information Structure size value relative to the - * SoftDevice base address. The size value is of type uint8_t. */ -#define SD_INFO_STRUCT_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET) - -/** @brief Defines the offset for the SoftDevice size value relative to the SoftDevice base address. - * The size value is of type uint32_t. */ -#define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08) - -/** @brief Defines the offset for FWID value relative to the SoftDevice base address. The FWID value - * is of type uint16_t. */ -#define SD_FWID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x0C) - -/** @brief Defines the offset for the SoftDevice ID relative to the SoftDevice base address. The ID - * is of type uint32_t. */ -#define SD_ID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x10) - -/** @brief Defines the offset for the SoftDevice version relative to the SoftDevice base address in - * the same format as @ref SD_VERSION, stored as an uint32_t. */ -#define SD_VERSION_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x14) - -/** @brief Defines the offset for the SoftDevice unique string relative to the SoftDevice base address. - * The SD_UNIQUE_STR is stored as an array of uint8_t. The size of array is @ref SD_UNIQUE_STR_SIZE. - */ -#define SD_UNIQUE_STR_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x18) - -/** @brief Defines a macro for retrieving the actual SoftDevice Information Structure size value - * from a given base address. Use @ref MBR_SIZE as the argument when the SoftDevice is - * installed just above the MBR (the usual case). */ -#define SD_INFO_STRUCT_SIZE_GET(baseaddr) (*((uint8_t *)((baseaddr) + SD_INFO_STRUCT_SIZE_OFFSET))) - -/** @brief Defines a macro for retrieving the actual SoftDevice size value from a given base - * address. Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above - * the MBR (the usual case). */ -#define SD_SIZE_GET(baseaddr) (*((uint32_t *)((baseaddr) + SD_SIZE_OFFSET))) - -/** @brief Defines the amount of flash that is used by the SoftDevice. - * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed - * just above the MBR (the usual case). - */ -#define SD_FLASH_SIZE 0x26000 - -/** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use - * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual - * case). */ -#define SD_FWID_GET(baseaddr) (*((uint16_t *)((baseaddr) + SD_FWID_OFFSET))) - -/** @brief Defines a macro for retrieving the actual SoftDevice ID from a given base address. Use - * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the - * usual case). */ -#define SD_ID_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_ID_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (*((uint32_t *)((baseaddr) + SD_ID_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/** @brief Defines a macro for retrieving the actual SoftDevice version from a given base address. - * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR - * (the usual case). */ -#define SD_VERSION_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_VERSION_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (*((uint32_t *)((baseaddr) + SD_VERSION_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/** @brief Defines a macro for retrieving the address of SoftDevice unique str based on a given base address. - * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR - * (the usual case). */ -#define SD_UNIQUE_STR_ADDR_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_UNIQUE_STR_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (((uint8_t *)((baseaddr) + SD_UNIQUE_STR_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/**@defgroup NRF_FAULT_ID_RANGES Fault ID ranges - * @{ */ -#define NRF_FAULT_ID_SD_RANGE_START 0x00000000 /**< SoftDevice ID range start. */ -#define NRF_FAULT_ID_APP_RANGE_START 0x00001000 /**< Application ID range start. */ -/**@} */ - -/**@defgroup NRF_FAULT_IDS Fault ID types - * @{ */ -#define NRF_FAULT_ID_SD_ASSERT \ - (NRF_FAULT_ID_SD_RANGE_START + 1) /**< SoftDevice assertion. The info parameter is reserved for future used. */ -#define NRF_FAULT_ID_APP_MEMACC \ - (NRF_FAULT_ID_APP_RANGE_START + 1) /**< Application invalid memory access. The info parameter will contain 0x00000000, \ - in case of SoftDevice RAM access violation. In case of SoftDevice peripheral \ - register violation the info parameter will contain the sub-region number of \ - PREGION[0], on whose address range the disallowed write access caused the \ - memory access fault. */ -/**@} */ - -/** @} */ - -/** @addtogroup NRF_SDM_ENUMS Enumerations - * @{ */ - -/**@brief nRF SoftDevice Manager API SVC numbers. */ -enum NRF_SD_SVCS { - SD_SOFTDEVICE_ENABLE = SDM_SVC_BASE, /**< ::sd_softdevice_enable */ - SD_SOFTDEVICE_DISABLE, /**< ::sd_softdevice_disable */ - SD_SOFTDEVICE_IS_ENABLED, /**< ::sd_softdevice_is_enabled */ - SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, /**< ::sd_softdevice_vector_table_base_set */ - SVC_SDM_LAST /**< Placeholder for last SDM SVC */ -}; - -/** @} */ - -/** @addtogroup NRF_SDM_DEFINES Defines - * @{ */ - -/**@defgroup NRF_CLOCK_LF_ACCURACY Clock accuracy - * @{ */ - -#define NRF_CLOCK_LF_ACCURACY_250_PPM (0) /**< Default: 250 ppm */ -#define NRF_CLOCK_LF_ACCURACY_500_PPM (1) /**< 500 ppm */ -#define NRF_CLOCK_LF_ACCURACY_150_PPM (2) /**< 150 ppm */ -#define NRF_CLOCK_LF_ACCURACY_100_PPM (3) /**< 100 ppm */ -#define NRF_CLOCK_LF_ACCURACY_75_PPM (4) /**< 75 ppm */ -#define NRF_CLOCK_LF_ACCURACY_50_PPM (5) /**< 50 ppm */ -#define NRF_CLOCK_LF_ACCURACY_30_PPM (6) /**< 30 ppm */ -#define NRF_CLOCK_LF_ACCURACY_20_PPM (7) /**< 20 ppm */ -#define NRF_CLOCK_LF_ACCURACY_10_PPM (8) /**< 10 ppm */ -#define NRF_CLOCK_LF_ACCURACY_5_PPM (9) /**< 5 ppm */ -#define NRF_CLOCK_LF_ACCURACY_2_PPM (10) /**< 2 ppm */ -#define NRF_CLOCK_LF_ACCURACY_1_PPM (11) /**< 1 ppm */ - -/** @} */ - -/**@defgroup NRF_CLOCK_LF_SRC Possible LFCLK oscillator sources - * @{ */ - -#define NRF_CLOCK_LF_SRC_RC (0) /**< LFCLK RC oscillator. */ -#define NRF_CLOCK_LF_SRC_XTAL (1) /**< LFCLK crystal oscillator. */ -#define NRF_CLOCK_LF_SRC_SYNTH (2) /**< LFCLK Synthesized from HFCLK. */ - -/** @} */ - -/** @} */ - -/** @addtogroup NRF_SDM_TYPES Types - * @{ */ - -/**@brief Type representing LFCLK oscillator source. */ -typedef struct { - uint8_t source; /**< LF oscillator clock source, see @ref NRF_CLOCK_LF_SRC. */ - uint8_t rc_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: Calibration timer interval in 1/4 second - units (nRF52: 1-32). - @note To avoid excessive clock drift, 0.5 degrees Celsius is the - maximum temperature change allowed in one calibration timer - interval. The interval should be selected to ensure this. - - @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. */ - uint8_t rc_temp_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: How often (in number of calibration - intervals) the RC oscillator shall be calibrated if the temperature - hasn't changed. - 0: Always calibrate even if the temperature hasn't changed. - 1: Only calibrate if the temperature has changed (legacy - nRF51 only). - 2-33: Check the temperature and only calibrate if it has changed, - however calibration will take place every rc_temp_ctiv - intervals in any case. - - @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. - - @note For nRF52, the application must ensure calibration at least once - every 8 seconds to ensure +/-500 ppm clock stability. The - recommended configuration for ::NRF_CLOCK_LF_SRC_RC on nRF52 is - rc_ctiv=16 and rc_temp_ctiv=2. This will ensure calibration at - least once every 8 seconds and for temperature changes of 0.5 - degrees Celsius every 4 seconds. See the Product Specification - for the nRF52 device being used for more information.*/ - uint8_t accuracy; /**< External clock accuracy used in the LL to compute timing - windows, see @ref NRF_CLOCK_LF_ACCURACY.*/ -} nrf_clock_lf_cfg_t; - -/**@brief Fault Handler type. - * - * When certain unrecoverable errors occur within the application or SoftDevice the fault handler will be called back. - * The protocol stack will be in an undefined state when this happens and the only way to recover will be to - * perform a reset, using e.g. CMSIS NVIC_SystemReset(). - * If the application returns from the fault handler the SoftDevice will call NVIC_SystemReset(). - * - * @note It is recommended to either perform a reset in the fault handler or to let the SoftDevice reset the device. - * Otherwise SoC peripherals may behave in an undefined way. For example, the RADIO peripherial may - * continously transmit packets. - * - * @note This callback is executed in HardFault context, thus SVC functions cannot be called from the fault callback. - * - * @param[in] id Fault identifier. See @ref NRF_FAULT_IDS. - * @param[in] pc The program counter of the instruction that triggered the fault. - * @param[in] info Optional additional information regarding the fault. Refer to each Fault identifier for details. - * - * @note When id is set to @ref NRF_FAULT_ID_APP_MEMACC, pc will contain the address of the instruction being executed at the time - * when the fault is detected by the CPU. The CPU program counter may have advanced up to 2 instructions (no branching) after the - * one that triggered the fault. - */ -typedef void (*nrf_fault_handler_t)(uint32_t id, uint32_t pc, uint32_t info); - -/** @} */ - -/** @addtogroup NRF_SDM_FUNCTIONS Functions - * @{ */ - -/**@brief Enables the SoftDevice and by extension the protocol stack. - * - * @note Some care must be taken if a low frequency clock source is already running when calling this function: - * If the LF clock has a different source then the one currently running, it will be stopped. Then, the new - * clock source will be started. - * - * @note This function has no effect when returning with an error. - * - * @post If return code is ::NRF_SUCCESS - * - SoC library and protocol stack APIs are made available. - * - A portion of RAM will be unavailable (see relevant SDS documentation). - * - Some peripherals will be unavailable or available only through the SoC API (see relevant SDS documentation). - * - Interrupts will not arrive from protected peripherals or interrupts. - * - nrf_nvic_ functions must be used instead of CMSIS NVIC_ functions for reliable usage of the SoftDevice. - * - Interrupt latency may be affected by the SoftDevice (see relevant SDS documentation). - * - Chosen low frequency clock source will be running. - * - * @param p_clock_lf_cfg Low frequency clock source and accuracy. - If NULL the clock will be configured as an RC source with rc_ctiv = 16 and .rc_temp_ctiv = 2 - In the case of XTAL source, the PPM accuracy of the chosen clock source must be greater than or equal to - the actual characteristics of your XTAL clock. - * @param fault_handler Callback to be invoked in case of fault, cannot be NULL. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE SoftDevice is already enabled, and the clock source and fault handler cannot be updated. - * @retval ::NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION SoftDevice interrupt is already enabled, or an enabled interrupt has - an illegal priority level. - * @retval ::NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN Unknown low frequency clock source selected. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid clock source configuration supplied in p_clock_lf_cfg. - */ -SVCALL(SD_SOFTDEVICE_ENABLE, uint32_t, - sd_softdevice_enable(nrf_clock_lf_cfg_t const *p_clock_lf_cfg, nrf_fault_handler_t fault_handler)); - -/**@brief Disables the SoftDevice and by extension the protocol stack. - * - * Idempotent function to disable the SoftDevice. - * - * @post SoC library and protocol stack APIs are made unavailable. - * @post All interrupts that was protected by the SoftDevice will be disabled and initialized to priority 0 (highest). - * @post All peripherals used by the SoftDevice will be reset to default values. - * @post All of RAM become available. - * @post All interrupts are forwarded to the application. - * @post LFCLK source chosen in ::sd_softdevice_enable will be left running. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_DISABLE, uint32_t, sd_softdevice_disable(void)); - -/**@brief Check if the SoftDevice is enabled. - * - * @param[out] p_softdevice_enabled If the SoftDevice is enabled: 1 else 0. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_IS_ENABLED, uint32_t, sd_softdevice_is_enabled(uint8_t *p_softdevice_enabled)); - -/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the SoftDevice - * - * This function is only intended to be called when a bootloader is enabled. - * - * @param[in] address The base address of the interrupt vector table for forwarded interrupts. - - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table_base_set(uint32_t address)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_SDM_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_soc.h b/variants/wio-tracker-wm1110/softdevice/nrf_soc.h deleted file mode 100644 index c649ca836d..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_soc.h +++ /dev/null @@ -1,1046 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @defgroup nrf_soc_api SoC Library API - * @{ - * - * @brief APIs for the SoC library. - * - */ - -#ifndef NRF_SOC_H__ -#define NRF_SOC_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup NRF_SOC_DEFINES Defines - * @{ */ - -/**@brief The number of the lowest SVC number reserved for the SoC library. */ -#define SOC_SVC_BASE (0x20) /**< Base value for SVCs that are available when the SoftDevice is disabled. */ -#define SOC_SVC_BASE_NOT_AVAILABLE (0x2C) /**< Base value for SVCs that are not available when the SoftDevice is disabled. */ - -/**@brief Guaranteed time for application to process radio inactive notification. */ -#define NRF_RADIO_NOTIFICATION_INACTIVE_GUARANTEED_TIME_US (62) - -/**@brief The minimum allowed timeslot extension time. */ -#define NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US (200) - -/**@brief The maximum processing time to handle a timeslot extension. */ -#define NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US (20) - -/**@brief The latest time before the end of a timeslot the timeslot can be extended. */ -#define NRF_RADIO_MIN_EXTENSION_MARGIN_US (82) - -#define SOC_ECB_KEY_LENGTH (16) /**< ECB key length. */ -#define SOC_ECB_CLEARTEXT_LENGTH (16) /**< ECB cleartext length. */ -#define SOC_ECB_CIPHERTEXT_LENGTH (SOC_ECB_CLEARTEXT_LENGTH) /**< ECB ciphertext length. */ - -#define SD_EVT_IRQn (SWI2_IRQn) /**< SoftDevice Event IRQ number. Used for both protocol events and SoC events. */ -#define SD_EVT_IRQHandler \ - (SWI2_IRQHandler) /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. \ - The default interrupt priority for this handler is set to 6 */ -#define RADIO_NOTIFICATION_IRQn (SWI1_IRQn) /**< The radio notification IRQ number. */ -#define RADIO_NOTIFICATION_IRQHandler \ - (SWI1_IRQHandler) /**< The radio notification IRQ handler. \ - The default interrupt priority for this handler is set to 6 */ -#define NRF_RADIO_LENGTH_MIN_US (100) /**< The shortest allowed radio timeslot, in microseconds. */ -#define NRF_RADIO_LENGTH_MAX_US (100000) /**< The longest allowed radio timeslot, in microseconds. */ - -#define NRF_RADIO_DISTANCE_MAX_US \ - (128000000UL - 1UL) /**< The longest timeslot distance, in microseconds, allowed for the distance parameter (see @ref \ - nrf_radio_request_normal_t) in the request. */ - -#define NRF_RADIO_EARLIEST_TIMEOUT_MAX_US \ - (128000000UL - 1UL) /**< The longest timeout, in microseconds, allowed when requesting the earliest possible timeslot. */ - -#define NRF_RADIO_START_JITTER_US \ - (2) /**< The maximum jitter in @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START relative to the requested start time. */ - -/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is disabled. */ -#define NRF_SOC_SD_PPI_CHANNELS_SD_DISABLED_MSK ((uint32_t)(0)) - -/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is enabled. */ -#define NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK \ - ((uint32_t)((1U << 17) | (1U << 18) | (1U << 19) | (1U << 20) | (1U << 21) | (1U << 22) | (1U << 23) | (1U << 24) | \ - (1U << 25) | (1U << 26) | (1U << 27) | (1U << 28) | (1U << 29) | (1U << 30) | (1U << 31))) - -/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is disabled. */ -#define NRF_SOC_SD_PPI_GROUPS_SD_DISABLED_MSK ((uint32_t)(0)) - -/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is enabled. */ -#define NRF_SOC_SD_PPI_GROUPS_SD_ENABLED_MSK ((uint32_t)((1U << 4) | (1U << 5))) - -/**@} */ - -/**@addtogroup NRF_SOC_ENUMS Enumerations - * @{ */ - -/**@brief The SVC numbers used by the SVC functions in the SoC library. */ -enum NRF_SOC_SVCS { - SD_PPI_CHANNEL_ENABLE_GET = SOC_SVC_BASE, - SD_PPI_CHANNEL_ENABLE_SET = SOC_SVC_BASE + 1, - SD_PPI_CHANNEL_ENABLE_CLR = SOC_SVC_BASE + 2, - SD_PPI_CHANNEL_ASSIGN = SOC_SVC_BASE + 3, - SD_PPI_GROUP_TASK_ENABLE = SOC_SVC_BASE + 4, - SD_PPI_GROUP_TASK_DISABLE = SOC_SVC_BASE + 5, - SD_PPI_GROUP_ASSIGN = SOC_SVC_BASE + 6, - SD_PPI_GROUP_GET = SOC_SVC_BASE + 7, - SD_FLASH_PAGE_ERASE = SOC_SVC_BASE + 8, - SD_FLASH_WRITE = SOC_SVC_BASE + 9, - SD_PROTECTED_REGISTER_WRITE = SOC_SVC_BASE + 11, - SD_MUTEX_NEW = SOC_SVC_BASE_NOT_AVAILABLE, - SD_MUTEX_ACQUIRE = SOC_SVC_BASE_NOT_AVAILABLE + 1, - SD_MUTEX_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 2, - SD_RAND_APPLICATION_POOL_CAPACITY_GET = SOC_SVC_BASE_NOT_AVAILABLE + 3, - SD_RAND_APPLICATION_BYTES_AVAILABLE_GET = SOC_SVC_BASE_NOT_AVAILABLE + 4, - SD_RAND_APPLICATION_VECTOR_GET = SOC_SVC_BASE_NOT_AVAILABLE + 5, - SD_POWER_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 6, - SD_POWER_SYSTEM_OFF = SOC_SVC_BASE_NOT_AVAILABLE + 7, - SD_POWER_RESET_REASON_GET = SOC_SVC_BASE_NOT_AVAILABLE + 8, - SD_POWER_RESET_REASON_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 9, - SD_POWER_POF_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 10, - SD_POWER_POF_THRESHOLD_SET = SOC_SVC_BASE_NOT_AVAILABLE + 11, - SD_POWER_POF_THRESHOLDVDDH_SET = SOC_SVC_BASE_NOT_AVAILABLE + 12, - SD_POWER_RAM_POWER_SET = SOC_SVC_BASE_NOT_AVAILABLE + 13, - SD_POWER_RAM_POWER_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 14, - SD_POWER_RAM_POWER_GET = SOC_SVC_BASE_NOT_AVAILABLE + 15, - SD_POWER_GPREGRET_SET = SOC_SVC_BASE_NOT_AVAILABLE + 16, - SD_POWER_GPREGRET_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 17, - SD_POWER_GPREGRET_GET = SOC_SVC_BASE_NOT_AVAILABLE + 18, - SD_POWER_DCDC_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 19, - SD_POWER_DCDC0_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 20, - SD_APP_EVT_WAIT = SOC_SVC_BASE_NOT_AVAILABLE + 21, - SD_CLOCK_HFCLK_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 22, - SD_CLOCK_HFCLK_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 23, - SD_CLOCK_HFCLK_IS_RUNNING = SOC_SVC_BASE_NOT_AVAILABLE + 24, - SD_RADIO_NOTIFICATION_CFG_SET = SOC_SVC_BASE_NOT_AVAILABLE + 25, - SD_ECB_BLOCK_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 26, - SD_ECB_BLOCKS_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 27, - SD_RADIO_SESSION_OPEN = SOC_SVC_BASE_NOT_AVAILABLE + 28, - SD_RADIO_SESSION_CLOSE = SOC_SVC_BASE_NOT_AVAILABLE + 29, - SD_RADIO_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 30, - SD_EVT_GET = SOC_SVC_BASE_NOT_AVAILABLE + 31, - SD_TEMP_GET = SOC_SVC_BASE_NOT_AVAILABLE + 32, - SD_POWER_USBPWRRDY_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 33, - SD_POWER_USBDETECTED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 34, - SD_POWER_USBREMOVED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 35, - SD_POWER_USBREGSTATUS_GET = SOC_SVC_BASE_NOT_AVAILABLE + 36, - SVC_SOC_LAST = SOC_SVC_BASE_NOT_AVAILABLE + 37 -}; - -/**@brief Possible values of a ::nrf_mutex_t. */ -enum NRF_MUTEX_VALUES { NRF_MUTEX_FREE, NRF_MUTEX_TAKEN }; - -/**@brief Power modes. */ -enum NRF_POWER_MODES { - NRF_POWER_MODE_CONSTLAT, /**< Constant latency mode. See power management in the reference manual. */ - NRF_POWER_MODE_LOWPWR /**< Low power mode. See power management in the reference manual. */ -}; - -/**@brief Power failure thresholds */ -enum NRF_POWER_THRESHOLDS { - NRF_POWER_THRESHOLD_V17 = 4UL, /**< 1.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V18, /**< 1.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V19, /**< 1.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V20, /**< 2.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V21, /**< 2.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V22, /**< 2.2 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V23, /**< 2.3 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V24, /**< 2.4 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V25, /**< 2.5 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V26, /**< 2.6 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V27, /**< 2.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V28 /**< 2.8 Volts power failure threshold. */ -}; - -/**@brief Power failure thresholds for high voltage */ -enum NRF_POWER_THRESHOLDVDDHS { - NRF_POWER_THRESHOLDVDDH_V27, /**< 2.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V28, /**< 2.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V29, /**< 2.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V30, /**< 3.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V31, /**< 3.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V32, /**< 3.2 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V33, /**< 3.3 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V34, /**< 3.4 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V35, /**< 3.5 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V36, /**< 3.6 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V37, /**< 3.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V38, /**< 3.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V39, /**< 3.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V40, /**< 4.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V41, /**< 4.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V42 /**< 4.2 Volts power failure threshold. */ -}; - -/**@brief DC/DC converter modes. */ -enum NRF_POWER_DCDC_MODES { - NRF_POWER_DCDC_DISABLE, /**< The DCDC is disabled. */ - NRF_POWER_DCDC_ENABLE /**< The DCDC is enabled. */ -}; - -/**@brief Radio notification distances. */ -enum NRF_RADIO_NOTIFICATION_DISTANCES { - NRF_RADIO_NOTIFICATION_DISTANCE_NONE = 0, /**< The event does not have a notification. */ - NRF_RADIO_NOTIFICATION_DISTANCE_800US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_1740US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_2680US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_3620US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_4560US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_5500US /**< The distance from the active notification to start of radio activity. */ -}; - -/**@brief Radio notification types. */ -enum NRF_RADIO_NOTIFICATION_TYPES { - NRF_RADIO_NOTIFICATION_TYPE_NONE = 0, /**< The event does not have a radio notification signal. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, /**< Using interrupt for notification when the radio will be enabled. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, /**< Using interrupt for notification when the radio has been disabled. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, /**< Using interrupt for notification both when the radio will be enabled and - disabled. */ -}; - -/**@brief The Radio signal callback types. */ -enum NRF_RADIO_CALLBACK_SIGNAL_TYPE { - NRF_RADIO_CALLBACK_SIGNAL_TYPE_START, /**< This signal indicates the start of the radio timeslot. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0, /**< This signal indicates the NRF_TIMER0 interrupt. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO, /**< This signal indicates the NRF_RADIO interrupt. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED, /**< This signal indicates extend action failed. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED /**< This signal indicates extend action succeeded. */ -}; - -/**@brief The actions requested by the signal callback. - * - * This code gives the SOC instructions about what action to take when the signal callback has - * returned. - */ -enum NRF_RADIO_SIGNAL_CALLBACK_ACTION { - NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE, /**< Return without action. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND, /**< Request an extension of the current - timeslot. Maximum execution time for this action: - @ref NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US. - This action must be started at least - @ref NRF_RADIO_MIN_EXTENSION_MARGIN_US before - the end of the timeslot. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_END, /**< End the current radio timeslot. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END /**< Request a new radio timeslot and end the current timeslot. */ -}; - -/**@brief Radio timeslot high frequency clock source configuration. */ -enum NRF_RADIO_HFCLK_CFG { - NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED, /**< The SoftDevice will guarantee that the high frequency clock source is the - external crystal for the whole duration of the timeslot. This should be the - preferred option for events that use the radio or require high timing accuracy. - @note The SoftDevice will automatically turn on and off the external crystal, - at the beginning and end of the timeslot, respectively. The crystal may also - intentionally be left running after the timeslot, in cases where it is needed - by the SoftDevice shortly after the end of the timeslot. */ - NRF_RADIO_HFCLK_CFG_NO_GUARANTEE /**< This configuration allows for earlier and tighter scheduling of timeslots. - The RC oscillator may be the clock source in part or for the whole duration of the - timeslot. The RC oscillator's accuracy must therefore be taken into consideration. - @note If the application will use the radio peripheral in timeslots with this - configuration, it must make sure that the crystal is running and stable before - starting the radio. */ -}; - -/**@brief Radio timeslot priorities. */ -enum NRF_RADIO_PRIORITY { - NRF_RADIO_PRIORITY_HIGH, /**< High (equal priority as the normal connection priority of the SoftDevice stack(s)). */ - NRF_RADIO_PRIORITY_NORMAL, /**< Normal (equal priority as the priority of secondary activities of the SoftDevice stack(s)). */ -}; - -/**@brief Radio timeslot request type. */ -enum NRF_RADIO_REQUEST_TYPE { - NRF_RADIO_REQ_TYPE_EARLIEST, /**< Request radio timeslot as early as possible. This should always be used for the first - request in a session. */ - NRF_RADIO_REQ_TYPE_NORMAL /**< Normal radio timeslot request. */ -}; - -/**@brief SoC Events. */ -enum NRF_SOC_EVTS { - NRF_EVT_HFCLKSTARTED, /**< Event indicating that the HFCLK has started. */ - NRF_EVT_POWER_FAILURE_WARNING, /**< Event indicating that a power failure warning has occurred. */ - NRF_EVT_FLASH_OPERATION_SUCCESS, /**< Event indicating that the ongoing flash operation has completed successfully. */ - NRF_EVT_FLASH_OPERATION_ERROR, /**< Event indicating that the ongoing flash operation has timed out with an error. */ - NRF_EVT_RADIO_BLOCKED, /**< Event indicating that a radio timeslot was blocked. */ - NRF_EVT_RADIO_CANCELED, /**< Event indicating that a radio timeslot was canceled by SoftDevice. */ - NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN, /**< Event indicating that a radio timeslot signal callback handler return was - invalid. */ - NRF_EVT_RADIO_SESSION_IDLE, /**< Event indicating that a radio timeslot session is idle. */ - NRF_EVT_RADIO_SESSION_CLOSED, /**< Event indicating that a radio timeslot session is closed. */ - NRF_EVT_POWER_USB_POWER_READY, /**< Event indicating that a USB 3.3 V supply is ready. */ - NRF_EVT_POWER_USB_DETECTED, /**< Event indicating that voltage supply is detected on VBUS. */ - NRF_EVT_POWER_USB_REMOVED, /**< Event indicating that voltage supply is removed from VBUS. */ - NRF_EVT_NUMBER_OF_EVTS -}; - -/**@} */ - -/**@addtogroup NRF_SOC_STRUCTURES Structures - * @{ */ - -/**@brief Represents a mutex for use with the nrf_mutex functions. - * @note Accessing the value directly is not safe, use the mutex functions! - */ -typedef volatile uint8_t nrf_mutex_t; - -/**@brief Parameters for a request for a timeslot as early as possible. */ -typedef struct { - uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ - uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ - uint32_t length_us; /**< The radio timeslot length (in the range 100 to 100,000] microseconds). */ - uint32_t timeout_us; /**< Longest acceptable delay until the start of the requested timeslot (up to @ref - NRF_RADIO_EARLIEST_TIMEOUT_MAX_US microseconds). */ -} nrf_radio_request_earliest_t; - -/**@brief Parameters for a normal radio timeslot request. */ -typedef struct { - uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ - uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ - uint32_t distance_us; /**< Distance from the start of the previous radio timeslot (up to @ref NRF_RADIO_DISTANCE_MAX_US - microseconds). */ - uint32_t length_us; /**< The radio timeslot length (in the range [100..100,000] microseconds). */ -} nrf_radio_request_normal_t; - -/**@brief Radio timeslot request parameters. */ -typedef struct { - uint8_t request_type; /**< Type of request, see @ref NRF_RADIO_REQUEST_TYPE. */ - union { - nrf_radio_request_earliest_t earliest; /**< Parameters for requesting a radio timeslot as early as possible. */ - nrf_radio_request_normal_t normal; /**< Parameters for requesting a normal radio timeslot. */ - } params; /**< Parameter union. */ -} nrf_radio_request_t; - -/**@brief Return parameters of the radio timeslot signal callback. */ -typedef struct { - uint8_t callback_action; /**< The action requested by the application when returning from the signal callback, see @ref - NRF_RADIO_SIGNAL_CALLBACK_ACTION. */ - union { - struct { - nrf_radio_request_t *p_next; /**< The request parameters for the next radio timeslot. */ - } request; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END. */ - struct { - uint32_t length_us; /**< Requested extension of the radio timeslot duration (microseconds) (for minimum time see @ref - NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US). */ - } extend; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND. */ - } params; /**< Parameter union. */ -} nrf_radio_signal_callback_return_param_t; - -/**@brief The radio timeslot signal callback type. - * - * @note In case of invalid return parameters, the radio timeslot will automatically end - * immediately after returning from the signal callback and the - * @ref NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN event will be sent. - * @note The returned struct pointer must remain valid after the signal callback - * function returns. For instance, this means that it must not point to a stack variable. - * - * @param[in] signal_type Type of signal, see @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE. - * - * @return Pointer to structure containing action requested by the application. - */ -typedef nrf_radio_signal_callback_return_param_t *(*nrf_radio_signal_callback_t)(uint8_t signal_type); - -/**@brief AES ECB parameter typedefs */ -typedef uint8_t soc_ecb_key_t[SOC_ECB_KEY_LENGTH]; /**< Encryption key type. */ -typedef uint8_t soc_ecb_cleartext_t[SOC_ECB_CLEARTEXT_LENGTH]; /**< Cleartext data type. */ -typedef uint8_t soc_ecb_ciphertext_t[SOC_ECB_CIPHERTEXT_LENGTH]; /**< Ciphertext data type. */ - -/**@brief AES ECB data structure */ -typedef struct { - soc_ecb_key_t key; /**< Encryption key. */ - soc_ecb_cleartext_t cleartext; /**< Cleartext data. */ - soc_ecb_ciphertext_t ciphertext; /**< Ciphertext data. */ -} nrf_ecb_hal_data_t; - -/**@brief AES ECB block. Used to provide multiple blocks in a single call - to @ref sd_ecb_blocks_encrypt.*/ -typedef struct { - soc_ecb_key_t const *p_key; /**< Pointer to the Encryption key. */ - soc_ecb_cleartext_t const *p_cleartext; /**< Pointer to the Cleartext data. */ - soc_ecb_ciphertext_t *p_ciphertext; /**< Pointer to the Ciphertext data. */ -} nrf_ecb_hal_data_block_t; - -/**@} */ - -/**@addtogroup NRF_SOC_FUNCTIONS Functions - * @{ */ - -/**@brief Initialize a mutex. - * - * @param[in] p_mutex Pointer to the mutex to initialize. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_MUTEX_NEW, uint32_t, sd_mutex_new(nrf_mutex_t *p_mutex)); - -/**@brief Attempt to acquire a mutex. - * - * @param[in] p_mutex Pointer to the mutex to acquire. - * - * @retval ::NRF_SUCCESS The mutex was successfully acquired. - * @retval ::NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN The mutex could not be acquired. - */ -SVCALL(SD_MUTEX_ACQUIRE, uint32_t, sd_mutex_acquire(nrf_mutex_t *p_mutex)); - -/**@brief Release a mutex. - * - * @param[in] p_mutex Pointer to the mutex to release. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_MUTEX_RELEASE, uint32_t, sd_mutex_release(nrf_mutex_t *p_mutex)); - -/**@brief Query the capacity of the application random pool. - * - * @param[out] p_pool_capacity The capacity of the pool. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RAND_APPLICATION_POOL_CAPACITY_GET, uint32_t, sd_rand_application_pool_capacity_get(uint8_t *p_pool_capacity)); - -/**@brief Get number of random bytes available to the application. - * - * @param[out] p_bytes_available The number of bytes currently available in the pool. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RAND_APPLICATION_BYTES_AVAILABLE_GET, uint32_t, sd_rand_application_bytes_available_get(uint8_t *p_bytes_available)); - -/**@brief Get random bytes from the application pool. - * - * @param[out] p_buff Pointer to unit8_t buffer for storing the bytes. - * @param[in] length Number of bytes to take from pool and place in p_buff. - * - * @retval ::NRF_SUCCESS The requested bytes were written to p_buff. - * @retval ::NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES No bytes were written to the buffer, because there were not enough bytes - * available. - */ -SVCALL(SD_RAND_APPLICATION_VECTOR_GET, uint32_t, sd_rand_application_vector_get(uint8_t *p_buff, uint8_t length)); - -/**@brief Gets the reset reason register. - * - * @param[out] p_reset_reason Contents of the NRF_POWER->RESETREAS register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RESET_REASON_GET, uint32_t, sd_power_reset_reason_get(uint32_t *p_reset_reason)); - -/**@brief Clears the bits of the reset reason register. - * - * @param[in] reset_reason_clr_msk Contains the bits to clear from the reset reason register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RESET_REASON_CLR, uint32_t, sd_power_reset_reason_clr(uint32_t reset_reason_clr_msk)); - -/**@brief Sets the power mode when in CPU sleep. - * - * @param[in] power_mode The power mode to use when in CPU sleep, see @ref NRF_POWER_MODES. @sa sd_app_evt_wait - * - * @retval ::NRF_SUCCESS The power mode was set. - * @retval ::NRF_ERROR_SOC_POWER_MODE_UNKNOWN The power mode was unknown. - */ -SVCALL(SD_POWER_MODE_SET, uint32_t, sd_power_mode_set(uint8_t power_mode)); - -/**@brief Puts the chip in System OFF mode. - * - * @retval ::NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN - */ -SVCALL(SD_POWER_SYSTEM_OFF, uint32_t, sd_power_system_off(void)); - -/**@brief Enables or disables the power-fail comparator. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_FAILURE_WARNING) when the power failure warning occurs. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] pof_enable True if the power-fail comparator should be enabled, false if it should be disabled. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_POF_ENABLE, uint32_t, sd_power_pof_enable(uint8_t pof_enable)); - -/**@brief Enables or disables the USB power ready event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_POWER_READY) when a USB 3.3 V supply is ready. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbpwrrdy_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBPWRRDY_ENABLE, uint32_t, sd_power_usbpwrrdy_enable(uint8_t usbpwrrdy_enable)); - -/**@brief Enables or disables the power USB-detected event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_DETECTED) when a voltage supply is detected on VBUS. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbdetected_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBDETECTED_ENABLE, uint32_t, sd_power_usbdetected_enable(uint8_t usbdetected_enable)); - -/**@brief Enables or disables the power USB-removed event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_REMOVED) when a voltage supply is removed from VBUS. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbremoved_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBREMOVED_ENABLE, uint32_t, sd_power_usbremoved_enable(uint8_t usbremoved_enable)); - -/**@brief Get USB supply status register content. - * - * @param[out] usbregstatus The content of USBREGSTATUS register. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBREGSTATUS_GET, uint32_t, sd_power_usbregstatus_get(uint32_t *usbregstatus)); - -/**@brief Sets the power failure comparator threshold value. - * - * @note: Power failure comparator threshold setting. This setting applies both for normal voltage - * mode (supply connected to both VDD and VDDH) and high voltage mode (supply connected to - * VDDH only). - * - * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDS. - * - * @retval ::NRF_SUCCESS The power failure threshold was set. - * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. - */ -SVCALL(SD_POWER_POF_THRESHOLD_SET, uint32_t, sd_power_pof_threshold_set(uint8_t threshold)); - -/**@brief Sets the power failure comparator threshold value for high voltage. - * - * @note: Power failure comparator threshold setting for high voltage mode (supply connected to - * VDDH only). This setting does not apply for normal voltage mode (supply connected to both - * VDD and VDDH). - * - * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDVDDHS. - * - * @retval ::NRF_SUCCESS The power failure threshold was set. - * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. - */ -SVCALL(SD_POWER_POF_THRESHOLDVDDH_SET, uint32_t, sd_power_pof_thresholdvddh_set(uint8_t threshold)); - -/**@brief Writes the NRF_POWER->RAM[index].POWERSET register. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERSET register to write to. - * @param[in] ram_powerset Contains the word to write to the NRF_POWER->RAM[index].POWERSET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_SET, uint32_t, sd_power_ram_power_set(uint8_t index, uint32_t ram_powerset)); - -/**@brief Writes the NRF_POWER->RAM[index].POWERCLR register. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERCLR register to write to. - * @param[in] ram_powerclr Contains the word to write to the NRF_POWER->RAM[index].POWERCLR register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_CLR, uint32_t, sd_power_ram_power_clr(uint8_t index, uint32_t ram_powerclr)); - -/**@brief Get contents of NRF_POWER->RAM[index].POWER register, indicates power status of RAM[index] blocks. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWER register to read from. - * @param[out] p_ram_power Content of NRF_POWER->RAM[index].POWER register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_GET, uint32_t, sd_power_ram_power_get(uint8_t index, uint32_t *p_ram_power)); - -/**@brief Set bits in the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[in] gpregret_msk Bits to be set in the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_SET, uint32_t, sd_power_gpregret_set(uint32_t gpregret_id, uint32_t gpregret_msk)); - -/**@brief Clear bits in the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[in] gpregret_msk Bits to be clear in the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_CLR, uint32_t, sd_power_gpregret_clr(uint32_t gpregret_id, uint32_t gpregret_msk)); - -/**@brief Get contents of the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[out] p_gpregret Contents of the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_GET, uint32_t, sd_power_gpregret_get(uint32_t gpregret_id, uint32_t *p_gpregret)); - -/**@brief Enable or disable the DC/DC regulator for the regulator stage 1 (REG1). - * - * @param[in] dcdc_mode The mode of the DCDC, see @ref NRF_POWER_DCDC_MODES. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_PARAM The DCDC mode is invalid. - */ -SVCALL(SD_POWER_DCDC_MODE_SET, uint32_t, sd_power_dcdc_mode_set(uint8_t dcdc_mode)); - -/**@brief Enable or disable the DC/DC regulator for the regulator stage 0 (REG0). - * - * For more details on the REG0 stage, please see product specification. - * - * @param[in] dcdc_mode The mode of the DCDC0, see @ref NRF_POWER_DCDC_MODES. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_PARAM The dcdc_mode is invalid. - */ -SVCALL(SD_POWER_DCDC0_MODE_SET, uint32_t, sd_power_dcdc0_mode_set(uint8_t dcdc_mode)); - -/**@brief Request the high frequency crystal oscillator. - * - * Will start the high frequency crystal oscillator, the startup time of the crystal varies - * and the ::sd_clock_hfclk_is_running function can be polled to check if it has started. - * - * @see sd_clock_hfclk_is_running - * @see sd_clock_hfclk_release - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_REQUEST, uint32_t, sd_clock_hfclk_request(void)); - -/**@brief Releases the high frequency crystal oscillator. - * - * Will stop the high frequency crystal oscillator, this happens immediately. - * - * @see sd_clock_hfclk_is_running - * @see sd_clock_hfclk_request - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_RELEASE, uint32_t, sd_clock_hfclk_release(void)); - -/**@brief Checks if the high frequency crystal oscillator is running. - * - * @see sd_clock_hfclk_request - * @see sd_clock_hfclk_release - * - * @param[out] p_is_running 1 if the external crystal oscillator is running, 0 if not. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_IS_RUNNING, uint32_t, sd_clock_hfclk_is_running(uint32_t *p_is_running)); - -/**@brief Waits for an application event. - * - * An application event is either an application interrupt or a pended interrupt when the interrupt - * is disabled. - * - * When the application waits for an application event by calling this function, an interrupt that - * is enabled will be taken immediately on pending since this function will wait in thread mode, - * then the execution will return in the application's main thread. - * - * In order to wake up from disabled interrupts, the SEVONPEND flag has to be set in the Cortex-M - * MCU's System Control Register (SCR), CMSIS_SCB. In that case, when a disabled interrupt gets - * pended, this function will return to the application's main thread. - * - * @note The application must ensure that the pended flag is cleared using ::sd_nvic_ClearPendingIRQ - * in order to sleep using this function. This is only necessary for disabled interrupts, as - * the interrupt handler will clear the pending flag automatically for enabled interrupts. - * - * @note If an application interrupt has happened since the last time sd_app_evt_wait was - * called this function will return immediately and not go to sleep. This is to avoid race - * conditions that can occur when a flag is updated in the interrupt handler and processed - * in the main loop. - * - * @post An application interrupt has happened or a interrupt pending flag is set. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_APP_EVT_WAIT, uint32_t, sd_app_evt_wait(void)); - -/**@brief Get PPI channel enable register contents. - * - * @param[out] p_channel_enable The contents of the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_GET, uint32_t, sd_ppi_channel_enable_get(uint32_t *p_channel_enable)); - -/**@brief Set PPI channel enable register. - * - * @param[in] channel_enable_set_msk Mask containing the bits to set in the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_SET, uint32_t, sd_ppi_channel_enable_set(uint32_t channel_enable_set_msk)); - -/**@brief Clear PPI channel enable register. - * - * @param[in] channel_enable_clr_msk Mask containing the bits to clear in the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_CLR, uint32_t, sd_ppi_channel_enable_clr(uint32_t channel_enable_clr_msk)); - -/**@brief Assign endpoints to a PPI channel. - * - * @param[in] channel_num Number of the PPI channel to assign. - * @param[in] evt_endpoint Event endpoint of the PPI channel. - * @param[in] task_endpoint Task endpoint of the PPI channel. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_CHANNEL The channel number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ASSIGN, uint32_t, - sd_ppi_channel_assign(uint8_t channel_num, const volatile void *evt_endpoint, const volatile void *task_endpoint)); - -/**@brief Task to enable a channel group. - * - * @param[in] group_num Number of the channel group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_TASK_ENABLE, uint32_t, sd_ppi_group_task_enable(uint8_t group_num)); - -/**@brief Task to disable a channel group. - * - * @param[in] group_num Number of the PPI group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_TASK_DISABLE, uint32_t, sd_ppi_group_task_disable(uint8_t group_num)); - -/**@brief Assign PPI channels to a channel group. - * - * @param[in] group_num Number of the channel group. - * @param[in] channel_msk Mask of the channels to assign to the group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_ASSIGN, uint32_t, sd_ppi_group_assign(uint8_t group_num, uint32_t channel_msk)); - -/**@brief Gets the PPI channels of a channel group. - * - * @param[in] group_num Number of the channel group. - * @param[out] p_channel_msk Mask of the channels assigned to the group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_GET, uint32_t, sd_ppi_group_get(uint8_t group_num, uint32_t *p_channel_msk)); - -/**@brief Configures the Radio Notification signal. - * - * @note - * - The notification signal latency depends on the interrupt priority settings of SWI used - * for notification signal. - * - To ensure that the radio notification signal behaves in a consistent way, the radio - * notifications must be configured when there is no protocol stack or other SoftDevice - * activity in progress. It is recommended that the radio notification signal is - * configured directly after the SoftDevice has been enabled. - * - In the period between the ACTIVE signal and the start of the Radio Event, the SoftDevice - * will interrupt the application to do Radio Event preparation. - * - Using the Radio Notification feature may limit the bandwidth, as the SoftDevice may have - * to shorten the connection events to have time for the Radio Notification signals. - * - * @param[in] type Type of notification signal, see @ref NRF_RADIO_NOTIFICATION_TYPES. - * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE shall be used to turn off radio - * notification. Using @ref NRF_RADIO_NOTIFICATION_DISTANCE_NONE is - * recommended (but not required) to be used with - * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE. - * - * @param[in] distance Distance between the notification signal and start of radio activity, see @ref - * NRF_RADIO_NOTIFICATION_DISTANCES. This parameter is ignored when @ref NRF_RADIO_NOTIFICATION_TYPE_NONE or - * @ref NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE is used. - * - * @retval ::NRF_ERROR_INVALID_PARAM The group number is invalid. - * @retval ::NRF_ERROR_INVALID_STATE A protocol stack or other SoftDevice is running. Stop all - * running activities and retry. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RADIO_NOTIFICATION_CFG_SET, uint32_t, sd_radio_notification_cfg_set(uint8_t type, uint8_t distance)); - -/**@brief Encrypts a block according to the specified parameters. - * - * 128-bit AES encryption. - * - * @note: - * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while - * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application - * main or low interrupt level. - * - * @param[in, out] p_ecb_data Pointer to the ECB parameters' struct (two input - * parameters and one output parameter). - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_ECB_BLOCK_ENCRYPT, uint32_t, sd_ecb_block_encrypt(nrf_ecb_hal_data_t *p_ecb_data)); - -/**@brief Encrypts multiple data blocks provided as an array of data block structures. - * - * @details: Performs 128-bit AES encryption on multiple data blocks - * - * @note: - * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while - * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application - * main or low interrupt level. - * - * @param[in] block_count Count of blocks in the p_data_blocks array. - * @param[in,out] p_data_blocks Pointer to the first entry in a contiguous array of - * @ref nrf_ecb_hal_data_block_t structures. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_ECB_BLOCKS_ENCRYPT, uint32_t, sd_ecb_blocks_encrypt(uint8_t block_count, nrf_ecb_hal_data_block_t *p_data_blocks)); - -/**@brief Gets any pending events generated by the SoC API. - * - * The application should keep calling this function to get events, until ::NRF_ERROR_NOT_FOUND is returned. - * - * @param[out] p_evt_id Set to one of the values in @ref NRF_SOC_EVTS, if any events are pending. - * - * @retval ::NRF_SUCCESS An event was pending. The event id is written in the p_evt_id parameter. - * @retval ::NRF_ERROR_NOT_FOUND No pending events. - */ -SVCALL(SD_EVT_GET, uint32_t, sd_evt_get(uint32_t *p_evt_id)); - -/**@brief Get the temperature measured on the chip - * - * This function will block until the temperature measurement is done. - * It takes around 50 us from call to return. - * - * @param[out] p_temp Result of temperature measurement. Die temperature in 0.25 degrees Celsius. - * - * @retval ::NRF_SUCCESS A temperature measurement was done, and the temperature was written to temp - */ -SVCALL(SD_TEMP_GET, uint32_t, sd_temp_get(int32_t *p_temp)); - -/**@brief Flash Write - * - * Commands to write a buffer to flash - * - * If the SoftDevice is enabled: - * This call initiates the flash access command, and its completion will be communicated to the - * application with exactly one of the following events: - * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. - * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. - * - * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the - * write has been completed - * - * @note - * - This call takes control over the radio and the CPU during flash erase and write to make sure that - * they will not interfere with the flash access. This means that all interrupts will be blocked - * for a predictable time (depending on the NVMC specification in the device's Product Specification - * and the command parameters). - * - The data in the p_src buffer should not be modified before the @ref NRF_EVT_FLASH_OPERATION_SUCCESS - * or the @ref NRF_EVT_FLASH_OPERATION_ERROR have been received if the SoftDevice is enabled. - * - This call will make the SoftDevice trigger a hardfault when the page is written, if it is - * protected. - * - * - * @param[in] p_dst Pointer to start of flash location to be written. - * @param[in] p_src Pointer to buffer with data to be written. - * @param[in] size Number of 32-bit words to write. Maximum size is the number of words in one - * flash page. See the device's Product Specification for details. - * - * @retval ::NRF_ERROR_INVALID_ADDR Tried to write to a non existing flash address, or p_dst or p_src was unaligned. - * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. - * @retval ::NRF_ERROR_INVALID_LENGTH Size was 0, or higher than the maximum allowed size. - * @retval ::NRF_ERROR_FORBIDDEN Tried to write to an address outside the application flash area. - * @retval ::NRF_SUCCESS The command was accepted. - */ -SVCALL(SD_FLASH_WRITE, uint32_t, sd_flash_write(uint32_t *p_dst, uint32_t const *p_src, uint32_t size)); - -/**@brief Flash Erase page - * - * Commands to erase a flash page - * If the SoftDevice is enabled: - * This call initiates the flash access command, and its completion will be communicated to the - * application with exactly one of the following events: - * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. - * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. - * - * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the - * erase has been completed - * - * @note - * - This call takes control over the radio and the CPU during flash erase and write to make sure that - * they will not interfere with the flash access. This means that all interrupts will be blocked - * for a predictable time (depending on the NVMC specification in the device's Product Specification - * and the command parameters). - * - This call will make the SoftDevice trigger a hardfault when the page is erased, if it is - * protected. - * - * - * @param[in] page_number Page number of the page to erase - * - * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. - * @retval ::NRF_ERROR_INVALID_ADDR Tried to erase to a non existing flash page. - * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. - * @retval ::NRF_ERROR_FORBIDDEN Tried to erase a page outside the application flash area. - * @retval ::NRF_SUCCESS The command was accepted. - */ -SVCALL(SD_FLASH_PAGE_ERASE, uint32_t, sd_flash_page_erase(uint32_t page_number)); - -/**@brief Opens a session for radio timeslot requests. - * - * @note Only one session can be open at a time. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) will be called when the radio timeslot - * starts. From this point the NRF_RADIO and NRF_TIMER0 peripherals can be freely accessed - * by the application. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0) is called whenever the NRF_TIMER0 - * interrupt occurs. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO) is called whenever the NRF_RADIO - * interrupt occurs. - * @note p_radio_signal_callback() will be called at ARM interrupt priority level 0. This - * implies that none of the sd_* API calls can be used from p_radio_signal_callback(). - * - * @param[in] p_radio_signal_callback The signal callback. - * - * @retval ::NRF_ERROR_INVALID_ADDR p_radio_signal_callback is an invalid function pointer. - * @retval ::NRF_ERROR_BUSY If session cannot be opened. - * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_SESSION_OPEN, uint32_t, sd_radio_session_open(nrf_radio_signal_callback_t p_radio_signal_callback)); - -/**@brief Closes a session for radio timeslot requests. - * - * @note Any current radio timeslot will be finished before the session is closed. - * @note If a radio timeslot is scheduled when the session is closed, it will be canceled. - * @note The application cannot consider the session closed until the @ref NRF_EVT_RADIO_SESSION_CLOSED - * event is received. - * - * @retval ::NRF_ERROR_FORBIDDEN If session not opened. - * @retval ::NRF_ERROR_BUSY If session is currently being closed. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_SESSION_CLOSE, uint32_t, sd_radio_session_close(void)); - -/**@brief Requests a radio timeslot. - * - * @note The request type is determined by p_request->request_type, and can be one of @ref NRF_RADIO_REQ_TYPE_EARLIEST - * and @ref NRF_RADIO_REQ_TYPE_NORMAL. The first request in a session must always be of type @ref - * NRF_RADIO_REQ_TYPE_EARLIEST. - * @note For a normal request (@ref NRF_RADIO_REQ_TYPE_NORMAL), the start time of a radio timeslot is specified by - * p_request->distance_us and is given relative to the start of the previous timeslot. - * @note A too small p_request->distance_us will lead to a @ref NRF_EVT_RADIO_BLOCKED event. - * @note Timeslots scheduled too close will lead to a @ref NRF_EVT_RADIO_BLOCKED event. - * @note See the SoftDevice Specification for more on radio timeslot scheduling, distances and lengths. - * @note If an opportunity for the first radio timeslot is not found before 100 ms after the call to this - * function, it is not scheduled, and instead a @ref NRF_EVT_RADIO_BLOCKED event is sent. - * The application may then try to schedule the first radio timeslot again. - * @note Successful requests will result in nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START). - * Unsuccessful requests will result in a @ref NRF_EVT_RADIO_BLOCKED event, see @ref NRF_SOC_EVTS. - * @note The jitter in the start time of the radio timeslots is +/- @ref NRF_RADIO_START_JITTER_US us. - * @note The nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) call has a latency relative to the - * specified radio timeslot start, but this does not affect the actual start time of the timeslot. - * @note NRF_TIMER0 is reset at the start of the radio timeslot, and is clocked at 1MHz from the high frequency - * (16 MHz) clock source. If p_request->hfclk_force_xtal is true, the high frequency clock is - * guaranteed to be clocked from the external crystal. - * @note The SoftDevice will neither access the NRF_RADIO peripheral nor the NRF_TIMER0 peripheral - * during the radio timeslot. - * - * @param[in] p_request Pointer to the request parameters. - * - * @retval ::NRF_ERROR_FORBIDDEN Either: - * - The session is not open. - * - The session is not IDLE. - * - This is the first request and its type is not @ref NRF_RADIO_REQ_TYPE_EARLIEST. - * - The request type was set to @ref NRF_RADIO_REQ_TYPE_NORMAL after a - * @ref NRF_RADIO_REQ_TYPE_EARLIEST request was blocked. - * @retval ::NRF_ERROR_INVALID_ADDR If the p_request pointer is invalid. - * @retval ::NRF_ERROR_INVALID_PARAM If the parameters of p_request are not valid. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_REQUEST, uint32_t, sd_radio_request(nrf_radio_request_t const *p_request)); - -/**@brief Write register protected by the SoftDevice - * - * This function writes to a register that is write-protected by the SoftDevice. Please refer to your - * SoftDevice Specification for more details about which registers that are protected by SoftDevice. - * This function can write to the following protected peripheral: - * - ACL - * - * @note Protected registers may be read directly. - * @note Register that are write-once will return @ref NRF_SUCCESS on second set, even the value in - * the register has not changed. See the Product Specification for more details about register - * properties. - * - * @param[in] p_register Pointer to register to be written. - * @param[in] value Value to be written to the register. - * - * @retval ::NRF_ERROR_INVALID_ADDR This function can not write to the reguested register. - * @retval ::NRF_SUCCESS Value successfully written to register. - * - */ -SVCALL(SD_PROTECTED_REGISTER_WRITE, uint32_t, sd_protected_register_write(volatile uint32_t *p_register, uint32_t value)); - -/**@} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_SOC_H__ - -/**@} */ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_svc.h b/variants/wio-tracker-wm1110/softdevice/nrf_svc.h deleted file mode 100644 index 1de44656f3..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_svc.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef NRF_SVC__ -#define NRF_SVC__ - -#include "stdint.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @brief Supervisor call declaration. - * - * A call to a function marked with @ref SVCALL, will trigger a Supervisor Call (SVC) Exception. - * The SVCs with SVC numbers 0x00-0x0F are forwared to the application. All other SVCs are handled by the SoftDevice. - * - * @param[in] number The SVC number to be used. - * @param[in] return_type The return type of the SVC function. - * @param[in] signature Function signature. The function can have at most four arguments. - */ - -#ifdef SVCALL_AS_NORMAL_FUNCTION -#define SVCALL(number, return_type, signature) return_type signature -#else - -#ifndef SVCALL -#if defined(__CC_ARM) -#define SVCALL(number, return_type, signature) return_type __svc(number) signature -#elif defined(__GNUC__) -#ifdef __cplusplus -#define GCC_CAST_CPP (uint16_t) -#else -#define GCC_CAST_CPP -#endif -#define SVCALL(number, return_type, signature) \ - _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") __attribute__((naked)) \ - __attribute__((unused)) static return_type signature \ - { \ - __asm("svc %0\n" \ - "bx r14" \ - : \ - : "I"(GCC_CAST_CPP number) \ - : "r0"); \ - } \ - _Pragma("GCC diagnostic pop") - -#elif defined(__ICCARM__) -#define PRAGMA(x) _Pragma(#x) -#define SVCALL(number, return_type, signature) \ - PRAGMA(swi_number = (number)) \ - __swi return_type signature; -#else -#define SVCALL(number, return_type, signature) return_type signature -#endif -#endif // SVCALL - -#endif // SVCALL_AS_NORMAL_FUNCTION - -#ifdef __cplusplus -} -#endif -#endif // NRF_SVC__ From a664d4597f8b9750785f637aae7ef445a69380fa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 14:26:19 -0500 Subject: [PATCH 132/211] [create-pull-request] automated change (#4247) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 1cb93ac2bf..c9336d539a 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 15 +build = 16 From 308060b1fe37dd0a76821d2b4ad34da821a45f77 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 9 Jul 2024 09:59:27 +0800 Subject: [PATCH 133/211] Add wio-sdk-wm1110 to build. (#4258) The wio-sdk-wm1110 is distinct from the wio-tracker-wm1110, with different platformio build options and pin config. This change adds the wio-sdk-wm1110 to the CI matrix so firmware is built as part of release. --- variants/wio-sdk-wm1110/platformio.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini index aa10f525d3..dc7d47310c 100644 --- a/variants/wio-sdk-wm1110/platformio.ini +++ b/variants/wio-sdk-wm1110/platformio.ini @@ -6,7 +6,6 @@ board = wio-sdk-wm1110 # Remove adafruit USB serial from the build (it is incompatible with using the ch340 serial chip on this board) build_unflags = ${nrf52840_base:build_unflags} -DUSBCON -DUSE_TINYUSB -board_level = extra ; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" From 33c46d6eb1981ee11412530bc82f321af391df8c Mon Sep 17 00:00:00 2001 From: geeksville Date: Tue, 9 Jul 2024 05:19:03 -0700 Subject: [PATCH 134/211] fix python warning in uf2conf (#4235) the old regex worked but was technically incorrect. fixes: Generating NRF52 uf2 file /home/kevinh/development/meshtastic/firmware/bin/uf2conv.py:195: SyntaxWarning: invalid escape sequence '\s' words = re.split('\s+', line) Converting to uf2, output size: 1458688, start address: 0x26000 --- bin/uf2conv.py | 223 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 145 insertions(+), 78 deletions(-) diff --git a/bin/uf2conv.py b/bin/uf2conv.py index b619d14db0..a1e241b7a6 100755 --- a/bin/uf2conv.py +++ b/bin/uf2conv.py @@ -1,39 +1,38 @@ #!/usr/bin/env python3 -import sys -import struct -import subprocess -import re +import argparse import os import os.path -import argparse - +import re +import struct +import subprocess +import sys -UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" -UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected -UF2_MAGIC_END = 0x0AB16F30 # Ditto +UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" +UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected +UF2_MAGIC_END = 0x0AB16F30 # Ditto families = { - 'SAMD21': 0x68ed2b88, - 'SAML21': 0x1851780a, - 'SAMD51': 0x55114460, - 'NRF52': 0x1b57745f, - 'STM32F0': 0x647824b6, - 'STM32F1': 0x5ee21072, - 'STM32F2': 0x5d1a0a2e, - 'STM32F3': 0x6b846188, - 'STM32F4': 0x57755a57, - 'STM32F7': 0x53b80f00, - 'STM32G0': 0x300f5633, - 'STM32G4': 0x4c71240a, - 'STM32H7': 0x6db66082, - 'STM32L0': 0x202e3a91, - 'STM32L1': 0x1e1f432d, - 'STM32L4': 0x00ff6919, - 'STM32L5': 0x04240bdf, - 'STM32WB': 0x70d16653, - 'STM32WL': 0x21460ff0, - 'ATMEGA32': 0x16573617, - 'MIMXRT10XX': 0x4FB2D5BD + "SAMD21": 0x68ED2B88, + "SAML21": 0x1851780A, + "SAMD51": 0x55114460, + "NRF52": 0x1B57745F, + "STM32F0": 0x647824B6, + "STM32F1": 0x5EE21072, + "STM32F2": 0x5D1A0A2E, + "STM32F3": 0x6B846188, + "STM32F4": 0x57755A57, + "STM32F7": 0x53B80F00, + "STM32G0": 0x300F5633, + "STM32G4": 0x4C71240A, + "STM32H7": 0x6DB66082, + "STM32L0": 0x202E3A91, + "STM32L1": 0x1E1F432D, + "STM32L4": 0x00FF6919, + "STM32L5": 0x04240BDF, + "STM32WB": 0x70D16653, + "STM32WL": 0x21460FF0, + "ATMEGA32": 0x16573617, + "MIMXRT10XX": 0x4FB2D5BD, } INFO_FILE = "/INFO_UF2.TXT" @@ -46,15 +45,17 @@ def is_uf2(buf): w = struct.unpack(" 10*1024*1024: + if padding > 10 * 1024 * 1024: assert False, "More than 10M of padding needed at " + ptr if padding % 4 != 0: assert False, "Non-word padding size at " + ptr @@ -91,6 +92,7 @@ def convert_from_uf2(buf): curraddr = newaddr + datalen return outp + def convert_to_carray(file_content): outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {" for i in range(len(file_content)): @@ -100,6 +102,7 @@ def convert_to_carray(file_content): outp += "\n};\n" return outp + def convert_to_uf2(file_content): global familyid datapadding = b"" @@ -109,13 +112,21 @@ def convert_to_uf2(file_content): outp = b"" for blockno in range(numblocks): ptr = 256 * blockno - chunk = file_content[ptr:ptr + 256] + chunk = file_content[ptr : ptr + 256] flags = 0x0 if familyid: flags |= 0x2000 - hd = struct.pack(b"= 3 and words[1] == "2" and words[2] == "FAT": drives.append(words[0]) else: @@ -206,7 +238,6 @@ def get_drives(): for d in os.listdir(rootpath): drives.append(os.path.join(rootpath, d)) - def has_info(d): try: return os.path.isfile(d + INFO_FILE) @@ -217,7 +248,7 @@ def has_info(d): def board_id(path): - with open(path + INFO_FILE, mode='r') as file: + with open(path + INFO_FILE, mode="r") as file: file_content = file.read() return re.search("Board-ID: ([^\r\n]*)", file_content).group(1) @@ -235,30 +266,61 @@ def write_file(name, buf): def main(): global appstartaddr, familyid + def error(msg): print(msg) sys.exit(1) - parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.') - parser.add_argument('input', metavar='INPUT', type=str, nargs='?', - help='input file (HEX, BIN or UF2)') - parser.add_argument('-b' , '--base', dest='base', type=str, - default="0x2000", - help='set base address of application for BIN format (default: 0x2000)') - parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str, - help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible') - parser.add_argument('-d' , '--device', dest="device_path", - help='select a device path to flash') - parser.add_argument('-l' , '--list', action='store_true', - help='list connected devices') - parser.add_argument('-c' , '--convert', action='store_true', - help='do not flash, just convert') - parser.add_argument('-D' , '--deploy', action='store_true', - help='just flash, do not convert') - parser.add_argument('-f' , '--family', dest='family', type=str, - default="0x0", - help='specify familyID - number or name (default: 0x0)') - parser.add_argument('-C' , '--carray', action='store_true', - help='convert binary file to a C array, not UF2') + + parser = argparse.ArgumentParser(description="Convert to UF2 or flash directly.") + parser.add_argument( + "input", + metavar="INPUT", + type=str, + nargs="?", + help="input file (HEX, BIN or UF2)", + ) + parser.add_argument( + "-b", + "--base", + dest="base", + type=str, + default="0x2000", + help="set base address of application for BIN format (default: 0x2000)", + ) + parser.add_argument( + "-o", + "--output", + metavar="FILE", + dest="output", + type=str, + help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible', + ) + parser.add_argument( + "-d", "--device", dest="device_path", help="select a device path to flash" + ) + parser.add_argument( + "-l", "--list", action="store_true", help="list connected devices" + ) + parser.add_argument( + "-c", "--convert", action="store_true", help="do not flash, just convert" + ) + parser.add_argument( + "-D", "--deploy", action="store_true", help="just flash, do not convert" + ) + parser.add_argument( + "-f", + "--family", + dest="family", + type=str, + default="0x0", + help="specify familyID - number or name (default: 0x0)", + ) + parser.add_argument( + "-C", + "--carray", + action="store_true", + help="convert binary file to a C array, not UF2", + ) args = parser.parse_args() appstartaddr = int(args.base, 0) @@ -268,14 +330,17 @@ def error(msg): try: familyid = int(args.family, 0) except ValueError: - error("Family ID needs to be a number or one of: " + ", ".join(families.keys())) + error( + "Family ID needs to be a number or one of: " + + ", ".join(families.keys()) + ) if args.list: list_drives() else: if not args.input: error("Need input file") - with open(args.input, mode='rb') as f: + with open(args.input, mode="rb") as f: inpbuf = f.read() from_uf2 = is_uf2(inpbuf) ext = "uf2" @@ -291,8 +356,10 @@ def error(msg): ext = "h" else: outbuf = convert_to_uf2(inpbuf) - print("Converting to %s, output size: %d, start address: 0x%x" % - (ext, len(outbuf), appstartaddr)) + print( + "Converting to %s, output size: %d, start address: 0x%x" + % (ext, len(outbuf), appstartaddr) + ) if args.convert or ext != "uf2": drives = [] if args.output == None: From 9f089746da9c7a5e06698b60174fb5cb4d19232f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 9 Jul 2024 08:31:16 -0500 Subject: [PATCH 135/211] Collect hex files and specifically wm1110 sdk --- .github/workflows/main_matrix.yml | 3 ++- bin/build-nrf52.sh | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 25a0fbad22..14c8a9d10c 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -136,7 +136,7 @@ jobs: build-rpi2040, package-raspbian, package-raspbian-armv7l, - package-native + package-native, ] steps: - name: Checkout code @@ -168,6 +168,7 @@ jobs: path: | ./firmware-*.bin ./firmware-*.uf2 + ./firmware-*.hex ./firmware-*-ota.zip ./device-*.sh ./device-*.bat diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index fa6eacd237..97b7cd4563 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -33,13 +33,15 @@ SRCHEX=.pio/build/$1/firmware.hex # if WM1110 target, merge hex with softdevice 7.3.0 if (echo $1 | grep -q "wio-sdk-wm1110"); then echo "Merging with softdevice" - sudo chmod +x ./bin/mergehex - bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/merged_fimware.hex - SRCHEX=.pio/build/$1/merged_fimware.hex + sudo chmod +x ./bin/mergehex + bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/$basename.hex + SRCHEX=.pio/build/$1/$basename.hex + bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 + cp $SRCHEX $OUTDIR + cp bin/*.uf2 $OUTDIR +else + bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 + cp bin/device-install.* $OUTDIR + cp bin/device-update.* $OUTDIR + cp bin/*.uf2 $OUTDIR fi - -bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 - -cp bin/device-install.* $OUTDIR -cp bin/device-update.* $OUTDIR -cp bin/*.uf2 $OUTDIR From 8b388d1e27f3a5fe4b73d8f73e957b71ccad38d2 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 9 Jul 2024 09:12:23 -0500 Subject: [PATCH 136/211] Skip dfu file for sdk (for now) --- bin/build-nrf52.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index 97b7cd4563..e4fadbb308 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -23,8 +23,17 @@ basename=firmware-$1-$VERSION pio run --environment $1 # -v SRCELF=.pio/build/$1/firmware.elf -DFUPKG=.pio/build/$1/firmware.zip cp $SRCELF $OUTDIR/$basename.elf + +if (echo $1 | grep -q "wio-sdk-wm1110"); then + echo "Skipping dfu file" +else + echo "Generating NRF52 dfu file" + DFUPKG=.pio/build/$1/firmware.zip + cp $DFUPKG $OUTDIR/$basename-ota.zip +fi + +DFUPKG=.pio/build/$1/firmware.zip cp $DFUPKG $OUTDIR/$basename-ota.zip echo "Generating NRF52 uf2 file" From a3777e8f29754a62c80ad1bb902075d517f76a28 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 9 Jul 2024 09:23:59 -0500 Subject: [PATCH 137/211] Helps if you remove the original clause --- .github/workflows/build_nrf52.yml | 1 + bin/build-nrf52.sh | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/build_nrf52.yml b/.github/workflows/build_nrf52.yml index eb17799635..ac509a096a 100644 --- a/.github/workflows/build_nrf52.yml +++ b/.github/workflows/build_nrf52.yml @@ -29,6 +29,7 @@ jobs: name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip overwrite: true path: | + release/*.hex release/*.uf2 release/*.elf release/*.zip diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index e4fadbb308..077e2af35a 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -33,9 +33,6 @@ else cp $DFUPKG $OUTDIR/$basename-ota.zip fi -DFUPKG=.pio/build/$1/firmware.zip -cp $DFUPKG $OUTDIR/$basename-ota.zip - echo "Generating NRF52 uf2 file" SRCHEX=.pio/build/$1/firmware.hex From 1626667400356911f95343ee715ac14078ab43f3 Mon Sep 17 00:00:00 2001 From: "Aaron.Lee" <32860565+Heltec-Aaron-Lee@users.noreply.github.com> Date: Wed, 10 Jul 2024 00:56:57 +0800 Subject: [PATCH 138/211] Add Heltec new boards. (#4226) * Add Heltec new boards * Update variant.h disable RTC by default * Add Heltec New boards * Add Heltec new boards * Update Heltec Mesh Node definition. * Update Heltec Vision Mater E290 --- boards/heltec_mesh_node_t114.json | 53 +++++ platformio.ini | 4 + src/Power.cpp | 8 + src/graphics/EInkDisplay2.cpp | 2 +- src/graphics/EInkDisplay2.h | 7 +- src/graphics/Screen.cpp | 27 ++- src/graphics/Screen.h | 2 + src/main.cpp | 5 +- src/mesh/NodeDB.cpp | 2 +- src/platform/esp32/architecture.h | 8 + src/sleep.cpp | 2 + variants/heltec_mesh_node_t114/platformio.ini | 15 ++ variants/heltec_mesh_node_t114/variant.cpp | 44 ++++ variants/heltec_mesh_node_t114/variant.h | 209 ++++++++++++++++++ .../heltec_vision_master_e213/pins_arduino.h | 63 ++++++ .../heltec_vision_master_e213/platformio.ini | 23 ++ variants/heltec_vision_master_e213/variant.h | 58 +++++ .../heltec_vision_master_e290/pins_arduino.h | 63 ++++++ .../heltec_vision_master_e290/platformio.ini | 24 ++ variants/heltec_vision_master_e290/variant.h | 58 +++++ .../heltec_vision_master_t190/pins_arduino.h | 63 ++++++ .../heltec_vision_master_t190/platformio.ini | 13 ++ variants/heltec_vision_master_t190/variant.h | 78 +++++++ variants/heltec_wireless_paper/pins_arduino.h | 5 - 24 files changed, 820 insertions(+), 16 deletions(-) create mode 100644 boards/heltec_mesh_node_t114.json create mode 100644 variants/heltec_mesh_node_t114/platformio.ini create mode 100644 variants/heltec_mesh_node_t114/variant.cpp create mode 100644 variants/heltec_mesh_node_t114/variant.h create mode 100644 variants/heltec_vision_master_e213/pins_arduino.h create mode 100644 variants/heltec_vision_master_e213/platformio.ini create mode 100644 variants/heltec_vision_master_e213/variant.h create mode 100644 variants/heltec_vision_master_e290/pins_arduino.h create mode 100644 variants/heltec_vision_master_e290/platformio.ini create mode 100644 variants/heltec_vision_master_e290/variant.h create mode 100644 variants/heltec_vision_master_t190/pins_arduino.h create mode 100644 variants/heltec_vision_master_t190/platformio.ini create mode 100644 variants/heltec_vision_master_t190/variant.h diff --git a/boards/heltec_mesh_node_t114.json b/boards/heltec_mesh_node_t114.json new file mode 100644 index 0000000000..5c97d8c755 --- /dev/null +++ b/boards/heltec_mesh_node_t114.json @@ -0,0 +1,53 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v6.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_NRF52840_PCA10056 -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + ["0x239A", "0x4405"], + ["0x239A", "0x0029"], + ["0x239A", "0x002A"] + ], + "usb_product": "HT-n5262", + "mcu": "nrf52840", + "variant": "heltec_mesh_node_t114", + "variants_dir": "variants", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "6.1.1", + "sd_fwid": "0x00B6" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": ["bluetooth"], + "debug": { + "jlink_device": "nRF52840_xxAA", + "onboard_tools": ["jlink"], + "svd_path": "nrf52840.svd", + "openocd_target": "nrf52840-mdk-rs" + }, + "frameworks": ["arduino"], + "name": "Heltec nrf (Adafruit BSP)", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "FIXME", + "vendor": "Heltec" +} diff --git a/platformio.ini b/platformio.ini index bcdcc0034b..b3f6772470 100644 --- a/platformio.ini +++ b/platformio.ini @@ -35,6 +35,10 @@ default_envs = tbeam ;default_envs = radiomaster_900_bandit_nano ;default_envs = radiomaster_900_bandit_micro ;default_envs = heltec_capsule_sensor_v3 +;default_envs = heltec_vision_master_t190 +;default_envs = heltec_vision_master_e213 +;default_envs = heltec_vision_master_e290 +;default_envs = heltec_mesh_node_t114 extra_configs = arch/*/*.ini diff --git a/src/Power.cpp b/src/Power.cpp index cea373806c..78024ee0c6 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -233,11 +233,19 @@ class AnalogBatteryLevel : public HasBatteryLevel scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs); scaled *= operativeAdcMultiplier; #else // block for all other platforms +#ifdef ADC_CTRL // enable adc voltage divider when we need to read + pinMode(ADC_CTRL, OUTPUT); + digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED); + delay(10); +#endif for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) { raw += analogRead(BATTERY_PIN); } raw = raw / BATTERY_SENSE_SAMPLES; scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw; +#ifdef ADC_CTRL // disable adc voltage divider when we need to read + digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED); +#endif #endif if (!initial_read_done) { diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index bbc12521a0..191c46e67f 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -156,7 +156,7 @@ bool EInkDisplay::connect() } } -#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) +#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || defined(HELTEC_VISION_MASTER_E290) { // Start HSPI hspi = new SPIClass(HSPI); diff --git a/src/graphics/EInkDisplay2.h b/src/graphics/EInkDisplay2.h index f744164949..426bb5f191 100644 --- a/src/graphics/EInkDisplay2.h +++ b/src/graphics/EInkDisplay2.h @@ -5,11 +5,6 @@ #include "GxEPD2_BW.h" #include -#if defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) -// Re-enable SPI after deep sleep: rtc_gpio_hold_dis() -#include "driver/rtc_io.h" -#endif - /** * An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation. * @@ -72,7 +67,7 @@ class EInkDisplay : public OLEDDisplay GxEPD2_BW *adafruitDisplay = NULL; // If display uses HSPI -#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) +#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || defined(HELTEC_VISION_MASTER_E290) SPIClass *hspi = NULL; #endif diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index f724ddd3d4..86d71dfde2 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1485,6 +1485,10 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ screen->drawColumns(display, x, y, fields); } +#if defined(ESP_PLATFORM) && defined(USE_ST7789) +SPIClass SPI1(HSPI); +#endif + Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry) : concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32) { @@ -1492,6 +1496,12 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O #if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64) dispdev = new SH1106Wire(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); +#elif defined(USE_ST7789) +#ifdef ESP_PLATFORM + dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS,GEOMETRY_RAWMODE,TFT_WIDTH,TFT_HEIGHT,ST7789_SDA,ST7789_MISO,ST7789_SCK); +#else + dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS,GEOMETRY_RAWMODE,TFT_WIDTH,TFT_HEIGHT); +#endif #elif defined(USE_SSD1306) dispdev = new SSD1306Wire(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); @@ -1570,7 +1580,14 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) #endif dispdev->displayOn(); - +#ifdef USE_ST7789 +#ifdef ESP_PLATFORM + analogWrite(VTFT_LEDA,BRIGHTNESS_DEFAULT); +#else + pinMode(VTFT_LEDA,OUTPUT); + digitalWrite(VTFT_LEDA,TFT_BACKLIGHT_ON); +#endif +#endif enabled = true; setInterval(0); // Draw ASAP runASAP = true; @@ -1581,6 +1598,12 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) #endif LOG_INFO("Turning off screen\n"); dispdev->displayOff(); + +#ifdef USE_ST7789 + pinMode(VTFT_LEDA,OUTPUT); + digitalWrite(VTFT_LEDA,!TFT_BACKLIGHT_ON); +#endif + #ifdef T_WATCH_S3 PMU->disablePowerOutput(XPOWERS_ALDO2); #endif @@ -1595,7 +1618,7 @@ void Screen::setup() // We don't set useDisplay until setup() is called, because some boards have a declaration of this object but the device // is never found when probing i2c and therefore we don't call setup and never want to do (invalid) accesses to this device. useDisplay = true; - + #ifdef AutoOLEDWire_h if (isAUTOOled) static_cast(dispdev)->setDetected(model); diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 83c9a7a946..b89a2917e8 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -45,6 +45,8 @@ class Screen #include #elif defined(USE_SSD1306) #include +#elif defined(USE_ST7789) +#include #else // the SH1106/SSD1306 variant is auto-detected #include diff --git a/src/main.cpp b/src/main.cpp index 1e0d998e15..95af5f6de5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -275,6 +275,9 @@ void setup() digitalWrite(VEXT_ENABLE_V05, 1); // turn on the lora antenna boost digitalWrite(ST7735_BL_V05, 1); // turn on display backligth LOG_DEBUG("HELTEC Detect Tracker V1.1\n"); +#elif defined(VEXT_ENABLE) && defined(VEXT_ON_VALUE) + pinMode(VEXT_ENABLE, OUTPUT); + digitalWrite(VEXT_ENABLE, VEXT_ON_VALUE); // turn on the display power #elif defined(VEXT_ENABLE) pinMode(VEXT_ENABLE, OUTPUT); digitalWrite(VEXT_ENABLE, 0); // turn on the display power @@ -713,7 +716,7 @@ void setup() // Don't call screen setup until after nodedb is setup (because we need // the current region name) -#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) +#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) screen->setup(); #elif defined(ARCH_PORTDUINO) if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) { diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 84872e4714..07184a6bcf 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -268,7 +268,7 @@ void NodeDB::installDefaultConfig() // FIXME: Default to bluetooth capability of platform as default config.bluetooth.enabled = true; config.bluetooth.fixed_pin = defaultBLEPin; -#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) +#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) bool hasScreen = true; #elif ARCH_PORTDUINO bool hasScreen = false; diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index 5565b64686..fd3f92a9c3 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -151,6 +151,14 @@ #define HW_VENDOR meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO #elif defined(HELTEC_CAPSULE_SENSOR_V3) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3 +#elif defined(HELTEC_VISION_MASTER_T190) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_VISION_MASTER_T190 +#elif defined(HELTEC_VISION_MASTER_E213) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_VISION_MASTER_E213 +#elif defined(HELTEC_VISION_MASTER_E290) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_VISION_MASTER_E290 +#elif defined(HELTEC_MESH_NODE_T114) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 #endif // ----------------------------------------------------------------------------- diff --git a/src/sleep.cpp b/src/sleep.cpp index e2c9549f3b..3918568a0a 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -257,6 +257,8 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) #elif defined(VEXT_ENABLE_V05) digitalWrite(VEXT_ENABLE_V05, 0); // turn off the lora amplifier power digitalWrite(ST7735_BL_V05, 0); // turn off the display power +#elif defined(VEXT_ENABLE) && defined(VEXT_ON_VALUE) + digitalWrite(VEXT_ENABLE, !VEXT_ON_VALUE); // turn on the display power #elif defined(VEXT_ENABLE) digitalWrite(VEXT_ENABLE, 1); // turn off the display power #endif diff --git a/variants/heltec_mesh_node_t114/platformio.ini b/variants/heltec_mesh_node_t114/platformio.ini new file mode 100644 index 0000000000..99bdf77a72 --- /dev/null +++ b/variants/heltec_mesh_node_t114/platformio.ini @@ -0,0 +1,15 @@ +; First prototype nrf52840/sx1262 device +[env:heltec-mesh-node-t114] +extends = nrf52840_base +board = heltec_mesh_node_t114 +debug_tool = jlink + +# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling. +build_flags = ${nrf52840_base.build_flags} -Ivariants/heltec_mesh_node_t114 + -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/heltec_mesh_node_t114> +lib_deps = + ${nrf52840_base.lib_deps} + lewisxhe/PCF8563_Library@^1.0.1 + https://github.com/Bei-Ji-Quan/st7789#b8e7e076714b670764139289d3829b0beff67edb \ No newline at end of file diff --git a/variants/heltec_mesh_node_t114/variant.cpp b/variants/heltec_mesh_node_t114/variant.cpp new file mode 100644 index 0000000000..cae079b749 --- /dev/null +++ b/variants/heltec_mesh_node_t114/variant.cpp @@ -0,0 +1,44 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 - pins 0 and 1 are hardwired for xtal and should never be enabled + 0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); + + pinMode(PIN_LED3, OUTPUT); + ledOff(PIN_LED3); +} diff --git a/variants/heltec_mesh_node_t114/variant.h b/variants/heltec_mesh_node_t114/variant.h new file mode 100644 index 0000000000..d6c11a01d5 --- /dev/null +++ b/variants/heltec_mesh_node_t114/variant.h @@ -0,0 +1,209 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_HELTEC_NRF_ +#define _VARIANT_HELTEC_NRF_ +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define HELTEC_MESH_NODE_T114 + +#define USE_ST7789 + +#define ST7789_NSS 11 +#define ST7789_RS 12 // DC +#define ST7789_SDA 41 // MOSI +#define ST7789_SCK 40 +#define ST7789_RESET 2 +#define ST7789_MISO -1 +#define ST7789_BUSY -1 +#define VTFT_CTRL 3 +#define VTFT_LEDA 15 +// #define ST7789_BL (32+6) +#define TFT_BACKLIGHT_ON LOW +#define ST7789_SPI_HOST SPI1_HOST +// #define ST7789_BACKLIGHT_EN (32+6) +#define SPI_FREQUENCY 40000000 +#define SPI_READ_FREQUENCY 16000000 +#define TFT_HEIGHT 135 +#define TFT_WIDTH 240 +#define TFT_OFFSET_X 0 +#define TFT_OFFSET_Y 0 +// #define TFT_OFFSET_ROTATION 0 +// #define SCREEN_ROTATE +// #define SCREEN_TRANSITION_FRAMERATE 5 + + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (1) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (32 + 3) // 13 red (confirmed on 1.0 board) +// Unused(by firmware) LEDs: +#define PIN_LED2 (1 + 1) // 14 blue +#define PIN_LED3 (1 + 11) // 15 green + +#define LED_RED PIN_LED3 +#define LED_BLUE PIN_LED1 +#define LED_GREEN PIN_LED2 + +#define LED_BUILTIN LED_BLUE +#define LED_CONN PIN_GREEN + +#define LED_STATE_ON 0 // State when LED is lit +#define LED_INVERTED 1 + +/* + * Buttons + */ +#define PIN_BUTTON1 (32 + 10) +//#define PIN_BUTTON2 (0 + 18) // 0.18 is labeled on the board as RESET but we configure it in the bootloader as a regular GPIO + +/* +No longer populated on PCB +*/ +#define PIN_SERIAL2_RX (0 + 9) +#define PIN_SERIAL2_TX (0 + 10) +// #define PIN_SERIAL2_EN (0 + 17) + +/** + Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (26) +#define PIN_WIRE_SCL (27) + + +// QSPI Pins +#define PIN_QSPI_SCK (32 + 14) +#define PIN_QSPI_CS (32 + 15) +#define PIN_QSPI_IO0 (32 + 12) // MOSI if using two bit interface +#define PIN_QSPI_IO1 (32 + 13) // MISO if using two bit interface +#define PIN_QSPI_IO2 (0 + 7) // WP if using two bit interface (i.e. not used) +#define PIN_QSPI_IO3 (0 + 5) // HOLD if using two bit interface (i.e. not used) + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES MX25R1635F +#define EXTERNAL_FLASH_USE_QSPI + +/* + * Lora radio + */ + +#define USE_SX1262 +// #define USE_SX1268 +#define SX126X_CS (0 + 24) // FIXME - we really should define LORA_CS instead +#define LORA_CS (0 + 24) +#define SX126X_DIO1 (0 + 20) +// Note DIO2 is attached internally to the module to an analog switch for TX/RX switching +//#define SX1262_DIO3 \ +// (0 + 21) // This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the main + // CPU? +#define SX126X_BUSY (0 + 17) +#define SX126X_RESET (0 + 25) +// Not really an E22 but TTGO seems to be trying to clone that +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +#define PIN_SPI1_MISO ST7789_MISO // FIXME not really needed, but for now the SPI code requires something to be defined, pick an used GPIO +#define PIN_SPI1_MOSI ST7789_SDA +#define PIN_SPI1_SCK ST7789_SCK + +/* + * GPS pins + */ + +#define GPS_L76K + +#define PIN_GPS_RESET (32 + 6) // An output to reset L76K GPS. As per datasheet, low for > 100ms will reset the L76K +#define GPS_RESET_MODE LOW +#define PIN_GPS_EN (21) +#define GPS_EN_ACTIVE HIGH +#define PIN_GPS_STANDBY (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake +#define PIN_GPS_PPS (32+4) +// Seems to be missing on this new board +// #define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS +#define GPS_TX_PIN (32 + 5) // This is for bits going TOWARDS the CPU +#define GPS_RX_PIN (32 + 7) // This is for bits going TOWARDS the GPS + +#define GPS_THREAD_INTERVAL 50 + +#define PIN_SERIAL1_RX GPS_TX_PIN +#define PIN_SERIAL1_TX GPS_RX_PIN + +// PCF8563 RTC Module +#define PCF8563_RTC 0x51 + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +// For LORA, spi 0 +#define PIN_SPI_MISO (0 + 23) +#define PIN_SPI_MOSI (0 + 22) +#define PIN_SPI_SCK (0 + 19) + +//#define PIN_PWR_EN (0 + 6) + +// To debug via the segger JLINK console rather than the CDC-ACM serial device +// #define USE_SEGGER + +// Battery +// The battery sense is hooked to pin A0 (4) +// it is defined in the anlaolgue pin section of this file +// and has 12 bit resolution + +#define ADC_CTRL 6 +#define ADC_CTRL_ENABLED HIGH +#define BATTERY_PIN 4 +#define ADC_RESOLUTION 14 + +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define BATTERY_SENSE_RESOLUTION 4096.0 +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER (4.90F) + +#define HAS_RTC 0 +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif \ No newline at end of file diff --git a/variants/heltec_vision_master_e213/pins_arduino.h b/variants/heltec_vision_master_e213/pins_arduino.h new file mode 100644 index 0000000000..01c16c496b --- /dev/null +++ b/variants/heltec_vision_master_e213/pins_arduino.h @@ -0,0 +1,63 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define HELTEC_VISION_MASTER_E213 true + +static const uint8_t LED_BUILTIN = 35; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 41; +static const uint8_t SCL = 42; + +static const uint8_t SS = 8; +static const uint8_t MOSI = 10; +static const uint8_t MISO = 11; +static const uint8_t SCK = 9; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +static const uint8_t RST_LoRa = 12; +static const uint8_t BUSY_LoRa = 13; +static const uint8_t DIO0 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/heltec_vision_master_e213/platformio.ini b/variants/heltec_vision_master_e213/platformio.ini new file mode 100644 index 0000000000..1044974c0a --- /dev/null +++ b/variants/heltec_vision_master_e213/platformio.ini @@ -0,0 +1,23 @@ +[env:heltec-vision-master-e213] +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +build_flags = + ${esp32s3_base.build_flags} + -I variants/heltec_vision_master_e213 + -D HELTEC_VISION_MASTER_E213 + -D EINK_DISPLAY_MODEL=GxEPD2_213_FC1 + -D EINK_WIDTH=250 + -D EINK_HEIGHT=122 + -D USE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk + -D EINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted + -D EINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates + -D EINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates +; -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated + -D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. + -D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" + -D EINK_HASQUIRK_WEAKFASTREFRESH ; Pixels set with fast-refresh are easy to clear, disrupted by sunlight +lib_deps = + ${esp32s3_base.lib_deps} + https://github.com/meshtastic/GxEPD2#b202ebfec6a4821e098cf7a625ba0f6f2400292d + lewisxhe/PCF8563_Library@^1.0.1 +upload_speed = 115200 \ No newline at end of file diff --git a/variants/heltec_vision_master_e213/variant.h b/variants/heltec_vision_master_e213/variant.h new file mode 100644 index 0000000000..6a57a0dd6f --- /dev/null +++ b/variants/heltec_vision_master_e213/variant.h @@ -0,0 +1,58 @@ +// #define LED_PIN 18 + +// Enable bus for external periherals +#define I2C_SDA SDA +#define I2C_SCL SCL + +#define USE_EINK + +/* + * eink display pins + */ +#define PIN_EINK_CS 5 +#define PIN_EINK_BUSY 1 +#define PIN_EINK_DC 2 +#define PIN_EINK_RES 3 +#define PIN_EINK_SCLK 4 +#define PIN_EINK_MOSI 6 + +/* + * SPI interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO 10 // MISO P0.17 +#define PIN_SPI_MOSI 11 // MOSI P0.15 +#define PIN_SPI_SCK 9 // SCK P0.13 + +#define VEXT_ENABLE 18 // powers the oled display and the lora antenna boost +#define VEXT_ON_VALUE 1 +#define BUTTON_PIN 21 + +#define ADC_CTRL 46 +#define ADC_CTRL_ENABLED HIGH +#define BATTERY_PIN 7 +#define ADC_CHANNEL ADC1_GPIO7_CHANNEL +#define ADC_MULTIPLIER 4.9*1.03 // Voltage divider is roughly 1:1 +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high + +#define USE_SX1262 + +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define LORA_SCK 9 +#define LORA_MISO 11 +#define LORA_MOSI 10 +#define LORA_CS 8 + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET + +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 \ No newline at end of file diff --git a/variants/heltec_vision_master_e290/pins_arduino.h b/variants/heltec_vision_master_e290/pins_arduino.h new file mode 100644 index 0000000000..a9b474c317 --- /dev/null +++ b/variants/heltec_vision_master_e290/pins_arduino.h @@ -0,0 +1,63 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define HELTEC_VISION_MASTER_E290 true + +static const uint8_t LED_BUILTIN = 35; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 41; +static const uint8_t SCL = 42; + +static const uint8_t SS = 8; +static const uint8_t MOSI = 10; +static const uint8_t MISO = 11; +static const uint8_t SCK = 9; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +static const uint8_t RST_LoRa = 12; +static const uint8_t BUSY_LoRa = 13; +static const uint8_t DIO0 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/heltec_vision_master_e290/platformio.ini b/variants/heltec_vision_master_e290/platformio.ini new file mode 100644 index 0000000000..fa89af32b5 --- /dev/null +++ b/variants/heltec_vision_master_e290/platformio.ini @@ -0,0 +1,24 @@ +[env:heltec-vision-master-e290] +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +build_flags = + ${esp32s3_base.build_flags} + -I variants/heltec_vision_master_e290 + -D HELTEC_VISION_MASTER_E290 + -D EINK_DISPLAY_MODEL=GxEPD2_290_BS + -D EINK_WIDTH=296 + -D EINK_HEIGHT=128 +; -D USE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk +; -D EINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted +; -D EINK_LIMIT_RATE_BACKGROUND_SEC=1 ; Minimum interval between BACKGROUND updates +; -D EINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates +; -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated +; -D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. +; -D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" +; -D EINK_HASQUIRK_WEAKFASTREFRESH ; Pixels set with fast-refresh are easy to clear, disrupted by sunlight + +lib_deps = + ${esp32s3_base.lib_deps} + https://github.com/meshtastic/GxEPD2#b202ebfec6a4821e098cf7a625ba0f6f2400292d + lewisxhe/PCF8563_Library@^1.0.1 +upload_speed = 115200 \ No newline at end of file diff --git a/variants/heltec_vision_master_e290/variant.h b/variants/heltec_vision_master_e290/variant.h new file mode 100644 index 0000000000..5b16d7b8fa --- /dev/null +++ b/variants/heltec_vision_master_e290/variant.h @@ -0,0 +1,58 @@ +// #define LED_PIN 18 + +// Enable bus for external periherals +#define I2C_SDA SDA +#define I2C_SCL SCL + +#define USE_EINK + +/* + * eink display pins + */ +#define PIN_EINK_CS 3 +#define PIN_EINK_BUSY 5 +#define PIN_EINK_DC 4 +#define PIN_EINK_RES 5 +#define PIN_EINK_SCLK 2 +#define PIN_EINK_MOSI 1 + +/* + * SPI interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO 10 // MISO +#define PIN_SPI_MOSI 11 // MOSI +#define PIN_SPI_SCK 9 // SCK + +#define VEXT_ENABLE 18 // powers the e-ink display +#define VEXT_ON_VALUE 1 +#define BUTTON_PIN 21 + +#define ADC_CTRL 46 +#define ADC_CTRL_ENABLED HIGH +#define BATTERY_PIN 7 +#define ADC_CHANNEL ADC1_GPIO7_CHANNEL +#define ADC_MULTIPLIER 4.9*1.03 +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high + +#define USE_SX1262 + +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define LORA_SCK 9 +#define LORA_MISO 11 +#define LORA_MOSI 10 +#define LORA_CS 8 + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET + +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 \ No newline at end of file diff --git a/variants/heltec_vision_master_t190/pins_arduino.h b/variants/heltec_vision_master_t190/pins_arduino.h new file mode 100644 index 0000000000..473187a026 --- /dev/null +++ b/variants/heltec_vision_master_t190/pins_arduino.h @@ -0,0 +1,63 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define HELTEC_VISION_MASTER_T190 true + +static const uint8_t LED_BUILTIN = 35; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 41; +static const uint8_t SCL = 42; + +static const uint8_t SS = 8; +static const uint8_t MOSI = 10; +static const uint8_t MISO = 11; +static const uint8_t SCK = 9; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +static const uint8_t RST_LoRa = 12; +static const uint8_t BUSY_LoRa = 13; +static const uint8_t DIO0 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/heltec_vision_master_t190/platformio.ini b/variants/heltec_vision_master_t190/platformio.ini new file mode 100644 index 0000000000..7ed64f5e03 --- /dev/null +++ b/variants/heltec_vision_master_t190/platformio.ini @@ -0,0 +1,13 @@ +[env:heltec-vision-master-t190] +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +build_flags = + ${esp32s3_base.build_flags} + -I variants/heltec_vision_master_t190 + -D PRIVATE_HW + ; -D PRIVATE_HW +lib_deps = + ${esp32s3_base.lib_deps} + lewisxhe/PCF8563_Library@^1.0.1 + https://github.com/Bei-Ji-Quan/st7789#b8e7e076714b670764139289d3829b0beff67edb +upload_speed = 921600 \ No newline at end of file diff --git a/variants/heltec_vision_master_t190/variant.h b/variants/heltec_vision_master_t190/variant.h new file mode 100644 index 0000000000..01830d7198 --- /dev/null +++ b/variants/heltec_vision_master_t190/variant.h @@ -0,0 +1,78 @@ +// #define LED_PIN 18 + +// Enable bus for external periherals +#define I2C_SDA 1 +#define I2C_SCL 2 +#define USE_ST7789 + +#define ST7789_NSS 39 +// #define ST7789_CS 39 +#define ST7789_RS 47 // DC +#define ST7789_SDA 48 // MOSI +#define ST7789_SCK 38 +#define ST7789_RESET 40 +#define ST7789_MISO 4 +#define ST7789_BUSY -1 +#define VTFT_CTRL 7 +// #define TFT_BL 3 +#define VTFT_LEDA 17 +#define TFT_BACKLIGHT_ON HIGH +// #define TFT_BL 17 +// #define TFT_BACKLIGHT_ON HIGH +// #define ST7789_BL 3 +#define ST7789_SPI_HOST SPI2_HOST +// #define ST7789_BACKLIGHT_EN 17 +#define SPI_FREQUENCY 10000000 +#define SPI_READ_FREQUENCY 10000000 +#define TFT_HEIGHT 170 +#define TFT_WIDTH 320 +#define TFT_OFFSET_X 0 +#define TFT_OFFSET_Y 0 +// #define TFT_OFFSET_ROTATION 0 +// #define SCREEN_ROTATE +// #define SCREEN_TRANSITION_FRAMERATE 5 +#define BRIGHTNESS_DEFAULT 100 // Medium Low Brightnes + + +// #define SLEEP_TIME 120 + + +/* + * SPI interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO 10 // MISO P0.17 +#define PIN_SPI_MOSI 11 // MOSI P0.15 +#define PIN_SPI_SCK 9 // SCK P0.13 + +// #define VEXT_ENABLE 7 // active low, powers the oled display and the lora antenna boost +#define BUTTON_PIN 0 + +#define ADC_CTRL 46 +#define ADC_CTRL_ENABLED HIGH +#define BATTERY_PIN 6 +#define ADC_CHANNEL ADC1_GPIO6_CHANNEL +#define ADC_MULTIPLIER 4.9*1.03 // Voltage divider is roughly 1:1 +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high + +#define USE_SX1262 + +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define LORA_SCK 9 +#define LORA_MISO 11 +#define LORA_MOSI 10 +#define LORA_CS 8 + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET + +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 \ No newline at end of file diff --git a/variants/heltec_wireless_paper/pins_arduino.h b/variants/heltec_wireless_paper/pins_arduino.h index 2bb44161ab..3e36d98f56 100644 --- a/variants/heltec_wireless_paper/pins_arduino.h +++ b/variants/heltec_wireless_paper/pins_arduino.h @@ -7,8 +7,6 @@ static const uint8_t LED_BUILTIN = 18; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN -static const uint8_t KEY_BUILTIN = 0; - static const uint8_t TX = 43; static const uint8_t RX = 44; @@ -56,9 +54,6 @@ static const uint8_t T12 = 12; static const uint8_t T13 = 13; static const uint8_t T14 = 14; -static const uint8_t Vext = 45; -static const uint8_t LED = 18; - static const uint8_t RST_LoRa = 12; static const uint8_t BUSY_LoRa = 13; static const uint8_t DIO1 = 14; From 9ad0addbbf8288bc15c8aa91c14db1cb5bc27c13 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 9 Jul 2024 12:07:23 -0500 Subject: [PATCH 139/211] [create-pull-request] automated change (#4259) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/config.pb.h | 10 +++++++--- src/mesh/generated/meshtastic/deviceonly.pb.h | 2 +- src/mesh/generated/meshtastic/localonly.pb.h | 4 ++-- src/mesh/generated/meshtastic/module_config.pb.h | 12 ++++++++---- 6 files changed, 20 insertions(+), 12 deletions(-) diff --git a/protobufs b/protobufs index 1198b7dbab..d191975ebc 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 1198b7dbabf9768cb0143d2897707b4c7a51a5da +Subproject commit d191975ebc572527c6d9eec48d5b0a1e3331999f diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index ba9f90873b..f5bacea52d 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 674 +#define meshtastic_ChannelSet_size 676 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index e3037c910d..44a86f4d64 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -497,6 +497,8 @@ typedef struct _meshtastic_Config_LoRaConfig { Please respect your local laws and regulations. If you are a HAM, make sure you enable HAM mode and turn off encryption. */ float override_frequency; + /* If true, disable the build-in PA FAN using pin define in RF95_FAN_EN. */ + bool pa_fan_disabled; /* For testing it is useful sometimes to force a node to never listen to particular other nodes (simulating radio out of range). All nodenums listed in ignore_incoming will have packets they send dropped on receive (by router.cpp) */ @@ -618,7 +620,7 @@ extern "C" { #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} -#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} +#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} #define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} #define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}} #define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} @@ -627,7 +629,7 @@ extern "C" { #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} -#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} +#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} #define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} /* Field tags (for use in manual encoding/decoding) */ @@ -702,6 +704,7 @@ extern "C" { #define meshtastic_Config_LoRaConfig_override_duty_cycle_tag 12 #define meshtastic_Config_LoRaConfig_sx126x_rx_boosted_gain_tag 13 #define meshtastic_Config_LoRaConfig_override_frequency_tag 14 +#define meshtastic_Config_LoRaConfig_pa_fan_disabled_tag 15 #define meshtastic_Config_LoRaConfig_ignore_incoming_tag 103 #define meshtastic_Config_LoRaConfig_ignore_mqtt_tag 104 #define meshtastic_Config_BluetoothConfig_enabled_tag 1 @@ -832,6 +835,7 @@ X(a, STATIC, SINGULAR, UINT32, channel_num, 11) \ X(a, STATIC, SINGULAR, BOOL, override_duty_cycle, 12) \ X(a, STATIC, SINGULAR, BOOL, sx126x_rx_boosted_gain, 13) \ X(a, STATIC, SINGULAR, FLOAT, override_frequency, 14) \ +X(a, STATIC, SINGULAR, BOOL, pa_fan_disabled, 15) \ X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \ X(a, STATIC, SINGULAR, BOOL, ignore_mqtt, 104) #define meshtastic_Config_LoRaConfig_CALLBACK NULL @@ -871,7 +875,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; #define meshtastic_Config_BluetoothConfig_size 12 #define meshtastic_Config_DeviceConfig_size 100 #define meshtastic_Config_DisplayConfig_size 30 -#define meshtastic_Config_LoRaConfig_size 80 +#define meshtastic_Config_LoRaConfig_size 82 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 196 #define meshtastic_Config_PositionConfig_size 62 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index fc7bea53a4..eb37f4f957 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -307,7 +307,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size #define meshtastic_ChannelFile_size 718 #define meshtastic_NodeInfoLite_size 166 -#define meshtastic_OEMStore_size 3384 +#define meshtastic_OEMStore_size 3388 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index c1d2a4ae3e..983f48ad3f 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -181,8 +181,8 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size -#define meshtastic_LocalConfig_size 553 -#define meshtastic_LocalModuleConfig_size 685 +#define meshtastic_LocalConfig_size 555 +#define meshtastic_LocalModuleConfig_size 687 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index f3c48ee6df..12087655ab 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -273,6 +273,8 @@ typedef struct _meshtastic_ModuleConfig_StoreForwardConfig { uint32_t history_return_max; /* TODO: REPLACE */ uint32_t history_return_window; + /* Set to true to let this node act as a server that stores received messages and resends them upon request. */ + bool is_server; } meshtastic_ModuleConfig_StoreForwardConfig; /* Preferences for the RangeTestModule */ @@ -474,7 +476,7 @@ extern "C" { #define meshtastic_ModuleConfig_PaxcounterConfig_init_default {0, 0, 0, 0} #define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0} #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0} #define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} @@ -490,7 +492,7 @@ extern "C" { #define meshtastic_ModuleConfig_PaxcounterConfig_init_zero {0, 0, 0, 0} #define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0} #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0} #define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} @@ -560,6 +562,7 @@ extern "C" { #define meshtastic_ModuleConfig_StoreForwardConfig_records_tag 3 #define meshtastic_ModuleConfig_StoreForwardConfig_history_return_max_tag 4 #define meshtastic_ModuleConfig_StoreForwardConfig_history_return_window_tag 5 +#define meshtastic_ModuleConfig_StoreForwardConfig_is_server_tag 6 #define meshtastic_ModuleConfig_RangeTestConfig_enabled_tag 1 #define meshtastic_ModuleConfig_RangeTestConfig_sender_tag 2 #define meshtastic_ModuleConfig_RangeTestConfig_save_tag 3 @@ -743,7 +746,8 @@ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ X(a, STATIC, SINGULAR, BOOL, heartbeat, 2) \ X(a, STATIC, SINGULAR, UINT32, records, 3) \ X(a, STATIC, SINGULAR, UINT32, history_return_max, 4) \ -X(a, STATIC, SINGULAR, UINT32, history_return_window, 5) +X(a, STATIC, SINGULAR, UINT32, history_return_window, 5) \ +X(a, STATIC, SINGULAR, BOOL, is_server, 6) #define meshtastic_ModuleConfig_StoreForwardConfig_CALLBACK NULL #define meshtastic_ModuleConfig_StoreForwardConfig_DEFAULT NULL @@ -848,7 +852,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_RangeTestConfig_size 10 #define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96 #define meshtastic_ModuleConfig_SerialConfig_size 28 -#define meshtastic_ModuleConfig_StoreForwardConfig_size 22 +#define meshtastic_ModuleConfig_StoreForwardConfig_size 24 #define meshtastic_ModuleConfig_TelemetryConfig_size 36 #define meshtastic_ModuleConfig_size 257 #define meshtastic_RemoteHardwarePin_size 21 From ba8d17b9c12f39f4bce1d15bc868a6be042fc82f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 9 Jul 2024 12:16:56 -0500 Subject: [PATCH 140/211] Trunk fmt --- src/Power.cpp | 12 ++++---- src/graphics/EInkDisplay2.cpp | 3 +- src/graphics/EInkDisplay2.h | 3 +- src/graphics/Screen.cpp | 17 ++++++----- src/main.cpp | 3 +- src/mesh/NodeDB.cpp | 3 +- src/sleep.cpp | 2 +- variants/heltec_capsule_sensor_v3/variant.h | 2 +- variants/heltec_mesh_node_t114/variant.h | 31 ++++++++++---------- variants/heltec_vision_master_e213/variant.h | 2 +- variants/heltec_vision_master_e290/variant.h | 8 ++--- variants/heltec_vision_master_t190/variant.h | 4 +-- 12 files changed, 47 insertions(+), 43 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 78024ee0c6..950ea741d8 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -232,11 +232,11 @@ class AnalogBatteryLevel : public HasBatteryLevel raw = espAdcRead(); scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs); scaled *= operativeAdcMultiplier; -#else // block for all other platforms -#ifdef ADC_CTRL // enable adc voltage divider when we need to read - pinMode(ADC_CTRL, OUTPUT); - digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED); - delay(10); +#else // block for all other platforms +#ifdef ADC_CTRL // enable adc voltage divider when we need to read + pinMode(ADC_CTRL, OUTPUT); + digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED); + delay(10); #endif for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) { raw += analogRead(BATTERY_PIN); @@ -244,7 +244,7 @@ class AnalogBatteryLevel : public HasBatteryLevel raw = raw / BATTERY_SENSE_SAMPLES; scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw; #ifdef ADC_CTRL // disable adc voltage divider when we need to read - digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED); + digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED); #endif #endif diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index 191c46e67f..d81ab6ff4e 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -156,7 +156,8 @@ bool EInkDisplay::connect() } } -#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || defined(HELTEC_VISION_MASTER_E290) +#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || \ + defined(HELTEC_VISION_MASTER_E290) { // Start HSPI hspi = new SPIClass(HSPI); diff --git a/src/graphics/EInkDisplay2.h b/src/graphics/EInkDisplay2.h index 426bb5f191..26091b2cd2 100644 --- a/src/graphics/EInkDisplay2.h +++ b/src/graphics/EInkDisplay2.h @@ -67,7 +67,8 @@ class EInkDisplay : public OLEDDisplay GxEPD2_BW *adafruitDisplay = NULL; // If display uses HSPI -#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || defined(HELTEC_VISION_MASTER_E290) +#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \ + defined(HELTEC_VISION_MASTER_E290) SPIClass *hspi = NULL; #endif diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 86d71dfde2..7f9c905a88 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1498,9 +1498,10 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); #elif defined(USE_ST7789) #ifdef ESP_PLATFORM - dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS,GEOMETRY_RAWMODE,TFT_WIDTH,TFT_HEIGHT,ST7789_SDA,ST7789_MISO,ST7789_SCK); + dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT, ST7789_SDA, + ST7789_MISO, ST7789_SCK); #else - dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS,GEOMETRY_RAWMODE,TFT_WIDTH,TFT_HEIGHT); + dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); #endif #elif defined(USE_SSD1306) dispdev = new SSD1306Wire(address.address, -1, -1, geometry, @@ -1582,10 +1583,10 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) dispdev->displayOn(); #ifdef USE_ST7789 #ifdef ESP_PLATFORM - analogWrite(VTFT_LEDA,BRIGHTNESS_DEFAULT); + analogWrite(VTFT_LEDA, BRIGHTNESS_DEFAULT); #else - pinMode(VTFT_LEDA,OUTPUT); - digitalWrite(VTFT_LEDA,TFT_BACKLIGHT_ON); + pinMode(VTFT_LEDA, OUTPUT); + digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON); #endif #endif enabled = true; @@ -1600,8 +1601,8 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) dispdev->displayOff(); #ifdef USE_ST7789 - pinMode(VTFT_LEDA,OUTPUT); - digitalWrite(VTFT_LEDA,!TFT_BACKLIGHT_ON); + pinMode(VTFT_LEDA, OUTPUT); + digitalWrite(VTFT_LEDA, !TFT_BACKLIGHT_ON); #endif #ifdef T_WATCH_S3 @@ -1618,7 +1619,7 @@ void Screen::setup() // We don't set useDisplay until setup() is called, because some boards have a declaration of this object but the device // is never found when probing i2c and therefore we don't call setup and never want to do (invalid) accesses to this device. useDisplay = true; - + #ifdef AutoOLEDWire_h if (isAUTOOled) static_cast(dispdev)->setDetected(model); diff --git a/src/main.cpp b/src/main.cpp index 95af5f6de5..95eeb998d9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -716,7 +716,8 @@ void setup() // Don't call screen setup until after nodedb is setup (because we need // the current region name) -#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) +#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || \ + defined(USE_ST7789) screen->setup(); #elif defined(ARCH_PORTDUINO) if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) { diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 07184a6bcf..fa5c437c42 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -268,7 +268,8 @@ void NodeDB::installDefaultConfig() // FIXME: Default to bluetooth capability of platform as default config.bluetooth.enabled = true; config.bluetooth.fixed_pin = defaultBLEPin; -#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || defined(USE_ST7789) +#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || \ + defined(USE_ST7789) bool hasScreen = true; #elif ARCH_PORTDUINO bool hasScreen = false; diff --git a/src/sleep.cpp b/src/sleep.cpp index 3918568a0a..721c7d1880 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -258,7 +258,7 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) digitalWrite(VEXT_ENABLE_V05, 0); // turn off the lora amplifier power digitalWrite(ST7735_BL_V05, 0); // turn off the display power #elif defined(VEXT_ENABLE) && defined(VEXT_ON_VALUE) - digitalWrite(VEXT_ENABLE, !VEXT_ON_VALUE); // turn on the display power + digitalWrite(VEXT_ENABLE, !VEXT_ON_VALUE); // turn on the display power #elif defined(VEXT_ENABLE) digitalWrite(VEXT_ENABLE, 1); // turn off the display power #endif diff --git a/variants/heltec_capsule_sensor_v3/variant.h b/variants/heltec_capsule_sensor_v3/variant.h index 0d5ab73cfb..51c3cb6adc 100644 --- a/variants/heltec_capsule_sensor_v3/variant.h +++ b/variants/heltec_capsule_sensor_v3/variant.h @@ -1,5 +1,5 @@ #define LED_PIN 33 -#define LED_PIN2 34 +#define LED_PIN2 34 #define EXT_PWR_DETECT 35 #define BUTTON_PIN 18 diff --git a/variants/heltec_mesh_node_t114/variant.h b/variants/heltec_mesh_node_t114/variant.h index d6c11a01d5..b233069c63 100644 --- a/variants/heltec_mesh_node_t114/variant.h +++ b/variants/heltec_mesh_node_t114/variant.h @@ -53,14 +53,13 @@ extern "C" { #define SPI_FREQUENCY 40000000 #define SPI_READ_FREQUENCY 16000000 #define TFT_HEIGHT 135 -#define TFT_WIDTH 240 +#define TFT_WIDTH 240 #define TFT_OFFSET_X 0 #define TFT_OFFSET_Y 0 // #define TFT_OFFSET_ROTATION 0 // #define SCREEN_ROTATE // #define SCREEN_TRANSITION_FRAMERATE 5 - // Number of pins defined in PinDescription array #define PINS_COUNT (48) #define NUM_DIGITAL_PINS (48) @@ -70,7 +69,7 @@ extern "C" { // LEDs #define PIN_LED1 (32 + 3) // 13 red (confirmed on 1.0 board) // Unused(by firmware) LEDs: -#define PIN_LED2 (1 + 1) // 14 blue +#define PIN_LED2 (1 + 1) // 14 blue #define PIN_LED3 (1 + 11) // 15 green #define LED_RED PIN_LED3 @@ -87,7 +86,8 @@ extern "C" { * Buttons */ #define PIN_BUTTON1 (32 + 10) -//#define PIN_BUTTON2 (0 + 18) // 0.18 is labeled on the board as RESET but we configure it in the bootloader as a regular GPIO +// #define PIN_BUTTON2 (0 + 18) // 0.18 is labeled on the board as RESET but we configure it in the bootloader as a regular +// GPIO /* No longer populated on PCB @@ -104,7 +104,6 @@ No longer populated on PCB #define PIN_WIRE_SDA (26) #define PIN_WIRE_SCL (27) - // QSPI Pins #define PIN_QSPI_SCK (32 + 14) #define PIN_QSPI_CS (32 + 15) @@ -124,21 +123,23 @@ No longer populated on PCB #define USE_SX1262 // #define USE_SX1268 #define SX126X_CS (0 + 24) // FIXME - we really should define LORA_CS instead -#define LORA_CS (0 + 24) +#define LORA_CS (0 + 24) #define SX126X_DIO1 (0 + 20) // Note DIO2 is attached internally to the module to an analog switch for TX/RX switching -//#define SX1262_DIO3 \ -// (0 + 21) // This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the main - // CPU? +// #define SX1262_DIO3 \ +// (0 + 21) // This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the +// main +// CPU? #define SX126X_BUSY (0 + 17) #define SX126X_RESET (0 + 25) // Not really an E22 but TTGO seems to be trying to clone that #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#define PIN_SPI1_MISO ST7789_MISO // FIXME not really needed, but for now the SPI code requires something to be defined, pick an used GPIO -#define PIN_SPI1_MOSI ST7789_SDA -#define PIN_SPI1_SCK ST7789_SCK +#define PIN_SPI1_MISO \ + ST7789_MISO // FIXME not really needed, but for now the SPI code requires something to be defined, pick an used GPIO +#define PIN_SPI1_MOSI ST7789_SDA +#define PIN_SPI1_SCK ST7789_SCK /* * GPS pins @@ -146,12 +147,12 @@ No longer populated on PCB #define GPS_L76K -#define PIN_GPS_RESET (32 + 6) // An output to reset L76K GPS. As per datasheet, low for > 100ms will reset the L76K +#define PIN_GPS_RESET (32 + 6) // An output to reset L76K GPS. As per datasheet, low for > 100ms will reset the L76K #define GPS_RESET_MODE LOW #define PIN_GPS_EN (21) #define GPS_EN_ACTIVE HIGH #define PIN_GPS_STANDBY (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake -#define PIN_GPS_PPS (32+4) +#define PIN_GPS_PPS (32 + 4) // Seems to be missing on this new board // #define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS #define GPS_TX_PIN (32 + 5) // This is for bits going TOWARDS the CPU @@ -175,7 +176,7 @@ No longer populated on PCB #define PIN_SPI_MOSI (0 + 22) #define PIN_SPI_SCK (0 + 19) -//#define PIN_PWR_EN (0 + 6) +// #define PIN_PWR_EN (0 + 6) // To debug via the segger JLINK console rather than the CDC-ACM serial device // #define USE_SEGGER diff --git a/variants/heltec_vision_master_e213/variant.h b/variants/heltec_vision_master_e213/variant.h index 6a57a0dd6f..169602a0d7 100644 --- a/variants/heltec_vision_master_e213/variant.h +++ b/variants/heltec_vision_master_e213/variant.h @@ -33,7 +33,7 @@ #define ADC_CTRL_ENABLED HIGH #define BATTERY_PIN 7 #define ADC_CHANNEL ADC1_GPIO7_CHANNEL -#define ADC_MULTIPLIER 4.9*1.03 // Voltage divider is roughly 1:1 +#define ADC_MULTIPLIER 4.9 * 1.03 // Voltage divider is roughly 1:1 #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high #define USE_SX1262 diff --git a/variants/heltec_vision_master_e290/variant.h b/variants/heltec_vision_master_e290/variant.h index 5b16d7b8fa..a122a7e0fa 100644 --- a/variants/heltec_vision_master_e290/variant.h +++ b/variants/heltec_vision_master_e290/variant.h @@ -21,9 +21,9 @@ */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO 10 // MISO -#define PIN_SPI_MOSI 11 // MOSI -#define PIN_SPI_SCK 9 // SCK +#define PIN_SPI_MISO 10 // MISO +#define PIN_SPI_MOSI 11 // MOSI +#define PIN_SPI_SCK 9 // SCK #define VEXT_ENABLE 18 // powers the e-ink display #define VEXT_ON_VALUE 1 @@ -33,7 +33,7 @@ #define ADC_CTRL_ENABLED HIGH #define BATTERY_PIN 7 #define ADC_CHANNEL ADC1_GPIO7_CHANNEL -#define ADC_MULTIPLIER 4.9*1.03 +#define ADC_MULTIPLIER 4.9 * 1.03 #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high #define USE_SX1262 diff --git a/variants/heltec_vision_master_t190/variant.h b/variants/heltec_vision_master_t190/variant.h index 01830d7198..97500d357e 100644 --- a/variants/heltec_vision_master_t190/variant.h +++ b/variants/heltec_vision_master_t190/variant.h @@ -33,10 +33,8 @@ // #define SCREEN_TRANSITION_FRAMERATE 5 #define BRIGHTNESS_DEFAULT 100 // Medium Low Brightnes - // #define SLEEP_TIME 120 - /* * SPI interfaces */ @@ -53,7 +51,7 @@ #define ADC_CTRL_ENABLED HIGH #define BATTERY_PIN 6 #define ADC_CHANNEL ADC1_GPIO6_CHANNEL -#define ADC_MULTIPLIER 4.9*1.03 // Voltage divider is roughly 1:1 +#define ADC_MULTIPLIER 4.9 * 1.03 // Voltage divider is roughly 1:1 #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high #define USE_SX1262 From e74d77dc44baac4aaa820d9cb08f319d8e309f8f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 9 Jul 2024 15:11:11 -0500 Subject: [PATCH 141/211] Fix macros --- .../heltec_vision_master_e213/platformio.ini | 24 +++++++++---------- .../heltec_vision_master_e290/pins_arduino.h | 2 -- .../heltec_vision_master_e290/platformio.ini | 10 ++++---- .../heltec_vision_master_t190/pins_arduino.h | 2 -- .../heltec_vision_master_t190/platformio.ini | 4 ++-- 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/variants/heltec_vision_master_e213/platformio.ini b/variants/heltec_vision_master_e213/platformio.ini index 1044974c0a..77cc659834 100644 --- a/variants/heltec_vision_master_e213/platformio.ini +++ b/variants/heltec_vision_master_e213/platformio.ini @@ -3,19 +3,19 @@ extends = esp32s3_base board = heltec_wifi_lora_32_V3 build_flags = ${esp32s3_base.build_flags} - -I variants/heltec_vision_master_e213 - -D HELTEC_VISION_MASTER_E213 - -D EINK_DISPLAY_MODEL=GxEPD2_213_FC1 - -D EINK_WIDTH=250 - -D EINK_HEIGHT=122 - -D USE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk - -D EINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted - -D EINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates - -D EINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates + -Ivariants/heltec_vision_master_e213 + -DHELTEC_VISION_MASTER_E213 + -DEINK_DISPLAY_MODEL=GxEPD2_213_FC1 + -DEINK_WIDTH=250 + -DEINK_HEIGHT=122 + -DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk + -DEINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted + -DEINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates + -DEINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates ; -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated - -D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. - -D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" - -D EINK_HASQUIRK_WEAKFASTREFRESH ; Pixels set with fast-refresh are easy to clear, disrupted by sunlight + -DEINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. + -DEINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" + -DEINK_HASQUIRK_WEAKFASTREFRESH ; Pixels set with fast-refresh are easy to clear, disrupted by sunlight lib_deps = ${esp32s3_base.lib_deps} https://github.com/meshtastic/GxEPD2#b202ebfec6a4821e098cf7a625ba0f6f2400292d diff --git a/variants/heltec_vision_master_e290/pins_arduino.h b/variants/heltec_vision_master_e290/pins_arduino.h index a9b474c317..e5d5078463 100644 --- a/variants/heltec_vision_master_e290/pins_arduino.h +++ b/variants/heltec_vision_master_e290/pins_arduino.h @@ -3,8 +3,6 @@ #include -#define HELTEC_VISION_MASTER_E290 true - static const uint8_t LED_BUILTIN = 35; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN diff --git a/variants/heltec_vision_master_e290/platformio.ini b/variants/heltec_vision_master_e290/platformio.ini index fa89af32b5..8deecf6288 100644 --- a/variants/heltec_vision_master_e290/platformio.ini +++ b/variants/heltec_vision_master_e290/platformio.ini @@ -3,11 +3,11 @@ extends = esp32s3_base board = heltec_wifi_lora_32_V3 build_flags = ${esp32s3_base.build_flags} - -I variants/heltec_vision_master_e290 - -D HELTEC_VISION_MASTER_E290 - -D EINK_DISPLAY_MODEL=GxEPD2_290_BS - -D EINK_WIDTH=296 - -D EINK_HEIGHT=128 + -Ivariants/heltec_vision_master_e290 + -DHELTEC_VISION_MASTER_E290 + -DEINK_DISPLAY_MODEL=GxEPD2_290_BS + -DEINK_WIDTH=296 + -DEINK_HEIGHT=128 ; -D USE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk ; -D EINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted ; -D EINK_LIMIT_RATE_BACKGROUND_SEC=1 ; Minimum interval between BACKGROUND updates diff --git a/variants/heltec_vision_master_t190/pins_arduino.h b/variants/heltec_vision_master_t190/pins_arduino.h index 473187a026..e5d5078463 100644 --- a/variants/heltec_vision_master_t190/pins_arduino.h +++ b/variants/heltec_vision_master_t190/pins_arduino.h @@ -3,8 +3,6 @@ #include -#define HELTEC_VISION_MASTER_T190 true - static const uint8_t LED_BUILTIN = 35; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN diff --git a/variants/heltec_vision_master_t190/platformio.ini b/variants/heltec_vision_master_t190/platformio.ini index 7ed64f5e03..bbaa0075c5 100644 --- a/variants/heltec_vision_master_t190/platformio.ini +++ b/variants/heltec_vision_master_t190/platformio.ini @@ -3,8 +3,8 @@ extends = esp32s3_base board = heltec_wifi_lora_32_V3 build_flags = ${esp32s3_base.build_flags} - -I variants/heltec_vision_master_t190 - -D PRIVATE_HW + -Ivariants/heltec_vision_master_t190 + -DHELTEC_VISION_MASTER_T190 ; -D PRIVATE_HW lib_deps = ${esp32s3_base.lib_deps} From 8048fab08410464e09f8d30dc597fadb2775de37 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 10 Jul 2024 07:28:29 -0500 Subject: [PATCH 142/211] Move e290 to board level extra while CI is broken --- variants/heltec_vision_master_e290/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/heltec_vision_master_e290/platformio.ini b/variants/heltec_vision_master_e290/platformio.ini index 8deecf6288..60ff60036a 100644 --- a/variants/heltec_vision_master_e290/platformio.ini +++ b/variants/heltec_vision_master_e290/platformio.ini @@ -1,4 +1,5 @@ [env:heltec-vision-master-e290] +board_level = extra extends = esp32s3_base board = heltec_wifi_lora_32_V3 build_flags = From 5c71187db1e50ceddc976aada5ab67d90e55c4ad Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 10 Jul 2024 07:34:41 -0500 Subject: [PATCH 143/211] Tell trunk to ignore bin folder --- .trunk/trunk.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 8a2f18ad5d..cbb4d83c96 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -1,6 +1,6 @@ version: 0.1 cli: - version: 1.22.1 + version: 1.22.2 plugins: sources: - id: trunk @@ -31,6 +31,9 @@ lint: - gitleaks@8.18.2 - clang-format@16.0.3 - prettier@3.2.5 +ignore: + - linters: [ALL] + paths: bin/** runtimes: enabled: - python@3.10.8 From c887675bb48a254608e9c9adb3f01f4cb39cc57a Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 10 Jul 2024 09:35:18 -0500 Subject: [PATCH 144/211] Fix missing --- .github/actions/setup-base/action.yml | 2 +- .github/workflows/build_native.yml | 2 +- .github/workflows/build_raspbian.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml index b5b4cb6f30..7f8659523b 100644 --- a/.github/actions/setup-base/action.yml +++ b/.github/actions/setup-base/action.yml @@ -14,7 +14,7 @@ runs: - name: Install dependencies shell: bash run: | - sudo apt-get -y update + sudo apt-get -y update --fix-missing sudo apt-get install -y cppcheck libbluetooth-dev libgpiod-dev libyaml-cpp-dev - name: Setup Python diff --git a/.github/workflows/build_native.yml b/.github/workflows/build_native.yml index 8fe8e6c318..3e8b4c001c 100644 --- a/.github/workflows/build_native.yml +++ b/.github/workflows/build_native.yml @@ -13,7 +13,7 @@ jobs: - name: Install libbluetooth shell: bash run: | - sudo apt-get update + sudo apt-get update --fix-missing sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code diff --git a/.github/workflows/build_raspbian.yml b/.github/workflows/build_raspbian.yml index d262d87395..1fd8fad307 100644 --- a/.github/workflows/build_raspbian.yml +++ b/.github/workflows/build_raspbian.yml @@ -13,7 +13,7 @@ jobs: - name: Install libbluetooth shell: bash run: | - apt-get update -y + apt-get update -y --fix-missing apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code From 17c2d60b789c5709d793afa406308f9864e3618c Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 10 Jul 2024 12:47:34 -0500 Subject: [PATCH 145/211] Update trunk.yaml, fix whitespace --- .trunk/trunk.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index cbb4d83c96..9bfeb2c2d3 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -31,7 +31,7 @@ lint: - gitleaks@8.18.2 - clang-format@16.0.3 - prettier@3.2.5 -ignore: + ignore: - linters: [ALL] paths: bin/** runtimes: From 51d54a7d99046051fbcd1f8d32d7f0547738dba7 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 10 Jul 2024 14:39:41 -0500 Subject: [PATCH 146/211] Update trunk.yaml --- .trunk/trunk.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 9bfeb2c2d3..2d9f608997 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -33,7 +33,8 @@ lint: - prettier@3.2.5 ignore: - linters: [ALL] - paths: bin/** + paths: + - bin/** runtimes: enabled: - python@3.10.8 From e59e50af0e4f216ab666df0b8e1a21093dfa0ec7 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 10 Jul 2024 14:42:29 -0500 Subject: [PATCH 147/211] Update build_raspbian_armv7l.yml --fix-missing --- .github/workflows/build_raspbian_armv7l.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_raspbian_armv7l.yml b/.github/workflows/build_raspbian_armv7l.yml index ee5eb66ebb..39b297d1b1 100644 --- a/.github/workflows/build_raspbian_armv7l.yml +++ b/.github/workflows/build_raspbian_armv7l.yml @@ -13,6 +13,7 @@ jobs: - name: Install libbluetooth shell: bash run: | + apt-get update -y --fix-missing apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code From 11bca437fd38534c194cf4902964c5c5bba1a09f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 15:15:57 -0500 Subject: [PATCH 148/211] [create-pull-request] automated change (#4263) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- .../generated/meshtastic/module_config.pb.h | 8 +++++--- src/mesh/generated/meshtastic/telemetry.pb.h | 18 +++++++++++++----- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/protobufs b/protobufs index d191975ebc..10494bf328 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit d191975ebc572527c6d9eec48d5b0a1e3331999f +Subproject commit 10494bf328ac051fc4add9ddeb677eebf337b531 diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index 12087655ab..7fd57fe006 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -60,7 +60,9 @@ typedef enum _meshtastic_ModuleConfig_SerialConfig_Serial_Mode { meshtastic_ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG = 3, meshtastic_ModuleConfig_SerialConfig_Serial_Mode_NMEA = 4, /* NMEA messages specifically tailored for CalTopo */ - meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO = 5 + meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO = 5, + /* Ecowitt WS85 weather station */ + meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85 = 6 } meshtastic_ModuleConfig_SerialConfig_Serial_Mode; /* TODO: REPLACE */ @@ -434,8 +436,8 @@ extern "C" { #define _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Baud)(meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600+1)) #define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN meshtastic_ModuleConfig_SerialConfig_Serial_Mode_DEFAULT -#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MAX meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO -#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Mode)(meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO+1)) +#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MAX meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85 +#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Mode)(meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85+1)) #define _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE #define _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MAX meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 28d3687548..82cd0a55d9 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -115,6 +115,10 @@ typedef struct _meshtastic_EnvironmentMetrics { float wind_speed; /* Weight in KG */ float weight; + /* Wind gust in m/s */ + float wind_gust; + /* Wind lull in m/s */ + float wind_lull; } meshtastic_EnvironmentMetrics; /* Power Metrics (voltage / current / etc) */ @@ -205,13 +209,13 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_DeviceMetrics_init_default {0, 0, 0, 0, 0} -#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_default {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}} #define meshtastic_Nau7802Config_init_default {0, 0} #define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0, 0} -#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_zero {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}} @@ -238,6 +242,8 @@ extern "C" { #define meshtastic_EnvironmentMetrics_wind_direction_tag 13 #define meshtastic_EnvironmentMetrics_wind_speed_tag 14 #define meshtastic_EnvironmentMetrics_weight_tag 15 +#define meshtastic_EnvironmentMetrics_wind_gust_tag 16 +#define meshtastic_EnvironmentMetrics_wind_lull_tag 17 #define meshtastic_PowerMetrics_ch1_voltage_tag 1 #define meshtastic_PowerMetrics_ch1_current_tag 2 #define meshtastic_PowerMetrics_ch2_voltage_tag 3 @@ -289,7 +295,9 @@ X(a, STATIC, SINGULAR, FLOAT, ir_lux, 11) \ X(a, STATIC, SINGULAR, FLOAT, uv_lux, 12) \ X(a, STATIC, SINGULAR, UINT32, wind_direction, 13) \ X(a, STATIC, SINGULAR, FLOAT, wind_speed, 14) \ -X(a, STATIC, SINGULAR, FLOAT, weight, 15) +X(a, STATIC, SINGULAR, FLOAT, weight, 15) \ +X(a, STATIC, SINGULAR, FLOAT, wind_gust, 16) \ +X(a, STATIC, SINGULAR, FLOAT, wind_lull, 17) #define meshtastic_EnvironmentMetrics_CALLBACK NULL #define meshtastic_EnvironmentMetrics_DEFAULT NULL @@ -357,10 +365,10 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; #define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size #define meshtastic_AirQualityMetrics_size 72 #define meshtastic_DeviceMetrics_size 27 -#define meshtastic_EnvironmentMetrics_size 73 +#define meshtastic_EnvironmentMetrics_size 85 #define meshtastic_Nau7802Config_size 16 #define meshtastic_PowerMetrics_size 30 -#define meshtastic_Telemetry_size 80 +#define meshtastic_Telemetry_size 92 #ifdef __cplusplus } /* extern "C" */ From 33831cd41c92ed9684c1df731a01836d20e9b4ee Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Thu, 11 Jul 2024 15:26:43 +1200 Subject: [PATCH 149/211] GPS Power State tidy-up (#4161) * Refactor GPSPowerState enum Identifies a case where the GPS hardware is awake, but an update is not yet desired * Change terminology * Clear old lock-time prediction on triple press * Use exponential smoothing to predict lock time * Rename averageLockTime to predictedLockTime * Attempt: Send PMREQ with duration 0 on MCU deep-sleep * Attempt 2: Send PMREQ with duration 0 on MCU deep-sleep * Revert "Attempt 2: Send PMREQ with duration 0 on MCU deep-sleep" This reverts commit 8b697cd2a445355dcfab5b33e0ce7a3128cab151. * Revert "Attempt: Send PMREQ with duration 0 on MCU deep-sleep" This reverts commit 9d29ec7603a88056b9115796b29b5023165a93bb. * Remove unused notifyGPSSleep Observable Handled with notifyDeepSleep, and enable() / disable() * WIP: simplify GPS power management An initial attempt only. * Honor #3e9e0fd * No-op when moving between GPS_IDLE and GPS_ACTIVE * Ensure U-blox GPS is awake to receive indefinite sleep command * Longer pause when waking U-blox to send sleep command * Actually implement soft and hard sleep.. * Dynamically estimate the threshold for GPS_HARDSLEEP * Fallback to GPS_HARDSLEEP, if GPS_SOFTSLEEP unsupported * Move "excessive search time" behavior to scheduler class * Minor logging adjustments * Promote log to warning * Gratuitous buffer clearing on boot * Fix inverted standby pin logic Specifically the standby pin for L76B, L76K and clones Discovered during T-Echo testing: totally broken function, probe method failing. * Remove redundant pin init Now handled by setPowerState * Replace max() with if statements Avoid those platform specific implementations.. * Trunk formatting New round of settings.json changes keep catching me out, have to remember to re-enable my "clang-format" for windows workaround. * Remove some asserts from setPowerState Original aim was to prevent sending a 0 second PMREQ to U-blox hardware as part of a timed sleep (GPS_HARDSLEEP, GPS_SOFTSLEEP). I'm not sure this is super important, and it feels tidier to just allow the 0 second sleeptime here, rather than fudge the sleeptime further up. * Fix an error determining whether GPS_SOFTSLEEP is supported * Clarify a log entry * Set PIN_STANDBY for MCU deep-sleep Required to reach TTGO's advertised 0.25mA sleep current for T-Echo. Without this change: ~6mA. --- src/gps/GPS.cpp | 517 ++++++++++++++++---------------- src/gps/GPS.h | 46 +-- src/gps/GPSUpdateScheduling.cpp | 118 ++++++++ src/gps/GPSUpdateScheduling.h | 29 ++ src/sleep.cpp | 8 - src/sleep.h | 2 - 6 files changed, 430 insertions(+), 290 deletions(-) create mode 100644 src/gps/GPSUpdateScheduling.cpp create mode 100644 src/gps/GPSUpdateScheduling.h diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index ec7d725b83..8eb7fef273 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -9,6 +9,7 @@ #include "main.h" // pmu_found #include "sleep.h" +#include "GPSUpdateScheduling.h" #include "cas.h" #include "ubx.h" @@ -22,19 +23,6 @@ #define GPS_RESET_MODE HIGH #endif -// How many minutes of sleep make it worthwhile to power-off the GPS -// Shorter than this, and GPS will only enter standby -// Affected by lock-time, and config.position.gps_update_interval -#ifndef GPS_STANDBY_THRESHOLD_MINUTES -#define GPS_STANDBY_THRESHOLD_MINUTES 15 -#endif - -// How many seconds of sleep make it worthwhile for the GPS to use powered-on standby -// Shorter than this, and we'll just wait instead -#ifndef GPS_IDLE_THRESHOLD_SECONDS -#define GPS_IDLE_THRESHOLD_SECONDS 10 -#endif - #if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) HardwareSerial *GPS::_serial_gps = &Serial1; #else @@ -43,6 +31,8 @@ HardwareSerial *GPS::_serial_gps = NULL; GPS *gps = nullptr; +GPSUpdateScheduling scheduling; + /// Multiple GPS instances might use the same serial port (in sequence), but we can /// only init that port once. static bool didSerialInit; @@ -52,6 +42,25 @@ uint8_t uBloxProtocolVersion; #define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway #define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc) +// For logging +const char *getGPSPowerStateString(GPSPowerState state) +{ + switch (state) { + case GPS_ACTIVE: + return "ACTIVE"; + case GPS_IDLE: + return "IDLE"; + case GPS_SOFTSLEEP: + return "SOFTSLEEP"; + case GPS_HARDSLEEP: + return "HARDSLEEP"; + case GPS_OFF: + return "OFF"; + default: + assert(false); // Unhandled enum value.. + } +} + void GPS::UBXChecksum(uint8_t *message, size_t length) { uint8_t CK_A = 0, CK_B = 0; @@ -767,7 +776,6 @@ bool GPS::setup() } notifyDeepSleepObserver.observe(¬ifyDeepSleep); - notifyGPSSleepObserver.observe(¬ifyGPSSleep); return true; } @@ -776,236 +784,243 @@ GPS::~GPS() { // we really should unregister our sleep observer notifyDeepSleepObserver.unobserve(¬ifyDeepSleep); - notifyGPSSleepObserver.observe(¬ifyGPSSleep); } -const char *GPS::powerStateToString() +// Put the GPS hardware into a specified state +void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime) { - switch (powerState) { - case GPS_OFF: - return "OFF"; - case GPS_IDLE: - return "IDLE"; - case GPS_STANDBY: - return "STANDBY"; + // Update the stored GPSPowerstate, and create local copies + GPSPowerState oldState = powerState; + powerState = newState; + LOG_INFO("GPS power state moving from %s to %s\n", getGPSPowerStateString(oldState), getGPSPowerStateString(newState)); + + switch (newState) { case GPS_ACTIVE: - return "ACTIVE"; - default: - return "UNKNOWN"; + case GPS_IDLE: + if (oldState == GPS_ACTIVE || oldState == GPS_IDLE) // If hardware already awake, no changes needed + break; + if (oldState != GPS_ACTIVE && oldState != GPS_IDLE) // If hardware just waking now, clear buffer + clearBuffer(); + powerMon->setState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) + writePinEN(true); // Power (EN pin): on + setPowerPMU(true); // Power (PMU): on + writePinStandby(false); // Standby (pin): awake (not standby) + setPowerUBLOX(true); // Standby (UBLOX): awake + break; + + case GPS_SOFTSLEEP: + powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) + writePinEN(true); // Power (EN pin): on + setPowerPMU(true); // Power (PMU): on + writePinStandby(true); // Standby (pin): asleep (not awake) + setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed + break; + + case GPS_HARDSLEEP: + powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) + writePinEN(false); // Power (EN pin): off + setPowerPMU(false); // Power (PMU): off + writePinStandby(true); // Standby (pin): asleep (not awake) + setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed + break; + + case GPS_OFF: + assert(sleepTime == 0); // This is an indefinite sleep + powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) + writePinEN(false); // Power (EN pin): off + setPowerPMU(false); // Power (PMU): off + writePinStandby(true); // Standby (pin): asleep + setPowerUBLOX(false, 0); // Standby (UBLOX): asleep, indefinitely + break; } } -void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) +// Set power with EN pin, if relevant +void GPS::writePinEN(bool on) { - // Record the current powerState - if (on) - powerState = GPS_ACTIVE; - else if (!enabled) // User has disabled with triple press - powerState = GPS_OFF; - else if (sleepTime <= GPS_IDLE_THRESHOLD_SECONDS * 1000UL) - powerState = GPS_IDLE; - else if (standbyOnly) - powerState = GPS_STANDBY; - else - powerState = GPS_OFF; - - LOG_DEBUG("GPS::powerState=%s\n", powerStateToString()); - - // If the next update is due *really soon*, don't actually power off or enter standby. Just wait it out. - if (!on && powerState == GPS_IDLE) + // Abort: if conflict with Canned Messages when using Wisblock(?) + if (HW_VENDOR == meshtastic_HardwareModel_RAK4631 && (rotaryEncoderInterruptImpl1 || upDownInterruptImpl1)) return; - if (on) { - powerMon->setState(meshtastic_PowerMon_State_GPS_Active); - clearBuffer(); // drop any old data waiting in the buffer before re-enabling - if (en_gpio) - digitalWrite(en_gpio, on ? GPS_EN_ACTIVE : !GPS_EN_ACTIVE); // turn this on if defined, every time - } else { - powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); - } - isInPowersave = !on; - if (!standbyOnly && en_gpio != 0 && - !(HW_VENDOR == meshtastic_HardwareModel_RAK4631 && (rotaryEncoderInterruptImpl1 || upDownInterruptImpl1))) { - LOG_DEBUG("GPS powerdown using GPS_EN_ACTIVE\n"); - digitalWrite(en_gpio, on ? GPS_EN_ACTIVE : !GPS_EN_ACTIVE); + // Abort: if pin unset + if (!en_gpio) return; - } -#ifdef HAS_PMU // We only have PMUs on the T-Beam, and that board has a tiny battery to save GPS ephemera, so treat as a standby. - if (pmu_found && PMU) { - uint8_t model = PMU->getChipModel(); - if (model == XPOWERS_AXP2101) { - if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) { - // t-beam v1.2 GNSS power channel - on ? PMU->enablePowerOutput(XPOWERS_ALDO3) : PMU->disablePowerOutput(XPOWERS_ALDO3); - } else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) { - // t-beam-s3-core GNSS power channel - on ? PMU->enablePowerOutput(XPOWERS_ALDO4) : PMU->disablePowerOutput(XPOWERS_ALDO4); - } - } else if (model == XPOWERS_AXP192) { - // t-beam v1.1 GNSS power channel - on ? PMU->enablePowerOutput(XPOWERS_LDO3) : PMU->disablePowerOutput(XPOWERS_LDO3); - } - return; - } + + // Determine new value for the pin + bool val = GPS_EN_ACTIVE ? on : !on; + + // Write and log + pinMode(en_gpio, OUTPUT); + digitalWrite(en_gpio, val); +#ifdef GPS_EXTRAVERBOSE + LOG_DEBUG("Pin EN %s\n", val == HIGH ? "HIGH" : "LOW"); #endif +} + +// Set the value of the STANDBY pin, if relevant +// true for standby state, false for awake +void GPS::writePinStandby(bool standby) +{ #ifdef PIN_GPS_STANDBY // Specifically the standby pin for L76B, L76K and clones - if (on) { - LOG_INFO("Waking GPS\n"); - pinMode(PIN_GPS_STANDBY, OUTPUT); - // Some PCB's use an inverse logic due to a transistor driver - // Example for this is the Pico-Waveshare Lora+GPS HAT -#ifdef PIN_GPS_STANDBY_INVERTED - digitalWrite(PIN_GPS_STANDBY, 0); + +// Determine the new value for the pin +// Normally: active HIGH for awake +#if PIN_GPS_STANDBY_INVERTED + bool val = standby; #else - digitalWrite(PIN_GPS_STANDBY, 1); + bool val = !standby; #endif - return; - } else { - LOG_INFO("GPS entering sleep\n"); - // notifyGPSSleep.notifyObservers(NULL); - pinMode(PIN_GPS_STANDBY, OUTPUT); -#ifdef PIN_GPS_STANDBY_INVERTED - digitalWrite(PIN_GPS_STANDBY, 1); -#else - digitalWrite(PIN_GPS_STANDBY, 0); + + // Write and log + pinMode(PIN_GPS_STANDBY, OUTPUT); + digitalWrite(PIN_GPS_STANDBY, val); +#ifdef GPS_EXTRAVERBOSE + LOG_DEBUG("Pin STANDBY %s\n", val == HIGH ? "HIGH" : "LOW"); #endif - return; - } #endif - if (!on) { - if (gnssModel == GNSS_MODEL_UBLOX) { - uint8_t msglen; - LOG_DEBUG("Sleep Time: %i\n", sleepTime); - if (strncmp(info.hwVersion, "000A0000", 8) != 0) { - for (int i = 0; i < 4; i++) { - gps->_message_PMREQ[0 + i] = sleepTime >> (i * 8); // Encode the sleep time in millis into the packet - } - msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ), gps->_message_PMREQ); - } else { - for (int i = 0; i < 4; i++) { - gps->_message_PMREQ_10[4 + i] = sleepTime >> (i * 8); // Encode the sleep time in millis into the packet - } - msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ_10), gps->_message_PMREQ_10); - } - gps->_serial_gps->write(gps->UBXscratch, msglen); - } - } else { - if (gnssModel == GNSS_MODEL_UBLOX) { - gps->_serial_gps->write(0xFF); - clearBuffer(); // This often returns old data, so drop it - } - } } -/// Record that we have a GPS -void GPS::setConnected() +// Enable / Disable GPS with PMU, if present +void GPS::setPowerPMU(bool on) { - if (!hasGPS) { - hasGPS = true; - shouldPublish = true; + // We only have PMUs on the T-Beam, and that board has a tiny battery to save GPS ephemera, + // so treat as a standby. +#ifdef HAS_PMU + // Abort: if no PMU + if (!pmu_found) + return; + + // Abort: if PMU not initialized + if (!PMU) + return; + + uint8_t model = PMU->getChipModel(); + if (model == XPOWERS_AXP2101) { + if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) { + // t-beam v1.2 GNSS power channel + on ? PMU->enablePowerOutput(XPOWERS_ALDO3) : PMU->disablePowerOutput(XPOWERS_ALDO3); + } else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) { + // t-beam-s3-core GNSS power channel + on ? PMU->enablePowerOutput(XPOWERS_ALDO4) : PMU->disablePowerOutput(XPOWERS_ALDO4); + } + } else if (model == XPOWERS_AXP192) { + // t-beam v1.1 GNSS power channel + on ? PMU->enablePowerOutput(XPOWERS_LDO3) : PMU->disablePowerOutput(XPOWERS_LDO3); } + +#ifdef GPS_EXTRAVERBOSE + LOG_DEBUG("PMU %s\n", on ? "on" : "off"); +#endif +#endif } -/** - * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode - * - * calls sleep/wake - */ -void GPS::setAwake(bool wantAwake) +// Set UBLOX power, if relevant +void GPS::setPowerUBLOX(bool on, uint32_t sleepMs) { - - // If user has disabled GPS, make sure it is off, not just in standby or idle - if (!wantAwake && !enabled && powerState != GPS_OFF) { - setGPSPower(false, false, 0); + // Abort: if not UBLOX hardware + if (gnssModel != GNSS_MODEL_UBLOX) return; + + // If waking + if (on) { + gps->_serial_gps->write(0xFF); + clearBuffer(); // This often returns old data, so drop it +#ifdef GPS_EXTRAVERBOSE + LOG_DEBUG("UBLOX: wake\n"); +#endif } - // If GPS power state needs to change - if ((wantAwake && powerState != GPS_ACTIVE) || (!wantAwake && powerState == GPS_ACTIVE)) { - LOG_DEBUG("WANT GPS=%d\n", wantAwake); + // If putting to sleep + else { + uint8_t msglen; - // Calculate how long it takes to get a GPS lock - if (wantAwake) { - // Record the time we start looking for a lock - lastWakeStartMsec = millis(); - } else { - // Record by how much we missed our ideal target postion.gps_update_interval (for logging only) - // Need to calculate this before we update lastSleepStartMsec, to make the new prediction - int32_t lateByMsec = (int32_t)(millis() - lastSleepStartMsec) - (int32_t)getSleepTime(); + // If we're being asked to sleep indefinitely, make *sure* we're awake first, to process the new sleep command + if (sleepMs == 0) { + setPowerUBLOX(true); + delay(500); + } - // Record the time we finish looking for a lock - lastSleepStartMsec = millis(); + // Determine hardware version + if (strncmp(info.hwVersion, "000A0000", 8) != 0) { + // Encode the sleep time in millis into the packet + for (int i = 0; i < 4; i++) + gps->_message_PMREQ[0 + i] = sleepMs >> (i * 8); - // How long did it take to get GPS lock this time? - uint32_t lockTime = lastSleepStartMsec - lastWakeStartMsec; + // Record the message length + msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ), gps->_message_PMREQ); + } else { + // Encode the sleep time in millis into the packet + for (int i = 0; i < 4; i++) + gps->_message_PMREQ_10[4 + i] = sleepMs >> (i * 8); - // Update the lock-time prediction - // Used pre-emptively, attempting to hit target of gps.position_update_interval - switch (GPSCycles) { - case 0: - LOG_DEBUG("Initial GPS lock took %ds\n", lockTime / 1000); - break; - case 1: - predictedLockTime = lockTime; // Avoid slow ramp-up - start with a real value - LOG_DEBUG("GPS Lock took %ds\n", lockTime / 1000); - break; - default: - // Predict lock-time using exponential smoothing: respond slowly to changes - predictedLockTime = (lockTime * 0.2) + (predictedLockTime * 0.8); // Latest lock time has 20% weight on prediction - LOG_INFO("GPS Lock took %ds. %s by %ds. Next lock predicted to take %ds.\n", lockTime / 1000, - (lateByMsec > 0) ? "Late" : "Early", abs(lateByMsec) / 1000, predictedLockTime / 1000); - } - GPSCycles++; + // Record the message length + msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ_10), gps->_message_PMREQ_10); } - // How long to wait before attempting next GPS update - // Aims to hit position.gps_update_interval by using the lock-time prediction - uint32_t compensatedSleepTime = (getSleepTime() > predictedLockTime) ? (getSleepTime() - predictedLockTime) : 0; + // Send the UBX packet + gps->_serial_gps->write(gps->UBXscratch, msglen); - // If long interval between updates: power off between updates - if (compensatedSleepTime > GPS_STANDBY_THRESHOLD_MINUTES * MS_IN_MINUTE) { - setGPSPower(wantAwake, false, getSleepTime() - predictedLockTime); - } - - // If waking relatively frequently: don't power off. Would use more energy trying to reacquire lock each time - // We'll either use a "powered-on" standby, or just wait it out, depending on how soon the next update is due - // Will decide which inside setGPSPower method - else { -#ifdef GPS_UC6580 - setGPSPower(wantAwake, false, compensatedSleepTime); -#else - setGPSPower(wantAwake, true, compensatedSleepTime); +#ifdef GPS_EXTRAVERBOSE + LOG_DEBUG("UBLOX: sleep for %dmS\n", sleepMs); #endif - } } } -/** Get how long we should stay looking for each acquisition in msecs - */ -uint32_t GPS::getWakeTime() const +/// Record that we have a GPS +void GPS::setConnected() { - uint32_t t = config.position.position_broadcast_secs; - - if (t == UINT32_MAX) - return t; // already maxint + if (!hasGPS) { + hasGPS = true; + shouldPublish = true; + } +} - return Default::getConfiguredOrDefaultMs(t, default_broadcast_interval_secs); +// We want a GPS lock. Wake the hardware +void GPS::up() +{ + scheduling.informSearching(); + setPowerState(GPS_ACTIVE); } -/** Get how long we should sleep between aqusition attempts in msecs - */ -uint32_t GPS::getSleepTime() const +// We've got a GPS lock. Enter a low power state, potentially. +void GPS::down() { - uint32_t t = config.position.gps_update_interval; + scheduling.informGotLock(); + uint32_t predictedSearchDuration = scheduling.predictedSearchDurationMs(); + uint32_t sleepTime = scheduling.msUntilNextSearch(); + uint32_t updateInterval = Default::getConfiguredOrDefaultMs(config.position.gps_update_interval); + + LOG_DEBUG("%us until next search\n", sleepTime / 1000); + + // If update interval less than 10 seconds, no attempt to sleep + if (updateInterval <= 10 * 1000UL) + setPowerState(GPS_IDLE); + + else { + // Check whether the GPS hardware is capable of GPS_SOFTSLEEP + // If not, fallback to GPS_HARDSLEEP instead + bool softsleepSupported = false; + if (gnssModel == GNSS_MODEL_UBLOX) // U-blox is supported via PMREQ + softsleepSupported = true; +#ifdef PIN_GPS_STANDBY // L76B, L76K and clones have a standby pin + softsleepSupported = true; +#endif - // We'll not need the GPS thread to wake up again after first acq. with fixed position. - if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED || config.position.fixed_position) - t = UINT32_MAX; // Sleep forever now + // How long does gps_update_interval need to be, for GPS_HARDSLEEP to become more efficient than GPS_SOFTSLEEP? + // Heuristic equation. A compromise manually fitted to power observations from U-blox NEO-6M and M10050 + // https://www.desmos.com/calculator/6gvjghoumr + // This is not particularly accurate, but probably an impromevement over a single, fixed threshold + uint32_t hardsleepThreshold = (2750 * pow(predictedSearchDuration / 1000, 1.22)); + LOG_DEBUG("gps_update_interval >= %us needed to justify hardsleep\n", hardsleepThreshold / 1000); - if (t == UINT32_MAX) - return t; // already maxint + // If update interval too short: softsleep (if supported by hardware) + if (softsleepSupported && updateInterval < hardsleepThreshold) + setPowerState(GPS_SOFTSLEEP, sleepTime); - return Default::getConfiguredOrDefaultMs(t, default_gps_update_interval); + // If update interval long enough (or softsleep unsupported): hardsleep instead + else + setPowerState(GPS_HARDSLEEP, sleepTime); + } } void GPS::publishUpdate() @@ -1056,13 +1071,13 @@ int32_t GPS::runOnce() return disable(); } - if (whileIdle()) { + if (whileActive()) { // if we have received valid NMEA claim we are connected setConnected(); } else { if ((config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) && (gnssModel == GNSS_MODEL_UBLOX)) { // reset the GPS on next bootup - if (devicestate.did_gps_reset && (millis() - lastWakeStartMsec > 60000) && !hasFlow()) { + if (devicestate.did_gps_reset && scheduling.elapsedSearchMs() > 60 * 1000UL && !hasFlow()) { LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n"); devicestate.did_gps_reset = false; nodeDB->saveDeviceStateToDisk(); @@ -1077,54 +1092,43 @@ int32_t GPS::runOnce() // gps->factoryReset(); } - // If we are overdue for an update, turn on the GPS and at least publish the current status - uint32_t now = millis(); - uint32_t timeAsleep = now - lastSleepStartMsec; + // If we're due for an update, wake the GPS + if (!config.position.fixed_position && powerState != GPS_ACTIVE && scheduling.isUpdateDue()) + up(); - auto sleepTime = getSleepTime(); - if (powerState != GPS_ACTIVE && (sleepTime != UINT32_MAX) && - ((timeAsleep > sleepTime) || (isInPowersave && timeAsleep > (sleepTime - predictedLockTime)))) { - // We now want to be awake - so wake up the GPS - setAwake(true); + // If we've already set time from the GPS, no need to ask the GPS + bool gotTime = (getRTCQuality() >= RTCQualityGPS); + if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time + gotTime = true; + shouldPublish = true; } - // While we are awake - if (powerState == GPS_ACTIVE) { - // LOG_DEBUG("looking for location\n"); - // If we've already set time from the GPS, no need to ask the GPS - bool gotTime = (getRTCQuality() >= RTCQualityGPS); - if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time - gotTime = true; - shouldPublish = true; - } - - bool gotLoc = lookForLocation(); - if (gotLoc && !hasValidLocation) { // declare that we have location ASAP - LOG_DEBUG("hasValidLocation RISING EDGE\n"); - hasValidLocation = true; - shouldPublish = true; - } + bool gotLoc = lookForLocation(); + if (gotLoc && !hasValidLocation) { // declare that we have location ASAP + LOG_DEBUG("hasValidLocation RISING EDGE\n"); + hasValidLocation = true; + shouldPublish = true; + } - now = millis(); - auto wakeTime = getWakeTime(); - bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime; + bool tooLong = scheduling.searchedTooLong(); + if (tooLong) + LOG_WARN("Couldn't publish a valid location: didn't get a GPS lock in time.\n"); - // Once we get a location we no longer desperately want an update - // LOG_DEBUG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime); - if ((gotLoc && gotTime) || tooLong) { + // Once we get a location we no longer desperately want an update + // LOG_DEBUG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime); + if ((gotLoc && gotTime) || tooLong) { - if (tooLong) { - // we didn't get a location during this ack window, therefore declare loss of lock - if (hasValidLocation) { - LOG_DEBUG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc); - } - p = meshtastic_Position_init_default; - hasValidLocation = false; + if (tooLong) { + // we didn't get a location during this ack window, therefore declare loss of lock + if (hasValidLocation) { + LOG_DEBUG("hasValidLocation FALLING EDGE\n"); } - - setAwake(false); - shouldPublish = true; // publish our update for this just finished acquisition window + p = meshtastic_Position_init_default; + hasValidLocation = false; } + + down(); + shouldPublish = true; // publish our update for this just finished acquisition window } // If state has changed do a publish @@ -1150,9 +1154,7 @@ void GPS::clearBuffer() int GPS::prepareDeepSleep(void *unused) { LOG_INFO("GPS deep sleep!\n"); - - setAwake(false); - + disable(); return 0; } @@ -1348,12 +1350,6 @@ GPS *GPS::createGps() new_gps->tx_gpio = _tx_gpio; new_gps->en_gpio = _en_gpio; - if (_en_gpio != 0) { - LOG_DEBUG("Setting %d to output.\n", _en_gpio); - pinMode(_en_gpio, OUTPUT); - digitalWrite(_en_gpio, !GPS_EN_ACTIVE); - } - #ifdef PIN_GPS_PPS // pulse per second pinMode(PIN_GPS_PPS, INPUT); @@ -1368,7 +1364,8 @@ GPS *GPS::createGps() LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n"); #endif - new_gps->setGPSPower(true, false, 0); + // Make sure the GPS is awake before performing any init. + new_gps->up(); #ifdef PIN_GPS_RESET pinMode(PIN_GPS_RESET, OUTPUT); @@ -1376,7 +1373,6 @@ GPS *GPS::createGps() delay(10); digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE); #endif - new_gps->setAwake(true); // Wake GPS power before doing any init if (_serial_gps) { #ifdef ARCH_ESP32 @@ -1662,13 +1658,13 @@ bool GPS::hasFlow() return reader.passedChecksum() > 0; } -bool GPS::whileIdle() +bool GPS::whileActive() { unsigned int charsInBuf = 0; bool isValid = false; if (powerState != GPS_ACTIVE) { clearBuffer(); - return (powerState == GPS_ACTIVE); + return false; } #ifdef SERIAL_BUFFER_SIZE if (_serial_gps->available() >= SERIAL_BUFFER_SIZE - 1) { @@ -1699,20 +1695,21 @@ bool GPS::whileIdle() } void GPS::enable() { - // Clear the old lock-time prediction - GPSCycles = 0; - predictedLockTime = 0; + // Clear the old scheduling info (reset the lock-time prediction) + scheduling.reset(); enabled = true; setInterval(GPS_THREAD_INTERVAL); - setAwake(true); + + scheduling.informSearching(); + setPowerState(GPS_ACTIVE); } int32_t GPS::disable() { enabled = false; setInterval(INT32_MAX); - setAwake(false); + setPowerState(GPS_OFF); return INT32_MAX; } @@ -1721,11 +1718,11 @@ void GPS::toggleGpsMode() { if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED; - LOG_DEBUG("Flag set to false for gps power. GpsMode: DISABLED\n"); + LOG_INFO("User toggled GpsMode. Now DISABLED.\n"); disable(); } else if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_DISABLED) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED; - LOG_DEBUG("Flag set to true to restore power. GpsMode: ENABLED\n"); + LOG_INFO("User toggled GpsMode. Now ENABLED\n"); enable(); } } diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 6afbd4faba..7cbf771bcc 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -39,10 +39,11 @@ typedef enum { } GPS_RESPONSE; enum GPSPowerState : uint8_t { - GPS_OFF = 0, // Physically powered off - GPS_ACTIVE = 1, // Awake and want a position - GPS_STANDBY = 2, // Physically powered on, but soft-sleeping - GPS_IDLE = 3, // Awake, but not wanting another position yet + GPS_ACTIVE, // Awake and want a position + GPS_IDLE, // Awake, but not wanting another position yet + GPS_SOFTSLEEP, // Physically powered on, but soft-sleeping + GPS_HARDSLEEP, // Physically powered off, but scheduled to wake + GPS_OFF // Powered off indefinitely }; // Generate a string representation of DOP @@ -67,14 +68,11 @@ class GPS : private concurrency::OSThread uint8_t fixType = 0; // fix type from GPGSA #endif private: - uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0; const int serialSpeeds[6] = {9600, 4800, 38400, 57600, 115200, 9600}; uint32_t rx_gpio = 0; uint32_t tx_gpio = 0; uint32_t en_gpio = 0; - uint32_t predictedLockTime = 0; - uint32_t GPSCycles = 0; int speedSelect = 0; int probeTries = 2; @@ -99,7 +97,6 @@ class GPS : private concurrency::OSThread uint8_t numSatellites = 0; CallbackObserver notifyDeepSleepObserver = CallbackObserver(this, &GPS::prepareDeepSleep); - CallbackObserver notifyGPSSleepObserver = CallbackObserver(this, &GPS::prepareDeepSleep); public: /** If !NULL we will use this serial port to construct our GPS */ @@ -175,7 +172,8 @@ class GPS : private concurrency::OSThread // toggle between enabled/disabled void toggleGpsMode(); - void setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime); + // Change the power state of the GPS - for power saving / shutdown + void setPowerState(GPSPowerState newState, uint32_t sleepMs = 0); /// Returns true if we have acquired GPS lock. virtual bool hasLock(); @@ -206,18 +204,18 @@ class GPS : private concurrency::OSThread GPS_RESPONSE getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis); - /** - * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode - * - * calls sleep/wake - */ - void setAwake(bool on); virtual bool factoryReset(); // Creates an instance of the GPS class. // Returns the new instance or null if the GPS is not present. static GPS *createGps(); + // Wake the GPS hardware - ready for an update + void up(); + + // Let the GPS hardware save power between updates + void down(); + protected: /** * Perform any processing that should be done only while the GPS is awake and looking for a fix. @@ -240,7 +238,7 @@ class GPS : private concurrency::OSThread * * Return true if we received a valid message from the GPS */ - virtual bool whileIdle(); + virtual bool whileActive(); /** * Perform any processing that should be done only while the GPS is awake and looking for a fix. @@ -267,13 +265,21 @@ class GPS : private concurrency::OSThread void UBXChecksum(uint8_t *message, size_t length); void CASChecksum(uint8_t *message, size_t length); - /** Get how long we should stay looking for each aquisition + /** Set power with EN pin, if relevant + */ + void writePinEN(bool on); + + /** Set the value of the STANDBY pin, if relevant + */ + void writePinStandby(bool standby); + + /** Set GPS power with PMU, if relevant */ - uint32_t getWakeTime() const; + void setPowerPMU(bool on); - /** Get how long we should sleep between aqusition attempts + /** Set UBLOX power, if relevant */ - uint32_t getSleepTime() const; + void setPowerUBLOX(bool on, uint32_t sleepMs = 0); /** * Tell users we have new GPS readings diff --git a/src/gps/GPSUpdateScheduling.cpp b/src/gps/GPSUpdateScheduling.cpp new file mode 100644 index 0000000000..949ef60397 --- /dev/null +++ b/src/gps/GPSUpdateScheduling.cpp @@ -0,0 +1,118 @@ +#include "GPSUpdateScheduling.h" + +#include "Default.h" + +// Mark the time when searching for GPS position begins +void GPSUpdateScheduling::informSearching() +{ + searchStartedMs = millis(); +} + +// Mark the time when searching for GPS is complete, +// then update the predicted lock-time +void GPSUpdateScheduling::informGotLock() +{ + searchEndedMs = millis(); + LOG_DEBUG("Took %us to get lock\n", (searchEndedMs - searchStartedMs) / 1000); + updateLockTimePrediction(); +} + +// Clear old lock-time prediction data. +// When re-enabling GPS with user button. +void GPSUpdateScheduling::reset() +{ + searchStartedMs = 0; + searchEndedMs = 0; + searchCount = 0; + predictedMsToGetLock = 0; +} + +// How many milliseconds before we should next search for GPS position +// Used by GPS hardware directly, to enter timed hardware sleep +uint32_t GPSUpdateScheduling::msUntilNextSearch() +{ + uint32_t now = millis(); + + // Target interval (seconds), between GPS updates + uint32_t updateInterval = Default::getConfiguredOrDefaultMs(config.position.gps_update_interval, default_gps_update_interval); + + // Check how long until we should start searching, to hopefully hit our target interval + uint32_t dueAtMs = searchEndedMs + updateInterval; + uint32_t compensatedStart = dueAtMs - predictedMsToGetLock; + int32_t remainingMs = compensatedStart - now; + + // If we should have already started (negative value), start ASAP + if (remainingMs < 0) + remainingMs = 0; + + return (uint32_t)remainingMs; +} + +// How long have we already been searching? +// Used to abort a search in progress, if it runs unnaceptably long +uint32_t GPSUpdateScheduling::elapsedSearchMs() +{ + // If searching + if (searchStartedMs > searchEndedMs) + return millis() - searchStartedMs; + + // If not searching - 0ms. We shouldn't really consume this value + else + return 0; +} + +// Is it now time to begin searching for a GPS position? +bool GPSUpdateScheduling::isUpdateDue() +{ + return (msUntilNextSearch() == 0); +} + +// Have we been searching for a GPS position for too long? +bool GPSUpdateScheduling::searchedTooLong() +{ + uint32_t maxSearchMs = + Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs); + + // If broadcast interval set to max, no such thing as "too long" + if (maxSearchMs == UINT32_MAX) + return false; + + // If we've been searching longer than our position broadcast interval: that's too long + else if (elapsedSearchMs() > maxSearchMs) + return true; + + // Otherwise, not too long yet! + else + return false; +} + +// Updates the predicted time-to-get-lock, by exponentially smoothing the latest observation +void GPSUpdateScheduling::updateLockTimePrediction() +{ + + // How long did it take to get GPS lock this time? + // Duration between down() calls + int32_t lockTime = searchEndedMs - searchStartedMs; + if (lockTime < 0) + lockTime = 0; + + // Ignore the first lock-time: likely to be long, will skew data + + // Second locktime: likely stable. Use to intialize the smoothing filter + if (searchCount == 1) + predictedMsToGetLock = lockTime; + + // Third locktime and after: predict using exponential smoothing. Respond slowly to changes + else if (searchCount > 1) + predictedMsToGetLock = (lockTime * weighting) + (predictedMsToGetLock * (1 - weighting)); + + searchCount++; // Only tracked so we can diregard initial lock-times + + LOG_DEBUG("Predicting %us to get next lock\n", predictedMsToGetLock / 1000); +} + +// How long do we expect to spend searching for a lock? +uint32_t GPSUpdateScheduling::predictedSearchDurationMs() +{ + return GPSUpdateScheduling::predictedMsToGetLock; +} \ No newline at end of file diff --git a/src/gps/GPSUpdateScheduling.h b/src/gps/GPSUpdateScheduling.h new file mode 100644 index 0000000000..7e121c9b68 --- /dev/null +++ b/src/gps/GPSUpdateScheduling.h @@ -0,0 +1,29 @@ +#pragma once + +#include "configuration.h" + +// Encapsulates code responsible for the timing of GPS updates +class GPSUpdateScheduling +{ + public: + // Marks the time of these events, for calculation use + void informSearching(); + void informGotLock(); // Predicted lock-time is recalculated here + + void reset(); // Reset the prediction - after GPS::disable() / GPS::enable() + bool isUpdateDue(); // Is it time to begin searching for a GPS position? + bool searchedTooLong(); // Have we been searching for too long? + + uint32_t msUntilNextSearch(); // How long until we need to begin searching for a GPS? Info provided to GPS hardware for sleep + uint32_t elapsedSearchMs(); // How long have we been searching so far? + uint32_t predictedSearchDurationMs(); // How long do we expect to spend searching for a lock? + + private: + void updateLockTimePrediction(); // Called from informGotLock + uint32_t searchStartedMs = 0; + uint32_t searchEndedMs = 0; + uint32_t searchCount = 0; + uint32_t predictedMsToGetLock = 0; + + const float weighting = 0.2; // Controls exponential smoothing of lock-times prediction. 20% weighting of "latest lock-time". +}; \ No newline at end of file diff --git a/src/sleep.cpp b/src/sleep.cpp index 721c7d1880..3793ee0cfa 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -37,10 +37,7 @@ Observable preflightSleep; /// Called to tell observers we are now entering sleep and you should prepare. Must return 0 /// notifySleep will be called for light or deep sleep, notifyDeepSleep is only called for deep sleep -/// notifyGPSSleep will be called when config.position.gps_enabled is set to 0 or from buttonthread when GPS_POWER_TOGGLE is -/// enabled. Observable notifySleep, notifyDeepSleep; -Observable notifyGPSSleep; // deep sleep support RTC_DATA_ATTR int bootCount = 0; @@ -240,11 +237,6 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) #ifdef PIN_POWER_EN pinMode(PIN_POWER_EN, INPUT); // power off peripherals // pinMode(PIN_POWER_EN1, INPUT_PULLDOWN); -#endif -#if HAS_GPS - // Kill GPS power completely (even if previously we just had it in sleep mode) - if (gps) - gps->setGPSPower(false, false, 0); #endif setLed(false); diff --git a/src/sleep.h b/src/sleep.h index 8d5b9a94f3..f154b8d445 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -41,8 +41,6 @@ extern Observable notifySleep; /// Called to tell observers we are now entering (deep) sleep and you should prepare. Must return 0 extern Observable notifyDeepSleep; -/// Called to tell GPS thread to enter deep sleep independently of LoRa/MCU sleep, prior to full poweroff. Must return 0 -extern Observable notifyGPSSleep; void enableModemSleep(); #ifdef ARCH_ESP32 void enableLoraInterrupt(); From e79a7dce070472317a57623d82700b26b7e1342b Mon Sep 17 00:00:00 2001 From: "Daniel.Cao" <144674500+DanielCao0@users.noreply.github.com> Date: Thu, 11 Jul 2024 21:34:33 +0800 Subject: [PATCH 150/211] Optimize the shutdown current of RAK10701 to around 25uA (#4260) Co-authored-by: Jonathan Bennett --- src/platform/nrf52/main-nrf52.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index b79f28f139..c5b217f0e3 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -234,6 +234,18 @@ void cpuDeepSleep(uint32_t msecToWake) // RAK-12039 set pin for Air quality sensor digitalWrite(AQ_SET_PIN, LOW); #endif +#ifdef RAK14014 + // GPIO restores input status, otherwise there will be leakage current + nrf_gpio_cfg_default(TFT_BL); + nrf_gpio_cfg_default(TFT_DC); + nrf_gpio_cfg_default(TFT_CS); + nrf_gpio_cfg_default(TFT_SCLK); + nrf_gpio_cfg_default(TFT_MOSI); + nrf_gpio_cfg_default(TFT_MISO); + nrf_gpio_cfg_default(SCREEN_TOUCH_INT); + nrf_gpio_cfg_default(WB_I2C1_SCL); + nrf_gpio_cfg_default(WB_I2C1_SDA); +#endif #endif // Sleepy trackers or sensors can low power "sleep" // Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event From 974fc318560b1cee4da69820c7d10819b9af593c Mon Sep 17 00:00:00 2001 From: Warren Guy <5602790+warrenguy@users.noreply.github.com> Date: Thu, 11 Jul 2024 14:34:55 +0100 Subject: [PATCH 151/211] INA3221 sensor: use for bus voltage & environment metrics (#4215) * use INA3221 for bus voltage; fixes for telemetry variants - add to sensors available for environment telemetry (to report voltage/current) - add vars to define channels to use for battery voltage (for getBusVoltage) and environment metrics (default to CH1 for both) - write to the correct fields on the measurement struct depending on the measurement variant, and DRY up the sensor measurement collection code a bit - this might be suitable for a common implementation for the INA* sensors in a future PR... * formatting * derp --------- Co-authored-by: Ben Meadors --- src/Power.cpp | 5 ++ .../Telemetry/EnvironmentTelemetry.cpp | 11 ++++ .../Telemetry/Sensor/INA3221Sensor.cpp | 65 ++++++++++++++++--- src/modules/Telemetry/Sensor/INA3221Sensor.h | 25 +++++++ 4 files changed, 97 insertions(+), 9 deletions(-) diff --git a/src/Power.cpp b/src/Power.cpp index 950ea741d8..19c5c99375 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -449,6 +449,11 @@ class AnalogBatteryLevel : public HasBatteryLevel if (!ina260Sensor.isInitialized()) return ina260Sensor.runOnce() > 0; return ina260Sensor.isRunning(); + } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA3221].first == + config.power.device_battery_ina_address) { + if (!ina3221Sensor.isInitialized()) + return ina3221Sensor.runOnce() > 0; + return ina3221Sensor.isRunning(); } return false; } diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index d37bb754de..23200fd00a 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -115,6 +115,8 @@ int32_t EnvironmentTelemetryModule::runOnce() result = ina219Sensor.runOnce(); if (ina260Sensor.hasSensor()) result = ina260Sensor.runOnce(); + if (ina3221Sensor.hasSensor()) + result = ina3221Sensor.runOnce(); if (veml7700Sensor.hasSensor()) result = veml7700Sensor.runOnce(); if (tsl2591Sensor.hasSensor()) @@ -325,6 +327,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m valid = valid && ina260Sensor.getMetrics(m); hasSensor = true; } + if (ina3221Sensor.hasSensor()) { + valid = valid && ina3221Sensor.getMetrics(m); + hasSensor = true; + } if (veml7700Sensor.hasSensor()) { valid = valid && veml7700Sensor.getMetrics(m); hasSensor = true; @@ -499,6 +505,11 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule if (result != AdminMessageHandleResult::NOT_HANDLED) return result; } + if (ina3221Sensor.hasSensor()) { + result = ina3221Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } if (veml7700Sensor.hasSensor()) { result = veml7700Sensor.handleAdminMessage(mp, request, response); if (result != AdminMessageHandleResult::NOT_HANDLED) diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp index edd29682e0..dec99c551c 100644 --- a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp +++ b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp @@ -27,22 +27,69 @@ int32_t INA3221Sensor::runOnce() void INA3221Sensor::setup() {} +struct _INA3221Measurement INA3221Sensor::getMeasurement(ina3221_ch_t ch) +{ + struct _INA3221Measurement measurement; + + measurement.voltage = ina3221.getVoltage(ch); + measurement.current = ina3221.getCurrent(ch); + + return measurement; +} + +struct _INA3221Measurements INA3221Sensor::getMeasurements() +{ + struct _INA3221Measurements measurements; + + // INA3221 has 3 channels starting from 0 + for (int i = 0; i < 3; i++) { + measurements.measurements[i] = getMeasurement((ina3221_ch_t)i); + } + + return measurements; +} + bool INA3221Sensor::getMetrics(meshtastic_Telemetry *measurement) { - measurement->variant.environment_metrics.voltage = ina3221.getVoltage(INA3221_CH1); - measurement->variant.environment_metrics.current = ina3221.getCurrent(INA3221_CH1); - measurement->variant.power_metrics.ch1_voltage = ina3221.getVoltage(INA3221_CH1); - measurement->variant.power_metrics.ch1_current = ina3221.getCurrent(INA3221_CH1); - measurement->variant.power_metrics.ch2_voltage = ina3221.getVoltage(INA3221_CH2); - measurement->variant.power_metrics.ch2_current = ina3221.getCurrent(INA3221_CH2); - measurement->variant.power_metrics.ch3_voltage = ina3221.getVoltage(INA3221_CH3); - measurement->variant.power_metrics.ch3_current = ina3221.getCurrent(INA3221_CH3); + switch (measurement->which_variant) { + case meshtastic_Telemetry_environment_metrics_tag: + return getEnvironmentMetrics(measurement); + + case meshtastic_Telemetry_power_metrics_tag: + return getPowerMetrics(measurement); + } + + // unsupported metric + return false; +} + +bool INA3221Sensor::getEnvironmentMetrics(meshtastic_Telemetry *measurement) +{ + struct _INA3221Measurement m = getMeasurement(ENV_CH); + + measurement->variant.environment_metrics.voltage = m.voltage; + measurement->variant.environment_metrics.current = m.current; + + return true; +} + +bool INA3221Sensor::getPowerMetrics(meshtastic_Telemetry *measurement) +{ + struct _INA3221Measurements m = getMeasurements(); + + measurement->variant.power_metrics.ch1_voltage = m.measurements[INA3221_CH1].voltage; + measurement->variant.power_metrics.ch1_current = m.measurements[INA3221_CH1].current; + measurement->variant.power_metrics.ch2_voltage = m.measurements[INA3221_CH2].voltage; + measurement->variant.power_metrics.ch2_current = m.measurements[INA3221_CH2].current; + measurement->variant.power_metrics.ch3_voltage = m.measurements[INA3221_CH3].voltage; + measurement->variant.power_metrics.ch3_current = m.measurements[INA3221_CH3].current; + return true; } uint16_t INA3221Sensor::getBusVoltageMv() { - return lround(ina3221.getVoltage(INA3221_CH1) * 1000); + return lround(ina3221.getVoltage(BAT_CH) * 1000); } #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.h b/src/modules/Telemetry/Sensor/INA3221Sensor.h index 3b8e382eea..d5121aab60 100644 --- a/src/modules/Telemetry/Sensor/INA3221Sensor.h +++ b/src/modules/Telemetry/Sensor/INA3221Sensor.h @@ -12,6 +12,21 @@ class INA3221Sensor : public TelemetrySensor, VoltageSensor private: INA3221 ina3221 = INA3221(INA3221_ADDR42_SDA); + // channel to report voltage/current for environment metrics + ina3221_ch_t ENV_CH = INA3221_CH1; + + // channel to report battery voltage for device_battery_ina_address + ina3221_ch_t BAT_CH = INA3221_CH1; + + // get a single measurement for a channel + struct _INA3221Measurement getMeasurement(ina3221_ch_t ch); + + // get all measurements for all channels + struct _INA3221Measurements getMeasurements(); + + bool getEnvironmentMetrics(meshtastic_Telemetry *measurement); + bool getPowerMetrics(meshtastic_Telemetry *measurement); + protected: void setup() override; @@ -22,4 +37,14 @@ class INA3221Sensor : public TelemetrySensor, VoltageSensor virtual uint16_t getBusVoltageMv() override; }; +struct _INA3221Measurement { + float voltage; + float current; +}; + +struct _INA3221Measurements { + // INA3221 has 3 channels + struct _INA3221Measurement measurements[3]; +}; + #endif \ No newline at end of file From df194ca0f06bb3546c6fb25c4ab1a40ec2702b74 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 11 Jul 2024 14:08:31 -0500 Subject: [PATCH 152/211] WM1110 SDK kit enter serial DFU and add deployment packages (#4266) * Switch default upload protocol to nrfutil so that pio generates zip deploy packages * Enter serial DFU on SDK board * Remove guard for DFU zip from SDK build * NRF_USE_SERIAL_DFU macro instead --- bin/build-nrf52.sh | 10 +++------- src/platform/nrf52/main-nrf52.cpp | 5 +++++ variants/wio-sdk-wm1110/platformio.ini | 2 +- variants/wio-sdk-wm1110/variant.h | 2 ++ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index 077e2af35a..cf4ca60cb2 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -25,13 +25,9 @@ pio run --environment $1 # -v SRCELF=.pio/build/$1/firmware.elf cp $SRCELF $OUTDIR/$basename.elf -if (echo $1 | grep -q "wio-sdk-wm1110"); then - echo "Skipping dfu file" -else - echo "Generating NRF52 dfu file" - DFUPKG=.pio/build/$1/firmware.zip - cp $DFUPKG $OUTDIR/$basename-ota.zip -fi +echo "Generating NRF52 dfu file" +DFUPKG=.pio/build/$1/firmware.zip +cp $DFUPKG $OUTDIR/$basename-ota.zip echo "Generating NRF52 uf2 file" SRCHEX=.pio/build/$1/firmware.hex diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index c5b217f0e3..7334f3a041 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -286,5 +286,10 @@ void clearBonds() void enterDfuMode() { +// SDK kit does not have native USB like almost all other NRF52 boards +#ifdef NRF_USE_SERIAL_DFU + enterSerialDfu(); +#else enterUf2Dfu(); +#endif } \ No newline at end of file diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini index dc7d47310c..7667174289 100644 --- a/variants/wio-sdk-wm1110/platformio.ini +++ b/variants/wio-sdk-wm1110/platformio.ini @@ -20,7 +20,7 @@ debug_tool = jlink ; No need to reflash if the binary hasn't changed debug_load_mode = modified ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -upload_protocol = jlink +upload_protocol = nrfutil ;upload_protocol = stlink ; we prefer to stop in setup() because we are an 'ardiuno' app debug_init_break = tbreak setup diff --git a/variants/wio-sdk-wm1110/variant.h b/variants/wio-sdk-wm1110/variant.h index 8ad8c769af..8f66b1f8c8 100644 --- a/variants/wio-sdk-wm1110/variant.h +++ b/variants/wio-sdk-wm1110/variant.h @@ -107,6 +107,8 @@ extern "C" { #define LR1110_GNSS_ANT_PIN (32 + 5) // P1.05 37 +#define NRF_USE_SERIAL_DFU + #ifdef __cplusplus } #endif From eabec5ae3451c0edc33979453c8af635d538c538 Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Fri, 12 Jul 2024 11:51:26 +1200 Subject: [PATCH 153/211] Show specific frame when updating screen (#4264) * Updated setFrames in Screen.cpp Added code to attempt to revert back to the same frame that user was on prior to setFrame reload. * Space added Screen.cpp * Update Screen.cpp Make screen to revert to Frame 0 if the originally displayed frame is no longer there. * Update Screen.cpp Inserted boolean holdPosition into setFrames to indicate the requirement to stay on the same frame ( if =true) or else it will switch to new frame . Only Screen::handleStatusUpdate calls with setFrame(true). ( For Node Updates) All other types of updates call as before setFrame(), so it will change focus as needed. * Hold position, even if number of frames increases * Hold position, if handling an outgoing text message * Update Screen.cpp * Reverted chnages related to devicestate.has_rx_text_message * Reset to master * CannedMessages only handles routing packets when waiting for ACK Previously, this was calling Screen::setFrames at unexpected times * Gather position info about screen frames while regenerating * Make admin module observable Notify only when relevant. Currently: only to handle remove_nodenum. * Optionally specify which frame to focus when setFrames runs * UIFrameEvent uses enum instead of multiple booleans * Allow modules to request their own frame to be focussed This is done internally by calling MeshModule::requestFocus() Easier this way, insteady of passing the info in the UIFrameEvent: * Modules don't always know whether they should be focussed until after the UIFrameEvent has been raised, in dramFrame * Don't have to pass reference to module instance as parameter though several methods * E-Ink screensaver uses FOCUS_PRESERVE Previously, it had its own basic implementation of this. * Spelling: regional variant * trunk * Fix HAS_SCREEN guarding * More HAS_SCREEN guarding --------- Co-authored-by: BIST <77391720+slash-bit@users.noreply.github.com> Co-authored-by: Ben Meadors Co-authored-by: slash-bit --- src/graphics/Screen.cpp | 134 ++++++++++++++++++++++++---- src/graphics/Screen.h | 35 +++++++- src/mesh/MeshModule.cpp | 15 +++- src/mesh/MeshModule.h | 28 +++++- src/modules/AdminModule.cpp | 1 + src/modules/AdminModule.h | 2 +- src/modules/CannedMessageModule.cpp | 45 ++++++---- src/modules/CannedMessageModule.h | 6 +- src/modules/WaypointModule.cpp | 18 +++- src/modules/esp32/AudioModule.cpp | 6 +- 10 files changed, 239 insertions(+), 51 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 7f9c905a88..b2059b71c6 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -41,6 +41,7 @@ along with this program. If not, see . #include "mesh/Channels.h" #include "mesh/generated/meshtastic/deviceonly.pb.h" #include "meshUtils.h" +#include "modules/AdminModule.h" #include "modules/ExternalNotificationModule.h" #include "modules/TextMessageModule.h" #include "sleep.h" @@ -1725,6 +1726,7 @@ void Screen::setup() powerStatusObserver.observe(&powerStatus->onNewStatus); gpsStatusObserver.observe(&gpsStatus->onNewStatus); nodeStatusObserver.observe(&nodeStatus->onNewStatus); + adminMessageObserver.observe(adminModule); if (textMessageModule) textMessageObserver.observe(textMessageModule); if (inputBroker) @@ -1953,9 +1955,6 @@ void Screen::setWelcomeFrames() /// Determine which screensaver frame to use, then set the FrameCallback void Screen::setScreensaverFrames(FrameCallback einkScreensaver) { - // Remember current frame, restore position at power-on - uint8_t frameNumber = ui->getUiState()->currentFrame; - // Retain specified frame / overlay callback beyond scope of this method static FrameCallback screensaverFrame; static OverlayCallback screensaverOverlay; @@ -1993,9 +1992,8 @@ void Screen::setScreensaverFrames(FrameCallback einkScreensaver) #endif // Prepare now for next frame, shown when display wakes - ui->setOverlays(NULL, 0); // Clear overlay - setFrames(); // Return to normal display updates - ui->switchToFrame(frameNumber); // Attempt to return to same frame after power-on + ui->setOverlays(NULL, 0); // Clear overlay + setFrames(FOCUS_PRESERVE); // Return to normal display updates, showing same frame as before screensaver, ideally // Pick a refresh method, for when display wakes #ifdef EINK_HASQUIRK_GHOSTING @@ -2006,9 +2004,13 @@ void Screen::setScreensaverFrames(FrameCallback einkScreensaver) } #endif -// restore our regular frame list -void Screen::setFrames() +// Regenerate the normal set of frames, focusing a specific frame if requested +// Called when a frame should be added / removed, or custom frames should be cleared +void Screen::setFrames(FrameFocus focus) { + uint8_t originalPosition = ui->getUiState()->currentFrame; + FramesetInfo fsi; // Location of specific frames, for applying focus parameter + LOG_DEBUG("showing standard frames\n"); showingNormalScreen = true; @@ -2042,20 +2044,33 @@ void Screen::setFrames() // is the same offset into the moduleFrames vector // so that we can invoke the module's callback for (auto i = moduleFrames.begin(); i != moduleFrames.end(); ++i) { - normalFrames[numframes++] = drawModuleFrame; + // Draw the module frame, using the hack described above + normalFrames[numframes] = drawModuleFrame; + + // Check if the module being drawn has requested focus + // We will honor this request later, if setFrames was triggered by a UIFrameEvent + MeshModule *m = *i; + if (m->isRequestingFocus()) + fsi.positions.focusedModule = numframes; + + numframes++; } LOG_DEBUG("Added modules. numframes: %d\n", numframes); // If we have a critical fault, show it first - if (error_code) + fsi.positions.fault = numframes; + if (error_code) { normalFrames[numframes++] = drawCriticalFaultFrame; + focus = FOCUS_FAULT; // Change our "focus" parameter, to ensure we show the fault frame + } #ifdef T_WATCH_S3 normalFrames[numframes++] = screen->digitalWatchFace ? &Screen::drawDigitalClockFrame : &Screen::drawAnalogClockFrame; #endif // If we have a text message - show it next, unless it's a phone message and we aren't using any special modules + fsi.positions.textMessage = numframes; if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) { normalFrames[numframes++] = drawTextMessageFrame; } @@ -2070,11 +2085,14 @@ void Screen::setFrames() // // Since frames are basic function pointers, we have to use a helper to // call a method on debugInfo object. + fsi.positions.log = numframes; normalFrames[numframes++] = &Screen::drawDebugInfoTrampoline; // call a method on debugInfoScreen object (for more details) + fsi.positions.settings = numframes; normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline; + fsi.positions.wifi = numframes; #if HAS_WIFI && !defined(ARCH_PORTDUINO) if (isWifiAvailable()) { // call a method on debugInfoScreen object (for more details) @@ -2082,6 +2100,7 @@ void Screen::setFrames() } #endif + fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE LOG_DEBUG("Finished building frames. numframes: %d\n", numframes); ui->setFrames(normalFrames, numframes); @@ -2095,6 +2114,55 @@ void Screen::setFrames() prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list // just changed) + // Focus on a specific frame, in the frame set we just created + switch (focus) { + case FOCUS_DEFAULT: + ui->switchToFrame(0); // First frame + break; + case FOCUS_FAULT: + ui->switchToFrame(fsi.positions.fault); + break; + case FOCUS_TEXTMESSAGE: + ui->switchToFrame(fsi.positions.textMessage); + break; + case FOCUS_MODULE: + // Whichever frame was marked by MeshModule::requestFocus(), if any + // If no module requested focus, will show the first frame instead + ui->switchToFrame(fsi.positions.focusedModule); + break; + + case FOCUS_PRESERVE: + // If we can identify which type of frame "originalPosition" was, can move directly to it in the new frameset + FramesetInfo &oldFsi = this->framesetInfo; + if (originalPosition == oldFsi.positions.log) + ui->switchToFrame(fsi.positions.log); + else if (originalPosition == oldFsi.positions.settings) + ui->switchToFrame(fsi.positions.settings); + else if (originalPosition == oldFsi.positions.wifi) + ui->switchToFrame(fsi.positions.wifi); + + // If frame count has decreased + else if (fsi.frameCount < oldFsi.frameCount) { + uint8_t numDropped = oldFsi.frameCount - fsi.frameCount; + // Move n frames backwards + if (numDropped <= originalPosition) + ui->switchToFrame(originalPosition - numDropped); + // Unless that would put us "out of bounds" (< 0) + else + ui->switchToFrame(0); + } + + // If we're not sure exactly which frame we were on, at least return to the same frame number + // (node frames; module frames) + else + ui->switchToFrame(originalPosition); + + break; + } + + // Store the info about this frameset, for future setFrames calls + this->framesetInfo = fsi; + setFastFramerate(); // Draw ASAP } @@ -2549,7 +2617,7 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg) switch (arg->getStatusType()) { case STATUS_TYPE_NODE: if (showingNormalScreen && nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) { - setFrames(); // Regen the list of screens + setFrames(FOCUS_PRESERVE); // Regen the list of screen frames (returning to same frame, if possible) } nodeDB->updateGUI = false; break; @@ -2561,23 +2629,33 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg) int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) { if (showingNormalScreen) { - setFrames(); // Regen the list of screens (will show new text message) + // Outgoing message + if (packet->from == 0) + setFrames(FOCUS_PRESERVE); // Return to same frame (quietly hiding the rx text message frame) + + // Incoming message + else + setFrames(FOCUS_TEXTMESSAGE); // Focus on the new message } return 0; } +// Triggered by MeshModules int Screen::handleUIFrameEvent(const UIFrameEvent *event) { if (showingNormalScreen) { - if (event->frameChanged) { - setFrames(); // Regen the list of screens (will show new text message) - } else if (event->needRedraw) { + // Regenerate the frameset, potentially honoring a module's internal requestFocus() call + if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET) + setFrames(FOCUS_MODULE); + + // Regenerate the frameset, while attempting to maintain focus on the current frame + else if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET_BACKGROUND) + setFrames(FOCUS_PRESERVE); + + // Don't regenerate the frameset, just re-draw whatever is on screen ASAP + else if (event->action == UIFrameEvent::Action::REDRAW_ONLY) setFastFramerate(); - // TODO: We might also want switch to corresponding frame, - // but we don't know the exact frame number. - // ui->switchToFrame(0); - } } return 0; @@ -2612,6 +2690,24 @@ int Screen::handleInputEvent(const InputEvent *event) return 0; } +int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg) +{ + // Note: only selected admin messages notify this observer + // If you wish to handle a new type of message, you should modify AdminModule.cpp first + + switch (arg->which_payload_variant) { + // Node removed manually (i.e. via app) + case meshtastic_AdminMessage_remove_by_nodenum_tag: + setFrames(FOCUS_PRESERVE); + break; + + // Default no-op, in case the admin message observable gets used by other classes in future + default: + break; + } + return 0; +} + } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index b89a2917e8..93e5f2ef78 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -173,9 +173,11 @@ class Screen : public concurrency::OSThread CallbackObserver textMessageObserver = CallbackObserver(this, &Screen::handleTextMessage); CallbackObserver uiFrameEventObserver = - CallbackObserver(this, &Screen::handleUIFrameEvent); + CallbackObserver(this, &Screen::handleUIFrameEvent); // Sent by Mesh Modules CallbackObserver inputObserver = CallbackObserver(this, &Screen::handleInputEvent); + CallbackObserver adminMessageObserver = + CallbackObserver(this, &Screen::handleAdminMessage); public: explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY); @@ -394,6 +396,7 @@ class Screen : public concurrency::OSThread int handleTextMessage(const meshtastic_MeshPacket *arg); int handleUIFrameEvent(const UIFrameEvent *arg); int handleInputEvent(const InputEvent *arg); + int handleAdminMessage(const meshtastic_AdminMessage *arg); /// Used to force (super slow) eink displays to draw critical frames void forceDisplay(bool forceUiUpdate = false); @@ -450,8 +453,34 @@ class Screen : public concurrency::OSThread void handleShowPrevFrame(); void handlePrint(const char *text); void handleStartFirmwareUpdateScreen(); - /// Rebuilds our list of frames (screens) to default ones. - void setFrames(); + + // Info collected by setFrames method. + // Index location of specific frames. Used to apply the FrameFocus parameter of setFrames + struct FramesetInfo { + struct FramePositions { + uint8_t fault = 0; + uint8_t textMessage = 0; + uint8_t focusedModule = 0; + uint8_t log = 0; + uint8_t settings = 0; + uint8_t wifi = 0; + } positions; + + uint8_t frameCount = 0; + } framesetInfo; + + // Which frame we want to be displayed, after we regen the frameset by calling setFrames + enum FrameFocus : uint8_t { + FOCUS_DEFAULT, // No specific frame + FOCUS_PRESERVE, // Return to the previous frame + FOCUS_FAULT, + FOCUS_TEXTMESSAGE, + FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus + }; + + // Regenerate the normal set of frames, focusing a specific frame if requested + // Call when a frame should be added / removed, or custom frames should be cleared + void setFrames(FrameFocus focus = FOCUS_DEFAULT); /// Try to start drawing ASAP void setFastFramerate(); diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp index 04fa250bff..1ef4f60d8c 100644 --- a/src/mesh/MeshModule.cpp +++ b/src/mesh/MeshModule.cpp @@ -284,4 +284,17 @@ AdminMessageHandleResult MeshModule::handleAdminMessageForAllModules(const mesht } } return handled; -} \ No newline at end of file +} + +#if HAS_SCREEN +// Would our module like its frame to be focused after Screen::setFrames has regenerated the list of frames? +// Only considered if setFrames is triggered by a UIFrameEvent +bool MeshModule::isRequestingFocus() +{ + if (_requestingFocus) { + _requestingFocus = false; // Consume the request + return true; + } else + return false; +} +#endif \ No newline at end of file diff --git a/src/mesh/MeshModule.h b/src/mesh/MeshModule.h index 2e2af33e07..c341b301ad 100644 --- a/src/mesh/MeshModule.h +++ b/src/mesh/MeshModule.h @@ -35,10 +35,16 @@ enum class AdminMessageHandleResult { /* * This struct is used by Screen to figure out whether screen frame should be updated. */ -typedef struct _UIFrameEvent { - bool frameChanged; - bool needRedraw; -} UIFrameEvent; +struct UIFrameEvent { + // What do we actually want to happen? + enum Action { + REDRAW_ONLY, // Don't change which frames are show, just redraw, asap + REGENERATE_FRAMESET, // Regenerate (change? add? remove?) screen frames, honoring requestFocus() + REGENERATE_FRAMESET_BACKGROUND, // Regenerate screen frames, attempting to remain on the same frame throughout + } action = REDRAW_ONLY; + + // We might want to pass additional data inside this struct at some point +}; /** A baseclass for any mesh "module". * @@ -73,6 +79,7 @@ class MeshModule meshtastic_AdminMessage *response); #if HAS_SCREEN virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; } + virtual bool isRequestingFocus(); // Checked by screen, when regenerating frameset #endif protected: const char *name; @@ -176,6 +183,19 @@ class MeshModule return AdminMessageHandleResult::NOT_HANDLED; }; +#if HAS_SCREEN + /** Request that our module's screen frame be focused when Screen::setFrames runs + * Only considered if Screen::setFrames is triggered via a UIFrameEvent + * + * Having this as a separate call, instead of part of the UIFrameEvent, allows the module to delay decision + * until drawFrame() is called. This required less restructuring. + */ + bool _requestingFocus = false; + void requestFocus() { _requestingFocus = true; } +#else + void requestFocus(){}; // No-op +#endif + private: /** * If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index e24c62712d..cab63e5594 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -200,6 +200,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta case meshtastic_AdminMessage_remove_by_nodenum_tag: { LOG_INFO("Client is receiving a remove_nodenum command.\n"); nodeDB->removeNodeByNum(r->remove_by_nodenum); + this->notifyObservers(r); // Observed by screen break; } case meshtastic_AdminMessage_set_favorite_node_tag: { diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h index 6ecc888294..a5ffeb7d60 100644 --- a/src/modules/AdminModule.h +++ b/src/modules/AdminModule.h @@ -7,7 +7,7 @@ /** * Admin module for admin messages */ -class AdminModule : public ProtobufModule +class AdminModule : public ProtobufModule, public Observable { public: /** Constructor diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index be414dce13..84b5a3260e 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -148,8 +148,9 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) if (this->currentMessageIndex == 0) { this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT; - UIFrameEvent e = {false, true}; - e.frameChanged = true; + requestFocus(); // Tell Screen::setFrames to move to our module's frame, next time it runs + UIFrameEvent e; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->notifyObservers(&e); return 0; @@ -166,8 +167,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } } if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL)) { - UIFrameEvent e = {false, true}; - e.frameChanged = true; + UIFrameEvent e; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->currentMessageIndex = -1; #if !defined(T_WATCH_S3) && !defined(RAK14014) @@ -353,6 +354,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } if (validEvent) { + requestFocus(); // Tell Screen::setFrames to move to our module's frame, next time it runs + // Let runOnce to be called immediately. if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) { setIntervalFromNow(0); // on fast keypresses, this isn't fast enough. @@ -378,6 +381,11 @@ void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const cha p->decoded.payload.size++; } + // Only receive routing messages when expecting ACK for a canned message + // Prevents the canned message module from regenerating the screen's frameset at unexpected times, + // or raising a UIFrameEvent before another module has the chance + this->waitingForAck = true; + LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes); service.sendToMesh( @@ -393,13 +401,13 @@ int32_t CannedMessageModule::runOnce() return INT32_MAX; } // LOG_DEBUG("Check status\n"); - UIFrameEvent e = {false, true}; + UIFrameEvent e; if ((this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) || (this->runState == CANNED_MESSAGE_RUN_STATE_MESSAGE)) { // TODO: might have some feedback of sending state this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; temporaryMessage = ""; - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->currentMessageIndex = -1; this->freetext = ""; // clear freetext this->cursor = 0; @@ -412,7 +420,7 @@ int32_t CannedMessageModule::runOnce() } else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) && ((millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)) { // Reset module - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->currentMessageIndex = -1; this->freetext = ""; // clear freetext this->cursor = 0; @@ -449,7 +457,7 @@ int32_t CannedMessageModule::runOnce() this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; } } - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->currentMessageIndex = -1; this->freetext = ""; // clear freetext this->cursor = 0; @@ -463,7 +471,7 @@ int32_t CannedMessageModule::runOnce() } else if ((this->runState != CANNED_MESSAGE_RUN_STATE_FREETEXT) && (this->currentMessageIndex == -1)) { this->currentMessageIndex = 0; LOG_DEBUG("First touch (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage()); - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE; } else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_UP) { if (this->messagesCount > 0) { @@ -567,7 +575,7 @@ int32_t CannedMessageModule::runOnce() break; } if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen switch (this->payload) { // code below all trigger the freetext window (where you type to send a message) or reset the // display back to the default window case 0x08: // backspace @@ -706,8 +714,8 @@ int CannedMessageModule::getPrevIndex() void CannedMessageModule::showTemporaryMessage(const String &message) { temporaryMessage = message; - UIFrameEvent e = {false, true}; - e.frameChanged = true; + UIFrameEvent e; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen notifyObservers(&e); runState = CANNED_MESSAGE_RUN_STATE_MESSAGE; // run this loop again in 2 seconds, next iteration will clear the display @@ -914,11 +922,13 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st char buffer[50]; if (temporaryMessage.length() != 0) { + requestFocus(); // Tell Screen::setFrames to move to our module's frame LOG_DEBUG("Drawing temporary message: %s", temporaryMessage.c_str()); display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(FONT_MEDIUM); display->drawString(display->getWidth() / 2 + x, 0 + y + 12, temporaryMessage); } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) { + requestFocus(); // Tell Screen::setFrames to move to our module's frame display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(FONT_MEDIUM); String displayString; @@ -940,6 +950,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st display->drawStringf(display->getWidth() / 2 + x, y + 130, buffer, rssiString, this->lastRxRssi); } } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) { + requestFocus(); // Tell Screen::setFrames to move to our module's frame display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(FONT_MEDIUM); display->drawString(display->getWidth() / 2 + x, 0 + y + 12, "Sending..."); @@ -948,7 +959,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st display->setFont(FONT_SMALL); display->drawString(10 + x, 0 + y + FONT_HEIGHT_SMALL, "Canned Message\nModule disabled."); } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { - + requestFocus(); // Tell Screen::setFrames to move to our module's frame #if defined(T_WATCH_S3) || defined(RAK14014) drawKeyboard(display, state, 0, 0); #else @@ -1030,16 +1041,18 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp) { - if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP) { + if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP && waitingForAck) { // look for a request_id if (mp.decoded.request_id != 0) { - UIFrameEvent e = {false, true}; - e.frameChanged = true; + UIFrameEvent e; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + requestFocus(); // Tell Screen::setFrames that our module's frame should be shown, even if not "first" in the frameset this->runState = CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED; this->incoming = service.getNodenumFromRequestId(mp.decoded.request_id); meshtastic_Routing decoded = meshtastic_Routing_init_default; pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_Routing_fields, &decoded); this->ack = decoded.error_reason == meshtastic_Routing_Error_NONE; + waitingForAck = false; // No longer want routing packets this->notifyObservers(&e); // run the next time 2 seconds later setIntervalFromNow(2000); diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h index 00e8c2bf9a..797b9f7cff 100644 --- a/src/modules/CannedMessageModule.h +++ b/src/modules/CannedMessageModule.h @@ -81,9 +81,8 @@ class CannedMessageModule : public SinglePortModule, public Observabledecoded.portnum) { - case meshtastic_PortNum_TEXT_MESSAGE_APP: case meshtastic_PortNum_ROUTING_APP: - return true; + return waitingForAck; default: return false; } @@ -140,7 +139,8 @@ class CannedMessageModule : public SinglePortModule, public ObservablenotifyObservers(&e); } } else { @@ -209,7 +209,7 @@ int32_t AudioModule::runOnce() } tx_encode_frame_index = sizeof(tx_header); radio_state = RadioState::rx; - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->notifyObservers(&e); } } From 699d37b04c5a87a07e0444dbd724ad0b3ef7a7b2 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 12 Jul 2024 09:24:42 -0500 Subject: [PATCH 154/211] Move up telemetry defaults to every 30 minutes (#4274) --- src/mesh/Default.h | 1 + src/modules/Telemetry/AirQualityTelemetry.cpp | 3 ++- src/modules/Telemetry/DeviceTelemetry.cpp | 3 ++- src/modules/Telemetry/EnvironmentTelemetry.cpp | 6 ++++-- src/modules/Telemetry/PowerTelemetry.cpp | 6 ++++-- src/modules/esp32/PaxcounterModule.cpp | 2 +- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/mesh/Default.h b/src/mesh/Default.h index 95723744b1..cc3927914b 100644 --- a/src/mesh/Default.h +++ b/src/mesh/Default.h @@ -5,6 +5,7 @@ #define ONE_MINUTE_MS 60 * 1000 #define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60) +#define default_telemetry_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 30 * 60) #define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60) #define default_wait_bluetooth_secs IF_ROUTER(1, 60) #define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index ba043feabf..43b0ac46c3 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -47,7 +47,8 @@ int32_t AirQualityTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval, + default_telemetry_broadcast_interval_secs))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 9cc4bf6ea5..9fe679b41f 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -17,7 +17,8 @@ int32_t DeviceTelemetryModule::runOnce() { refreshUptime(); if (((lastSentToMesh == 0) || - ((uptimeLastMs - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval))) && + ((uptimeLastMs - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval, + default_telemetry_broadcast_interval_secs))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil() && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER && config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) { diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 23200fd00a..a9740879d6 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -63,7 +63,8 @@ int32_t EnvironmentTelemetryModule::runOnce() { if (sleepOnNextExecution == true) { sleepOnNextExecution = false; - uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval); + uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval, + default_telemetry_broadcast_interval_secs); LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs); doDeepSleep(nightyNightMs, true); } @@ -144,7 +145,8 @@ int32_t EnvironmentTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval, + default_telemetry_broadcast_interval_secs))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index fb5aee375b..6915d67e3d 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -24,7 +24,8 @@ int32_t PowerTelemetryModule::runOnce() { if (sleepOnNextExecution == true) { sleepOnNextExecution = false; - uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval); + uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval, + default_telemetry_broadcast_interval_secs); LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs); doDeepSleep(nightyNightMs, true); } @@ -70,7 +71,8 @@ int32_t PowerTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval, + default_telemetry_broadcast_interval_secs))) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); lastSentToMesh = now; diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index 0bae515dfa..34d6fb1d09 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -101,7 +101,7 @@ int32_t PaxcounterModule::runOnce() sendInfo(NODENUM_BROADCAST); } return Default::getConfiguredOrDefaultMs(moduleConfig.paxcounter.paxcounter_update_interval, - default_broadcast_interval_secs); + default_telemetry_broadcast_interval_secs); } else { return disable(); } From 0fa99745181cf3c0b193603d89e89b1411e5c40c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 12 Jul 2024 11:48:35 -0500 Subject: [PATCH 155/211] Don't send node info interrogation when ch. util is >25% (#4273) --- src/mesh/MeshService.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 9e2a5b1102..a652d0a50e 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -94,7 +94,11 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp) } else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user && nodeInfoModule) { LOG_INFO("Heard a node on channel %d we don't know, sending NodeInfo and asking for a response.\n", mp->channel); - nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel); + if (airTime->isTxAllowedChannelUtil(true)) { + nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel); + } else { + LOG_DEBUG("Skip sending NodeInfo due to > 25 percent channel util.\n"); + } } printPacket("Forwarding to phone", mp); From c5d747cd3e059448d0057fdcefb590eafb4c45aa Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 13 Jul 2024 05:59:19 -0500 Subject: [PATCH 156/211] Scale default intervals based for *online* mesh size past 40 nodes (#4277) * Add congestion scaling coefficient * Added active mesh sized based interval scaling * Moved back to bottom * Format * Add observers and use correct number of online nodes --- src/mesh/Default.cpp | 30 +++++++++++++++---- src/mesh/Default.h | 13 ++++++++ src/mesh/ProtobufModule.h | 9 ++++++ src/modules/DetectionSensorModule.cpp | 4 +-- src/modules/NeighborInfoModule.cpp | 8 +++-- src/modules/NeighborInfoModule.h | 3 ++ src/modules/PositionModule.cpp | 6 ++-- src/modules/PositionModule.h | 5 +++- src/modules/Telemetry/AirQualityTelemetry.cpp | 5 ++-- src/modules/Telemetry/AirQualityTelemetry.h | 5 ++++ src/modules/Telemetry/DeviceTelemetry.cpp | 5 ++-- src/modules/Telemetry/DeviceTelemetry.h | 4 +++ .../Telemetry/EnvironmentTelemetry.cpp | 5 ++-- src/modules/Telemetry/EnvironmentTelemetry.h | 5 ++++ src/modules/Telemetry/PowerTelemetry.cpp | 5 ++-- src/modules/Telemetry/PowerTelemetry.h | 4 +++ src/modules/esp32/PaxcounterModule.cpp | 4 +-- 17 files changed, 97 insertions(+), 23 deletions(-) diff --git a/src/mesh/Default.cpp b/src/mesh/Default.cpp index db058c5b0c..d4e9b3d790 100644 --- a/src/mesh/Default.cpp +++ b/src/mesh/Default.cpp @@ -1,23 +1,43 @@ #include "Default.h" -uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval) +uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval) { if (configuredInterval > 0) return configuredInterval * 1000; - return default_broadcast_interval_secs * 1000; + return defaultInterval * 1000; } -uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval) +uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval) { if (configuredInterval > 0) return configuredInterval * 1000; - return defaultInterval * 1000; + return default_broadcast_interval_secs * 1000; } uint32_t Default::getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue) { if (configured > 0) return configured; - return defaultValue; +} +/** + * Calculates the scaled value of the configured or default value in ms based on the number of online nodes. + * + * For example a default of 30 minutes (1800 seconds * 1000) would yield: + * 45 nodes = 2475 * 1000 + * 60 nodes = 4500 * 1000 + * 75 nodes = 6525 * 1000 + * 90 nodes = 8550 * 1000 + * @param configured The configured value. + * @param defaultValue The default value. + * @param numOnlineNodes The number of online nodes. + * @return The scaled value of the configured or default value. + */ +uint32_t Default::getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes) +{ + // If we are a router, we don't scale the value. It's already significantly higher. + if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) + return getConfiguredOrDefaultMs(configured, defaultValue); + + return getConfiguredOrDefaultMs(configured, defaultValue) * congestionScalingCoefficient(numOnlineNodes); } \ No newline at end of file diff --git a/src/mesh/Default.h b/src/mesh/Default.h index cc3927914b..7d79d696e5 100644 --- a/src/mesh/Default.h +++ b/src/mesh/Default.h @@ -29,4 +29,17 @@ class Default static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval); static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval); static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue); + static uint32_t getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes); + + private: + static float congestionScalingCoefficient(int numOnlineNodes) + { + if (numOnlineNodes <= 40) { + return 1.0; // No scaling for 40 or fewer nodes + } else { + // Sscaling based on number of nodes over 40 + int nodesOverForty = (numOnlineNodes - 40); + return 1.0 + (nodesOverForty * 0.075); // Each number of online node scales by 0.075 + } + } }; \ No newline at end of file diff --git a/src/mesh/ProtobufModule.h b/src/mesh/ProtobufModule.h index 0d3da95683..ed76b877f1 100644 --- a/src/mesh/ProtobufModule.h +++ b/src/mesh/ProtobufModule.h @@ -13,6 +13,7 @@ template class ProtobufModule : protected SinglePortModule const pb_msgdesc_t *fields; public: + uint8_t numOnlineNodes = 0; /** Constructor * name is for debugging output */ @@ -61,6 +62,14 @@ template class ProtobufModule : protected SinglePortModule return sender; } + int handleStatusUpdate(const meshtastic::Status *arg) + { + if (arg->getStatusType() == STATUS_TYPE_NODE) { + numOnlineNodes = nodeStatus->getNumOnline(); + } + return 0; + } + private: /** Called to handle a particular incoming message diff --git a/src/modules/DetectionSensorModule.cpp b/src/modules/DetectionSensorModule.cpp index fd26749c1e..b6e5f1e298 100644 --- a/src/modules/DetectionSensorModule.cpp +++ b/src/modules/DetectionSensorModule.cpp @@ -58,8 +58,8 @@ int32_t DetectionSensorModule::runOnce() // of heartbeat. We only do this if the minimum broadcast interval is greater than zero, otherwise we'll only broadcast state // change detections. else if (moduleConfig.detection_sensor.state_broadcast_secs > 0 && - (millis() - lastSentToMesh) >= - Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs)) { + (millis() - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.detection_sensor.state_broadcast_secs, + default_telemetry_broadcast_interval_secs)) { sendCurrentStateMessage(); return DELAYED_INTERVAL; } diff --git a/src/modules/NeighborInfoModule.cpp b/src/modules/NeighborInfoModule.cpp index 3925bea9a8..774b42d7bd 100644 --- a/src/modules/NeighborInfoModule.cpp +++ b/src/modules/NeighborInfoModule.cpp @@ -39,11 +39,12 @@ NeighborInfoModule::NeighborInfoModule() concurrency::OSThread("NeighborInfoModule") { ourPortNum = meshtastic_PortNum_NEIGHBORINFO_APP; + nodeStatusObserver.observe(&nodeStatus->onNewStatus); if (moduleConfig.neighbor_info.enabled) { isPromiscuous = true; // Update neighbors from all packets - setIntervalFromNow( - Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs)); + setIntervalFromNow(Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, + default_telemetry_broadcast_interval_secs)); } else { LOG_DEBUG("NeighborInfoModule is disabled\n"); disable(); @@ -119,7 +120,8 @@ int32_t NeighborInfoModule::runOnce() if (airTime->isTxAllowedChannelUtil(true) && airTime->isTxAllowedAirUtil()) { sendNeighborInfo(NODENUM_BROADCAST, false); } - return Default::getConfiguredOrDefaultMs(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs); + return Default::getConfiguredOrDefaultMsScaled(moduleConfig.neighbor_info.update_interval, default_broadcast_interval_secs, + numOnlineNodes); } /* diff --git a/src/modules/NeighborInfoModule.h b/src/modules/NeighborInfoModule.h index 496fdece58..aa76a21871 100644 --- a/src/modules/NeighborInfoModule.h +++ b/src/modules/NeighborInfoModule.h @@ -7,6 +7,9 @@ */ class NeighborInfoModule : public ProtobufModule, private concurrency::OSThread { + CallbackObserver nodeStatusObserver = + CallbackObserver(this, &NeighborInfoModule::handleStatusUpdate); + std::vector neighbors; public: diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index 61616841b3..b3294a8669 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -28,6 +28,8 @@ PositionModule::PositionModule() { precision = 0; // safe starting value isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others + nodeStatusObserver.observe(&nodeStatus->onNewStatus); + if (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER && config.device.role != meshtastic_Config_DeviceConfig_Role_TAK_TRACKER) setIntervalFromNow(60 * 1000); @@ -333,8 +335,8 @@ int32_t PositionModule::runOnce() // We limit our GPS broadcasts to a max rate uint32_t now = millis(); - uint32_t intervalMs = - Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs); + uint32_t intervalMs = Default::getConfiguredOrDefaultMsScaled(config.position.position_broadcast_secs, + default_broadcast_interval_secs, numOnlineNodes); uint32_t msSinceLastSend = now - lastGpsSend; // Only send packets if the channel util. is less than 25% utilized or we're a tracker with less than 40% utilized. if (!airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER && diff --git a/src/modules/PositionModule.h b/src/modules/PositionModule.h index 763b51e5cb..a5277aff69 100644 --- a/src/modules/PositionModule.h +++ b/src/modules/PositionModule.h @@ -8,6 +8,9 @@ */ class PositionModule : public ProtobufModule, private concurrency::OSThread { + CallbackObserver nodeStatusObserver = + CallbackObserver(this, &PositionModule::handleStatusUpdate); + /// The id of the last packet we sent, to allow us to cancel it if we make something fresher PacketId prevPacketId = 0; @@ -59,7 +62,7 @@ class PositionModule : public ProtobufModule, private concu void sendLostAndFoundText(); const uint32_t minimumTimeThreshold = - Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30); + Default::getConfiguredOrDefaultMsScaled(config.position.broadcast_smart_minimum_interval_secs, 30, numOnlineNodes); }; struct SmartPosition { diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index 43b0ac46c3..6d2bf5e015 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -47,8 +47,9 @@ int32_t AirQualityTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval, - default_telemetry_broadcast_interval_secs))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.air_quality_interval, + default_telemetry_broadcast_interval_secs, + numOnlineNodes))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); diff --git a/src/modules/Telemetry/AirQualityTelemetry.h b/src/modules/Telemetry/AirQualityTelemetry.h index 9d09078b11..23df6ac586 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.h +++ b/src/modules/Telemetry/AirQualityTelemetry.h @@ -10,6 +10,10 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public ProtobufModule { + CallbackObserver nodeStatusObserver = + CallbackObserver(this, + &AirQualityTelemetryModule::handleStatusUpdate); + public: AirQualityTelemetryModule() : concurrency::OSThread("AirQualityTelemetryModule"), @@ -18,6 +22,7 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf lastMeasurementPacket = nullptr; setIntervalFromNow(10 * 1000); aqi = Adafruit_PM25AQI(); + nodeStatusObserver.observe(&nodeStatus->onNewStatus); } protected: diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 9fe679b41f..9c1ac289ca 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -17,8 +17,9 @@ int32_t DeviceTelemetryModule::runOnce() { refreshUptime(); if (((lastSentToMesh == 0) || - ((uptimeLastMs - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval, - default_telemetry_broadcast_interval_secs))) && + ((uptimeLastMs - lastSentToMesh) >= + Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.device_update_interval, + default_telemetry_broadcast_interval_secs, numOnlineNodes))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil() && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER && config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) { diff --git a/src/modules/Telemetry/DeviceTelemetry.h b/src/modules/Telemetry/DeviceTelemetry.h index 5f4e761f96..baaf59f280 100644 --- a/src/modules/Telemetry/DeviceTelemetry.h +++ b/src/modules/Telemetry/DeviceTelemetry.h @@ -7,6 +7,9 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModule { + CallbackObserver nodeStatusObserver = + CallbackObserver(this, &DeviceTelemetryModule::handleStatusUpdate); + public: DeviceTelemetryModule() : concurrency::OSThread("DeviceTelemetryModule"), @@ -14,6 +17,7 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu { uptimeWrapCount = 0; uptimeLastMs = millis(); + nodeStatusObserver.observe(&nodeStatus->onNewStatus); setIntervalFromNow(45 * 1000); // Wait until NodeInfo is sent } virtual bool wantUIFrame() { return false; } diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index a9740879d6..0784f680d4 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -145,8 +145,9 @@ int32_t EnvironmentTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval, - default_telemetry_broadcast_interval_secs))) && + ((now - lastSentToMesh) >= + Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.environment_update_interval, + default_telemetry_broadcast_interval_secs, numOnlineNodes))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); diff --git a/src/modules/Telemetry/EnvironmentTelemetry.h b/src/modules/Telemetry/EnvironmentTelemetry.h index ced617c2fc..59d272e78d 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.h +++ b/src/modules/Telemetry/EnvironmentTelemetry.h @@ -11,12 +11,17 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public ProtobufModule { + CallbackObserver nodeStatusObserver = + CallbackObserver(this, + &EnvironmentTelemetryModule::handleStatusUpdate); + public: EnvironmentTelemetryModule() : concurrency::OSThread("EnvironmentTelemetryModule"), ProtobufModule("EnvironmentTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg) { lastMeasurementPacket = nullptr; + nodeStatusObserver.observe(&nodeStatus->onNewStatus); setIntervalFromNow(10 * 1000); } virtual bool wantUIFrame() override; diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index 6915d67e3d..a6f922e563 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -71,8 +71,9 @@ int32_t PowerTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval, - default_telemetry_broadcast_interval_secs))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMsScaled(moduleConfig.telemetry.power_update_interval, + default_telemetry_broadcast_interval_secs, + numOnlineNodes))) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); lastSentToMesh = now; diff --git a/src/modules/Telemetry/PowerTelemetry.h b/src/modules/Telemetry/PowerTelemetry.h index 1b68847dba..f8248304eb 100644 --- a/src/modules/Telemetry/PowerTelemetry.h +++ b/src/modules/Telemetry/PowerTelemetry.h @@ -12,12 +12,16 @@ class PowerTelemetryModule : private concurrency::OSThread, public ProtobufModule { + CallbackObserver nodeStatusObserver = + CallbackObserver(this, &PowerTelemetryModule::handleStatusUpdate); + public: PowerTelemetryModule() : concurrency::OSThread("PowerTelemetryModule"), ProtobufModule("PowerTelemetry", meshtastic_PortNum_TELEMETRY_APP, &meshtastic_Telemetry_msg) { lastMeasurementPacket = nullptr; + nodeStatusObserver.observe(&nodeStatus->onNewStatus); setIntervalFromNow(10 * 1000); } virtual bool wantUIFrame() override; diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index 34d6fb1d09..a8fe5c4c5b 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -100,8 +100,8 @@ int32_t PaxcounterModule::runOnce() } else { sendInfo(NODENUM_BROADCAST); } - return Default::getConfiguredOrDefaultMs(moduleConfig.paxcounter.paxcounter_update_interval, - default_telemetry_broadcast_interval_secs); + return Default::getConfiguredOrDefaultMsScaled(moduleConfig.paxcounter.paxcounter_update_interval, + default_telemetry_broadcast_interval_secs, numOnlineNodes); } else { return disable(); } From 4286f2c2ddb60728f91e3b89cf19a1bf20503813 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 13 Jul 2024 06:07:20 -0500 Subject: [PATCH 157/211] Minor version bump --- version.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.properties b/version.properties index c9336d539a..7d2c262489 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 -minor = 3 -build = 16 +minor = 4 +build = 0 From ca2b45a6e2843b6f17df740da29ad5b9cc68c5a3 Mon Sep 17 00:00:00 2001 From: Lennart Buhl Date: Sat, 13 Jul 2024 13:09:51 +0200 Subject: [PATCH 158/211] Fix that Dockerfile would not run with podman (#4262) * Fix that Dockerfile would not run with podman * Migrate away from non-OCI-compliant SHELL command in Dockerfile --- Dockerfile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 08cb3925d2..fc34fbd4c3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,8 +7,6 @@ ENV TZ=Etc/UTC # > At the moment, setting "LANG=C" on a Linux system *fundamentally breaks Python 3*, and that's not OK. ENV LANG C.UTF-8 -SHELL ["/bin/bash", "-o", "pipefail", "-c"] - # Install build deps USER root @@ -24,10 +22,10 @@ USER mesh WORKDIR /tmp/firmware RUN python3 -m venv /tmp/firmware -RUN source ./bin/activate && pip3 install --no-cache-dir -U platformio==6.1.14 +RUN bash -o pipefail -c "source bin/activate; pip3 install --no-cache-dir -U platformio==6.1.15" # trunk-ignore(terrascan/AC_DOCKER_00024): We would actually like these files to be owned by mesh tyvm COPY --chown=mesh:mesh . /tmp/firmware -RUN source ./bin/activate && chmod +x /tmp/firmware/bin/build-native.sh && ./bin/build-native.sh +RUN bash -o pipefail -c "source ./bin/activate && bash ./bin/build-native.sh" RUN cp "/tmp/firmware/release/meshtasticd_linux_$(uname -m)" "/tmp/firmware/release/meshtasticd" From 141ae296b73819be64d963076d309973d966e863 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Sat, 13 Jul 2024 19:47:38 +0800 Subject: [PATCH 159/211] Add Seeed Wio WM1110 to Github issue template (#4283) --- .github/ISSUE_TEMPLATE/Bug Report.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/Bug Report.yml b/.github/ISSUE_TEMPLATE/Bug Report.yml index 7fe42051cc..b5ca0db403 100644 --- a/.github/ISSUE_TEMPLATE/Bug Report.yml +++ b/.github/ISSUE_TEMPLATE/Bug Report.yml @@ -52,6 +52,7 @@ body: - Raspberry Pi Pico (W) - Relay v1 - Relay v2 + - Seeed Wio Tracker 1110 - DIY - Other validations: From 9e4ce86c2af78129b0f6c4b0b8bcf8915cae0132 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sat, 13 Jul 2024 19:36:44 +0200 Subject: [PATCH 160/211] Let StoreForward server send history to phoneAPI (#4282) * Send StoreForward history of the server to a connected client To extend the ToPhoneQueue * Add delay after sending history info * Don't allow history request over LoRa on default channel --------- Co-authored-by: Ben Meadors --- src/mesh/Channels.cpp | 22 +- src/mesh/Channels.h | 5 +- src/mesh/MeshService.cpp | 11 + src/mesh/MeshService.h | 5 + src/mesh/PhoneAPI.cpp | 8 + src/modules/AdminModule.cpp | 5 + src/modules/esp32/StoreForwardModule.cpp | 358 +++++++++++++---------- src/modules/esp32/StoreForwardModule.h | 22 +- 8 files changed, 256 insertions(+), 180 deletions(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 079af4eca0..bb4d629e7b 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -277,6 +277,17 @@ const char *Channels::getName(size_t chIndex) return channelName; } +bool Channels::isDefaultChannel(const meshtastic_Channel &ch) +{ + if (ch.settings.psk.size == 1 && ch.settings.psk.bytes[0] == 1) { + const char *presetName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false); + // Check if the name is the default derived from the modem preset + if (strcmp(ch.settings.name, presetName) == 0) + return true; + } + return false; +} + bool Channels::hasDefaultChannel() { // If we don't use a preset or the default frequency slot, or we override the frequency, we don't have a default channel @@ -285,13 +296,8 @@ bool Channels::hasDefaultChannel() // Check if any of the channels are using the default name and PSK for (size_t i = 0; i < getNumChannels(); i++) { const auto &ch = getByIndex(i); - if (ch.settings.psk.size == 1 && ch.settings.psk.bytes[0] == 1) { - const char *name = getName(i); - const char *presetName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false); - // Check if the name is the default derived from the modem preset - if (strcmp(name, presetName) == 0) - return true; - } + if (isDefaultChannel(ch)) + return true; } return false; } @@ -324,4 +330,4 @@ bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash) int16_t Channels::setActiveByIndex(ChannelIndex channelIndex) { return setCrypto(channelIndex); -} \ No newline at end of file +} diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index 952445a1da..eaccea8e1d 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -83,6 +83,9 @@ class Channels */ int16_t setActiveByIndex(ChannelIndex channelIndex); + // Returns true if the channel has the default name and PSK + bool isDefaultChannel(const meshtastic_Channel &ch); + // Returns true if we can be reached via a channel with the default settings given a region and modem preset bool hasDefaultChannel(); @@ -126,4 +129,4 @@ class Channels }; /// Singleton channel table -extern Channels channels; \ No newline at end of file +extern Channels channels; diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index a652d0a50e..1181ffb9a8 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -293,6 +293,17 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p) { perhapsDecode(p); +#ifdef ARCH_ESP32 +#if !MESHTASTIC_EXCLUDE_STOREFORWARD + if (moduleConfig.store_forward.enabled && storeForwardModule->isServer() && + p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) { + releaseToPool(p); // Copy is already stored in StoreForward history + fromNum++; // Notify observers for packet from radio + return; + } +#endif +#endif + if (toPhoneQueue.numFree() == 0) { if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP || p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) { diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index d777b7a01a..3ac35bb627 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -13,6 +13,11 @@ #if defined(ARCH_PORTDUINO) && !HAS_RADIO #include "../platform/portduino/SimRadio.h" #endif +#ifdef ARCH_ESP32 +#if !MESHTASTIC_EXCLUDE_STOREFORWARD +#include "modules/esp32/StoreForwardModule.h" +#endif +#endif extern Allocator &queueStatusPool; extern Allocator &mqttClientProxyMessagePool; diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 0f69b21f9c..0b63b4a581 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -503,6 +503,14 @@ bool PhoneAPI::available() return true; } +#ifdef ARCH_ESP32 +#if !MESHTASTIC_EXCLUDE_STOREFORWARD + // Check if StoreForward has packets stored for us. + if (!packetForPhone && storeForwardModule) + packetForPhone = storeForwardModule->getForPhone(); +#endif +#endif + if (!packetForPhone) packetForPhone = service.getForPhone(); hasPacket = !!packetForPhone; diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index cab63e5594..98b789f41d 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -392,6 +392,11 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) // Router Client is deprecated; Set it to client if (c.payload_variant.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT) { config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT; + if (moduleConfig.store_forward.enabled && !moduleConfig.store_forward.is_server) { + moduleConfig.store_forward.is_server = true; + changes |= SEGMENT_MODULECONFIG; + requiresReboot = true; + } } break; case meshtastic_Config_position_tag: diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp index dc8650ad0b..ff0f796a1b 100644 --- a/src/modules/esp32/StoreForwardModule.cpp +++ b/src/modules/esp32/StoreForwardModule.cpp @@ -35,13 +35,10 @@ int32_t StoreForwardModule::runOnce() if (moduleConfig.store_forward.enabled && is_server) { // Send out the message queue. if (this->busy) { - // Only send packets if the channel is less than 25% utilized. - if (airTime->isTxAllowedChannelUtil(true)) { - storeForwardModule->sendPayload(this->busyTo, this->packetHistoryTXQueue_index); - if (this->packetHistoryTXQueue_index < packetHistoryTXQueue_size - 1) { - this->packetHistoryTXQueue_index++; - } else { - this->packetHistoryTXQueue_index = 0; + // Only send packets if the channel is less than 25% utilized and until historyReturnMax + if (airTime->isTxAllowedChannelUtil(true) && this->requestCount < this->historyReturnMax) { + if (!storeForwardModule->sendPayload(this->busyTo, this->last_time)) { + this->requestCount = 0; this->busy = false; } } @@ -75,9 +72,6 @@ void StoreForwardModule::populatePSRAM() LOG_DEBUG("*** Before PSRAM initialization: heap %d/%d PSRAM %d/%d\n", memGet.getFreeHeap(), memGet.getHeapSize(), memGet.getFreePsram(), memGet.getPsramSize()); - this->packetHistoryTXQueue = - static_cast(ps_calloc(this->historyReturnMax, sizeof(PacketHistoryStruct))); - /* Use a maximum of 2/3 the available PSRAM unless otherwise specified. Note: This needs to be done after every thing that would use PSRAM */ @@ -95,13 +89,15 @@ void StoreForwardModule::populatePSRAM() /** * Sends messages from the message history to the specified recipient. * - * @param msAgo The number of milliseconds ago from which to start sending messages. + * @param sAgo The number of seconds ago from which to start sending messages. * @param to The recipient ID to send the messages to. */ -void StoreForwardModule::historySend(uint32_t msAgo, uint32_t to) +void StoreForwardModule::historySend(uint32_t secAgo, uint32_t to) { - uint32_t lastIndex = lastRequest.find(to) != lastRequest.end() ? lastRequest[to] : 0; - uint32_t queueSize = storeForwardModule->historyQueueCreate(msAgo, to, &lastIndex); + this->last_time = getTime() < secAgo ? 0 : getTime() - secAgo; + uint32_t queueSize = getNumAvailablePackets(to, last_time); + if (queueSize > this->historyReturnMax) + queueSize = this->historyReturnMax; if (queueSize) { LOG_INFO("*** S&F - Sending %u message(s)\n", queueSize); @@ -114,62 +110,66 @@ void StoreForwardModule::historySend(uint32_t msAgo, uint32_t to) sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_HISTORY; sf.which_variant = meshtastic_StoreAndForward_history_tag; sf.variant.history.history_messages = queueSize; - sf.variant.history.window = msAgo; - sf.variant.history.last_request = lastIndex; - lastRequest[to] = lastIndex; + sf.variant.history.window = secAgo * 1000; + sf.variant.history.last_request = lastRequest[to]; storeForwardModule->sendMessage(to, sf); + setIntervalFromNow(this->packetTimeMax); // Delay start of sending payloads } /** - * Creates a new history queue with messages that were received within the specified time frame. + * Returns the number of available packets in the message history for a specified destination node. * - * @param msAgo The number of milliseconds ago to start the history queue. - * @param to The NodeNum of the recipient. - * @param last_request_index The index in the packet history of the last request from this node. - * @return The ID of the newly created history queue. + * @param dest The destination node number. + * @param last_time The relative time to start counting messages from. + * @return The number of available packets in the message history. */ -uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to, uint32_t *last_request_index) +uint32_t StoreForwardModule::getNumAvailablePackets(NodeNum dest, uint32_t last_time) { + uint32_t count = 0; + if (lastRequest.find(dest) == lastRequest.end()) { + lastRequest[dest] = 0; + } + for (uint32_t i = lastRequest[dest]; i < this->packetHistoryTotalCount; i++) { + if (this->packetHistory[i].time && (this->packetHistory[i].time > last_time)) { + // Client is only interested in packets not from itself and only in broadcast packets or packets towards it. + if (this->packetHistory[i].from != dest && + (this->packetHistory[i].to == NODENUM_BROADCAST || this->packetHistory[i].to == dest)) { + count++; + } + } + } + return count; +} - this->packetHistoryTXQueue_size = 0; - // If our history was cleared, ignore the last request index - uint32_t last_index = *last_request_index > this->packetHistoryCurrent ? 0 : *last_request_index; - - for (uint32_t i = last_index; i < this->packetHistoryCurrent; i++) { - /* - LOG_DEBUG("SF historyQueueCreate\n"); - LOG_DEBUG("SF historyQueueCreate - time %d\n", this->packetHistory[i].time); - LOG_DEBUG("SF historyQueueCreate - millis %d\n", millis()); - LOG_DEBUG("SF historyQueueCreate - math %d\n", (millis() - msAgo)); - */ - if (this->packetHistoryTXQueue_size < this->historyReturnMax) { - if (this->packetHistory[i].time && (this->packetHistory[i].time < (millis() - msAgo))) { - /* Copy the messages that were received by the router in the last msAgo - to the packetHistoryTXQueue structure. - Client not interested in packets from itself and only in broadcast packets or packets towards it. */ - if (this->packetHistory[i].from != to && - (this->packetHistory[i].to == NODENUM_BROADCAST || this->packetHistory[i].to == to)) { - this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].time = this->packetHistory[i].time; - this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].to = this->packetHistory[i].to; - this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].from = this->packetHistory[i].from; - this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].channel = this->packetHistory[i].channel; - this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].payload_size = - this->packetHistory[i].payload_size; - memcpy(this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].payload, this->packetHistory[i].payload, - meshtastic_Constants_DATA_PAYLOAD_LEN); - this->packetHistoryTXQueue_size++; - *last_request_index = i + 1; // Set to one higher such that we don't send the same message again - - LOG_DEBUG("*** PacketHistoryStruct time=%d, msg=%s\n", this->packetHistory[i].time, - this->packetHistory[i].payload); - } +/** + * Allocates a mesh packet for sending to the phone. + * + * @return A pointer to the allocated mesh packet or nullptr if none is available. + */ +meshtastic_MeshPacket *StoreForwardModule::getForPhone() +{ + if (moduleConfig.store_forward.enabled && is_server) { + NodeNum to = nodeDB->getNodeNum(); + if (!this->busy) { + // Get number of packets we're going to send in this loop + uint32_t histSize = getNumAvailablePackets(to, 0); // No time limit + if (histSize) { + this->busy = true; + this->busyTo = to; + } else { + return nullptr; } - } else { - LOG_WARN("*** S&F - Maximum history return reached.\n"); - return this->packetHistoryTXQueue_size; + } + + // We're busy with sending to us until no payload is available anymore + if (this->busy && this->busyTo == to) { + meshtastic_MeshPacket *p = preparePayload(to, 0, true); // No time limit + if (!p) // No more messages to send + this->busy = false; + return p; } } - return this->packetHistoryTXQueue_size; + return nullptr; } /** @@ -181,66 +181,97 @@ void StoreForwardModule::historyAdd(const meshtastic_MeshPacket &mp) { const auto &p = mp.decoded; - if (this->packetHistoryCurrent == this->records) { + if (this->packetHistoryTotalCount == this->records) { LOG_WARN("*** S&F - PSRAM Full. Starting overwrite now.\n"); - this->packetHistoryCurrent = 0; - this->packetHistoryMax = 0; + this->packetHistoryTotalCount = 0; for (auto &i : lastRequest) { i.second = 0; // Clear the last request index for each client device } } - this->packetHistory[this->packetHistoryCurrent].time = millis(); - this->packetHistory[this->packetHistoryCurrent].to = mp.to; - this->packetHistory[this->packetHistoryCurrent].channel = mp.channel; - this->packetHistory[this->packetHistoryCurrent].from = mp.from; - this->packetHistory[this->packetHistoryCurrent].payload_size = p.payload.size; - memcpy(this->packetHistory[this->packetHistoryCurrent].payload, p.payload.bytes, meshtastic_Constants_DATA_PAYLOAD_LEN); + this->packetHistory[this->packetHistoryTotalCount].time = getTime(); + this->packetHistory[this->packetHistoryTotalCount].to = mp.to; + this->packetHistory[this->packetHistoryTotalCount].channel = mp.channel; + this->packetHistory[this->packetHistoryTotalCount].from = getFrom(&mp); + this->packetHistory[this->packetHistoryTotalCount].payload_size = p.payload.size; + memcpy(this->packetHistory[this->packetHistoryTotalCount].payload, p.payload.bytes, meshtastic_Constants_DATA_PAYLOAD_LEN); - this->packetHistoryCurrent++; - this->packetHistoryMax++; + this->packetHistoryTotalCount++; } -meshtastic_MeshPacket *StoreForwardModule::allocReply() +/** + * Sends a payload to a specified destination node using the store and forward mechanism. + * + * @param dest The destination node number. + * @param last_time The relative time to start sending messages from. + * @return True if a packet was successfully sent, false otherwise. + */ +bool StoreForwardModule::sendPayload(NodeNum dest, uint32_t last_time) { - auto reply = allocDataPacket(); // Allocate a packet for sending - return reply; + meshtastic_MeshPacket *p = preparePayload(dest, last_time); + if (p) { + LOG_INFO("*** Sending S&F Payload\n"); + service.sendToMesh(p); + this->requestCount++; + return true; + } + return false; } /** - * Sends a payload to a specified destination node using the store and forward mechanism. + * Prepares a payload to be sent to a specified destination node from the S&F packet history. * * @param dest The destination node number. - * @param packetHistory_index The index of the packet in the packet history buffer. + * @param last_time The relative time to start sending messages from. + * @return A pointer to the prepared mesh packet or nullptr if none is available. */ -void StoreForwardModule::sendPayload(NodeNum dest, uint32_t packetHistory_index) +meshtastic_MeshPacket *StoreForwardModule::preparePayload(NodeNum dest, uint32_t last_time, bool local) { - LOG_INFO("*** Sending S&F Payload\n"); - meshtastic_MeshPacket *p = allocReply(); + for (uint32_t i = lastRequest[dest]; i < this->packetHistoryTotalCount; i++) { + if (this->packetHistory[i].time && (this->packetHistory[i].time > last_time)) { + /* Copy the messages that were received by the server in the last msAgo + to the packetHistoryTXQueue structure. + Client not interested in packets from itself and only in broadcast packets or packets towards it. */ + if (this->packetHistory[i].from != dest && + (this->packetHistory[i].to == NODENUM_BROADCAST || this->packetHistory[i].to == dest)) { + + meshtastic_MeshPacket *p = allocDataPacket(); + + p->to = local ? this->packetHistory[i].to : dest; // PhoneAPI can handle original `to` + p->from = this->packetHistory[i].from; + p->channel = this->packetHistory[i].channel; + p->rx_time = this->packetHistory[i].time; + + // Let's assume that if the server received the S&F request that the client is in range. + // TODO: Make this configurable. + p->want_ack = false; + + if (local) { // PhoneAPI gets normal TEXT_MESSAGE_APP + p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP; + memcpy(p->decoded.payload.bytes, this->packetHistory[i].payload, this->packetHistory[i].payload_size); + p->decoded.payload.size = this->packetHistory[i].payload_size; + } else { + meshtastic_StoreAndForward sf = meshtastic_StoreAndForward_init_zero; + sf.which_variant = meshtastic_StoreAndForward_text_tag; + sf.variant.text.size = this->packetHistory[i].payload_size; + memcpy(sf.variant.text.bytes, this->packetHistory[i].payload, this->packetHistory[i].payload_size); + if (this->packetHistory[i].to == NODENUM_BROADCAST) { + sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_BROADCAST; + } else { + sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_DIRECT; + } - p->to = dest; - p->from = this->packetHistoryTXQueue[packetHistory_index].from; - p->channel = this->packetHistoryTXQueue[packetHistory_index].channel; + p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), + &meshtastic_StoreAndForward_msg, &sf); + } - // Let's assume that if the router received the S&F request that the client is in range. - // TODO: Make this configurable. - p->want_ack = false; + lastRequest[dest] = i + 1; // Update the last request index for the client device - meshtastic_StoreAndForward sf = meshtastic_StoreAndForward_init_zero; - sf.which_variant = meshtastic_StoreAndForward_text_tag; - sf.variant.text.size = this->packetHistoryTXQueue[packetHistory_index].payload_size; - memcpy(sf.variant.text.bytes, this->packetHistoryTXQueue[packetHistory_index].payload, - this->packetHistoryTXQueue[packetHistory_index].payload_size); - if (this->packetHistoryTXQueue[packetHistory_index].to == NODENUM_BROADCAST) { - sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_BROADCAST; - } else { - sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_DIRECT; + return p; + } + } } - - p->decoded.payload.size = - pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_StoreAndForward_msg, &sf); - - service.sendToMesh(p); + return nullptr; } /** @@ -257,11 +288,7 @@ void StoreForwardModule::sendMessage(NodeNum dest, const meshtastic_StoreAndForw p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; - // FIXME - Determine if the delayed packet is broadcast or delayed. For now, assume - // everything is broadcast. - p->delayed = meshtastic_MeshPacket_Delayed_DELAYED_BROADCAST; - - // Let's assume that if the router received the S&F request that the client is in range. + // Let's assume that if the server received the S&F request that the client is in range. // TODO: Make this configurable. p->want_ack = false; p->decoded.want_response = false; @@ -283,6 +310,35 @@ void StoreForwardModule::sendMessage(NodeNum dest, meshtastic_StoreAndForward_Re storeForwardModule->sendMessage(dest, sf); } +/** + * Sends a text message with an error (busy or channel not available) to the specified destination node. + * + * @param dest The destination node number. + * @param want_response True if the original message requested a response, false otherwise. + */ +void StoreForwardModule::sendErrorTextMessage(NodeNum dest, bool want_response) +{ + meshtastic_MeshPacket *pr = allocDataPacket(); + pr->to = dest; + pr->priority = meshtastic_MeshPacket_Priority_BACKGROUND; + pr->want_ack = false; + pr->decoded.want_response = false; + pr->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP; + const char *str; + if (this->busy) { + str = "** S&F - Busy. Try again shortly."; + } else { + str = "** S&F - Not available on this channel."; + } + LOG_WARN("%s\n", str); + memcpy(pr->decoded.payload.bytes, str, strlen(str)); + pr->decoded.payload.size = strlen(str); + if (want_response) { + ignoreRequest = true; // This text message counts as response. + } + service.sendToMesh(pr); +} + /** * Sends statistics about the store and forward module to the specified node. * @@ -294,8 +350,8 @@ void StoreForwardModule::statsSend(uint32_t to) sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_STATS; sf.which_variant = meshtastic_StoreAndForward_stats_tag; - sf.variant.stats.messages_total = this->packetHistoryMax; - sf.variant.stats.messages_saved = this->packetHistoryCurrent; + sf.variant.stats.messages_total = this->records; + sf.variant.stats.messages_saved = this->packetHistoryTotalCount; sf.variant.stats.messages_max = this->records; sf.variant.stats.up_time = millis() / 1000; sf.variant.stats.requests = this->requests; @@ -319,51 +375,37 @@ ProcessMessage StoreForwardModule::handleReceived(const meshtastic_MeshPacket &m #ifdef ARCH_ESP32 if (moduleConfig.store_forward.enabled) { - // The router node should not be sending messages as a client - if ((getFrom(&mp) != nodeDB->getNodeNum())) { - - if ((mp.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) && is_server) { - auto &p = mp.decoded; - if (mp.to == nodeDB->getNodeNum() && (p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && - (p.payload.bytes[2] == 0x00)) { - LOG_DEBUG("*** Legacy Request to send\n"); - - // Send the last 60 minutes of messages. - if (this->busy) { - storeForwardModule->sendMessage(getFrom(&mp), meshtastic_StoreAndForward_RequestResponse_ROUTER_BUSY); - LOG_INFO("*** S&F - Busy. Try again shortly.\n"); - meshtastic_MeshPacket *pr = allocReply(); - pr->to = getFrom(&mp); - pr->priority = meshtastic_MeshPacket_Priority_BACKGROUND; - pr->want_ack = false; - pr->decoded.want_response = false; - pr->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP; - memcpy(pr->decoded.payload.bytes, "** S&F - Busy. Try again shortly.", 34); - pr->decoded.payload.size = 34; - service.sendToMesh(pr); - } else { - storeForwardModule->historySend(historyReturnWindow * 60000, getFrom(&mp)); - } + if ((mp.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) && is_server) { + auto &p = mp.decoded; + if (mp.to == nodeDB->getNodeNum() && (p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && + (p.payload.bytes[2] == 0x00)) { + LOG_DEBUG("*** Legacy Request to send\n"); + + // Send the last 60 minutes of messages. + if (this->busy || channels.isDefaultChannel(channels.getByIndex(mp.channel))) { + sendErrorTextMessage(getFrom(&mp), mp.decoded.want_response); } else { - storeForwardModule->historyAdd(mp); - LOG_INFO("*** S&F stored. Message history contains %u records now.\n", this->packetHistoryCurrent); + storeForwardModule->historySend(historyReturnWindow * 60, getFrom(&mp)); } - } else if (mp.decoded.portnum == meshtastic_PortNum_STORE_FORWARD_APP) { - auto &p = mp.decoded; - meshtastic_StoreAndForward scratch; - meshtastic_StoreAndForward *decoded = NULL; - if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag) { - if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_StoreAndForward_msg, &scratch)) { - decoded = &scratch; - } else { - LOG_ERROR("Error decoding protobuf module!\n"); - // if we can't decode it, nobody can process it! - return ProcessMessage::STOP; - } - return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE; + } else { + storeForwardModule->historyAdd(mp); + LOG_INFO("*** S&F stored. Message history contains %u records now.\n", this->packetHistoryTotalCount); + } + } else if (getFrom(&mp) != nodeDB->getNodeNum() && mp.decoded.portnum == meshtastic_PortNum_STORE_FORWARD_APP) { + auto &p = mp.decoded; + meshtastic_StoreAndForward scratch; + meshtastic_StoreAndForward *decoded = NULL; + if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_StoreAndForward_msg, &scratch)) { + decoded = &scratch; + } else { + LOG_ERROR("Error decoding protobuf module!\n"); + // if we can't decode it, nobody can process it! + return ProcessMessage::STOP; } - } // all others are irrelevant - } + return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE; + } + } // all others are irrelevant } #endif @@ -394,7 +436,7 @@ bool StoreForwardModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, // stop sending stuff, the client wants to abort or has another error if ((this->busy) && (this->busyTo == getFrom(&mp))) { LOG_ERROR("*** Client in ERROR or ABORT requested\n"); - this->packetHistoryTXQueue_index = 0; + this->requestCount = 0; this->busy = false; } } @@ -405,15 +447,14 @@ bool StoreForwardModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, requests_history++; LOG_INFO("*** Client Request to send HISTORY\n"); // Send the last 60 minutes of messages. - if (this->busy) { - storeForwardModule->sendMessage(getFrom(&mp), meshtastic_StoreAndForward_RequestResponse_ROUTER_BUSY); - LOG_INFO("*** S&F - Busy. Try again shortly.\n"); + if (this->busy || channels.isDefaultChannel(channels.getByIndex(mp.channel))) { + sendErrorTextMessage(getFrom(&mp), mp.decoded.want_response); } else { if ((p->which_variant == meshtastic_StoreAndForward_history_tag) && (p->variant.history.window > 0)) { // window is in minutes - storeForwardModule->historySend(p->variant.history.window * 60000, getFrom(&mp)); + storeForwardModule->historySend(p->variant.history.window * 60, getFrom(&mp)); } else { - storeForwardModule->historySend(historyReturnWindow * 60000, getFrom(&mp)); // defaults to 4 hours + storeForwardModule->historySend(historyReturnWindow * 60, getFrom(&mp)); // defaults to 4 hours } } } @@ -451,7 +492,7 @@ bool StoreForwardModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, if (is_client) { LOG_DEBUG("*** StoreAndForward_RequestResponse_ROUTER_BUSY\n"); // retry in messages_saved * packetTimeMax ms - retry_delay = millis() + packetHistoryCurrent * packetTimeMax * + retry_delay = millis() + getNumAvailablePackets(this->busyTo, this->last_time) * packetTimeMax * (meshtastic_StoreAndForward_RequestResponse_ROUTER_ERROR ? 2 : 1); } break; @@ -482,8 +523,6 @@ bool StoreForwardModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, LOG_DEBUG("*** Router Response STATS\n"); // These fields only have informational purpose on a client. Fill them to consume later. if (p->which_variant == meshtastic_StoreAndForward_stats_tag) { - this->packetHistoryMax = p->variant.stats.messages_total; - this->packetHistoryCurrent = p->variant.stats.messages_saved; this->records = p->variant.stats.messages_max; this->requests = p->variant.stats.requests; this->requests_history = p->variant.stats.requests_history; @@ -508,7 +547,7 @@ bool StoreForwardModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, default: break; // no need to do anything } - return true; // There's no need for others to look at this message. + return false; // RoutingModule sends it to the phone } StoreForwardModule::StoreForwardModule() @@ -532,9 +571,8 @@ StoreForwardModule::StoreForwardModule() if (moduleConfig.store_forward.enabled) { // Router - if ((config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER) || - (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT)) { - LOG_INFO("*** Initializing Store & Forward Module in Router mode\n"); + if ((config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || moduleConfig.store_forward.is_server)) { + LOG_INFO("*** Initializing Store & Forward Module in Server mode\n"); if (memGet.getPsramSize() > 0) { if (memGet.getFreePsram() >= 1024 * 1024) { diff --git a/src/modules/esp32/StoreForwardModule.h b/src/modules/esp32/StoreForwardModule.h index 0d2fb9fceb..e3273470b6 100644 --- a/src/modules/esp32/StoreForwardModule.h +++ b/src/modules/esp32/StoreForwardModule.h @@ -25,12 +25,9 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule< char routerMessage[meshtastic_Constants_DATA_PAYLOAD_LEN] = {0}; PacketHistoryStruct *packetHistory = 0; - uint32_t packetHistoryCurrent = 0; - uint32_t packetHistoryMax = 0; - - PacketHistoryStruct *packetHistoryTXQueue = 0; - uint32_t packetHistoryTXQueue_size = 0; - uint32_t packetHistoryTXQueue_index = 0; + uint32_t packetHistoryTotalCount = 0; + uint32_t last_time = 0; + uint32_t requestCount = 0; uint32_t packetTimeMax = 5000; // Interval between sending history packets as a server. @@ -52,18 +49,21 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule< */ void historyAdd(const meshtastic_MeshPacket &mp); void statsSend(uint32_t to); - void historySend(uint32_t msAgo, uint32_t to); - - uint32_t historyQueueCreate(uint32_t msAgo, uint32_t to, uint32_t *last_request_index); + void historySend(uint32_t secAgo, uint32_t to); + uint32_t getNumAvailablePackets(NodeNum dest, uint32_t last_time); /** * Send our payload into the mesh */ - void sendPayload(NodeNum dest = NODENUM_BROADCAST, uint32_t packetHistory_index = 0); + bool sendPayload(NodeNum dest = NODENUM_BROADCAST, uint32_t packetHistory_index = 0); + meshtastic_MeshPacket *preparePayload(NodeNum dest, uint32_t packetHistory_index, bool local = false); void sendMessage(NodeNum dest, const meshtastic_StoreAndForward &payload); void sendMessage(NodeNum dest, meshtastic_StoreAndForward_RequestResponse rr); + void sendErrorTextMessage(NodeNum dest, bool want_response); + meshtastic_MeshPacket *getForPhone(); + // Returns true if we are configured as server AND we could allocate PSRAM. + bool isServer() { return is_server; } - virtual meshtastic_MeshPacket *allocReply() override; /* -Override the wantPacket method. */ From 3fa8b357e580bd4d2047f1dff0aba3949c5467ff Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Sun, 14 Jul 2024 10:36:07 +1200 Subject: [PATCH 161/211] Initial work for Heltec Vision Master 213 (#4286) * Fix for serial monitoring and I2C for Vision Master e213 (#4280) * Fix for serial monitoring and I2C The board did not allow serial monitoring while on boot mode, i was able to fix this by adding a board variant. I also corrected the i2c pins. I was able to test it with a cardkb * oops I delete some code by mistake, all back now * Made some adjustments * Minimize the diff --------- Co-authored-by: Todd Herbert * Don't redefine board identifier Suppresses compiler warnings * Detect Vision Master 213 with PIO serial monitor * Use outermost button as user-button Less chance of accidentally hitting reset * Use 1200bps touch (213) Allows upload without manually entering bootloader --------- Co-authored-by: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> --- boards/heltec_vision_master_e213.json | 42 +++++++++++++++++++ .../heltec_vision_master_e213/pins_arduino.h | 6 +-- .../heltec_vision_master_e213/platformio.ini | 2 +- variants/heltec_vision_master_e213/variant.h | 2 +- variants/heltec_vision_master_e290/variant.h | 2 +- 5 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 boards/heltec_vision_master_e213.json diff --git a/boards/heltec_vision_master_e213.json b/boards/heltec_vision_master_e213.json new file mode 100644 index 0000000000..bf5fe15ad8 --- /dev/null +++ b/boards/heltec_vision_master_e213.json @@ -0,0 +1,42 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld", + "partitions": "default_8MB.csv" + }, + "core": "esp32", + "extra_flags": [ + "-DBOARD_HAS_PSRAM", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_USB_MODE=0", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "hwids": [ + ["0x303A", "0x1001"], + ["0x303A", "0x0002"] + ], + "mcu": "esp32s3", + "variant": "heltec_vision_master_e213" + }, + "connectivity": ["wifi", "bluetooth", "lora"], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": ["arduino", "espidf"], + "name": "Heltec Vision Master E213", + "upload": { + "flash_size": "8MB", + "maximum_ram_size": 327680, + "maximum_size": 8388608, + "use_1200bps_touch": true, + "wait_for_upload_port": true, + "require_upload_port": true, + "speed": 921600 + }, + "url": "https://heltec.org/project/vision-master-e213/", + "vendor": "Heltec" +} diff --git a/variants/heltec_vision_master_e213/pins_arduino.h b/variants/heltec_vision_master_e213/pins_arduino.h index 01c16c496b..359922499e 100644 --- a/variants/heltec_vision_master_e213/pins_arduino.h +++ b/variants/heltec_vision_master_e213/pins_arduino.h @@ -3,8 +3,6 @@ #include -#define HELTEC_VISION_MASTER_E213 true - static const uint8_t LED_BUILTIN = 35; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN @@ -12,8 +10,8 @@ static const uint8_t LED_BUILTIN = 35; static const uint8_t TX = 43; static const uint8_t RX = 44; -static const uint8_t SDA = 41; -static const uint8_t SCL = 42; +static const uint8_t SDA = 39; +static const uint8_t SCL = 38; static const uint8_t SS = 8; static const uint8_t MOSI = 10; diff --git a/variants/heltec_vision_master_e213/platformio.ini b/variants/heltec_vision_master_e213/platformio.ini index 77cc659834..709ae321f2 100644 --- a/variants/heltec_vision_master_e213/platformio.ini +++ b/variants/heltec_vision_master_e213/platformio.ini @@ -1,6 +1,6 @@ [env:heltec-vision-master-e213] extends = esp32s3_base -board = heltec_wifi_lora_32_V3 +board = heltec_vision_master_e213 build_flags = ${esp32s3_base.build_flags} -Ivariants/heltec_vision_master_e213 diff --git a/variants/heltec_vision_master_e213/variant.h b/variants/heltec_vision_master_e213/variant.h index 169602a0d7..d4e42ad1cc 100644 --- a/variants/heltec_vision_master_e213/variant.h +++ b/variants/heltec_vision_master_e213/variant.h @@ -27,7 +27,7 @@ #define VEXT_ENABLE 18 // powers the oled display and the lora antenna boost #define VEXT_ON_VALUE 1 -#define BUTTON_PIN 21 +#define BUTTON_PIN 0 #define ADC_CTRL 46 #define ADC_CTRL_ENABLED HIGH diff --git a/variants/heltec_vision_master_e290/variant.h b/variants/heltec_vision_master_e290/variant.h index a122a7e0fa..a8ec5485b7 100644 --- a/variants/heltec_vision_master_e290/variant.h +++ b/variants/heltec_vision_master_e290/variant.h @@ -27,7 +27,7 @@ #define VEXT_ENABLE 18 // powers the e-ink display #define VEXT_ON_VALUE 1 -#define BUTTON_PIN 21 +#define BUTTON_PIN 0 #define ADC_CTRL 46 #define ADC_CTRL_ENABLED HIGH From 5cc8ca59a37d87943781caf655bb9df2d95a045b Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Sun, 14 Jul 2024 09:38:19 +0800 Subject: [PATCH 162/211] Sync Wio lr1110 refresh with master (#4288) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix protobuf structs handling (#4140) * Fix protobuf structs handling * Log instead of assert --------- Co-authored-by: Ben Meadors * BLE based logging (#4146) * WIP log characteristic * Bluetooth logging plumbing * Characteristic * Callback * Check for nullptr * Esp32 bluetooth impl * Formatting * Add thread name and log level * Add settings guard * Remove comments * Field name * Fixes esp32 * Open it up * Whoops * Move va_end past our logic * Use `upload_protocol = esptool` as with the other heltec devices instead of `esp-builtin` (#4151) * Standardize lat/lon position logs (#4156) * Standardize lat/lon position logs * Missed sone and condensed logs * [create-pull-request] automated change (#4157) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Pause BLE logging during want_config flow (#4162) * Update NimBLE to 1.4.2 (#4163) * Implement replies for all telemetry types based on variant tag (#4164) * Implement replies for all telemetry types based on variant tag * Remove check for `ignoreRequest`: modules can set this, don't need to check --------- Co-authored-by: Ben Meadors * Esptool is better * Explicitly set characteristic * fix INA3221 sensor (#4168) - pass wire to begin() - remove redundant setAddr() (already set in header) * Show compass on waypoint frame; clear when waypoint deleted (#4116) * Clear expired or deleted waypoint frame * Return 0 to CallbackObserver * Add a missing comment * Draw compass for waypoint frame * Display our own waypoints * [create-pull-request] automated change (#4171) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Add semihosting support for nrf52 devices (#4137) * Turn off vscode cmake prompt - we don't use cmake on meshtastic * Add rak4631_dap variant for debugging with NanoDAP debug probe device. * The rak device can also run freertos (which is underneath nrf52 arduino) * Add semihosting support for nrf52840 devices Initial platformio.ini file only supports rak4630 Default to non TCP for the semihosting log output for now... Fixes https://github.com/meshtastic/firmware/issues/4135 * fix my botched merge - keep board_level = extra flag for rak3631_dbg --------- Co-authored-by: Ben Meadors * [create-pull-request] automated change (#4174) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Display alerts (#4170) * Move static functions into Screen.h, show compass during calibration * Move to _fontHeight macro to avoid collision * Move some alert functions to new alert handler * Catch missed reboot code * ESP32 fixes * Bump esp8266-oled-ssd1306 * Fixes for when a device has no screen * Use new startAlert(char*) helper class * Add EINK bits back to alert handling * Add noop class for no-display devices --------- Co-authored-by: Ben Meadors * Send file system manifest up on want_config (#4176) * Send file system manifest up on want_config * Platform specific methods * Helps to actually make the change * Clear * tell vscode, if formatting, use whatever our trunk formatter wants (#4186) without this flag if the user has set some other formatter (clang) in their user level settings, it will be looking in the wrong directory for the clang options (we want the options in .trunk/clang) Note: formatOnSave is true in master, which means a bunch of our older files are non compliant and if you edit them it will generate lots of formatting related diffs. I guess I'll start letting that happen with my future commits ;-). * fix the build - would loop forever if there were no files to send (#4188) * Show owner.short_name on boot (and E-Ink sleep screen) (#4134) * Show owner.short_name on boot and sleep screen (on e-ink) * Update Screen.cpp - new line for short_name Boot screen short_name now below the region setting. Looks better on small screens. * Draw short_name on right --------- Co-authored-by: Thomas Göttgens Co-authored-by: todd-herbert Co-authored-by: Ben Meadors * nrf52 soft device will watchdog if you use ICE while BT on... (#4189) so have debugger disable bluetooth. * correct xiao_ble build preventing sx1262 init (#4191) * Force a compile time failur if FromRadio or ToRadio get larger than (#4190) a BLE packet size. We are actually very close to this threshold so important to make sure we don't accidentally pass it. * Clear vector after complete config state (#4194) * Clear after complete config * Don't collect . entries * Log file name and size * [create-pull-request] automated change (#4200) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Make the logs Colorful! (#4199) * Squash needlessly static functions (#4183) * Trim extra vprintf and filter for unprintable characters * Deprecate Router Client role (and make it Client) (#4201) * [create-pull-request] automated change (#4205) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Move waypoint (#4202) * Move waypoint screen draw into the waypoint module * Get the observer set up for the waypoint screen draw * Static squashing: screen dimensions Macros moved back to Screen.cpp, as a band-aid until we eventually move all those static functions into the Screen class. * Move getCompassDiam into Screen class (supress compiler warnings) At this stage, the method is still static, because it's used by drawNodeInfo, which has no tidy reference to our screen instance. This is probably just another band-aid until these static functions all move. * Use new getCompassDiam function in AccelerometerThread * Properly gate display code in WaypointModule --------- Co-authored-by: Todd Herbert * Fix flakey phone api transition from file manifest to complete (#4209) * Try fix flakey phone api transition from file manifest to complete * Skip * enable colors in platformio serial monitor (#4217) * When talking via serial, encapsulate log messages in protobufs if necessary (#4187) * clean up RedirectablePrint::log so it doesn't have three very different implementations inline. * remove NoopPrint - it is no longer needed * when talking to API clients via serial, don't turn off log msgs instead encapsuate them * fix the build - would loop forever if there were no files to send * don't use Segger code if not talking to a Segger debugger * when encapsulating logs, make sure the strings always has nul terminators * nrf52 soft device will watchdog if you use ICE while BT on... so have debugger disable bluetooth. * Important to not print debug messages while writing to the toPhone scratch buffer * don't include newlines if encapsulating log records as protobufs --------- Co-authored-by: Ben Meadors * [create-pull-request] automated change (#4218) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Fix SHT41 support (#4222) * Add SHT41 Serial to I2c Detection Code On the Seeed Wio-WM1110 Dev Kit board, the SHT41 chip was being incorrectly detected as SHT31. This patch adds the necessary serial number for the SHT41 chip to be correctly detected. fixes meshtastic/firmware#4221 * Add missing sensor read for SHT41 * Typo fix in logs - mhz - MHz (#4225) As reported by karamo, a few different places in our logs had incorrect capitalization of MHz. fixes meshtastic/firmware#4126 * New new BLE logging characteristic with LogRecord protos (#4220) * New UUID * New log radio characteristic with LogRecord protobuf * LogRecord * Merge derp * How did you get there * Trunk * Fix length * Remove assert * minor cleanup proposal (#4169) * MESHTASTIC_EXCLUDE_WIFI and HAS_WIFI cleanup... Our code was checking HAS_WIFI and the new MESHTASTIC_EXCLUDE_WIFI flags in various places (even though EXCLUDE_WIFI forces HAS_WIFI to 0). Instead just check HAS_WIFI, only use EXCLUDE_WIFI inside configuration.h * cleanup: use HAS_NETWORKING instead of HAS_WIFI || HAS_ETHERNET We already had HAS_NETWORKING as flag in MQTT to mean 'we have tcpip'. Generallize that and move it into configuration.h so that we can use it elsewhere. * Use #pragma once, because supported by gcc and all modern compilers instead of #ifdef DOTHFILE_H etc... --------- Co-authored-by: Jonathan Bennett * Add PowerMon support (#4155) * Turn off vscode cmake prompt - we don't use cmake on meshtastic * Add rak4631_dap variant for debugging with NanoDAP debug probe device. * The rak device can also run freertos (which is underneath nrf52 arduino) * Add semihosting support for nrf52840 devices Initial platformio.ini file only supports rak4630 Default to non TCP for the semihosting log output for now... Fixes https://github.com/meshtastic/firmware/issues/4135 * powermon WIP (for https://github.com/meshtastic/firmware/issues/4136 ) * oops - mean't to mark the _dbg variant as an 'extra' board. * powermon wip * Make serial port on wio-sdk-wm1110 board work By disabling the (inaccessible) adafruit USB * Instrument (radiolib only for now) lora for powermon per https://github.com/meshtastic/firmware/issues/4136 * powermon gps support https://github.com/meshtastic/firmware/issues/4136 * Add CPU deep and light sleep powermon states https://github.com/meshtastic/firmware/issues/4136 * Change the board/swversion bootstring so it is a new "structured" log msg. * powermon wip * add example script for getting esp S3 debugging working Not yet used but I didn't want these nasty tricks to get lost yet. * Add PowerMon reporting for screen and bluetooth pwr. * make power.powermon_enables config setting work. * update to latest protobufs * fix bogus shellcheck warning * make powermon optional (but default enabled because tiny and no runtime impact) * tell vscode, if formatting, use whatever our trunk formatter wants without this flag if the user has set some other formatter (clang) in their user level settings, it will be looking in the wrong directory for the clang options (we want the options in .trunk/clang) Note: formatOnSave is true in master, which means a bunch of our older files are non compliant and if you edit them it will generate lots of formatting related diffs. I guess I'll start letting that happen with my future commits ;-). * add PowerStress module * nrf52 arduino is built upon freertos, so let platformio debug it * don't accidentally try to Segger ICE if we are using another ICE * clean up RedirectablePrint::log so it doesn't have three very different implementations inline. * remove NoopPrint - it is no longer needed * when talking to API clients via serial, don't turn off log msgs instead encapsuate them * fix the build - would loop forever if there were no files to send * don't use Segger code if not talking to a Segger debugger * when encapsulating logs, make sure the strings always has nul terminators * nrf52 soft device will watchdog if you use ICE while BT on... so have debugger disable bluetooth. * Important to not print debug messages while writing to the toPhone scratch buffer * don't include newlines if encapsulating log records as protobufs * update to latest protobufs (needed for powermon goo) * PowerStress WIP * fix linter warning * Cleanup buffer * Merge hex for wm1110 target(s) * Only sdk * Sudo * Fix exclude macros (#4233) * fix MESHTASTIC_EXCLUDE_BLUETOOTH * fix HAS_SCREEN=0 * fix MESHTASTIC_EXCLUDE_GPS * fix typo in build-nrf52.sh (#4231) chmod is the command, '+x' is the argument. * Tidy Wireless Paper variant files (#4238) * Quick tidy of pins_arduino.h Matches requests made at https://github.com/meshtastic/firmware/pull/4226#discussion_r1664183480) * Tidy variant.h * Change deprecated ADC attenuation parameter From 11dB to 12dB. Resolves compiler warning. Allegly, no impact on function: `This is deprecated, it behaves the same as `ADC_ATTEN_DB_12` * Updated raspbian CI to update apt repository ahead of libbluetooth. (#4243) * Fix BLE logging on nrf52 (#4244) * allow ble logrecords to be fetched either by NOTIFY or INDICATE ble types This allows 'lossless' log reading. If client has requested INDICATE (rather than NOTIFY) each log record emitted via log() will have to fetched by the client device before the meshtastic node can continue. * Fix serious problem with nrf52 BLE logging. When doing notifies of LogRecords it is important to use the binary write routines - writing using the 'string' write won't work. Because protobufs can contain \0 nuls inside of them which if being parsed as a string will cause only a portion of the protobuf to be sent. I noticed this because some log messages were not getting through. --------- Co-authored-by: Ben Meadors * Fix build when HAS_NETWORKING is false on nrf52 (#4237) (tested on a rak4631 by setting HAS_ETHERNET false when shrinking image) * If `toPhoneQueue` is full, still increment `fromNum` to avoid client never getting packets (#4246) * Update to SoftDevice 7.3.0 for wio-sdk-wm1110 and wio-tracker-wm1110 (#4248) * Update variant.h * Update wio-tracker-wm1110.json * Update wio-sdk-wm1110.json * Update platformio.ini * Update platformio.ini * Add files via upload * Add files via upload * Update variant.h * Cleanup NRF s140 Softdevice variants (#4252) Note: This idea is originally from @caveman99 and should be credited as such. Submitting as a separate PR so the work in meshtastic/firmware#4148 can be a bit cleaner and Seeed boards can build while that work is ongoing. The nrf52 boards that depend on the v7 softdevice all use the same code and linker files. Rather than duplicate the code, keep it all together with the platform. * Remove tracker variant specific soft device headers (#4255) * [create-pull-request] automated change (#4247) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Add wio-sdk-wm1110 to build. (#4258) The wio-sdk-wm1110 is distinct from the wio-tracker-wm1110, with different platformio build options and pin config. This change adds the wio-sdk-wm1110 to the CI matrix so firmware is built as part of release. * fix python warning in uf2conf (#4235) the old regex worked but was technically incorrect. fixes: Generating NRF52 uf2 file /home/kevinh/development/meshtastic/firmware/bin/uf2conv.py:195: SyntaxWarning: invalid escape sequence '\s' words = re.split('\s+', line) Converting to uf2, output size: 1458688, start address: 0x26000 * Collect hex files and specifically wm1110 sdk * Skip dfu file for sdk (for now) * Helps if you remove the original clause * Add Heltec new boards. (#4226) * Add Heltec new boards * Update variant.h disable RTC by default * Add Heltec New boards * Add Heltec new boards * Update Heltec Mesh Node definition. * Update Heltec Vision Mater E290 * [create-pull-request] automated change (#4259) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * Trunk fmt * Fix macros * Move e290 to board level extra while CI is broken * Tell trunk to ignore bin folder * Fix missing * Update trunk.yaml, fix whitespace * Update trunk.yaml * Update build_raspbian_armv7l.yml --fix-missing * [create-pull-request] automated change (#4263) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> * GPS Power State tidy-up (#4161) * Refactor GPSPowerState enum Identifies a case where the GPS hardware is awake, but an update is not yet desired * Change terminology * Clear old lock-time prediction on triple press * Use exponential smoothing to predict lock time * Rename averageLockTime to predictedLockTime * Attempt: Send PMREQ with duration 0 on MCU deep-sleep * Attempt 2: Send PMREQ with duration 0 on MCU deep-sleep * Revert "Attempt 2: Send PMREQ with duration 0 on MCU deep-sleep" This reverts commit 8b697cd2a445355dcfab5b33e0ce7a3128cab151. * Revert "Attempt: Send PMREQ with duration 0 on MCU deep-sleep" This reverts commit 9d29ec7603a88056b9115796b29b5023165a93bb. * Remove unused notifyGPSSleep Observable Handled with notifyDeepSleep, and enable() / disable() * WIP: simplify GPS power management An initial attempt only. * Honor #3e9e0fd * No-op when moving between GPS_IDLE and GPS_ACTIVE * Ensure U-blox GPS is awake to receive indefinite sleep command * Longer pause when waking U-blox to send sleep command * Actually implement soft and hard sleep.. * Dynamically estimate the threshold for GPS_HARDSLEEP * Fallback to GPS_HARDSLEEP, if GPS_SOFTSLEEP unsupported * Move "excessive search time" behavior to scheduler class * Minor logging adjustments * Promote log to warning * Gratuitous buffer clearing on boot * Fix inverted standby pin logic Specifically the standby pin for L76B, L76K and clones Discovered during T-Echo testing: totally broken function, probe method failing. * Remove redundant pin init Now handled by setPowerState * Replace max() with if statements Avoid those platform specific implementations.. * Trunk formatting New round of settings.json changes keep catching me out, have to remember to re-enable my "clang-format" for windows workaround. * Remove some asserts from setPowerState Original aim was to prevent sending a 0 second PMREQ to U-blox hardware as part of a timed sleep (GPS_HARDSLEEP, GPS_SOFTSLEEP). I'm not sure this is super important, and it feels tidier to just allow the 0 second sleeptime here, rather than fudge the sleeptime further up. * Fix an error determining whether GPS_SOFTSLEEP is supported * Clarify a log entry * Set PIN_STANDBY for MCU deep-sleep Required to reach TTGO's advertised 0.25mA sleep current for T-Echo. Without this change: ~6mA. * Optimize the shutdown current of RAK10701 to around 25uA (#4260) Co-authored-by: Jonathan Bennett * INA3221 sensor: use for bus voltage & environment metrics (#4215) * use INA3221 for bus voltage; fixes for telemetry variants - add to sensors available for environment telemetry (to report voltage/current) - add vars to define channels to use for battery voltage (for getBusVoltage) and environment metrics (default to CH1 for both) - write to the correct fields on the measurement struct depending on the measurement variant, and DRY up the sensor measurement collection code a bit - this might be suitable for a common implementation for the INA* sensors in a future PR... * formatting * derp --------- Co-authored-by: Ben Meadors * WM1110 SDK kit enter serial DFU and add deployment packages (#4266) * Switch default upload protocol to nrfutil so that pio generates zip deploy packages * Enter serial DFU on SDK board * Remove guard for DFU zip from SDK build * NRF_USE_SERIAL_DFU macro instead * Show specific frame when updating screen (#4264) * Updated setFrames in Screen.cpp Added code to attempt to revert back to the same frame that user was on prior to setFrame reload. * Space added Screen.cpp * Update Screen.cpp Make screen to revert to Frame 0 if the originally displayed frame is no longer there. * Update Screen.cpp Inserted boolean holdPosition into setFrames to indicate the requirement to stay on the same frame ( if =true) or else it will switch to new frame . Only Screen::handleStatusUpdate calls with setFrame(true). ( For Node Updates) All other types of updates call as before setFrame(), so it will change focus as needed. * Hold position, even if number of frames increases * Hold position, if handling an outgoing text message * Update Screen.cpp * Reverted chnages related to devicestate.has_rx_text_message * Reset to master * CannedMessages only handles routing packets when waiting for ACK Previously, this was calling Screen::setFrames at unexpected times * Gather position info about screen frames while regenerating * Make admin module observable Notify only when relevant. Currently: only to handle remove_nodenum. * Optionally specify which frame to focus when setFrames runs * UIFrameEvent uses enum instead of multiple booleans * Allow modules to request their own frame to be focussed This is done internally by calling MeshModule::requestFocus() Easier this way, insteady of passing the info in the UIFrameEvent: * Modules don't always know whether they should be focussed until after the UIFrameEvent has been raised, in dramFrame * Don't have to pass reference to module instance as parameter though several methods * E-Ink screensaver uses FOCUS_PRESERVE Previously, it had its own basic implementation of this. * Spelling: regional variant * trunk * Fix HAS_SCREEN guarding * More HAS_SCREEN guarding --------- Co-authored-by: BIST <77391720+slash-bit@users.noreply.github.com> Co-authored-by: Ben Meadors Co-authored-by: slash-bit * Move up telemetry defaults to every 30 minutes (#4274) * Don't send node info interrogation when ch. util is >25% (#4273) * Moar LR1110 Targets * update SD_FLASH_SIZE to 0x27000 (#4232) The 7.3.0 softdevice needs the extra 1000 :) * Fix spacing. --------- Co-authored-by: Mike Co-authored-by: Ben Meadors Co-authored-by: Mike G Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> Co-authored-by: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Co-authored-by: Warren Guy <5602790+warrenguy@users.noreply.github.com> Co-authored-by: todd-herbert Co-authored-by: geeksville Co-authored-by: Jonathan Bennett Co-authored-by: Alexander <156134901+Dorn8010@users.noreply.github.com> Co-authored-by: Thomas Göttgens Co-authored-by: quimnut Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com> Co-authored-by: Agent Blu, 006 Co-authored-by: Mark Trevor Birss Co-authored-by: Aaron.Lee <32860565+Heltec-Aaron-Lee@users.noreply.github.com> Co-authored-by: Daniel.Cao <144674500+DanielCao0@users.noreply.github.com> Co-authored-by: BIST <77391720+slash-bit@users.noreply.github.com> Co-authored-by: slash-bit --- .github/actions/setup-base/action.yml | 2 +- .github/workflows/build_native.yml | 2 +- .github/workflows/build_nrf52.yml | 1 + .github/workflows/build_raspbian.yml | 2 +- .github/workflows/build_raspbian_armv7l.yml | 1 + .github/workflows/main_matrix.yml | 3 +- .trunk/trunk.yaml | 6 +- bin/build-nrf52.sh | 24 +- bin/uf2conv.py | 223 +- boards/heltec_mesh_node_t114.json | 53 + platformio.ini | 4 + protobufs | 2 +- src/Power.cpp | 15 +- src/gps/GPS.cpp | 532 ++- src/gps/GPS.h | 47 +- src/gps/GPSUpdateScheduling.cpp | 118 + src/gps/GPSUpdateScheduling.h | 29 + src/graphics/EInkDisplay2.cpp | 3 +- src/graphics/EInkDisplay2.h | 8 +- src/graphics/Screen.cpp | 160 +- src/graphics/Screen.h | 37 +- src/main.cpp | 6 +- src/mesh/Default.h | 1 + src/mesh/MeshModule.cpp | 15 +- src/mesh/MeshModule.h | 28 +- src/mesh/MeshService.cpp | 6 +- src/mesh/NodeDB.cpp | 3 +- src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/config.pb.h | 10 +- src/mesh/generated/meshtastic/deviceonly.pb.h | 2 +- src/mesh/generated/meshtastic/localonly.pb.h | 4 +- .../generated/meshtastic/module_config.pb.h | 20 +- src/mesh/generated/meshtastic/telemetry.pb.h | 18 +- src/modules/AdminModule.cpp | 1 + src/modules/AdminModule.h | 2 +- src/modules/CannedMessageModule.cpp | 45 +- src/modules/CannedMessageModule.h | 6 +- src/modules/Telemetry/AirQualityTelemetry.cpp | 3 +- src/modules/Telemetry/DeviceTelemetry.cpp | 3 +- .../Telemetry/EnvironmentTelemetry.cpp | 17 +- src/modules/Telemetry/PowerTelemetry.cpp | 6 +- .../Telemetry/Sensor/INA3221Sensor.cpp | 65 +- src/modules/Telemetry/Sensor/INA3221Sensor.h | 25 + src/modules/WaypointModule.cpp | 18 +- src/modules/esp32/AudioModule.cpp | 6 +- src/modules/esp32/PaxcounterModule.cpp | 2 +- src/platform/esp32/architecture.h | 8 + src/platform/nrf52/NRF52Bluetooth.cpp | 1 + src/platform/nrf52/main-nrf52.cpp | 17 + src/sleep.cpp | 6 +- src/sleep.h | 2 - variants/heltec_capsule_sensor_v3/variant.h | 2 +- variants/heltec_mesh_node_t114/platformio.ini | 15 + variants/heltec_mesh_node_t114/variant.cpp | 44 + variants/heltec_mesh_node_t114/variant.h | 210 ++ .../heltec_vision_master_e213/pins_arduino.h | 63 + .../heltec_vision_master_e213/platformio.ini | 23 + variants/heltec_vision_master_e213/variant.h | 58 + .../heltec_vision_master_e290/pins_arduino.h | 61 + .../heltec_vision_master_e290/platformio.ini | 25 + variants/heltec_vision_master_e290/variant.h | 58 + .../heltec_vision_master_t190/pins_arduino.h | 61 + .../heltec_vision_master_t190/platformio.ini | 13 + variants/heltec_vision_master_t190/variant.h | 76 + variants/heltec_wireless_paper/pins_arduino.h | 5 - variants/wio-sdk-wm1110/nrf52840_s140_v7.ld | 38 - variants/wio-sdk-wm1110/platformio.ini | 6 +- variants/wio-sdk-wm1110/softdevice/nrf_sdm.h | 380 --- variants/wio-sdk-wm1110/variant.h | 2 + .../wio-tracker-wm1110/nrf52840_s140_v7.ld | 38 - variants/wio-tracker-wm1110/platformio.ini | 3 +- variants/wio-tracker-wm1110/softdevice/ble.h | 652 ---- .../wio-tracker-wm1110/softdevice/ble_err.h | 92 - .../wio-tracker-wm1110/softdevice/ble_gap.h | 2895 ----------------- .../wio-tracker-wm1110/softdevice/ble_gatt.h | 232 -- .../wio-tracker-wm1110/softdevice/ble_gattc.h | 764 ----- .../wio-tracker-wm1110/softdevice/ble_gatts.h | 904 ----- .../wio-tracker-wm1110/softdevice/ble_hci.h | 135 - .../wio-tracker-wm1110/softdevice/ble_l2cap.h | 495 --- .../softdevice/ble_ranges.h | 149 - .../wio-tracker-wm1110/softdevice/ble_types.h | 217 -- .../softdevice/nrf52/nrf_mbr.h | 259 -- .../wio-tracker-wm1110/softdevice/nrf_error.h | 90 - .../softdevice/nrf_error_sdm.h | 73 - .../softdevice/nrf_error_soc.h | 85 - .../wio-tracker-wm1110/softdevice/nrf_nvic.h | 449 --- .../wio-tracker-wm1110/softdevice/nrf_sdm.h | 380 --- .../wio-tracker-wm1110/softdevice/nrf_soc.h | 1046 ------ .../wio-tracker-wm1110/softdevice/nrf_svc.h | 98 - version.properties | 2 +- 90 files changed, 1851 insertions(+), 9967 deletions(-) create mode 100644 boards/heltec_mesh_node_t114.json create mode 100644 src/gps/GPSUpdateScheduling.cpp create mode 100644 src/gps/GPSUpdateScheduling.h create mode 100644 variants/heltec_mesh_node_t114/platformio.ini create mode 100644 variants/heltec_mesh_node_t114/variant.cpp create mode 100644 variants/heltec_mesh_node_t114/variant.h create mode 100644 variants/heltec_vision_master_e213/pins_arduino.h create mode 100644 variants/heltec_vision_master_e213/platformio.ini create mode 100644 variants/heltec_vision_master_e213/variant.h create mode 100644 variants/heltec_vision_master_e290/pins_arduino.h create mode 100644 variants/heltec_vision_master_e290/platformio.ini create mode 100644 variants/heltec_vision_master_e290/variant.h create mode 100644 variants/heltec_vision_master_t190/pins_arduino.h create mode 100644 variants/heltec_vision_master_t190/platformio.ini create mode 100644 variants/heltec_vision_master_t190/variant.h delete mode 100644 variants/wio-sdk-wm1110/nrf52840_s140_v7.ld delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_sdm.h delete mode 100644 variants/wio-tracker-wm1110/nrf52840_s140_v7.ld delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_err.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gap.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gatt.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gattc.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_gatts.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_hci.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_l2cap.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_ranges.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/ble_types.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_nvic.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_sdm.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_soc.h delete mode 100644 variants/wio-tracker-wm1110/softdevice/nrf_svc.h diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml index b5b4cb6f30..7f8659523b 100644 --- a/.github/actions/setup-base/action.yml +++ b/.github/actions/setup-base/action.yml @@ -14,7 +14,7 @@ runs: - name: Install dependencies shell: bash run: | - sudo apt-get -y update + sudo apt-get -y update --fix-missing sudo apt-get install -y cppcheck libbluetooth-dev libgpiod-dev libyaml-cpp-dev - name: Setup Python diff --git a/.github/workflows/build_native.yml b/.github/workflows/build_native.yml index 8fe8e6c318..3e8b4c001c 100644 --- a/.github/workflows/build_native.yml +++ b/.github/workflows/build_native.yml @@ -13,7 +13,7 @@ jobs: - name: Install libbluetooth shell: bash run: | - sudo apt-get update + sudo apt-get update --fix-missing sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code diff --git a/.github/workflows/build_nrf52.yml b/.github/workflows/build_nrf52.yml index eb17799635..ac509a096a 100644 --- a/.github/workflows/build_nrf52.yml +++ b/.github/workflows/build_nrf52.yml @@ -29,6 +29,7 @@ jobs: name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip overwrite: true path: | + release/*.hex release/*.uf2 release/*.elf release/*.zip diff --git a/.github/workflows/build_raspbian.yml b/.github/workflows/build_raspbian.yml index d262d87395..1fd8fad307 100644 --- a/.github/workflows/build_raspbian.yml +++ b/.github/workflows/build_raspbian.yml @@ -13,7 +13,7 @@ jobs: - name: Install libbluetooth shell: bash run: | - apt-get update -y + apt-get update -y --fix-missing apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code diff --git a/.github/workflows/build_raspbian_armv7l.yml b/.github/workflows/build_raspbian_armv7l.yml index ee5eb66ebb..39b297d1b1 100644 --- a/.github/workflows/build_raspbian_armv7l.yml +++ b/.github/workflows/build_raspbian_armv7l.yml @@ -13,6 +13,7 @@ jobs: - name: Install libbluetooth shell: bash run: | + apt-get update -y --fix-missing apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 25a0fbad22..14c8a9d10c 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -136,7 +136,7 @@ jobs: build-rpi2040, package-raspbian, package-raspbian-armv7l, - package-native + package-native, ] steps: - name: Checkout code @@ -168,6 +168,7 @@ jobs: path: | ./firmware-*.bin ./firmware-*.uf2 + ./firmware-*.hex ./firmware-*-ota.zip ./device-*.sh ./device-*.bat diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 8a2f18ad5d..2d9f608997 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -1,6 +1,6 @@ version: 0.1 cli: - version: 1.22.1 + version: 1.22.2 plugins: sources: - id: trunk @@ -31,6 +31,10 @@ lint: - gitleaks@8.18.2 - clang-format@16.0.3 - prettier@3.2.5 + ignore: + - linters: [ALL] + paths: + - bin/** runtimes: enabled: - python@3.10.8 diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index fa6eacd237..cf4ca60cb2 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -23,8 +23,10 @@ basename=firmware-$1-$VERSION pio run --environment $1 # -v SRCELF=.pio/build/$1/firmware.elf -DFUPKG=.pio/build/$1/firmware.zip cp $SRCELF $OUTDIR/$basename.elf + +echo "Generating NRF52 dfu file" +DFUPKG=.pio/build/$1/firmware.zip cp $DFUPKG $OUTDIR/$basename-ota.zip echo "Generating NRF52 uf2 file" @@ -33,13 +35,15 @@ SRCHEX=.pio/build/$1/firmware.hex # if WM1110 target, merge hex with softdevice 7.3.0 if (echo $1 | grep -q "wio-sdk-wm1110"); then echo "Merging with softdevice" - sudo chmod +x ./bin/mergehex - bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/merged_fimware.hex - SRCHEX=.pio/build/$1/merged_fimware.hex + sudo chmod +x ./bin/mergehex + bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/$basename.hex + SRCHEX=.pio/build/$1/$basename.hex + bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 + cp $SRCHEX $OUTDIR + cp bin/*.uf2 $OUTDIR +else + bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 + cp bin/device-install.* $OUTDIR + cp bin/device-update.* $OUTDIR + cp bin/*.uf2 $OUTDIR fi - -bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 - -cp bin/device-install.* $OUTDIR -cp bin/device-update.* $OUTDIR -cp bin/*.uf2 $OUTDIR diff --git a/bin/uf2conv.py b/bin/uf2conv.py index b619d14db0..a1e241b7a6 100755 --- a/bin/uf2conv.py +++ b/bin/uf2conv.py @@ -1,39 +1,38 @@ #!/usr/bin/env python3 -import sys -import struct -import subprocess -import re +import argparse import os import os.path -import argparse - +import re +import struct +import subprocess +import sys -UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" -UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected -UF2_MAGIC_END = 0x0AB16F30 # Ditto +UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" +UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected +UF2_MAGIC_END = 0x0AB16F30 # Ditto families = { - 'SAMD21': 0x68ed2b88, - 'SAML21': 0x1851780a, - 'SAMD51': 0x55114460, - 'NRF52': 0x1b57745f, - 'STM32F0': 0x647824b6, - 'STM32F1': 0x5ee21072, - 'STM32F2': 0x5d1a0a2e, - 'STM32F3': 0x6b846188, - 'STM32F4': 0x57755a57, - 'STM32F7': 0x53b80f00, - 'STM32G0': 0x300f5633, - 'STM32G4': 0x4c71240a, - 'STM32H7': 0x6db66082, - 'STM32L0': 0x202e3a91, - 'STM32L1': 0x1e1f432d, - 'STM32L4': 0x00ff6919, - 'STM32L5': 0x04240bdf, - 'STM32WB': 0x70d16653, - 'STM32WL': 0x21460ff0, - 'ATMEGA32': 0x16573617, - 'MIMXRT10XX': 0x4FB2D5BD + "SAMD21": 0x68ED2B88, + "SAML21": 0x1851780A, + "SAMD51": 0x55114460, + "NRF52": 0x1B57745F, + "STM32F0": 0x647824B6, + "STM32F1": 0x5EE21072, + "STM32F2": 0x5D1A0A2E, + "STM32F3": 0x6B846188, + "STM32F4": 0x57755A57, + "STM32F7": 0x53B80F00, + "STM32G0": 0x300F5633, + "STM32G4": 0x4C71240A, + "STM32H7": 0x6DB66082, + "STM32L0": 0x202E3A91, + "STM32L1": 0x1E1F432D, + "STM32L4": 0x00FF6919, + "STM32L5": 0x04240BDF, + "STM32WB": 0x70D16653, + "STM32WL": 0x21460FF0, + "ATMEGA32": 0x16573617, + "MIMXRT10XX": 0x4FB2D5BD, } INFO_FILE = "/INFO_UF2.TXT" @@ -46,15 +45,17 @@ def is_uf2(buf): w = struct.unpack(" 10*1024*1024: + if padding > 10 * 1024 * 1024: assert False, "More than 10M of padding needed at " + ptr if padding % 4 != 0: assert False, "Non-word padding size at " + ptr @@ -91,6 +92,7 @@ def convert_from_uf2(buf): curraddr = newaddr + datalen return outp + def convert_to_carray(file_content): outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {" for i in range(len(file_content)): @@ -100,6 +102,7 @@ def convert_to_carray(file_content): outp += "\n};\n" return outp + def convert_to_uf2(file_content): global familyid datapadding = b"" @@ -109,13 +112,21 @@ def convert_to_uf2(file_content): outp = b"" for blockno in range(numblocks): ptr = 256 * blockno - chunk = file_content[ptr:ptr + 256] + chunk = file_content[ptr : ptr + 256] flags = 0x0 if familyid: flags |= 0x2000 - hd = struct.pack(b"= 3 and words[1] == "2" and words[2] == "FAT": drives.append(words[0]) else: @@ -206,7 +238,6 @@ def get_drives(): for d in os.listdir(rootpath): drives.append(os.path.join(rootpath, d)) - def has_info(d): try: return os.path.isfile(d + INFO_FILE) @@ -217,7 +248,7 @@ def has_info(d): def board_id(path): - with open(path + INFO_FILE, mode='r') as file: + with open(path + INFO_FILE, mode="r") as file: file_content = file.read() return re.search("Board-ID: ([^\r\n]*)", file_content).group(1) @@ -235,30 +266,61 @@ def write_file(name, buf): def main(): global appstartaddr, familyid + def error(msg): print(msg) sys.exit(1) - parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.') - parser.add_argument('input', metavar='INPUT', type=str, nargs='?', - help='input file (HEX, BIN or UF2)') - parser.add_argument('-b' , '--base', dest='base', type=str, - default="0x2000", - help='set base address of application for BIN format (default: 0x2000)') - parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str, - help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible') - parser.add_argument('-d' , '--device', dest="device_path", - help='select a device path to flash') - parser.add_argument('-l' , '--list', action='store_true', - help='list connected devices') - parser.add_argument('-c' , '--convert', action='store_true', - help='do not flash, just convert') - parser.add_argument('-D' , '--deploy', action='store_true', - help='just flash, do not convert') - parser.add_argument('-f' , '--family', dest='family', type=str, - default="0x0", - help='specify familyID - number or name (default: 0x0)') - parser.add_argument('-C' , '--carray', action='store_true', - help='convert binary file to a C array, not UF2') + + parser = argparse.ArgumentParser(description="Convert to UF2 or flash directly.") + parser.add_argument( + "input", + metavar="INPUT", + type=str, + nargs="?", + help="input file (HEX, BIN or UF2)", + ) + parser.add_argument( + "-b", + "--base", + dest="base", + type=str, + default="0x2000", + help="set base address of application for BIN format (default: 0x2000)", + ) + parser.add_argument( + "-o", + "--output", + metavar="FILE", + dest="output", + type=str, + help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible', + ) + parser.add_argument( + "-d", "--device", dest="device_path", help="select a device path to flash" + ) + parser.add_argument( + "-l", "--list", action="store_true", help="list connected devices" + ) + parser.add_argument( + "-c", "--convert", action="store_true", help="do not flash, just convert" + ) + parser.add_argument( + "-D", "--deploy", action="store_true", help="just flash, do not convert" + ) + parser.add_argument( + "-f", + "--family", + dest="family", + type=str, + default="0x0", + help="specify familyID - number or name (default: 0x0)", + ) + parser.add_argument( + "-C", + "--carray", + action="store_true", + help="convert binary file to a C array, not UF2", + ) args = parser.parse_args() appstartaddr = int(args.base, 0) @@ -268,14 +330,17 @@ def error(msg): try: familyid = int(args.family, 0) except ValueError: - error("Family ID needs to be a number or one of: " + ", ".join(families.keys())) + error( + "Family ID needs to be a number or one of: " + + ", ".join(families.keys()) + ) if args.list: list_drives() else: if not args.input: error("Need input file") - with open(args.input, mode='rb') as f: + with open(args.input, mode="rb") as f: inpbuf = f.read() from_uf2 = is_uf2(inpbuf) ext = "uf2" @@ -291,8 +356,10 @@ def error(msg): ext = "h" else: outbuf = convert_to_uf2(inpbuf) - print("Converting to %s, output size: %d, start address: 0x%x" % - (ext, len(outbuf), appstartaddr)) + print( + "Converting to %s, output size: %d, start address: 0x%x" + % (ext, len(outbuf), appstartaddr) + ) if args.convert or ext != "uf2": drives = [] if args.output == None: diff --git a/boards/heltec_mesh_node_t114.json b/boards/heltec_mesh_node_t114.json new file mode 100644 index 0000000000..5c97d8c755 --- /dev/null +++ b/boards/heltec_mesh_node_t114.json @@ -0,0 +1,53 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v6.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_NRF52840_PCA10056 -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + ["0x239A", "0x4405"], + ["0x239A", "0x0029"], + ["0x239A", "0x002A"] + ], + "usb_product": "HT-n5262", + "mcu": "nrf52840", + "variant": "heltec_mesh_node_t114", + "variants_dir": "variants", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "6.1.1", + "sd_fwid": "0x00B6" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": ["bluetooth"], + "debug": { + "jlink_device": "nRF52840_xxAA", + "onboard_tools": ["jlink"], + "svd_path": "nrf52840.svd", + "openocd_target": "nrf52840-mdk-rs" + }, + "frameworks": ["arduino"], + "name": "Heltec nrf (Adafruit BSP)", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "FIXME", + "vendor": "Heltec" +} diff --git a/platformio.ini b/platformio.ini index bcdcc0034b..b3f6772470 100644 --- a/platformio.ini +++ b/platformio.ini @@ -35,6 +35,10 @@ default_envs = tbeam ;default_envs = radiomaster_900_bandit_nano ;default_envs = radiomaster_900_bandit_micro ;default_envs = heltec_capsule_sensor_v3 +;default_envs = heltec_vision_master_t190 +;default_envs = heltec_vision_master_e213 +;default_envs = heltec_vision_master_e290 +;default_envs = heltec_mesh_node_t114 extra_configs = arch/*/*.ini diff --git a/protobufs b/protobufs index 1198b7dbab..10494bf328 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 1198b7dbabf9768cb0143d2897707b4c7a51a5da +Subproject commit 10494bf328ac051fc4add9ddeb677eebf337b531 diff --git a/src/Power.cpp b/src/Power.cpp index cea373806c..19c5c99375 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -232,12 +232,20 @@ class AnalogBatteryLevel : public HasBatteryLevel raw = espAdcRead(); scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs); scaled *= operativeAdcMultiplier; -#else // block for all other platforms +#else // block for all other platforms +#ifdef ADC_CTRL // enable adc voltage divider when we need to read + pinMode(ADC_CTRL, OUTPUT); + digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED); + delay(10); +#endif for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) { raw += analogRead(BATTERY_PIN); } raw = raw / BATTERY_SENSE_SAMPLES; scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw; +#ifdef ADC_CTRL // disable adc voltage divider when we need to read + digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED); +#endif #endif if (!initial_read_done) { @@ -441,6 +449,11 @@ class AnalogBatteryLevel : public HasBatteryLevel if (!ina260Sensor.isInitialized()) return ina260Sensor.runOnce() > 0; return ina260Sensor.isRunning(); + } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA3221].first == + config.power.device_battery_ina_address) { + if (!ina3221Sensor.isInitialized()) + return ina3221Sensor.runOnce() > 0; + return ina3221Sensor.isRunning(); } return false; } diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index fe70bcdcdd..017a2d025e 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -9,6 +9,7 @@ #include "main.h" // pmu_found #include "sleep.h" +#include "GPSUpdateScheduling.h" #include "cas.h" #include "ubx.h" @@ -22,19 +23,6 @@ #define GPS_RESET_MODE HIGH #endif -// How many minutes of sleep make it worthwhile to power-off the GPS -// Shorter than this, and GPS will only enter standby -// Affected by lock-time, and config.position.gps_update_interval -#ifndef GPS_STANDBY_THRESHOLD_MINUTES -#define GPS_STANDBY_THRESHOLD_MINUTES 15 -#endif - -// How many seconds of sleep make it worthwhile for the GPS to use powered-on standby -// Shorter than this, and we'll just wait instead -#ifndef GPS_IDLE_THRESHOLD_SECONDS -#define GPS_IDLE_THRESHOLD_SECONDS 10 -#endif - #if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) HardwareSerial *GPS::_serial_gps = &Serial1; #else @@ -43,6 +31,8 @@ HardwareSerial *GPS::_serial_gps = NULL; GPS *gps = nullptr; +GPSUpdateScheduling scheduling; + /// Multiple GPS instances might use the same serial port (in sequence), but we can /// only init that port once. static bool didSerialInit; @@ -52,6 +42,25 @@ uint8_t uBloxProtocolVersion; #define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway #define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc) +// For logging +const char *getGPSPowerStateString(GPSPowerState state) +{ + switch (state) { + case GPS_ACTIVE: + return "ACTIVE"; + case GPS_IDLE: + return "IDLE"; + case GPS_SOFTSLEEP: + return "SOFTSLEEP"; + case GPS_HARDSLEEP: + return "HARDSLEEP"; + case GPS_OFF: + return "OFF"; + default: + assert(false); // Unhandled enum value.. + } +} + void GPS::UBXChecksum(uint8_t *message, size_t length) { uint8_t CK_A = 0, CK_B = 0; @@ -773,7 +782,6 @@ bool GPS::setup() } notifyDeepSleepObserver.observe(¬ifyDeepSleep); - notifyGPSSleepObserver.observe(¬ifyGPSSleep); return true; } @@ -782,132 +790,192 @@ GPS::~GPS() { // we really should unregister our sleep observer notifyDeepSleepObserver.unobserve(¬ifyDeepSleep); - notifyGPSSleepObserver.observe(¬ifyGPSSleep); } -const char *GPS::powerStateToString() +// Put the GPS hardware into a specified state +void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime) { - switch (powerState) { - case GPS_OFF: - return "OFF"; - case GPS_IDLE: - return "IDLE"; - case GPS_STANDBY: - return "STANDBY"; + // Update the stored GPSPowerstate, and create local copies + GPSPowerState oldState = powerState; + powerState = newState; + LOG_INFO("GPS power state moving from %s to %s\n", getGPSPowerStateString(oldState), getGPSPowerStateString(newState)); + + switch (newState) { case GPS_ACTIVE: - return "ACTIVE"; - default: - return "UNKNOWN"; + case GPS_IDLE: + if (oldState == GPS_ACTIVE || oldState == GPS_IDLE) // If hardware already awake, no changes needed + break; + if (oldState != GPS_ACTIVE && oldState != GPS_IDLE) // If hardware just waking now, clear buffer + clearBuffer(); + powerMon->setState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) + writePinEN(true); // Power (EN pin): on + setPowerPMU(true); // Power (PMU): on + writePinStandby(false); // Standby (pin): awake (not standby) + setPowerUBLOX(true); // Standby (UBLOX): awake + break; + + case GPS_SOFTSLEEP: + powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) + writePinEN(true); // Power (EN pin): on + setPowerPMU(true); // Power (PMU): on + writePinStandby(true); // Standby (pin): asleep (not awake) + setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed + break; + + case GPS_HARDSLEEP: + powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) + writePinEN(false); // Power (EN pin): off + setPowerPMU(false); // Power (PMU): off + writePinStandby(true); // Standby (pin): asleep (not awake) + setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed + break; + + case GPS_OFF: + assert(sleepTime == 0); // This is an indefinite sleep + powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) + writePinEN(false); // Power (EN pin): off + setPowerPMU(false); // Power (PMU): off + writePinStandby(true); // Standby (pin): asleep + setPowerUBLOX(false, 0); // Standby (UBLOX): asleep, indefinitely + break; } } -void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) +// Set power with EN pin, if relevant +void GPS::writePinEN(bool on) { - // Record the current powerState - if (on) - powerState = GPS_ACTIVE; - else if (!enabled) // User has disabled with triple press - powerState = GPS_OFF; - else if (sleepTime <= GPS_IDLE_THRESHOLD_SECONDS * 1000UL) - powerState = GPS_IDLE; - else if (standbyOnly) - powerState = GPS_STANDBY; - else - powerState = GPS_OFF; - - LOG_DEBUG("GPS::powerState=%s\n", powerStateToString()); - - // If the next update is due *really soon*, don't actually power off or enter standby. Just wait it out. - if (!on && powerState == GPS_IDLE) + // Abort: if conflict with Canned Messages when using Wisblock(?) + if (HW_VENDOR == meshtastic_HardwareModel_RAK4631 && (rotaryEncoderInterruptImpl1 || upDownInterruptImpl1)) return; - if (on) { - powerMon->setState(meshtastic_PowerMon_State_GPS_Active); - clearBuffer(); // drop any old data waiting in the buffer before re-enabling - if (en_gpio) - digitalWrite(en_gpio, on ? GPS_EN_ACTIVE : !GPS_EN_ACTIVE); // turn this on if defined, every time - } else { - powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); - } - isInPowersave = !on; - if (!standbyOnly && en_gpio != 0 && - !(HW_VENDOR == meshtastic_HardwareModel_RAK4631 && (rotaryEncoderInterruptImpl1 || upDownInterruptImpl1))) { - LOG_DEBUG("GPS powerdown using GPS_EN_ACTIVE\n"); - digitalWrite(en_gpio, on ? GPS_EN_ACTIVE : !GPS_EN_ACTIVE); - return; - } -#ifdef HAS_PMU // We only have PMUs on the T-Beam, and that board has a tiny battery to save GPS ephemera, so treat as a standby. - if (pmu_found && PMU) { - uint8_t model = PMU->getChipModel(); - if (model == XPOWERS_AXP2101) { - if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) { - // t-beam v1.2 GNSS power channel - on ? PMU->enablePowerOutput(XPOWERS_ALDO3) : PMU->disablePowerOutput(XPOWERS_ALDO3); - } else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) { - // t-beam-s3-core GNSS power channel - on ? PMU->enablePowerOutput(XPOWERS_ALDO4) : PMU->disablePowerOutput(XPOWERS_ALDO4); - } - } else if (model == XPOWERS_AXP192) { - // t-beam v1.1 GNSS power channel - on ? PMU->enablePowerOutput(XPOWERS_LDO3) : PMU->disablePowerOutput(XPOWERS_LDO3); - } + // Abort: if pin unset + if (!en_gpio) return; - } + + // Determine new value for the pin + bool val = GPS_EN_ACTIVE ? on : !on; + + // Write and log + pinMode(en_gpio, OUTPUT); + digitalWrite(en_gpio, val); +#ifdef GPS_EXTRAVERBOSE + LOG_DEBUG("Pin EN %s\n", val == HIGH ? "HIGH" : "LOW"); #endif +} + +// Set the value of the STANDBY pin, if relevant +// true for standby state, false for awake +void GPS::writePinStandby(bool standby) +{ #ifdef PIN_GPS_STANDBY // Specifically the standby pin for L76B, L76K and clones - if (on) { - LOG_INFO("Waking GPS\n"); - pinMode(PIN_GPS_STANDBY, OUTPUT); - // Some PCB's use an inverse logic due to a transistor driver - // Example for this is the Pico-Waveshare Lora+GPS HAT -#ifdef PIN_GPS_STANDBY_INVERTED - digitalWrite(PIN_GPS_STANDBY, 0); + +// Determine the new value for the pin +// Normally: active HIGH for awake +#if PIN_GPS_STANDBY_INVERTED + bool val = standby; #else - digitalWrite(PIN_GPS_STANDBY, 1); + bool val = !standby; #endif - return; - } else { - LOG_INFO("GPS entering sleep\n"); - // notifyGPSSleep.notifyObservers(NULL); - pinMode(PIN_GPS_STANDBY, OUTPUT); -#ifdef PIN_GPS_STANDBY_INVERTED - digitalWrite(PIN_GPS_STANDBY, 1); -#else - digitalWrite(PIN_GPS_STANDBY, 0); + + // Write and log + pinMode(PIN_GPS_STANDBY, OUTPUT); + digitalWrite(PIN_GPS_STANDBY, val); +#ifdef GPS_EXTRAVERBOSE + LOG_DEBUG("Pin STANDBY %s\n", val == HIGH ? "HIGH" : "LOW"); #endif +#endif +} + +// Enable / Disable GPS with PMU, if present +void GPS::setPowerPMU(bool on) +{ + // We only have PMUs on the T-Beam, and that board has a tiny battery to save GPS ephemera, + // so treat as a standby. +#ifdef HAS_PMU + // Abort: if no PMU + if (!pmu_found) return; + + // Abort: if PMU not initialized + if (!PMU) + return; + + uint8_t model = PMU->getChipModel(); + if (model == XPOWERS_AXP2101) { + if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) { + // t-beam v1.2 GNSS power channel + on ? PMU->enablePowerOutput(XPOWERS_ALDO3) : PMU->disablePowerOutput(XPOWERS_ALDO3); + } else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) { + // t-beam-s3-core GNSS power channel + on ? PMU->enablePowerOutput(XPOWERS_ALDO4) : PMU->disablePowerOutput(XPOWERS_ALDO4); + } + } else if (model == XPOWERS_AXP192) { + // t-beam v1.1 GNSS power channel + on ? PMU->enablePowerOutput(XPOWERS_LDO3) : PMU->disablePowerOutput(XPOWERS_LDO3); } + +#ifdef GPS_EXTRAVERBOSE + LOG_DEBUG("PMU %s\n", on ? "on" : "off"); #endif - if (!on) { - if (gnssModel == GNSS_MODEL_UBLOX) { - uint8_t msglen; - LOG_DEBUG("Sleep Time: %i\n", sleepTime); - if (strncmp(info.hwVersion, "000A0000", 8) != 0) { - for (int i = 0; i < 4; i++) { - gps->_message_PMREQ[0 + i] = sleepTime >> (i * 8); // Encode the sleep time in millis into the packet - } - msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ), gps->_message_PMREQ); - } else { - for (int i = 0; i < 4; i++) { - gps->_message_PMREQ_10[4 + i] = sleepTime >> (i * 8); // Encode the sleep time in millis into the packet - } - msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ_10), gps->_message_PMREQ_10); - } - gps->_serial_gps->write(gps->UBXscratch, msglen); +#endif +} + +// Set UBLOX power, if relevant +void GPS::setPowerUBLOX(bool on, uint32_t sleepMs) +{ + // Abort: if not UBLOX hardware + if (gnssModel != GNSS_MODEL_UBLOX) + return; + + // If waking + if (on) { + gps->_serial_gps->write(0xFF); + clearBuffer(); // This often returns old data, so drop it +#ifdef GPS_EXTRAVERBOSE + LOG_DEBUG("UBLOX: wake\n"); +#endif + } + + // If putting to sleep + else { + uint8_t msglen; + + // If we're being asked to sleep indefinitely, make *sure* we're awake first, to process the new sleep command + if (sleepMs == 0) { + setPowerUBLOX(true); + delay(500); } + + // Determine hardware version + if (strncmp(info.hwVersion, "000A0000", 8) != 0) { + // Encode the sleep time in millis into the packet + for (int i = 0; i < 4; i++) + gps->_message_PMREQ[0 + i] = sleepMs >> (i * 8); + + // Record the message length + msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ), gps->_message_PMREQ); + } else { + // Encode the sleep time in millis into the packet + for (int i = 0; i < 4; i++) + gps->_message_PMREQ_10[4 + i] = sleepMs >> (i * 8); + + // Record the message length + msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ_10), gps->_message_PMREQ_10); + #ifdef GNSS_Airoha // add by WayenWeng - else { if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) { // TODO, send rtc mode command digitalWrite(PIN_GPS_EN, LOW); } - } #endif - } else { - if (gnssModel == GNSS_MODEL_UBLOX) { - gps->_serial_gps->write(0xFF); - clearBuffer(); // This often returns old data, so drop it } + + // Send the UBX packet + gps->_serial_gps->write(gps->UBXscratch, msglen); + +#ifdef GPS_EXTRAVERBOSE + LOG_DEBUG("UBLOX: sleep for %dmS\n", sleepMs); +#endif } } @@ -920,109 +988,55 @@ void GPS::setConnected() } } -/** - * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode - * - * calls sleep/wake - */ -void GPS::setAwake(bool wantAwake) +// We want a GPS lock. Wake the hardware +void GPS::up() { + scheduling.informSearching(); + setPowerState(GPS_ACTIVE); +} - // If user has disabled GPS, make sure it is off, not just in standby or idle - if (!wantAwake && !enabled && powerState != GPS_OFF) { - setGPSPower(false, false, 0); - return; - } +// We've got a GPS lock. Enter a low power state, potentially. +void GPS::down() +{ + scheduling.informGotLock(); + uint32_t predictedSearchDuration = scheduling.predictedSearchDurationMs(); + uint32_t sleepTime = scheduling.msUntilNextSearch(); + uint32_t updateInterval = Default::getConfiguredOrDefaultMs(config.position.gps_update_interval); - // If GPS power state needs to change - if ((wantAwake && powerState != GPS_ACTIVE) || (!wantAwake && powerState == GPS_ACTIVE)) { - LOG_DEBUG("WANT GPS=%d\n", wantAwake); + LOG_DEBUG("%us until next search\n", sleepTime / 1000); - // Calculate how long it takes to get a GPS lock - if (wantAwake) { - // Record the time we start looking for a lock - lastWakeStartMsec = millis(); #ifdef GNSS_Airoha - lastFixStartMsec = 0; + lastFixStartMsec = 0; #endif - } else { - // Record by how much we missed our ideal target postion.gps_update_interval (for logging only) - // Need to calculate this before we update lastSleepStartMsec, to make the new prediction - int32_t lateByMsec = (int32_t)(millis() - lastSleepStartMsec) - (int32_t)getSleepTime(); - - // Record the time we finish looking for a lock - lastSleepStartMsec = millis(); - - // How long did it take to get GPS lock this time? - uint32_t lockTime = lastSleepStartMsec - lastWakeStartMsec; - - // Update the lock-time prediction - // Used pre-emptively, attempting to hit target of gps.position_update_interval - switch (GPSCycles) { - case 0: - LOG_DEBUG("Initial GPS lock took %ds\n", lockTime / 1000); - break; - case 1: - predictedLockTime = lockTime; // Avoid slow ramp-up - start with a real value - LOG_DEBUG("GPS Lock took %ds\n", lockTime / 1000); - break; - default: - // Predict lock-time using exponential smoothing: respond slowly to changes - predictedLockTime = (lockTime * 0.2) + (predictedLockTime * 0.8); // Latest lock time has 20% weight on prediction - LOG_INFO("GPS Lock took %ds. %s by %ds. Next lock predicted to take %ds.\n", lockTime / 1000, - (lateByMsec > 0) ? "Late" : "Early", abs(lateByMsec) / 1000, predictedLockTime / 1000); - } - GPSCycles++; - } - - // How long to wait before attempting next GPS update - // Aims to hit position.gps_update_interval by using the lock-time prediction - uint32_t compensatedSleepTime = (getSleepTime() > predictedLockTime) ? (getSleepTime() - predictedLockTime) : 0; - // If long interval between updates: power off between updates - if (compensatedSleepTime > GPS_STANDBY_THRESHOLD_MINUTES * MS_IN_MINUTE) { - setGPSPower(wantAwake, false, getSleepTime() - predictedLockTime); - } - - // If waking relatively frequently: don't power off. Would use more energy trying to reacquire lock each time - // We'll either use a "powered-on" standby, or just wait it out, depending on how soon the next update is due - // Will decide which inside setGPSPower method - else { -#ifdef GPS_UC6580 - setGPSPower(wantAwake, false, compensatedSleepTime); -#else - setGPSPower(wantAwake, true, compensatedSleepTime); + // If update interval less than 10 seconds, no attempt to sleep + if (updateInterval <= 10 * 1000UL) + setPowerState(GPS_IDLE); + else { + // Check whether the GPS hardware is capable of GPS_SOFTSLEEP + // If not, fallback to GPS_HARDSLEEP instead + bool softsleepSupported = false; + if (gnssModel == GNSS_MODEL_UBLOX) // U-blox is supported via PMREQ + softsleepSupported = true; +#ifdef PIN_GPS_STANDBY // L76B, L76K and clones have a standby pin + softsleepSupported = true; #endif - } - } -} - -/** Get how long we should stay looking for each acquisition in msecs - */ -uint32_t GPS::getWakeTime() const -{ - uint32_t t = config.position.position_broadcast_secs; - - if (t == UINT32_MAX) - return t; // already maxint - - return Default::getConfiguredOrDefaultMs(t, default_broadcast_interval_secs); -} - -/** Get how long we should sleep between aqusition attempts in msecs - */ -uint32_t GPS::getSleepTime() const -{ - uint32_t t = config.position.gps_update_interval; - // We'll not need the GPS thread to wake up again after first acq. with fixed position. - if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED || config.position.fixed_position) - t = UINT32_MAX; // Sleep forever now + // How long does gps_update_interval need to be, for GPS_HARDSLEEP to become more efficient than GPS_SOFTSLEEP? + // Heuristic equation. A compromise manually fitted to power observations from U-blox NEO-6M and M10050 + // https://www.desmos.com/calculator/6gvjghoumr + // This is not particularly accurate, but probably an impromevement over a single, fixed threshold + uint32_t hardsleepThreshold = (2750 * pow(predictedSearchDuration / 1000, 1.22)); + LOG_DEBUG("gps_update_interval >= %us needed to justify hardsleep\n", hardsleepThreshold / 1000); - if (t == UINT32_MAX) - return t; // already maxint + // If update interval too short: softsleep (if supported by hardware) + if (softsleepSupported && updateInterval < hardsleepThreshold) + setPowerState(GPS_SOFTSLEEP, sleepTime); - return Default::getConfiguredOrDefaultMs(t, default_gps_update_interval); + // If update interval long enough (or softsleep unsupported): hardsleep instead + else + setPowerState(GPS_HARDSLEEP, sleepTime); + } } void GPS::publishUpdate() @@ -1073,13 +1087,13 @@ int32_t GPS::runOnce() return disable(); } - if (whileIdle()) { + if (whileActive()) { // if we have received valid NMEA claim we are connected setConnected(); } else { if ((config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) && (gnssModel == GNSS_MODEL_UBLOX)) { // reset the GPS on next bootup - if (devicestate.did_gps_reset && (millis() - lastWakeStartMsec > 60000) && !hasFlow()) { + if (devicestate.did_gps_reset && scheduling.elapsedSearchMs() > 60 * 1000UL && !hasFlow()) { LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n"); devicestate.did_gps_reset = false; nodeDB->saveDeviceStateToDisk(); @@ -1094,54 +1108,43 @@ int32_t GPS::runOnce() // gps->factoryReset(); } - // If we are overdue for an update, turn on the GPS and at least publish the current status - uint32_t now = millis(); - uint32_t timeAsleep = now - lastSleepStartMsec; + // If we're due for an update, wake the GPS + if (!config.position.fixed_position && powerState != GPS_ACTIVE && scheduling.isUpdateDue()) + up(); - auto sleepTime = getSleepTime(); - if (powerState != GPS_ACTIVE && (sleepTime != UINT32_MAX) && - ((timeAsleep > sleepTime) || (isInPowersave && timeAsleep > (sleepTime - predictedLockTime)))) { - // We now want to be awake - so wake up the GPS - setAwake(true); + // If we've already set time from the GPS, no need to ask the GPS + bool gotTime = (getRTCQuality() >= RTCQualityGPS); + if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time + gotTime = true; + shouldPublish = true; } - // While we are awake - if (powerState == GPS_ACTIVE) { - // LOG_DEBUG("looking for location\n"); - // If we've already set time from the GPS, no need to ask the GPS - bool gotTime = (getRTCQuality() >= RTCQualityGPS); - if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time - gotTime = true; - shouldPublish = true; - } - - bool gotLoc = lookForLocation(); - if (gotLoc && !hasValidLocation) { // declare that we have location ASAP - LOG_DEBUG("hasValidLocation RISING EDGE\n"); - hasValidLocation = true; - shouldPublish = true; - } + bool gotLoc = lookForLocation(); + if (gotLoc && !hasValidLocation) { // declare that we have location ASAP + LOG_DEBUG("hasValidLocation RISING EDGE\n"); + hasValidLocation = true; + shouldPublish = true; + } - now = millis(); - auto wakeTime = getWakeTime(); - bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime; + bool tooLong = scheduling.searchedTooLong(); + if (tooLong) + LOG_WARN("Couldn't publish a valid location: didn't get a GPS lock in time.\n"); - // Once we get a location we no longer desperately want an update - // LOG_DEBUG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime); - if ((gotLoc && gotTime) || tooLong) { + // Once we get a location we no longer desperately want an update + // LOG_DEBUG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime); + if ((gotLoc && gotTime) || tooLong) { - if (tooLong) { - // we didn't get a location during this ack window, therefore declare loss of lock - if (hasValidLocation) { - LOG_DEBUG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc); - } - p = meshtastic_Position_init_default; - hasValidLocation = false; + if (tooLong) { + // we didn't get a location during this ack window, therefore declare loss of lock + if (hasValidLocation) { + LOG_DEBUG("hasValidLocation FALLING EDGE\n"); } - - setAwake(false); - shouldPublish = true; // publish our update for this just finished acquisition window + p = meshtastic_Position_init_default; + hasValidLocation = false; } + + down(); + shouldPublish = true; // publish our update for this just finished acquisition window } // If state has changed do a publish @@ -1167,9 +1170,7 @@ void GPS::clearBuffer() int GPS::prepareDeepSleep(void *unused) { LOG_INFO("GPS deep sleep!\n"); - - setAwake(false); - + disable(); return 0; } @@ -1369,12 +1370,6 @@ GPS *GPS::createGps() new_gps->tx_gpio = _tx_gpio; new_gps->en_gpio = _en_gpio; - if (_en_gpio != 0) { - LOG_DEBUG("Setting %d to output.\n", _en_gpio); - pinMode(_en_gpio, OUTPUT); - digitalWrite(_en_gpio, !GPS_EN_ACTIVE); - } - #ifdef PIN_GPS_PPS // pulse per second pinMode(PIN_GPS_PPS, INPUT); @@ -1389,7 +1384,8 @@ GPS *GPS::createGps() LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n"); #endif - new_gps->setGPSPower(true, false, 0); + // Make sure the GPS is awake before performing any init. + new_gps->up(); #ifdef PIN_GPS_RESET pinMode(PIN_GPS_RESET, OUTPUT); @@ -1397,7 +1393,6 @@ GPS *GPS::createGps() delay(10); digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE); #endif - new_gps->setAwake(true); // Wake GPS power before doing any init if (_serial_gps) { #ifdef ARCH_ESP32 @@ -1723,13 +1718,13 @@ bool GPS::hasFlow() return reader.passedChecksum() > 0; } -bool GPS::whileIdle() +bool GPS::whileActive() { unsigned int charsInBuf = 0; bool isValid = false; if (powerState != GPS_ACTIVE) { clearBuffer(); - return (powerState == GPS_ACTIVE); + return false; } #ifdef SERIAL_BUFFER_SIZE if (_serial_gps->available() >= SERIAL_BUFFER_SIZE - 1) { @@ -1760,20 +1755,21 @@ bool GPS::whileIdle() } void GPS::enable() { - // Clear the old lock-time prediction - GPSCycles = 0; - predictedLockTime = 0; + // Clear the old scheduling info (reset the lock-time prediction) + scheduling.reset(); enabled = true; setInterval(GPS_THREAD_INTERVAL); - setAwake(true); + + scheduling.informSearching(); + setPowerState(GPS_ACTIVE); } int32_t GPS::disable() { enabled = false; setInterval(INT32_MAX); - setAwake(false); + setPowerState(GPS_OFF); return INT32_MAX; } @@ -1782,7 +1778,7 @@ void GPS::toggleGpsMode() { if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED; - LOG_DEBUG("Flag set to false for gps power. GpsMode: DISABLED\n"); + LOG_INFO("User toggled GpsMode. Now DISABLED.\n"); #ifdef GNSS_Airoha if (powerState != GPS_ACTIVE) { LOG_DEBUG("User power Off GPS\n"); @@ -1792,8 +1788,8 @@ void GPS::toggleGpsMode() disable(); } else if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_DISABLED) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED; - LOG_DEBUG("Flag set to true to restore power. GpsMode: ENABLED\n"); + LOG_INFO("User toggled GpsMode. Now ENABLED\n"); enable(); } } -#endif // Exclude GPS \ No newline at end of file +#endif // Exclude GPS diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 7fa37cb7a4..1505b98434 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -39,10 +39,11 @@ typedef enum { } GPS_RESPONSE; enum GPSPowerState : uint8_t { - GPS_OFF = 0, // Physically powered off - GPS_ACTIVE = 1, // Awake and want a position - GPS_STANDBY = 2, // Physically powered on, but soft-sleeping - GPS_IDLE = 3, // Awake, but not wanting another position yet + GPS_ACTIVE, // Awake and want a position + GPS_IDLE, // Awake, but not wanting another position yet + GPS_SOFTSLEEP, // Physically powered on, but soft-sleeping + GPS_HARDSLEEP, // Physically powered off, but scheduled to wake + GPS_OFF // Powered off indefinitely }; // Generate a string representation of DOP @@ -73,8 +74,6 @@ class GPS : private concurrency::OSThread uint32_t rx_gpio = 0; uint32_t tx_gpio = 0; uint32_t en_gpio = 0; - uint32_t predictedLockTime = 0; - uint32_t GPSCycles = 0; int speedSelect = 0; int probeTries = 2; @@ -99,7 +98,6 @@ class GPS : private concurrency::OSThread uint8_t numSatellites = 0; CallbackObserver notifyDeepSleepObserver = CallbackObserver(this, &GPS::prepareDeepSleep); - CallbackObserver notifyGPSSleepObserver = CallbackObserver(this, &GPS::prepareDeepSleep); public: /** If !NULL we will use this serial port to construct our GPS */ @@ -175,7 +173,8 @@ class GPS : private concurrency::OSThread // toggle between enabled/disabled void toggleGpsMode(); - void setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime); + // Change the power state of the GPS - for power saving / shutdown + void setPowerState(GPSPowerState newState, uint32_t sleepMs = 0); /// Returns true if we have acquired GPS lock. virtual bool hasLock(); @@ -206,18 +205,18 @@ class GPS : private concurrency::OSThread GPS_RESPONSE getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis); - /** - * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode - * - * calls sleep/wake - */ - void setAwake(bool on); virtual bool factoryReset(); // Creates an instance of the GPS class. // Returns the new instance or null if the GPS is not present. static GPS *createGps(); + // Wake the GPS hardware - ready for an update + void up(); + + // Let the GPS hardware save power between updates + void down(); + protected: /** * Perform any processing that should be done only while the GPS is awake and looking for a fix. @@ -240,7 +239,7 @@ class GPS : private concurrency::OSThread * * Return true if we received a valid message from the GPS */ - virtual bool whileIdle(); + virtual bool whileActive(); /** * Perform any processing that should be done only while the GPS is awake and looking for a fix. @@ -267,13 +266,21 @@ class GPS : private concurrency::OSThread void UBXChecksum(uint8_t *message, size_t length); void CASChecksum(uint8_t *message, size_t length); - /** Get how long we should stay looking for each aquisition + /** Set power with EN pin, if relevant + */ + void writePinEN(bool on); + + /** Set the value of the STANDBY pin, if relevant + */ + void writePinStandby(bool standby); + + /** Set GPS power with PMU, if relevant */ - uint32_t getWakeTime() const; + void setPowerPMU(bool on); - /** Get how long we should sleep between aqusition attempts + /** Set UBLOX power, if relevant */ - uint32_t getSleepTime() const; + void setPowerUBLOX(bool on, uint32_t sleepMs = 0); /** * Tell users we have new GPS readings @@ -296,4 +303,4 @@ class GPS : private concurrency::OSThread }; extern GPS *gps; -#endif // Exclude GPS \ No newline at end of file +#endif // Exclude GPS diff --git a/src/gps/GPSUpdateScheduling.cpp b/src/gps/GPSUpdateScheduling.cpp new file mode 100644 index 0000000000..949ef60397 --- /dev/null +++ b/src/gps/GPSUpdateScheduling.cpp @@ -0,0 +1,118 @@ +#include "GPSUpdateScheduling.h" + +#include "Default.h" + +// Mark the time when searching for GPS position begins +void GPSUpdateScheduling::informSearching() +{ + searchStartedMs = millis(); +} + +// Mark the time when searching for GPS is complete, +// then update the predicted lock-time +void GPSUpdateScheduling::informGotLock() +{ + searchEndedMs = millis(); + LOG_DEBUG("Took %us to get lock\n", (searchEndedMs - searchStartedMs) / 1000); + updateLockTimePrediction(); +} + +// Clear old lock-time prediction data. +// When re-enabling GPS with user button. +void GPSUpdateScheduling::reset() +{ + searchStartedMs = 0; + searchEndedMs = 0; + searchCount = 0; + predictedMsToGetLock = 0; +} + +// How many milliseconds before we should next search for GPS position +// Used by GPS hardware directly, to enter timed hardware sleep +uint32_t GPSUpdateScheduling::msUntilNextSearch() +{ + uint32_t now = millis(); + + // Target interval (seconds), between GPS updates + uint32_t updateInterval = Default::getConfiguredOrDefaultMs(config.position.gps_update_interval, default_gps_update_interval); + + // Check how long until we should start searching, to hopefully hit our target interval + uint32_t dueAtMs = searchEndedMs + updateInterval; + uint32_t compensatedStart = dueAtMs - predictedMsToGetLock; + int32_t remainingMs = compensatedStart - now; + + // If we should have already started (negative value), start ASAP + if (remainingMs < 0) + remainingMs = 0; + + return (uint32_t)remainingMs; +} + +// How long have we already been searching? +// Used to abort a search in progress, if it runs unnaceptably long +uint32_t GPSUpdateScheduling::elapsedSearchMs() +{ + // If searching + if (searchStartedMs > searchEndedMs) + return millis() - searchStartedMs; + + // If not searching - 0ms. We shouldn't really consume this value + else + return 0; +} + +// Is it now time to begin searching for a GPS position? +bool GPSUpdateScheduling::isUpdateDue() +{ + return (msUntilNextSearch() == 0); +} + +// Have we been searching for a GPS position for too long? +bool GPSUpdateScheduling::searchedTooLong() +{ + uint32_t maxSearchMs = + Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs); + + // If broadcast interval set to max, no such thing as "too long" + if (maxSearchMs == UINT32_MAX) + return false; + + // If we've been searching longer than our position broadcast interval: that's too long + else if (elapsedSearchMs() > maxSearchMs) + return true; + + // Otherwise, not too long yet! + else + return false; +} + +// Updates the predicted time-to-get-lock, by exponentially smoothing the latest observation +void GPSUpdateScheduling::updateLockTimePrediction() +{ + + // How long did it take to get GPS lock this time? + // Duration between down() calls + int32_t lockTime = searchEndedMs - searchStartedMs; + if (lockTime < 0) + lockTime = 0; + + // Ignore the first lock-time: likely to be long, will skew data + + // Second locktime: likely stable. Use to intialize the smoothing filter + if (searchCount == 1) + predictedMsToGetLock = lockTime; + + // Third locktime and after: predict using exponential smoothing. Respond slowly to changes + else if (searchCount > 1) + predictedMsToGetLock = (lockTime * weighting) + (predictedMsToGetLock * (1 - weighting)); + + searchCount++; // Only tracked so we can diregard initial lock-times + + LOG_DEBUG("Predicting %us to get next lock\n", predictedMsToGetLock / 1000); +} + +// How long do we expect to spend searching for a lock? +uint32_t GPSUpdateScheduling::predictedSearchDurationMs() +{ + return GPSUpdateScheduling::predictedMsToGetLock; +} \ No newline at end of file diff --git a/src/gps/GPSUpdateScheduling.h b/src/gps/GPSUpdateScheduling.h new file mode 100644 index 0000000000..7e121c9b68 --- /dev/null +++ b/src/gps/GPSUpdateScheduling.h @@ -0,0 +1,29 @@ +#pragma once + +#include "configuration.h" + +// Encapsulates code responsible for the timing of GPS updates +class GPSUpdateScheduling +{ + public: + // Marks the time of these events, for calculation use + void informSearching(); + void informGotLock(); // Predicted lock-time is recalculated here + + void reset(); // Reset the prediction - after GPS::disable() / GPS::enable() + bool isUpdateDue(); // Is it time to begin searching for a GPS position? + bool searchedTooLong(); // Have we been searching for too long? + + uint32_t msUntilNextSearch(); // How long until we need to begin searching for a GPS? Info provided to GPS hardware for sleep + uint32_t elapsedSearchMs(); // How long have we been searching so far? + uint32_t predictedSearchDurationMs(); // How long do we expect to spend searching for a lock? + + private: + void updateLockTimePrediction(); // Called from informGotLock + uint32_t searchStartedMs = 0; + uint32_t searchEndedMs = 0; + uint32_t searchCount = 0; + uint32_t predictedMsToGetLock = 0; + + const float weighting = 0.2; // Controls exponential smoothing of lock-times prediction. 20% weighting of "latest lock-time". +}; \ No newline at end of file diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index bbc12521a0..d81ab6ff4e 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -156,7 +156,8 @@ bool EInkDisplay::connect() } } -#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) +#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || \ + defined(HELTEC_VISION_MASTER_E290) { // Start HSPI hspi = new SPIClass(HSPI); diff --git a/src/graphics/EInkDisplay2.h b/src/graphics/EInkDisplay2.h index f744164949..26091b2cd2 100644 --- a/src/graphics/EInkDisplay2.h +++ b/src/graphics/EInkDisplay2.h @@ -5,11 +5,6 @@ #include "GxEPD2_BW.h" #include -#if defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) -// Re-enable SPI after deep sleep: rtc_gpio_hold_dis() -#include "driver/rtc_io.h" -#endif - /** * An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation. * @@ -72,7 +67,8 @@ class EInkDisplay : public OLEDDisplay GxEPD2_BW *adafruitDisplay = NULL; // If display uses HSPI -#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) +#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \ + defined(HELTEC_VISION_MASTER_E290) SPIClass *hspi = NULL; #endif diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index f724ddd3d4..b2059b71c6 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -41,6 +41,7 @@ along with this program. If not, see . #include "mesh/Channels.h" #include "mesh/generated/meshtastic/deviceonly.pb.h" #include "meshUtils.h" +#include "modules/AdminModule.h" #include "modules/ExternalNotificationModule.h" #include "modules/TextMessageModule.h" #include "sleep.h" @@ -1485,6 +1486,10 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ screen->drawColumns(display, x, y, fields); } +#if defined(ESP_PLATFORM) && defined(USE_ST7789) +SPIClass SPI1(HSPI); +#endif + Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry) : concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32) { @@ -1492,6 +1497,13 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O #if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64) dispdev = new SH1106Wire(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); +#elif defined(USE_ST7789) +#ifdef ESP_PLATFORM + dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT, ST7789_SDA, + ST7789_MISO, ST7789_SCK); +#else + dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); +#endif #elif defined(USE_SSD1306) dispdev = new SSD1306Wire(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); @@ -1570,7 +1582,14 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) #endif dispdev->displayOn(); - +#ifdef USE_ST7789 +#ifdef ESP_PLATFORM + analogWrite(VTFT_LEDA, BRIGHTNESS_DEFAULT); +#else + pinMode(VTFT_LEDA, OUTPUT); + digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON); +#endif +#endif enabled = true; setInterval(0); // Draw ASAP runASAP = true; @@ -1581,6 +1600,12 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) #endif LOG_INFO("Turning off screen\n"); dispdev->displayOff(); + +#ifdef USE_ST7789 + pinMode(VTFT_LEDA, OUTPUT); + digitalWrite(VTFT_LEDA, !TFT_BACKLIGHT_ON); +#endif + #ifdef T_WATCH_S3 PMU->disablePowerOutput(XPOWERS_ALDO2); #endif @@ -1701,6 +1726,7 @@ void Screen::setup() powerStatusObserver.observe(&powerStatus->onNewStatus); gpsStatusObserver.observe(&gpsStatus->onNewStatus); nodeStatusObserver.observe(&nodeStatus->onNewStatus); + adminMessageObserver.observe(adminModule); if (textMessageModule) textMessageObserver.observe(textMessageModule); if (inputBroker) @@ -1929,9 +1955,6 @@ void Screen::setWelcomeFrames() /// Determine which screensaver frame to use, then set the FrameCallback void Screen::setScreensaverFrames(FrameCallback einkScreensaver) { - // Remember current frame, restore position at power-on - uint8_t frameNumber = ui->getUiState()->currentFrame; - // Retain specified frame / overlay callback beyond scope of this method static FrameCallback screensaverFrame; static OverlayCallback screensaverOverlay; @@ -1969,9 +1992,8 @@ void Screen::setScreensaverFrames(FrameCallback einkScreensaver) #endif // Prepare now for next frame, shown when display wakes - ui->setOverlays(NULL, 0); // Clear overlay - setFrames(); // Return to normal display updates - ui->switchToFrame(frameNumber); // Attempt to return to same frame after power-on + ui->setOverlays(NULL, 0); // Clear overlay + setFrames(FOCUS_PRESERVE); // Return to normal display updates, showing same frame as before screensaver, ideally // Pick a refresh method, for when display wakes #ifdef EINK_HASQUIRK_GHOSTING @@ -1982,9 +2004,13 @@ void Screen::setScreensaverFrames(FrameCallback einkScreensaver) } #endif -// restore our regular frame list -void Screen::setFrames() +// Regenerate the normal set of frames, focusing a specific frame if requested +// Called when a frame should be added / removed, or custom frames should be cleared +void Screen::setFrames(FrameFocus focus) { + uint8_t originalPosition = ui->getUiState()->currentFrame; + FramesetInfo fsi; // Location of specific frames, for applying focus parameter + LOG_DEBUG("showing standard frames\n"); showingNormalScreen = true; @@ -2018,20 +2044,33 @@ void Screen::setFrames() // is the same offset into the moduleFrames vector // so that we can invoke the module's callback for (auto i = moduleFrames.begin(); i != moduleFrames.end(); ++i) { - normalFrames[numframes++] = drawModuleFrame; + // Draw the module frame, using the hack described above + normalFrames[numframes] = drawModuleFrame; + + // Check if the module being drawn has requested focus + // We will honor this request later, if setFrames was triggered by a UIFrameEvent + MeshModule *m = *i; + if (m->isRequestingFocus()) + fsi.positions.focusedModule = numframes; + + numframes++; } LOG_DEBUG("Added modules. numframes: %d\n", numframes); // If we have a critical fault, show it first - if (error_code) + fsi.positions.fault = numframes; + if (error_code) { normalFrames[numframes++] = drawCriticalFaultFrame; + focus = FOCUS_FAULT; // Change our "focus" parameter, to ensure we show the fault frame + } #ifdef T_WATCH_S3 normalFrames[numframes++] = screen->digitalWatchFace ? &Screen::drawDigitalClockFrame : &Screen::drawAnalogClockFrame; #endif // If we have a text message - show it next, unless it's a phone message and we aren't using any special modules + fsi.positions.textMessage = numframes; if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) { normalFrames[numframes++] = drawTextMessageFrame; } @@ -2046,11 +2085,14 @@ void Screen::setFrames() // // Since frames are basic function pointers, we have to use a helper to // call a method on debugInfo object. + fsi.positions.log = numframes; normalFrames[numframes++] = &Screen::drawDebugInfoTrampoline; // call a method on debugInfoScreen object (for more details) + fsi.positions.settings = numframes; normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline; + fsi.positions.wifi = numframes; #if HAS_WIFI && !defined(ARCH_PORTDUINO) if (isWifiAvailable()) { // call a method on debugInfoScreen object (for more details) @@ -2058,6 +2100,7 @@ void Screen::setFrames() } #endif + fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE LOG_DEBUG("Finished building frames. numframes: %d\n", numframes); ui->setFrames(normalFrames, numframes); @@ -2071,6 +2114,55 @@ void Screen::setFrames() prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list // just changed) + // Focus on a specific frame, in the frame set we just created + switch (focus) { + case FOCUS_DEFAULT: + ui->switchToFrame(0); // First frame + break; + case FOCUS_FAULT: + ui->switchToFrame(fsi.positions.fault); + break; + case FOCUS_TEXTMESSAGE: + ui->switchToFrame(fsi.positions.textMessage); + break; + case FOCUS_MODULE: + // Whichever frame was marked by MeshModule::requestFocus(), if any + // If no module requested focus, will show the first frame instead + ui->switchToFrame(fsi.positions.focusedModule); + break; + + case FOCUS_PRESERVE: + // If we can identify which type of frame "originalPosition" was, can move directly to it in the new frameset + FramesetInfo &oldFsi = this->framesetInfo; + if (originalPosition == oldFsi.positions.log) + ui->switchToFrame(fsi.positions.log); + else if (originalPosition == oldFsi.positions.settings) + ui->switchToFrame(fsi.positions.settings); + else if (originalPosition == oldFsi.positions.wifi) + ui->switchToFrame(fsi.positions.wifi); + + // If frame count has decreased + else if (fsi.frameCount < oldFsi.frameCount) { + uint8_t numDropped = oldFsi.frameCount - fsi.frameCount; + // Move n frames backwards + if (numDropped <= originalPosition) + ui->switchToFrame(originalPosition - numDropped); + // Unless that would put us "out of bounds" (< 0) + else + ui->switchToFrame(0); + } + + // If we're not sure exactly which frame we were on, at least return to the same frame number + // (node frames; module frames) + else + ui->switchToFrame(originalPosition); + + break; + } + + // Store the info about this frameset, for future setFrames calls + this->framesetInfo = fsi; + setFastFramerate(); // Draw ASAP } @@ -2525,7 +2617,7 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg) switch (arg->getStatusType()) { case STATUS_TYPE_NODE: if (showingNormalScreen && nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) { - setFrames(); // Regen the list of screens + setFrames(FOCUS_PRESERVE); // Regen the list of screen frames (returning to same frame, if possible) } nodeDB->updateGUI = false; break; @@ -2537,23 +2629,33 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg) int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) { if (showingNormalScreen) { - setFrames(); // Regen the list of screens (will show new text message) + // Outgoing message + if (packet->from == 0) + setFrames(FOCUS_PRESERVE); // Return to same frame (quietly hiding the rx text message frame) + + // Incoming message + else + setFrames(FOCUS_TEXTMESSAGE); // Focus on the new message } return 0; } +// Triggered by MeshModules int Screen::handleUIFrameEvent(const UIFrameEvent *event) { if (showingNormalScreen) { - if (event->frameChanged) { - setFrames(); // Regen the list of screens (will show new text message) - } else if (event->needRedraw) { + // Regenerate the frameset, potentially honoring a module's internal requestFocus() call + if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET) + setFrames(FOCUS_MODULE); + + // Regenerate the frameset, while attempting to maintain focus on the current frame + else if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET_BACKGROUND) + setFrames(FOCUS_PRESERVE); + + // Don't regenerate the frameset, just re-draw whatever is on screen ASAP + else if (event->action == UIFrameEvent::Action::REDRAW_ONLY) setFastFramerate(); - // TODO: We might also want switch to corresponding frame, - // but we don't know the exact frame number. - // ui->switchToFrame(0); - } } return 0; @@ -2588,6 +2690,24 @@ int Screen::handleInputEvent(const InputEvent *event) return 0; } +int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg) +{ + // Note: only selected admin messages notify this observer + // If you wish to handle a new type of message, you should modify AdminModule.cpp first + + switch (arg->which_payload_variant) { + // Node removed manually (i.e. via app) + case meshtastic_AdminMessage_remove_by_nodenum_tag: + setFrames(FOCUS_PRESERVE); + break; + + // Default no-op, in case the admin message observable gets used by other classes in future + default: + break; + } + return 0; +} + } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 83c9a7a946..93e5f2ef78 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -45,6 +45,8 @@ class Screen #include #elif defined(USE_SSD1306) #include +#elif defined(USE_ST7789) +#include #else // the SH1106/SSD1306 variant is auto-detected #include @@ -171,9 +173,11 @@ class Screen : public concurrency::OSThread CallbackObserver textMessageObserver = CallbackObserver(this, &Screen::handleTextMessage); CallbackObserver uiFrameEventObserver = - CallbackObserver(this, &Screen::handleUIFrameEvent); + CallbackObserver(this, &Screen::handleUIFrameEvent); // Sent by Mesh Modules CallbackObserver inputObserver = CallbackObserver(this, &Screen::handleInputEvent); + CallbackObserver adminMessageObserver = + CallbackObserver(this, &Screen::handleAdminMessage); public: explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY); @@ -392,6 +396,7 @@ class Screen : public concurrency::OSThread int handleTextMessage(const meshtastic_MeshPacket *arg); int handleUIFrameEvent(const UIFrameEvent *arg); int handleInputEvent(const InputEvent *arg); + int handleAdminMessage(const meshtastic_AdminMessage *arg); /// Used to force (super slow) eink displays to draw critical frames void forceDisplay(bool forceUiUpdate = false); @@ -448,8 +453,34 @@ class Screen : public concurrency::OSThread void handleShowPrevFrame(); void handlePrint(const char *text); void handleStartFirmwareUpdateScreen(); - /// Rebuilds our list of frames (screens) to default ones. - void setFrames(); + + // Info collected by setFrames method. + // Index location of specific frames. Used to apply the FrameFocus parameter of setFrames + struct FramesetInfo { + struct FramePositions { + uint8_t fault = 0; + uint8_t textMessage = 0; + uint8_t focusedModule = 0; + uint8_t log = 0; + uint8_t settings = 0; + uint8_t wifi = 0; + } positions; + + uint8_t frameCount = 0; + } framesetInfo; + + // Which frame we want to be displayed, after we regen the frameset by calling setFrames + enum FrameFocus : uint8_t { + FOCUS_DEFAULT, // No specific frame + FOCUS_PRESERVE, // Return to the previous frame + FOCUS_FAULT, + FOCUS_TEXTMESSAGE, + FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus + }; + + // Regenerate the normal set of frames, focusing a specific frame if requested + // Call when a frame should be added / removed, or custom frames should be cleared + void setFrames(FrameFocus focus = FOCUS_DEFAULT); /// Try to start drawing ASAP void setFastFramerate(); diff --git a/src/main.cpp b/src/main.cpp index 1e0d998e15..95eeb998d9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -275,6 +275,9 @@ void setup() digitalWrite(VEXT_ENABLE_V05, 1); // turn on the lora antenna boost digitalWrite(ST7735_BL_V05, 1); // turn on display backligth LOG_DEBUG("HELTEC Detect Tracker V1.1\n"); +#elif defined(VEXT_ENABLE) && defined(VEXT_ON_VALUE) + pinMode(VEXT_ENABLE, OUTPUT); + digitalWrite(VEXT_ENABLE, VEXT_ON_VALUE); // turn on the display power #elif defined(VEXT_ENABLE) pinMode(VEXT_ENABLE, OUTPUT); digitalWrite(VEXT_ENABLE, 0); // turn on the display power @@ -713,7 +716,8 @@ void setup() // Don't call screen setup until after nodedb is setup (because we need // the current region name) -#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) +#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || \ + defined(USE_ST7789) screen->setup(); #elif defined(ARCH_PORTDUINO) if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) { diff --git a/src/mesh/Default.h b/src/mesh/Default.h index 95723744b1..cc3927914b 100644 --- a/src/mesh/Default.h +++ b/src/mesh/Default.h @@ -5,6 +5,7 @@ #define ONE_MINUTE_MS 60 * 1000 #define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60) +#define default_telemetry_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 30 * 60) #define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60) #define default_wait_bluetooth_secs IF_ROUTER(1, 60) #define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp index 04fa250bff..1ef4f60d8c 100644 --- a/src/mesh/MeshModule.cpp +++ b/src/mesh/MeshModule.cpp @@ -284,4 +284,17 @@ AdminMessageHandleResult MeshModule::handleAdminMessageForAllModules(const mesht } } return handled; -} \ No newline at end of file +} + +#if HAS_SCREEN +// Would our module like its frame to be focused after Screen::setFrames has regenerated the list of frames? +// Only considered if setFrames is triggered by a UIFrameEvent +bool MeshModule::isRequestingFocus() +{ + if (_requestingFocus) { + _requestingFocus = false; // Consume the request + return true; + } else + return false; +} +#endif \ No newline at end of file diff --git a/src/mesh/MeshModule.h b/src/mesh/MeshModule.h index 2e2af33e07..c341b301ad 100644 --- a/src/mesh/MeshModule.h +++ b/src/mesh/MeshModule.h @@ -35,10 +35,16 @@ enum class AdminMessageHandleResult { /* * This struct is used by Screen to figure out whether screen frame should be updated. */ -typedef struct _UIFrameEvent { - bool frameChanged; - bool needRedraw; -} UIFrameEvent; +struct UIFrameEvent { + // What do we actually want to happen? + enum Action { + REDRAW_ONLY, // Don't change which frames are show, just redraw, asap + REGENERATE_FRAMESET, // Regenerate (change? add? remove?) screen frames, honoring requestFocus() + REGENERATE_FRAMESET_BACKGROUND, // Regenerate screen frames, attempting to remain on the same frame throughout + } action = REDRAW_ONLY; + + // We might want to pass additional data inside this struct at some point +}; /** A baseclass for any mesh "module". * @@ -73,6 +79,7 @@ class MeshModule meshtastic_AdminMessage *response); #if HAS_SCREEN virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; } + virtual bool isRequestingFocus(); // Checked by screen, when regenerating frameset #endif protected: const char *name; @@ -176,6 +183,19 @@ class MeshModule return AdminMessageHandleResult::NOT_HANDLED; }; +#if HAS_SCREEN + /** Request that our module's screen frame be focused when Screen::setFrames runs + * Only considered if Screen::setFrames is triggered via a UIFrameEvent + * + * Having this as a separate call, instead of part of the UIFrameEvent, allows the module to delay decision + * until drawFrame() is called. This required less restructuring. + */ + bool _requestingFocus = false; + void requestFocus() { _requestingFocus = true; } +#else + void requestFocus(){}; // No-op +#endif + private: /** * If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 9e2a5b1102..a652d0a50e 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -94,7 +94,11 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp) } else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user && nodeInfoModule) { LOG_INFO("Heard a node on channel %d we don't know, sending NodeInfo and asking for a response.\n", mp->channel); - nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel); + if (airTime->isTxAllowedChannelUtil(true)) { + nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel); + } else { + LOG_DEBUG("Skip sending NodeInfo due to > 25 percent channel util.\n"); + } } printPacket("Forwarding to phone", mp); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 84872e4714..fa5c437c42 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -268,7 +268,8 @@ void NodeDB::installDefaultConfig() // FIXME: Default to bluetooth capability of platform as default config.bluetooth.enabled = true; config.bluetooth.fixed_pin = defaultBLEPin; -#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) +#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || \ + defined(USE_ST7789) bool hasScreen = true; #elif ARCH_PORTDUINO bool hasScreen = false; diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index ba9f90873b..f5bacea52d 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 674 +#define meshtastic_ChannelSet_size 676 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index e3037c910d..44a86f4d64 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -497,6 +497,8 @@ typedef struct _meshtastic_Config_LoRaConfig { Please respect your local laws and regulations. If you are a HAM, make sure you enable HAM mode and turn off encryption. */ float override_frequency; + /* If true, disable the build-in PA FAN using pin define in RF95_FAN_EN. */ + bool pa_fan_disabled; /* For testing it is useful sometimes to force a node to never listen to particular other nodes (simulating radio out of range). All nodenums listed in ignore_incoming will have packets they send dropped on receive (by router.cpp) */ @@ -618,7 +620,7 @@ extern "C" { #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} -#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} +#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} #define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} #define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}} #define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} @@ -627,7 +629,7 @@ extern "C" { #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} -#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} +#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} #define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} /* Field tags (for use in manual encoding/decoding) */ @@ -702,6 +704,7 @@ extern "C" { #define meshtastic_Config_LoRaConfig_override_duty_cycle_tag 12 #define meshtastic_Config_LoRaConfig_sx126x_rx_boosted_gain_tag 13 #define meshtastic_Config_LoRaConfig_override_frequency_tag 14 +#define meshtastic_Config_LoRaConfig_pa_fan_disabled_tag 15 #define meshtastic_Config_LoRaConfig_ignore_incoming_tag 103 #define meshtastic_Config_LoRaConfig_ignore_mqtt_tag 104 #define meshtastic_Config_BluetoothConfig_enabled_tag 1 @@ -832,6 +835,7 @@ X(a, STATIC, SINGULAR, UINT32, channel_num, 11) \ X(a, STATIC, SINGULAR, BOOL, override_duty_cycle, 12) \ X(a, STATIC, SINGULAR, BOOL, sx126x_rx_boosted_gain, 13) \ X(a, STATIC, SINGULAR, FLOAT, override_frequency, 14) \ +X(a, STATIC, SINGULAR, BOOL, pa_fan_disabled, 15) \ X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \ X(a, STATIC, SINGULAR, BOOL, ignore_mqtt, 104) #define meshtastic_Config_LoRaConfig_CALLBACK NULL @@ -871,7 +875,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; #define meshtastic_Config_BluetoothConfig_size 12 #define meshtastic_Config_DeviceConfig_size 100 #define meshtastic_Config_DisplayConfig_size 30 -#define meshtastic_Config_LoRaConfig_size 80 +#define meshtastic_Config_LoRaConfig_size 82 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 196 #define meshtastic_Config_PositionConfig_size 62 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index fc7bea53a4..eb37f4f957 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -307,7 +307,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size #define meshtastic_ChannelFile_size 718 #define meshtastic_NodeInfoLite_size 166 -#define meshtastic_OEMStore_size 3384 +#define meshtastic_OEMStore_size 3388 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index c1d2a4ae3e..983f48ad3f 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -181,8 +181,8 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size -#define meshtastic_LocalConfig_size 553 -#define meshtastic_LocalModuleConfig_size 685 +#define meshtastic_LocalConfig_size 555 +#define meshtastic_LocalModuleConfig_size 687 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index f3c48ee6df..7fd57fe006 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -60,7 +60,9 @@ typedef enum _meshtastic_ModuleConfig_SerialConfig_Serial_Mode { meshtastic_ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG = 3, meshtastic_ModuleConfig_SerialConfig_Serial_Mode_NMEA = 4, /* NMEA messages specifically tailored for CalTopo */ - meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO = 5 + meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO = 5, + /* Ecowitt WS85 weather station */ + meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85 = 6 } meshtastic_ModuleConfig_SerialConfig_Serial_Mode; /* TODO: REPLACE */ @@ -273,6 +275,8 @@ typedef struct _meshtastic_ModuleConfig_StoreForwardConfig { uint32_t history_return_max; /* TODO: REPLACE */ uint32_t history_return_window; + /* Set to true to let this node act as a server that stores received messages and resends them upon request. */ + bool is_server; } meshtastic_ModuleConfig_StoreForwardConfig; /* Preferences for the RangeTestModule */ @@ -432,8 +436,8 @@ extern "C" { #define _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Baud)(meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600+1)) #define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN meshtastic_ModuleConfig_SerialConfig_Serial_Mode_DEFAULT -#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MAX meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO -#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Mode)(meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO+1)) +#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MAX meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85 +#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Mode)(meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85+1)) #define _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE #define _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MAX meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK @@ -474,7 +478,7 @@ extern "C" { #define meshtastic_ModuleConfig_PaxcounterConfig_init_default {0, 0, 0, 0} #define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0} #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0} #define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} @@ -490,7 +494,7 @@ extern "C" { #define meshtastic_ModuleConfig_PaxcounterConfig_init_zero {0, 0, 0, 0} #define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0} #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0} #define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} @@ -560,6 +564,7 @@ extern "C" { #define meshtastic_ModuleConfig_StoreForwardConfig_records_tag 3 #define meshtastic_ModuleConfig_StoreForwardConfig_history_return_max_tag 4 #define meshtastic_ModuleConfig_StoreForwardConfig_history_return_window_tag 5 +#define meshtastic_ModuleConfig_StoreForwardConfig_is_server_tag 6 #define meshtastic_ModuleConfig_RangeTestConfig_enabled_tag 1 #define meshtastic_ModuleConfig_RangeTestConfig_sender_tag 2 #define meshtastic_ModuleConfig_RangeTestConfig_save_tag 3 @@ -743,7 +748,8 @@ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ X(a, STATIC, SINGULAR, BOOL, heartbeat, 2) \ X(a, STATIC, SINGULAR, UINT32, records, 3) \ X(a, STATIC, SINGULAR, UINT32, history_return_max, 4) \ -X(a, STATIC, SINGULAR, UINT32, history_return_window, 5) +X(a, STATIC, SINGULAR, UINT32, history_return_window, 5) \ +X(a, STATIC, SINGULAR, BOOL, is_server, 6) #define meshtastic_ModuleConfig_StoreForwardConfig_CALLBACK NULL #define meshtastic_ModuleConfig_StoreForwardConfig_DEFAULT NULL @@ -848,7 +854,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_RangeTestConfig_size 10 #define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96 #define meshtastic_ModuleConfig_SerialConfig_size 28 -#define meshtastic_ModuleConfig_StoreForwardConfig_size 22 +#define meshtastic_ModuleConfig_StoreForwardConfig_size 24 #define meshtastic_ModuleConfig_TelemetryConfig_size 36 #define meshtastic_ModuleConfig_size 257 #define meshtastic_RemoteHardwarePin_size 21 diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 28d3687548..82cd0a55d9 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -115,6 +115,10 @@ typedef struct _meshtastic_EnvironmentMetrics { float wind_speed; /* Weight in KG */ float weight; + /* Wind gust in m/s */ + float wind_gust; + /* Wind lull in m/s */ + float wind_lull; } meshtastic_EnvironmentMetrics; /* Power Metrics (voltage / current / etc) */ @@ -205,13 +209,13 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_DeviceMetrics_init_default {0, 0, 0, 0, 0} -#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_default {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}} #define meshtastic_Nau7802Config_init_default {0, 0} #define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0, 0} -#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_zero {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}} @@ -238,6 +242,8 @@ extern "C" { #define meshtastic_EnvironmentMetrics_wind_direction_tag 13 #define meshtastic_EnvironmentMetrics_wind_speed_tag 14 #define meshtastic_EnvironmentMetrics_weight_tag 15 +#define meshtastic_EnvironmentMetrics_wind_gust_tag 16 +#define meshtastic_EnvironmentMetrics_wind_lull_tag 17 #define meshtastic_PowerMetrics_ch1_voltage_tag 1 #define meshtastic_PowerMetrics_ch1_current_tag 2 #define meshtastic_PowerMetrics_ch2_voltage_tag 3 @@ -289,7 +295,9 @@ X(a, STATIC, SINGULAR, FLOAT, ir_lux, 11) \ X(a, STATIC, SINGULAR, FLOAT, uv_lux, 12) \ X(a, STATIC, SINGULAR, UINT32, wind_direction, 13) \ X(a, STATIC, SINGULAR, FLOAT, wind_speed, 14) \ -X(a, STATIC, SINGULAR, FLOAT, weight, 15) +X(a, STATIC, SINGULAR, FLOAT, weight, 15) \ +X(a, STATIC, SINGULAR, FLOAT, wind_gust, 16) \ +X(a, STATIC, SINGULAR, FLOAT, wind_lull, 17) #define meshtastic_EnvironmentMetrics_CALLBACK NULL #define meshtastic_EnvironmentMetrics_DEFAULT NULL @@ -357,10 +365,10 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; #define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size #define meshtastic_AirQualityMetrics_size 72 #define meshtastic_DeviceMetrics_size 27 -#define meshtastic_EnvironmentMetrics_size 73 +#define meshtastic_EnvironmentMetrics_size 85 #define meshtastic_Nau7802Config_size 16 #define meshtastic_PowerMetrics_size 30 -#define meshtastic_Telemetry_size 80 +#define meshtastic_Telemetry_size 92 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index e24c62712d..cab63e5594 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -200,6 +200,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta case meshtastic_AdminMessage_remove_by_nodenum_tag: { LOG_INFO("Client is receiving a remove_nodenum command.\n"); nodeDB->removeNodeByNum(r->remove_by_nodenum); + this->notifyObservers(r); // Observed by screen break; } case meshtastic_AdminMessage_set_favorite_node_tag: { diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h index 6ecc888294..a5ffeb7d60 100644 --- a/src/modules/AdminModule.h +++ b/src/modules/AdminModule.h @@ -7,7 +7,7 @@ /** * Admin module for admin messages */ -class AdminModule : public ProtobufModule +class AdminModule : public ProtobufModule, public Observable { public: /** Constructor diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index be414dce13..84b5a3260e 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -148,8 +148,9 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) if (this->currentMessageIndex == 0) { this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT; - UIFrameEvent e = {false, true}; - e.frameChanged = true; + requestFocus(); // Tell Screen::setFrames to move to our module's frame, next time it runs + UIFrameEvent e; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->notifyObservers(&e); return 0; @@ -166,8 +167,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } } if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL)) { - UIFrameEvent e = {false, true}; - e.frameChanged = true; + UIFrameEvent e; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->currentMessageIndex = -1; #if !defined(T_WATCH_S3) && !defined(RAK14014) @@ -353,6 +354,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } if (validEvent) { + requestFocus(); // Tell Screen::setFrames to move to our module's frame, next time it runs + // Let runOnce to be called immediately. if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) { setIntervalFromNow(0); // on fast keypresses, this isn't fast enough. @@ -378,6 +381,11 @@ void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const cha p->decoded.payload.size++; } + // Only receive routing messages when expecting ACK for a canned message + // Prevents the canned message module from regenerating the screen's frameset at unexpected times, + // or raising a UIFrameEvent before another module has the chance + this->waitingForAck = true; + LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes); service.sendToMesh( @@ -393,13 +401,13 @@ int32_t CannedMessageModule::runOnce() return INT32_MAX; } // LOG_DEBUG("Check status\n"); - UIFrameEvent e = {false, true}; + UIFrameEvent e; if ((this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) || (this->runState == CANNED_MESSAGE_RUN_STATE_MESSAGE)) { // TODO: might have some feedback of sending state this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; temporaryMessage = ""; - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->currentMessageIndex = -1; this->freetext = ""; // clear freetext this->cursor = 0; @@ -412,7 +420,7 @@ int32_t CannedMessageModule::runOnce() } else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) && ((millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)) { // Reset module - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->currentMessageIndex = -1; this->freetext = ""; // clear freetext this->cursor = 0; @@ -449,7 +457,7 @@ int32_t CannedMessageModule::runOnce() this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; } } - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->currentMessageIndex = -1; this->freetext = ""; // clear freetext this->cursor = 0; @@ -463,7 +471,7 @@ int32_t CannedMessageModule::runOnce() } else if ((this->runState != CANNED_MESSAGE_RUN_STATE_FREETEXT) && (this->currentMessageIndex == -1)) { this->currentMessageIndex = 0; LOG_DEBUG("First touch (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage()); - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE; } else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_UP) { if (this->messagesCount > 0) { @@ -567,7 +575,7 @@ int32_t CannedMessageModule::runOnce() break; } if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen switch (this->payload) { // code below all trigger the freetext window (where you type to send a message) or reset the // display back to the default window case 0x08: // backspace @@ -706,8 +714,8 @@ int CannedMessageModule::getPrevIndex() void CannedMessageModule::showTemporaryMessage(const String &message) { temporaryMessage = message; - UIFrameEvent e = {false, true}; - e.frameChanged = true; + UIFrameEvent e; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen notifyObservers(&e); runState = CANNED_MESSAGE_RUN_STATE_MESSAGE; // run this loop again in 2 seconds, next iteration will clear the display @@ -914,11 +922,13 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st char buffer[50]; if (temporaryMessage.length() != 0) { + requestFocus(); // Tell Screen::setFrames to move to our module's frame LOG_DEBUG("Drawing temporary message: %s", temporaryMessage.c_str()); display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(FONT_MEDIUM); display->drawString(display->getWidth() / 2 + x, 0 + y + 12, temporaryMessage); } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) { + requestFocus(); // Tell Screen::setFrames to move to our module's frame display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(FONT_MEDIUM); String displayString; @@ -940,6 +950,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st display->drawStringf(display->getWidth() / 2 + x, y + 130, buffer, rssiString, this->lastRxRssi); } } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) { + requestFocus(); // Tell Screen::setFrames to move to our module's frame display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(FONT_MEDIUM); display->drawString(display->getWidth() / 2 + x, 0 + y + 12, "Sending..."); @@ -948,7 +959,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st display->setFont(FONT_SMALL); display->drawString(10 + x, 0 + y + FONT_HEIGHT_SMALL, "Canned Message\nModule disabled."); } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { - + requestFocus(); // Tell Screen::setFrames to move to our module's frame #if defined(T_WATCH_S3) || defined(RAK14014) drawKeyboard(display, state, 0, 0); #else @@ -1030,16 +1041,18 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp) { - if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP) { + if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP && waitingForAck) { // look for a request_id if (mp.decoded.request_id != 0) { - UIFrameEvent e = {false, true}; - e.frameChanged = true; + UIFrameEvent e; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + requestFocus(); // Tell Screen::setFrames that our module's frame should be shown, even if not "first" in the frameset this->runState = CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED; this->incoming = service.getNodenumFromRequestId(mp.decoded.request_id); meshtastic_Routing decoded = meshtastic_Routing_init_default; pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_Routing_fields, &decoded); this->ack = decoded.error_reason == meshtastic_Routing_Error_NONE; + waitingForAck = false; // No longer want routing packets this->notifyObservers(&e); // run the next time 2 seconds later setIntervalFromNow(2000); diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h index 00e8c2bf9a..797b9f7cff 100644 --- a/src/modules/CannedMessageModule.h +++ b/src/modules/CannedMessageModule.h @@ -81,9 +81,8 @@ class CannedMessageModule : public SinglePortModule, public Observabledecoded.portnum) { - case meshtastic_PortNum_TEXT_MESSAGE_APP: case meshtastic_PortNum_ROUTING_APP: - return true; + return waitingForAck; default: return false; } @@ -140,7 +139,8 @@ class CannedMessageModule : public SinglePortModule, public Observable= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval, + default_telemetry_broadcast_interval_secs))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 9cc4bf6ea5..9fe679b41f 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -17,7 +17,8 @@ int32_t DeviceTelemetryModule::runOnce() { refreshUptime(); if (((lastSentToMesh == 0) || - ((uptimeLastMs - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval))) && + ((uptimeLastMs - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval, + default_telemetry_broadcast_interval_secs))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil() && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER && config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) { diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index dcaf000777..9f0dc7b79c 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -69,7 +69,8 @@ int32_t EnvironmentTelemetryModule::runOnce() { if (sleepOnNextExecution == true) { sleepOnNextExecution = false; - uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval); + uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval, + default_telemetry_broadcast_interval_secs); LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs); doDeepSleep(nightyNightMs, true); } @@ -124,6 +125,8 @@ int32_t EnvironmentTelemetryModule::runOnce() result = ina219Sensor.runOnce(); if (ina260Sensor.hasSensor()) result = ina260Sensor.runOnce(); + if (ina3221Sensor.hasSensor()) + result = ina3221Sensor.runOnce(); if (veml7700Sensor.hasSensor()) result = veml7700Sensor.runOnce(); if (tsl2591Sensor.hasSensor()) @@ -152,7 +155,8 @@ int32_t EnvironmentTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval, + default_telemetry_broadcast_interval_secs))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); @@ -339,6 +343,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m valid = valid && ina260Sensor.getMetrics(m); hasSensor = true; } + if (ina3221Sensor.hasSensor()) { + valid = valid && ina3221Sensor.getMetrics(m); + hasSensor = true; + } if (veml7700Sensor.hasSensor()) { valid = valid && veml7700Sensor.getMetrics(m); hasSensor = true; @@ -514,6 +522,11 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule if (result != AdminMessageHandleResult::NOT_HANDLED) return result; } + if (ina3221Sensor.hasSensor()) { + result = ina3221Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } if (veml7700Sensor.hasSensor()) { result = veml7700Sensor.handleAdminMessage(mp, request, response); if (result != AdminMessageHandleResult::NOT_HANDLED) diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index fb5aee375b..6915d67e3d 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -24,7 +24,8 @@ int32_t PowerTelemetryModule::runOnce() { if (sleepOnNextExecution == true) { sleepOnNextExecution = false; - uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval); + uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval, + default_telemetry_broadcast_interval_secs); LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs); doDeepSleep(nightyNightMs, true); } @@ -70,7 +71,8 @@ int32_t PowerTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval, + default_telemetry_broadcast_interval_secs))) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); lastSentToMesh = now; diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp index edd29682e0..dec99c551c 100644 --- a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp +++ b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp @@ -27,22 +27,69 @@ int32_t INA3221Sensor::runOnce() void INA3221Sensor::setup() {} +struct _INA3221Measurement INA3221Sensor::getMeasurement(ina3221_ch_t ch) +{ + struct _INA3221Measurement measurement; + + measurement.voltage = ina3221.getVoltage(ch); + measurement.current = ina3221.getCurrent(ch); + + return measurement; +} + +struct _INA3221Measurements INA3221Sensor::getMeasurements() +{ + struct _INA3221Measurements measurements; + + // INA3221 has 3 channels starting from 0 + for (int i = 0; i < 3; i++) { + measurements.measurements[i] = getMeasurement((ina3221_ch_t)i); + } + + return measurements; +} + bool INA3221Sensor::getMetrics(meshtastic_Telemetry *measurement) { - measurement->variant.environment_metrics.voltage = ina3221.getVoltage(INA3221_CH1); - measurement->variant.environment_metrics.current = ina3221.getCurrent(INA3221_CH1); - measurement->variant.power_metrics.ch1_voltage = ina3221.getVoltage(INA3221_CH1); - measurement->variant.power_metrics.ch1_current = ina3221.getCurrent(INA3221_CH1); - measurement->variant.power_metrics.ch2_voltage = ina3221.getVoltage(INA3221_CH2); - measurement->variant.power_metrics.ch2_current = ina3221.getCurrent(INA3221_CH2); - measurement->variant.power_metrics.ch3_voltage = ina3221.getVoltage(INA3221_CH3); - measurement->variant.power_metrics.ch3_current = ina3221.getCurrent(INA3221_CH3); + switch (measurement->which_variant) { + case meshtastic_Telemetry_environment_metrics_tag: + return getEnvironmentMetrics(measurement); + + case meshtastic_Telemetry_power_metrics_tag: + return getPowerMetrics(measurement); + } + + // unsupported metric + return false; +} + +bool INA3221Sensor::getEnvironmentMetrics(meshtastic_Telemetry *measurement) +{ + struct _INA3221Measurement m = getMeasurement(ENV_CH); + + measurement->variant.environment_metrics.voltage = m.voltage; + measurement->variant.environment_metrics.current = m.current; + + return true; +} + +bool INA3221Sensor::getPowerMetrics(meshtastic_Telemetry *measurement) +{ + struct _INA3221Measurements m = getMeasurements(); + + measurement->variant.power_metrics.ch1_voltage = m.measurements[INA3221_CH1].voltage; + measurement->variant.power_metrics.ch1_current = m.measurements[INA3221_CH1].current; + measurement->variant.power_metrics.ch2_voltage = m.measurements[INA3221_CH2].voltage; + measurement->variant.power_metrics.ch2_current = m.measurements[INA3221_CH2].current; + measurement->variant.power_metrics.ch3_voltage = m.measurements[INA3221_CH3].voltage; + measurement->variant.power_metrics.ch3_current = m.measurements[INA3221_CH3].current; + return true; } uint16_t INA3221Sensor::getBusVoltageMv() { - return lround(ina3221.getVoltage(INA3221_CH1) * 1000); + return lround(ina3221.getVoltage(BAT_CH) * 1000); } #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.h b/src/modules/Telemetry/Sensor/INA3221Sensor.h index 3b8e382eea..d5121aab60 100644 --- a/src/modules/Telemetry/Sensor/INA3221Sensor.h +++ b/src/modules/Telemetry/Sensor/INA3221Sensor.h @@ -12,6 +12,21 @@ class INA3221Sensor : public TelemetrySensor, VoltageSensor private: INA3221 ina3221 = INA3221(INA3221_ADDR42_SDA); + // channel to report voltage/current for environment metrics + ina3221_ch_t ENV_CH = INA3221_CH1; + + // channel to report battery voltage for device_battery_ina_address + ina3221_ch_t BAT_CH = INA3221_CH1; + + // get a single measurement for a channel + struct _INA3221Measurement getMeasurement(ina3221_ch_t ch); + + // get all measurements for all channels + struct _INA3221Measurements getMeasurements(); + + bool getEnvironmentMetrics(meshtastic_Telemetry *measurement); + bool getPowerMetrics(meshtastic_Telemetry *measurement); + protected: void setup() override; @@ -22,4 +37,14 @@ class INA3221Sensor : public TelemetrySensor, VoltageSensor virtual uint16_t getBusVoltageMv() override; }; +struct _INA3221Measurement { + float voltage; + float current; +}; + +struct _INA3221Measurements { + // INA3221 has 3 channels + struct _INA3221Measurement measurements[3]; +}; + #endif \ No newline at end of file diff --git a/src/modules/WaypointModule.cpp b/src/modules/WaypointModule.cpp index d5b7d29ee5..e1974db730 100644 --- a/src/modules/WaypointModule.cpp +++ b/src/modules/WaypointModule.cpp @@ -16,15 +16,31 @@ ProcessMessage WaypointModule::handleReceived(const meshtastic_MeshPacket &mp) auto &p = mp.decoded; LOG_INFO("Received waypoint msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes); #endif - UIFrameEvent e = {true, true}; // We only store/display messages destined for us. // Keep a copy of the most recent text message. devicestate.rx_waypoint = mp; devicestate.has_rx_waypoint = true; powerFSM.trigger(EVENT_RECEIVED_MSG); + +#if HAS_SCREEN + + UIFrameEvent e; + + // New or updated waypoint: focus on this frame next time Screen::setFrames runs + if (shouldDraw()) { + requestFocus(); + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; + } + + // Deleting an old waypoint: remove the frame quietly, don't change frame position if possible + else + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET_BACKGROUND; + notifyObservers(&e); +#endif + return ProcessMessage::CONTINUE; // Let others look at this message also if they want } diff --git a/src/modules/esp32/AudioModule.cpp b/src/modules/esp32/AudioModule.cpp index 4a7b1c2c60..2e2e4f5287 100644 --- a/src/modules/esp32/AudioModule.cpp +++ b/src/modules/esp32/AudioModule.cpp @@ -190,13 +190,13 @@ int32_t AudioModule::runOnce() firstTime = false; } else { - UIFrameEvent e = {false, true}; + UIFrameEvent e; // Check if PTT is pressed. TODO hook that into Onebutton/Interrupt drive. if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == HIGH) { if (radio_state == RadioState::rx) { LOG_INFO("PTT pressed, switching to TX\n"); radio_state = RadioState::tx; - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->notifyObservers(&e); } } else { @@ -209,7 +209,7 @@ int32_t AudioModule::runOnce() } tx_encode_frame_index = sizeof(tx_header); radio_state = RadioState::rx; - e.frameChanged = true; + e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->notifyObservers(&e); } } diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index 0bae515dfa..34d6fb1d09 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -101,7 +101,7 @@ int32_t PaxcounterModule::runOnce() sendInfo(NODENUM_BROADCAST); } return Default::getConfiguredOrDefaultMs(moduleConfig.paxcounter.paxcounter_update_interval, - default_broadcast_interval_secs); + default_telemetry_broadcast_interval_secs); } else { return disable(); } diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index 5565b64686..fd3f92a9c3 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -151,6 +151,14 @@ #define HW_VENDOR meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO #elif defined(HELTEC_CAPSULE_SENSOR_V3) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3 +#elif defined(HELTEC_VISION_MASTER_T190) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_VISION_MASTER_T190 +#elif defined(HELTEC_VISION_MASTER_E213) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_VISION_MASTER_E213 +#elif defined(HELTEC_VISION_MASTER_E290) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_VISION_MASTER_E290 +#elif defined(HELTEC_MESH_NODE_T114) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 #endif // ----------------------------------------------------------------------------- diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 455219d2b3..6138e2aefc 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -19,6 +19,7 @@ static BLEBas blebas; // BAS (Battery Service) helper class instance static BLEDfu bledfu; // DFU software update helper service static BLEDfuSecure bledfusecure; // DFU software update helper service +static BLEDfu bledfu; // DFU software update helper service // This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in // process at once // static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)]; diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index b79f28f139..7334f3a041 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -234,6 +234,18 @@ void cpuDeepSleep(uint32_t msecToWake) // RAK-12039 set pin for Air quality sensor digitalWrite(AQ_SET_PIN, LOW); #endif +#ifdef RAK14014 + // GPIO restores input status, otherwise there will be leakage current + nrf_gpio_cfg_default(TFT_BL); + nrf_gpio_cfg_default(TFT_DC); + nrf_gpio_cfg_default(TFT_CS); + nrf_gpio_cfg_default(TFT_SCLK); + nrf_gpio_cfg_default(TFT_MOSI); + nrf_gpio_cfg_default(TFT_MISO); + nrf_gpio_cfg_default(SCREEN_TOUCH_INT); + nrf_gpio_cfg_default(WB_I2C1_SCL); + nrf_gpio_cfg_default(WB_I2C1_SDA); +#endif #endif // Sleepy trackers or sensors can low power "sleep" // Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event @@ -274,5 +286,10 @@ void clearBonds() void enterDfuMode() { +// SDK kit does not have native USB like almost all other NRF52 boards +#ifdef NRF_USE_SERIAL_DFU + enterSerialDfu(); +#else enterUf2Dfu(); +#endif } \ No newline at end of file diff --git a/src/sleep.cpp b/src/sleep.cpp index 04963b8a2e..ed02ba44ab 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -37,10 +37,7 @@ Observable preflightSleep; /// Called to tell observers we are now entering sleep and you should prepare. Must return 0 /// notifySleep will be called for light or deep sleep, notifyDeepSleep is only called for deep sleep -/// notifyGPSSleep will be called when config.position.gps_enabled is set to 0 or from buttonthread when GPS_POWER_TOGGLE is -/// enabled. Observable notifySleep, notifyDeepSleep; -Observable notifyGPSSleep; // deep sleep support RTC_DATA_ATTR int bootCount = 0; @@ -241,6 +238,7 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) pinMode(PIN_POWER_EN, INPUT); // power off peripherals // pinMode(PIN_POWER_EN1, INPUT_PULLDOWN); #endif + #if HAS_GPS // Kill GPS power completely (even if previously we just had it in sleep mode) if (gps) @@ -275,6 +273,8 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) #elif defined(VEXT_ENABLE_V05) digitalWrite(VEXT_ENABLE_V05, 0); // turn off the lora amplifier power digitalWrite(ST7735_BL_V05, 0); // turn off the display power +#elif defined(VEXT_ENABLE) && defined(VEXT_ON_VALUE) + digitalWrite(VEXT_ENABLE, !VEXT_ON_VALUE); // turn on the display power #elif defined(VEXT_ENABLE) digitalWrite(VEXT_ENABLE, 1); // turn off the display power #endif diff --git a/src/sleep.h b/src/sleep.h index 8d5b9a94f3..f154b8d445 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -41,8 +41,6 @@ extern Observable notifySleep; /// Called to tell observers we are now entering (deep) sleep and you should prepare. Must return 0 extern Observable notifyDeepSleep; -/// Called to tell GPS thread to enter deep sleep independently of LoRa/MCU sleep, prior to full poweroff. Must return 0 -extern Observable notifyGPSSleep; void enableModemSleep(); #ifdef ARCH_ESP32 void enableLoraInterrupt(); diff --git a/variants/heltec_capsule_sensor_v3/variant.h b/variants/heltec_capsule_sensor_v3/variant.h index 0d5ab73cfb..51c3cb6adc 100644 --- a/variants/heltec_capsule_sensor_v3/variant.h +++ b/variants/heltec_capsule_sensor_v3/variant.h @@ -1,5 +1,5 @@ #define LED_PIN 33 -#define LED_PIN2 34 +#define LED_PIN2 34 #define EXT_PWR_DETECT 35 #define BUTTON_PIN 18 diff --git a/variants/heltec_mesh_node_t114/platformio.ini b/variants/heltec_mesh_node_t114/platformio.ini new file mode 100644 index 0000000000..99bdf77a72 --- /dev/null +++ b/variants/heltec_mesh_node_t114/platformio.ini @@ -0,0 +1,15 @@ +; First prototype nrf52840/sx1262 device +[env:heltec-mesh-node-t114] +extends = nrf52840_base +board = heltec_mesh_node_t114 +debug_tool = jlink + +# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling. +build_flags = ${nrf52840_base.build_flags} -Ivariants/heltec_mesh_node_t114 + -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/heltec_mesh_node_t114> +lib_deps = + ${nrf52840_base.lib_deps} + lewisxhe/PCF8563_Library@^1.0.1 + https://github.com/Bei-Ji-Quan/st7789#b8e7e076714b670764139289d3829b0beff67edb \ No newline at end of file diff --git a/variants/heltec_mesh_node_t114/variant.cpp b/variants/heltec_mesh_node_t114/variant.cpp new file mode 100644 index 0000000000..cae079b749 --- /dev/null +++ b/variants/heltec_mesh_node_t114/variant.cpp @@ -0,0 +1,44 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 - pins 0 and 1 are hardwired for xtal and should never be enabled + 0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(PIN_LED1, OUTPUT); + ledOff(PIN_LED1); + + pinMode(PIN_LED2, OUTPUT); + ledOff(PIN_LED2); + + pinMode(PIN_LED3, OUTPUT); + ledOff(PIN_LED3); +} diff --git a/variants/heltec_mesh_node_t114/variant.h b/variants/heltec_mesh_node_t114/variant.h new file mode 100644 index 0000000000..b233069c63 --- /dev/null +++ b/variants/heltec_mesh_node_t114/variant.h @@ -0,0 +1,210 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_HELTEC_NRF_ +#define _VARIANT_HELTEC_NRF_ +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define HELTEC_MESH_NODE_T114 + +#define USE_ST7789 + +#define ST7789_NSS 11 +#define ST7789_RS 12 // DC +#define ST7789_SDA 41 // MOSI +#define ST7789_SCK 40 +#define ST7789_RESET 2 +#define ST7789_MISO -1 +#define ST7789_BUSY -1 +#define VTFT_CTRL 3 +#define VTFT_LEDA 15 +// #define ST7789_BL (32+6) +#define TFT_BACKLIGHT_ON LOW +#define ST7789_SPI_HOST SPI1_HOST +// #define ST7789_BACKLIGHT_EN (32+6) +#define SPI_FREQUENCY 40000000 +#define SPI_READ_FREQUENCY 16000000 +#define TFT_HEIGHT 135 +#define TFT_WIDTH 240 +#define TFT_OFFSET_X 0 +#define TFT_OFFSET_Y 0 +// #define TFT_OFFSET_ROTATION 0 +// #define SCREEN_ROTATE +// #define SCREEN_TRANSITION_FRAMERATE 5 + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (1) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (32 + 3) // 13 red (confirmed on 1.0 board) +// Unused(by firmware) LEDs: +#define PIN_LED2 (1 + 1) // 14 blue +#define PIN_LED3 (1 + 11) // 15 green + +#define LED_RED PIN_LED3 +#define LED_BLUE PIN_LED1 +#define LED_GREEN PIN_LED2 + +#define LED_BUILTIN LED_BLUE +#define LED_CONN PIN_GREEN + +#define LED_STATE_ON 0 // State when LED is lit +#define LED_INVERTED 1 + +/* + * Buttons + */ +#define PIN_BUTTON1 (32 + 10) +// #define PIN_BUTTON2 (0 + 18) // 0.18 is labeled on the board as RESET but we configure it in the bootloader as a regular +// GPIO + +/* +No longer populated on PCB +*/ +#define PIN_SERIAL2_RX (0 + 9) +#define PIN_SERIAL2_TX (0 + 10) +// #define PIN_SERIAL2_EN (0 + 17) + +/** + Wire Interfaces + */ +#define WIRE_INTERFACES_COUNT 1 + +#define PIN_WIRE_SDA (26) +#define PIN_WIRE_SCL (27) + +// QSPI Pins +#define PIN_QSPI_SCK (32 + 14) +#define PIN_QSPI_CS (32 + 15) +#define PIN_QSPI_IO0 (32 + 12) // MOSI if using two bit interface +#define PIN_QSPI_IO1 (32 + 13) // MISO if using two bit interface +#define PIN_QSPI_IO2 (0 + 7) // WP if using two bit interface (i.e. not used) +#define PIN_QSPI_IO3 (0 + 5) // HOLD if using two bit interface (i.e. not used) + +// On-board QSPI Flash +#define EXTERNAL_FLASH_DEVICES MX25R1635F +#define EXTERNAL_FLASH_USE_QSPI + +/* + * Lora radio + */ + +#define USE_SX1262 +// #define USE_SX1268 +#define SX126X_CS (0 + 24) // FIXME - we really should define LORA_CS instead +#define LORA_CS (0 + 24) +#define SX126X_DIO1 (0 + 20) +// Note DIO2 is attached internally to the module to an analog switch for TX/RX switching +// #define SX1262_DIO3 \ +// (0 + 21) // This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the +// main +// CPU? +#define SX126X_BUSY (0 + 17) +#define SX126X_RESET (0 + 25) +// Not really an E22 but TTGO seems to be trying to clone that +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +#define PIN_SPI1_MISO \ + ST7789_MISO // FIXME not really needed, but for now the SPI code requires something to be defined, pick an used GPIO +#define PIN_SPI1_MOSI ST7789_SDA +#define PIN_SPI1_SCK ST7789_SCK + +/* + * GPS pins + */ + +#define GPS_L76K + +#define PIN_GPS_RESET (32 + 6) // An output to reset L76K GPS. As per datasheet, low for > 100ms will reset the L76K +#define GPS_RESET_MODE LOW +#define PIN_GPS_EN (21) +#define GPS_EN_ACTIVE HIGH +#define PIN_GPS_STANDBY (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake +#define PIN_GPS_PPS (32 + 4) +// Seems to be missing on this new board +// #define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS +#define GPS_TX_PIN (32 + 5) // This is for bits going TOWARDS the CPU +#define GPS_RX_PIN (32 + 7) // This is for bits going TOWARDS the GPS + +#define GPS_THREAD_INTERVAL 50 + +#define PIN_SERIAL1_RX GPS_TX_PIN +#define PIN_SERIAL1_TX GPS_RX_PIN + +// PCF8563 RTC Module +#define PCF8563_RTC 0x51 + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +// For LORA, spi 0 +#define PIN_SPI_MISO (0 + 23) +#define PIN_SPI_MOSI (0 + 22) +#define PIN_SPI_SCK (0 + 19) + +// #define PIN_PWR_EN (0 + 6) + +// To debug via the segger JLINK console rather than the CDC-ACM serial device +// #define USE_SEGGER + +// Battery +// The battery sense is hooked to pin A0 (4) +// it is defined in the anlaolgue pin section of this file +// and has 12 bit resolution + +#define ADC_CTRL 6 +#define ADC_CTRL_ENABLED HIGH +#define BATTERY_PIN 4 +#define ADC_RESOLUTION 14 + +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define BATTERY_SENSE_RESOLUTION 4096.0 +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER (4.90F) + +#define HAS_RTC 0 +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif \ No newline at end of file diff --git a/variants/heltec_vision_master_e213/pins_arduino.h b/variants/heltec_vision_master_e213/pins_arduino.h new file mode 100644 index 0000000000..01c16c496b --- /dev/null +++ b/variants/heltec_vision_master_e213/pins_arduino.h @@ -0,0 +1,63 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define HELTEC_VISION_MASTER_E213 true + +static const uint8_t LED_BUILTIN = 35; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 41; +static const uint8_t SCL = 42; + +static const uint8_t SS = 8; +static const uint8_t MOSI = 10; +static const uint8_t MISO = 11; +static const uint8_t SCK = 9; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +static const uint8_t RST_LoRa = 12; +static const uint8_t BUSY_LoRa = 13; +static const uint8_t DIO0 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/heltec_vision_master_e213/platformio.ini b/variants/heltec_vision_master_e213/platformio.ini new file mode 100644 index 0000000000..77cc659834 --- /dev/null +++ b/variants/heltec_vision_master_e213/platformio.ini @@ -0,0 +1,23 @@ +[env:heltec-vision-master-e213] +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +build_flags = + ${esp32s3_base.build_flags} + -Ivariants/heltec_vision_master_e213 + -DHELTEC_VISION_MASTER_E213 + -DEINK_DISPLAY_MODEL=GxEPD2_213_FC1 + -DEINK_WIDTH=250 + -DEINK_HEIGHT=122 + -DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk + -DEINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted + -DEINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates + -DEINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates +; -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated + -DEINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. + -DEINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" + -DEINK_HASQUIRK_WEAKFASTREFRESH ; Pixels set with fast-refresh are easy to clear, disrupted by sunlight +lib_deps = + ${esp32s3_base.lib_deps} + https://github.com/meshtastic/GxEPD2#b202ebfec6a4821e098cf7a625ba0f6f2400292d + lewisxhe/PCF8563_Library@^1.0.1 +upload_speed = 115200 \ No newline at end of file diff --git a/variants/heltec_vision_master_e213/variant.h b/variants/heltec_vision_master_e213/variant.h new file mode 100644 index 0000000000..169602a0d7 --- /dev/null +++ b/variants/heltec_vision_master_e213/variant.h @@ -0,0 +1,58 @@ +// #define LED_PIN 18 + +// Enable bus for external periherals +#define I2C_SDA SDA +#define I2C_SCL SCL + +#define USE_EINK + +/* + * eink display pins + */ +#define PIN_EINK_CS 5 +#define PIN_EINK_BUSY 1 +#define PIN_EINK_DC 2 +#define PIN_EINK_RES 3 +#define PIN_EINK_SCLK 4 +#define PIN_EINK_MOSI 6 + +/* + * SPI interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO 10 // MISO P0.17 +#define PIN_SPI_MOSI 11 // MOSI P0.15 +#define PIN_SPI_SCK 9 // SCK P0.13 + +#define VEXT_ENABLE 18 // powers the oled display and the lora antenna boost +#define VEXT_ON_VALUE 1 +#define BUTTON_PIN 21 + +#define ADC_CTRL 46 +#define ADC_CTRL_ENABLED HIGH +#define BATTERY_PIN 7 +#define ADC_CHANNEL ADC1_GPIO7_CHANNEL +#define ADC_MULTIPLIER 4.9 * 1.03 // Voltage divider is roughly 1:1 +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high + +#define USE_SX1262 + +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define LORA_SCK 9 +#define LORA_MISO 11 +#define LORA_MOSI 10 +#define LORA_CS 8 + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET + +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 \ No newline at end of file diff --git a/variants/heltec_vision_master_e290/pins_arduino.h b/variants/heltec_vision_master_e290/pins_arduino.h new file mode 100644 index 0000000000..e5d5078463 --- /dev/null +++ b/variants/heltec_vision_master_e290/pins_arduino.h @@ -0,0 +1,61 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +static const uint8_t LED_BUILTIN = 35; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 41; +static const uint8_t SCL = 42; + +static const uint8_t SS = 8; +static const uint8_t MOSI = 10; +static const uint8_t MISO = 11; +static const uint8_t SCK = 9; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +static const uint8_t RST_LoRa = 12; +static const uint8_t BUSY_LoRa = 13; +static const uint8_t DIO0 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/heltec_vision_master_e290/platformio.ini b/variants/heltec_vision_master_e290/platformio.ini new file mode 100644 index 0000000000..60ff60036a --- /dev/null +++ b/variants/heltec_vision_master_e290/platformio.ini @@ -0,0 +1,25 @@ +[env:heltec-vision-master-e290] +board_level = extra +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +build_flags = + ${esp32s3_base.build_flags} + -Ivariants/heltec_vision_master_e290 + -DHELTEC_VISION_MASTER_E290 + -DEINK_DISPLAY_MODEL=GxEPD2_290_BS + -DEINK_WIDTH=296 + -DEINK_HEIGHT=128 +; -D USE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk +; -D EINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted +; -D EINK_LIMIT_RATE_BACKGROUND_SEC=1 ; Minimum interval between BACKGROUND updates +; -D EINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates +; -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated +; -D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. +; -D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" +; -D EINK_HASQUIRK_WEAKFASTREFRESH ; Pixels set with fast-refresh are easy to clear, disrupted by sunlight + +lib_deps = + ${esp32s3_base.lib_deps} + https://github.com/meshtastic/GxEPD2#b202ebfec6a4821e098cf7a625ba0f6f2400292d + lewisxhe/PCF8563_Library@^1.0.1 +upload_speed = 115200 \ No newline at end of file diff --git a/variants/heltec_vision_master_e290/variant.h b/variants/heltec_vision_master_e290/variant.h new file mode 100644 index 0000000000..a122a7e0fa --- /dev/null +++ b/variants/heltec_vision_master_e290/variant.h @@ -0,0 +1,58 @@ +// #define LED_PIN 18 + +// Enable bus for external periherals +#define I2C_SDA SDA +#define I2C_SCL SCL + +#define USE_EINK + +/* + * eink display pins + */ +#define PIN_EINK_CS 3 +#define PIN_EINK_BUSY 5 +#define PIN_EINK_DC 4 +#define PIN_EINK_RES 5 +#define PIN_EINK_SCLK 2 +#define PIN_EINK_MOSI 1 + +/* + * SPI interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO 10 // MISO +#define PIN_SPI_MOSI 11 // MOSI +#define PIN_SPI_SCK 9 // SCK + +#define VEXT_ENABLE 18 // powers the e-ink display +#define VEXT_ON_VALUE 1 +#define BUTTON_PIN 21 + +#define ADC_CTRL 46 +#define ADC_CTRL_ENABLED HIGH +#define BATTERY_PIN 7 +#define ADC_CHANNEL ADC1_GPIO7_CHANNEL +#define ADC_MULTIPLIER 4.9 * 1.03 +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high + +#define USE_SX1262 + +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define LORA_SCK 9 +#define LORA_MISO 11 +#define LORA_MOSI 10 +#define LORA_CS 8 + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET + +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 \ No newline at end of file diff --git a/variants/heltec_vision_master_t190/pins_arduino.h b/variants/heltec_vision_master_t190/pins_arduino.h new file mode 100644 index 0000000000..e5d5078463 --- /dev/null +++ b/variants/heltec_vision_master_t190/pins_arduino.h @@ -0,0 +1,61 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +static const uint8_t LED_BUILTIN = 35; +#define BUILTIN_LED LED_BUILTIN // backward compatibility +#define LED_BUILTIN LED_BUILTIN + +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +static const uint8_t SDA = 41; +static const uint8_t SCL = 42; + +static const uint8_t SS = 8; +static const uint8_t MOSI = 10; +static const uint8_t MISO = 11; +static const uint8_t SCK = 9; + +static const uint8_t A0 = 1; +static const uint8_t A1 = 2; +static const uint8_t A2 = 3; +static const uint8_t A3 = 4; +static const uint8_t A4 = 5; +static const uint8_t A5 = 6; +static const uint8_t A6 = 7; +static const uint8_t A7 = 8; +static const uint8_t A8 = 9; +static const uint8_t A9 = 10; +static const uint8_t A10 = 11; +static const uint8_t A11 = 12; +static const uint8_t A12 = 13; +static const uint8_t A13 = 14; +static const uint8_t A14 = 15; +static const uint8_t A15 = 16; +static const uint8_t A16 = 17; +static const uint8_t A17 = 18; +static const uint8_t A18 = 19; +static const uint8_t A19 = 20; + +static const uint8_t T1 = 1; +static const uint8_t T2 = 2; +static const uint8_t T3 = 3; +static const uint8_t T4 = 4; +static const uint8_t T5 = 5; +static const uint8_t T6 = 6; +static const uint8_t T7 = 7; +static const uint8_t T8 = 8; +static const uint8_t T9 = 9; +static const uint8_t T10 = 10; +static const uint8_t T11 = 11; +static const uint8_t T12 = 12; +static const uint8_t T13 = 13; +static const uint8_t T14 = 14; + +static const uint8_t RST_LoRa = 12; +static const uint8_t BUSY_LoRa = 13; +static const uint8_t DIO0 = 14; + +#endif /* Pins_Arduino_h */ diff --git a/variants/heltec_vision_master_t190/platformio.ini b/variants/heltec_vision_master_t190/platformio.ini new file mode 100644 index 0000000000..bbaa0075c5 --- /dev/null +++ b/variants/heltec_vision_master_t190/platformio.ini @@ -0,0 +1,13 @@ +[env:heltec-vision-master-t190] +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +build_flags = + ${esp32s3_base.build_flags} + -Ivariants/heltec_vision_master_t190 + -DHELTEC_VISION_MASTER_T190 + ; -D PRIVATE_HW +lib_deps = + ${esp32s3_base.lib_deps} + lewisxhe/PCF8563_Library@^1.0.1 + https://github.com/Bei-Ji-Quan/st7789#b8e7e076714b670764139289d3829b0beff67edb +upload_speed = 921600 \ No newline at end of file diff --git a/variants/heltec_vision_master_t190/variant.h b/variants/heltec_vision_master_t190/variant.h new file mode 100644 index 0000000000..97500d357e --- /dev/null +++ b/variants/heltec_vision_master_t190/variant.h @@ -0,0 +1,76 @@ +// #define LED_PIN 18 + +// Enable bus for external periherals +#define I2C_SDA 1 +#define I2C_SCL 2 +#define USE_ST7789 + +#define ST7789_NSS 39 +// #define ST7789_CS 39 +#define ST7789_RS 47 // DC +#define ST7789_SDA 48 // MOSI +#define ST7789_SCK 38 +#define ST7789_RESET 40 +#define ST7789_MISO 4 +#define ST7789_BUSY -1 +#define VTFT_CTRL 7 +// #define TFT_BL 3 +#define VTFT_LEDA 17 +#define TFT_BACKLIGHT_ON HIGH +// #define TFT_BL 17 +// #define TFT_BACKLIGHT_ON HIGH +// #define ST7789_BL 3 +#define ST7789_SPI_HOST SPI2_HOST +// #define ST7789_BACKLIGHT_EN 17 +#define SPI_FREQUENCY 10000000 +#define SPI_READ_FREQUENCY 10000000 +#define TFT_HEIGHT 170 +#define TFT_WIDTH 320 +#define TFT_OFFSET_X 0 +#define TFT_OFFSET_Y 0 +// #define TFT_OFFSET_ROTATION 0 +// #define SCREEN_ROTATE +// #define SCREEN_TRANSITION_FRAMERATE 5 +#define BRIGHTNESS_DEFAULT 100 // Medium Low Brightnes + +// #define SLEEP_TIME 120 + +/* + * SPI interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +#define PIN_SPI_MISO 10 // MISO P0.17 +#define PIN_SPI_MOSI 11 // MOSI P0.15 +#define PIN_SPI_SCK 9 // SCK P0.13 + +// #define VEXT_ENABLE 7 // active low, powers the oled display and the lora antenna boost +#define BUTTON_PIN 0 + +#define ADC_CTRL 46 +#define ADC_CTRL_ENABLED HIGH +#define BATTERY_PIN 6 +#define ADC_CHANNEL ADC1_GPIO6_CHANNEL +#define ADC_MULTIPLIER 4.9 * 1.03 // Voltage divider is roughly 1:1 +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high + +#define USE_SX1262 + +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define LORA_SCK 9 +#define LORA_MISO 11 +#define LORA_MOSI 10 +#define LORA_CS 8 + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET + +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 \ No newline at end of file diff --git a/variants/heltec_wireless_paper/pins_arduino.h b/variants/heltec_wireless_paper/pins_arduino.h index 2bb44161ab..3e36d98f56 100644 --- a/variants/heltec_wireless_paper/pins_arduino.h +++ b/variants/heltec_wireless_paper/pins_arduino.h @@ -7,8 +7,6 @@ static const uint8_t LED_BUILTIN = 18; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN -static const uint8_t KEY_BUILTIN = 0; - static const uint8_t TX = 43; static const uint8_t RX = 44; @@ -56,9 +54,6 @@ static const uint8_t T12 = 12; static const uint8_t T13 = 13; static const uint8_t T14 = 14; -static const uint8_t Vext = 45; -static const uint8_t LED = 18; - static const uint8_t RST_LoRa = 12; static const uint8_t BUSY_LoRa = 13; static const uint8_t DIO1 = 14; diff --git a/variants/wio-sdk-wm1110/nrf52840_s140_v7.ld b/variants/wio-sdk-wm1110/nrf52840_s140_v7.ld deleted file mode 100644 index 6aaeb4034f..0000000000 --- a/variants/wio-sdk-wm1110/nrf52840_s140_v7.ld +++ /dev/null @@ -1,38 +0,0 @@ -/* Linker script to configure memory regions. */ - -SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) - -MEMORY -{ - FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xED000 - 0x27000 - - /* SRAM required by Softdevice depend on - * - Attribute Table Size (Number of Services and Characteristics) - * - Vendor UUID count - * - Max ATT MTU - * - Concurrent connection peripheral + central + secure links - * - Event Len, HVN queue, Write CMD queue - */ - RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x20040000 - 0x20006000 -} - -SECTIONS -{ - . = ALIGN(4); - .svc_data : - { - PROVIDE(__start_svc_data = .); - KEEP(*(.svc_data)) - PROVIDE(__stop_svc_data = .); - } > RAM - - .fs_data : - { - PROVIDE(__start_fs_data = .); - KEEP(*(.fs_data)) - PROVIDE(__stop_fs_data = .); - } > RAM -} INSERT AFTER .data; - -INCLUDE "nrf52_common.ld" diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini index 4410eff112..7667174289 100644 --- a/variants/wio-sdk-wm1110/platformio.ini +++ b/variants/wio-sdk-wm1110/platformio.ini @@ -6,11 +6,11 @@ board = wio-sdk-wm1110 # Remove adafruit USB serial from the build (it is incompatible with using the ch340 serial chip on this board) build_unflags = ${nrf52840_base:build_unflags} -DUSBCON -DUSE_TINYUSB -board_level = extra +; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -board_build.ldscript = variants/wio-sdk-wm1110/nrf52840_s140_v7.ld +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-sdk-wm1110> lib_deps = ${nrf52840_base.lib_deps} @@ -20,7 +20,7 @@ debug_tool = jlink ; No need to reflash if the binary hasn't changed debug_load_mode = modified ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -upload_protocol = jlink +upload_protocol = nrfutil ;upload_protocol = stlink ; we prefer to stop in setup() because we are an 'ardiuno' app debug_init_break = tbreak setup diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h b/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h deleted file mode 100644 index 2786a86a45..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_sdm_api SoftDevice Manager API - @{ - - @brief APIs for SoftDevice management. - -*/ - -#ifndef NRF_SDM_H__ -#define NRF_SDM_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_sdm.h" -#include "nrf_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup NRF_SDM_DEFINES Defines - * @{ */ -#ifdef NRFSOC_DOXYGEN -/// Declared in nrf_mbr.h -#define MBR_SIZE 0 -#warning test -#endif - -/** @brief The major version for the SoftDevice binary distributed with this header file. */ -#define SD_MAJOR_VERSION (7) - -/** @brief The minor version for the SoftDevice binary distributed with this header file. */ -#define SD_MINOR_VERSION (3) - -/** @brief The bugfix version for the SoftDevice binary distributed with this header file. */ -#define SD_BUGFIX_VERSION (0) - -/** @brief The SoftDevice variant of this firmware. */ -#define SD_VARIANT_ID 140 - -/** @brief The full version number for the SoftDevice binary this header file was distributed - * with, as a decimal number in the form Mmmmbbb, where: - * - M is major version (one or more digits) - * - mmm is minor version (three digits) - * - bbb is bugfix version (three digits). */ -#define SD_VERSION (SD_MAJOR_VERSION * 1000000 + SD_MINOR_VERSION * 1000 + SD_BUGFIX_VERSION) - -/** @brief SoftDevice Manager SVC Base number. */ -#define SDM_SVC_BASE 0x10 - -/** @brief SoftDevice unique string size in bytes. */ -#define SD_UNIQUE_STR_SIZE 20 - -/** @brief Invalid info field. Returned when an info field does not exist. */ -#define SDM_INFO_FIELD_INVALID (0) - -/** @brief Defines the SoftDevice Information Structure location (address) as an offset from -the start of the SoftDevice (without MBR)*/ -#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000) - -/** @brief Defines the absolute SoftDevice Information Structure location (address) when the - * SoftDevice is installed just above the MBR (the usual case). */ -#define SOFTDEVICE_INFO_STRUCT_ADDRESS (SOFTDEVICE_INFO_STRUCT_OFFSET + MBR_SIZE) - -/** @brief Defines the offset for the SoftDevice Information Structure size value relative to the - * SoftDevice base address. The size value is of type uint8_t. */ -#define SD_INFO_STRUCT_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET) - -/** @brief Defines the offset for the SoftDevice size value relative to the SoftDevice base address. - * The size value is of type uint32_t. */ -#define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08) - -/** @brief Defines the offset for FWID value relative to the SoftDevice base address. The FWID value - * is of type uint16_t. */ -#define SD_FWID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x0C) - -/** @brief Defines the offset for the SoftDevice ID relative to the SoftDevice base address. The ID - * is of type uint32_t. */ -#define SD_ID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x10) - -/** @brief Defines the offset for the SoftDevice version relative to the SoftDevice base address in - * the same format as @ref SD_VERSION, stored as an uint32_t. */ -#define SD_VERSION_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x14) - -/** @brief Defines the offset for the SoftDevice unique string relative to the SoftDevice base address. - * The SD_UNIQUE_STR is stored as an array of uint8_t. The size of array is @ref SD_UNIQUE_STR_SIZE. - */ -#define SD_UNIQUE_STR_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x18) - -/** @brief Defines a macro for retrieving the actual SoftDevice Information Structure size value - * from a given base address. Use @ref MBR_SIZE as the argument when the SoftDevice is - * installed just above the MBR (the usual case). */ -#define SD_INFO_STRUCT_SIZE_GET(baseaddr) (*((uint8_t *)((baseaddr) + SD_INFO_STRUCT_SIZE_OFFSET))) - -/** @brief Defines a macro for retrieving the actual SoftDevice size value from a given base - * address. Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above - * the MBR (the usual case). */ -#define SD_SIZE_GET(baseaddr) (*((uint32_t *)((baseaddr) + SD_SIZE_OFFSET))) - -/** @brief Defines the amount of flash that is used by the SoftDevice. - * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed - * just above the MBR (the usual case). - */ -#define SD_FLASH_SIZE 0x26000 - -/** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use - * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual - * case). */ -#define SD_FWID_GET(baseaddr) (*((uint16_t *)((baseaddr) + SD_FWID_OFFSET))) - -/** @brief Defines a macro for retrieving the actual SoftDevice ID from a given base address. Use - * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the - * usual case). */ -#define SD_ID_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_ID_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (*((uint32_t *)((baseaddr) + SD_ID_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/** @brief Defines a macro for retrieving the actual SoftDevice version from a given base address. - * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR - * (the usual case). */ -#define SD_VERSION_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_VERSION_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (*((uint32_t *)((baseaddr) + SD_VERSION_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/** @brief Defines a macro for retrieving the address of SoftDevice unique str based on a given base address. - * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR - * (the usual case). */ -#define SD_UNIQUE_STR_ADDR_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_UNIQUE_STR_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (((uint8_t *)((baseaddr) + SD_UNIQUE_STR_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/**@defgroup NRF_FAULT_ID_RANGES Fault ID ranges - * @{ */ -#define NRF_FAULT_ID_SD_RANGE_START 0x00000000 /**< SoftDevice ID range start. */ -#define NRF_FAULT_ID_APP_RANGE_START 0x00001000 /**< Application ID range start. */ -/**@} */ - -/**@defgroup NRF_FAULT_IDS Fault ID types - * @{ */ -#define NRF_FAULT_ID_SD_ASSERT \ - (NRF_FAULT_ID_SD_RANGE_START + 1) /**< SoftDevice assertion. The info parameter is reserved for future used. */ -#define NRF_FAULT_ID_APP_MEMACC \ - (NRF_FAULT_ID_APP_RANGE_START + 1) /**< Application invalid memory access. The info parameter will contain 0x00000000, \ - in case of SoftDevice RAM access violation. In case of SoftDevice peripheral \ - register violation the info parameter will contain the sub-region number of \ - PREGION[0], on whose address range the disallowed write access caused the \ - memory access fault. */ -/**@} */ - -/** @} */ - -/** @addtogroup NRF_SDM_ENUMS Enumerations - * @{ */ - -/**@brief nRF SoftDevice Manager API SVC numbers. */ -enum NRF_SD_SVCS { - SD_SOFTDEVICE_ENABLE = SDM_SVC_BASE, /**< ::sd_softdevice_enable */ - SD_SOFTDEVICE_DISABLE, /**< ::sd_softdevice_disable */ - SD_SOFTDEVICE_IS_ENABLED, /**< ::sd_softdevice_is_enabled */ - SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, /**< ::sd_softdevice_vector_table_base_set */ - SVC_SDM_LAST /**< Placeholder for last SDM SVC */ -}; - -/** @} */ - -/** @addtogroup NRF_SDM_DEFINES Defines - * @{ */ - -/**@defgroup NRF_CLOCK_LF_ACCURACY Clock accuracy - * @{ */ - -#define NRF_CLOCK_LF_ACCURACY_250_PPM (0) /**< Default: 250 ppm */ -#define NRF_CLOCK_LF_ACCURACY_500_PPM (1) /**< 500 ppm */ -#define NRF_CLOCK_LF_ACCURACY_150_PPM (2) /**< 150 ppm */ -#define NRF_CLOCK_LF_ACCURACY_100_PPM (3) /**< 100 ppm */ -#define NRF_CLOCK_LF_ACCURACY_75_PPM (4) /**< 75 ppm */ -#define NRF_CLOCK_LF_ACCURACY_50_PPM (5) /**< 50 ppm */ -#define NRF_CLOCK_LF_ACCURACY_30_PPM (6) /**< 30 ppm */ -#define NRF_CLOCK_LF_ACCURACY_20_PPM (7) /**< 20 ppm */ -#define NRF_CLOCK_LF_ACCURACY_10_PPM (8) /**< 10 ppm */ -#define NRF_CLOCK_LF_ACCURACY_5_PPM (9) /**< 5 ppm */ -#define NRF_CLOCK_LF_ACCURACY_2_PPM (10) /**< 2 ppm */ -#define NRF_CLOCK_LF_ACCURACY_1_PPM (11) /**< 1 ppm */ - -/** @} */ - -/**@defgroup NRF_CLOCK_LF_SRC Possible LFCLK oscillator sources - * @{ */ - -#define NRF_CLOCK_LF_SRC_RC (0) /**< LFCLK RC oscillator. */ -#define NRF_CLOCK_LF_SRC_XTAL (1) /**< LFCLK crystal oscillator. */ -#define NRF_CLOCK_LF_SRC_SYNTH (2) /**< LFCLK Synthesized from HFCLK. */ - -/** @} */ - -/** @} */ - -/** @addtogroup NRF_SDM_TYPES Types - * @{ */ - -/**@brief Type representing LFCLK oscillator source. */ -typedef struct { - uint8_t source; /**< LF oscillator clock source, see @ref NRF_CLOCK_LF_SRC. */ - uint8_t rc_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: Calibration timer interval in 1/4 second - units (nRF52: 1-32). - @note To avoid excessive clock drift, 0.5 degrees Celsius is the - maximum temperature change allowed in one calibration timer - interval. The interval should be selected to ensure this. - - @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. */ - uint8_t rc_temp_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: How often (in number of calibration - intervals) the RC oscillator shall be calibrated if the temperature - hasn't changed. - 0: Always calibrate even if the temperature hasn't changed. - 1: Only calibrate if the temperature has changed (legacy - nRF51 only). - 2-33: Check the temperature and only calibrate if it has changed, - however calibration will take place every rc_temp_ctiv - intervals in any case. - - @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. - - @note For nRF52, the application must ensure calibration at least once - every 8 seconds to ensure +/-500 ppm clock stability. The - recommended configuration for ::NRF_CLOCK_LF_SRC_RC on nRF52 is - rc_ctiv=16 and rc_temp_ctiv=2. This will ensure calibration at - least once every 8 seconds and for temperature changes of 0.5 - degrees Celsius every 4 seconds. See the Product Specification - for the nRF52 device being used for more information.*/ - uint8_t accuracy; /**< External clock accuracy used in the LL to compute timing - windows, see @ref NRF_CLOCK_LF_ACCURACY.*/ -} nrf_clock_lf_cfg_t; - -/**@brief Fault Handler type. - * - * When certain unrecoverable errors occur within the application or SoftDevice the fault handler will be called back. - * The protocol stack will be in an undefined state when this happens and the only way to recover will be to - * perform a reset, using e.g. CMSIS NVIC_SystemReset(). - * If the application returns from the fault handler the SoftDevice will call NVIC_SystemReset(). - * - * @note It is recommended to either perform a reset in the fault handler or to let the SoftDevice reset the device. - * Otherwise SoC peripherals may behave in an undefined way. For example, the RADIO peripherial may - * continously transmit packets. - * - * @note This callback is executed in HardFault context, thus SVC functions cannot be called from the fault callback. - * - * @param[in] id Fault identifier. See @ref NRF_FAULT_IDS. - * @param[in] pc The program counter of the instruction that triggered the fault. - * @param[in] info Optional additional information regarding the fault. Refer to each Fault identifier for details. - * - * @note When id is set to @ref NRF_FAULT_ID_APP_MEMACC, pc will contain the address of the instruction being executed at the time - * when the fault is detected by the CPU. The CPU program counter may have advanced up to 2 instructions (no branching) after the - * one that triggered the fault. - */ -typedef void (*nrf_fault_handler_t)(uint32_t id, uint32_t pc, uint32_t info); - -/** @} */ - -/** @addtogroup NRF_SDM_FUNCTIONS Functions - * @{ */ - -/**@brief Enables the SoftDevice and by extension the protocol stack. - * - * @note Some care must be taken if a low frequency clock source is already running when calling this function: - * If the LF clock has a different source then the one currently running, it will be stopped. Then, the new - * clock source will be started. - * - * @note This function has no effect when returning with an error. - * - * @post If return code is ::NRF_SUCCESS - * - SoC library and protocol stack APIs are made available. - * - A portion of RAM will be unavailable (see relevant SDS documentation). - * - Some peripherals will be unavailable or available only through the SoC API (see relevant SDS documentation). - * - Interrupts will not arrive from protected peripherals or interrupts. - * - nrf_nvic_ functions must be used instead of CMSIS NVIC_ functions for reliable usage of the SoftDevice. - * - Interrupt latency may be affected by the SoftDevice (see relevant SDS documentation). - * - Chosen low frequency clock source will be running. - * - * @param p_clock_lf_cfg Low frequency clock source and accuracy. - If NULL the clock will be configured as an RC source with rc_ctiv = 16 and .rc_temp_ctiv = 2 - In the case of XTAL source, the PPM accuracy of the chosen clock source must be greater than or equal to - the actual characteristics of your XTAL clock. - * @param fault_handler Callback to be invoked in case of fault, cannot be NULL. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE SoftDevice is already enabled, and the clock source and fault handler cannot be updated. - * @retval ::NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION SoftDevice interrupt is already enabled, or an enabled interrupt has - an illegal priority level. - * @retval ::NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN Unknown low frequency clock source selected. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid clock source configuration supplied in p_clock_lf_cfg. - */ -SVCALL(SD_SOFTDEVICE_ENABLE, uint32_t, - sd_softdevice_enable(nrf_clock_lf_cfg_t const *p_clock_lf_cfg, nrf_fault_handler_t fault_handler)); - -/**@brief Disables the SoftDevice and by extension the protocol stack. - * - * Idempotent function to disable the SoftDevice. - * - * @post SoC library and protocol stack APIs are made unavailable. - * @post All interrupts that was protected by the SoftDevice will be disabled and initialized to priority 0 (highest). - * @post All peripherals used by the SoftDevice will be reset to default values. - * @post All of RAM become available. - * @post All interrupts are forwarded to the application. - * @post LFCLK source chosen in ::sd_softdevice_enable will be left running. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_DISABLE, uint32_t, sd_softdevice_disable(void)); - -/**@brief Check if the SoftDevice is enabled. - * - * @param[out] p_softdevice_enabled If the SoftDevice is enabled: 1 else 0. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_IS_ENABLED, uint32_t, sd_softdevice_is_enabled(uint8_t *p_softdevice_enabled)); - -/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the SoftDevice - * - * This function is only intended to be called when a bootloader is enabled. - * - * @param[in] address The base address of the interrupt vector table for forwarded interrupts. - - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table_base_set(uint32_t address)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_SDM_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/variant.h b/variants/wio-sdk-wm1110/variant.h index 8ad8c769af..8f66b1f8c8 100644 --- a/variants/wio-sdk-wm1110/variant.h +++ b/variants/wio-sdk-wm1110/variant.h @@ -107,6 +107,8 @@ extern "C" { #define LR1110_GNSS_ANT_PIN (32 + 5) // P1.05 37 +#define NRF_USE_SERIAL_DFU + #ifdef __cplusplus } #endif diff --git a/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld b/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld deleted file mode 100644 index 6aaeb4034f..0000000000 --- a/variants/wio-tracker-wm1110/nrf52840_s140_v7.ld +++ /dev/null @@ -1,38 +0,0 @@ -/* Linker script to configure memory regions. */ - -SEARCH_DIR(.) -GROUP(-lgcc -lc -lnosys) - -MEMORY -{ - FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xED000 - 0x27000 - - /* SRAM required by Softdevice depend on - * - Attribute Table Size (Number of Services and Characteristics) - * - Vendor UUID count - * - Max ATT MTU - * - Concurrent connection peripheral + central + secure links - * - Event Len, HVN queue, Write CMD queue - */ - RAM (rwx) : ORIGIN = 0x20006000, LENGTH = 0x20040000 - 0x20006000 -} - -SECTIONS -{ - . = ALIGN(4); - .svc_data : - { - PROVIDE(__start_svc_data = .); - KEEP(*(.svc_data)) - PROVIDE(__stop_svc_data = .); - } > RAM - - .fs_data : - { - PROVIDE(__start_fs_data = .); - KEEP(*(.fs_data)) - PROVIDE(__stop_fs_data = .); - } > RAM -} INSERT AFTER .data; - -INCLUDE "nrf52_common.ld" diff --git a/variants/wio-tracker-wm1110/platformio.ini b/variants/wio-tracker-wm1110/platformio.ini index 9c04e36f16..5ecc414adc 100644 --- a/variants/wio-tracker-wm1110/platformio.ini +++ b/variants/wio-tracker-wm1110/platformio.ini @@ -2,10 +2,11 @@ [env:wio-tracker-wm1110] extends = nrf52840_base board = wio-tracker-wm1110 +; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-tracker-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -board_build.ldscript = variants/wio-tracker-wm1110/nrf52840_s140_v7.ld +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-tracker-wm1110> lib_deps = ${nrf52840_base.lib_deps} diff --git a/variants/wio-tracker-wm1110/softdevice/ble.h b/variants/wio-tracker-wm1110/softdevice/ble.h deleted file mode 100644 index 177b436ad8..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble.h +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON BLE SoftDevice Common - @{ - @defgroup ble_api Events, type definitions and API calls - @{ - - @brief Module independent events, type definitions and API calls for the BLE SoftDevice. - - */ - -#ifndef BLE_H__ -#define BLE_H__ - -#include "ble_err.h" -#include "ble_gap.h" -#include "ble_gatt.h" -#include "ble_gattc.h" -#include "ble_gatts.h" -#include "ble_l2cap.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_COMMON_ENUMERATIONS Enumerations - * @{ */ - -/** - * @brief Common API SVC numbers. - */ -enum BLE_COMMON_SVCS { - SD_BLE_ENABLE = BLE_SVC_BASE, /**< Enable and initialize the BLE stack */ - SD_BLE_EVT_GET, /**< Get an event from the pending events queue. */ - SD_BLE_UUID_VS_ADD, /**< Add a Vendor Specific base UUID. */ - SD_BLE_UUID_DECODE, /**< Decode UUID bytes. */ - SD_BLE_UUID_ENCODE, /**< Encode UUID bytes. */ - SD_BLE_VERSION_GET, /**< Get the local version information (company ID, Link Layer Version, Link Layer Subversion). */ - SD_BLE_USER_MEM_REPLY, /**< User Memory Reply. */ - SD_BLE_OPT_SET, /**< Set a BLE option. */ - SD_BLE_OPT_GET, /**< Get a BLE option. */ - SD_BLE_CFG_SET, /**< Add a configuration to the BLE stack. */ - SD_BLE_UUID_VS_REMOVE, /**< Remove a Vendor Specific base UUID. */ -}; - -/** - * @brief BLE Module Independent Event IDs. - */ -enum BLE_COMMON_EVTS { - BLE_EVT_USER_MEM_REQUEST = BLE_EVT_BASE + 0, /**< User Memory request. See @ref ble_evt_user_mem_request_t - \n Reply with @ref sd_ble_user_mem_reply. */ - BLE_EVT_USER_MEM_RELEASE = BLE_EVT_BASE + 1, /**< User Memory release. See @ref ble_evt_user_mem_release_t */ -}; - -/**@brief BLE Connection Configuration IDs. - * - * IDs that uniquely identify a connection configuration. - */ -enum BLE_CONN_CFGS { - BLE_CONN_CFG_GAP = BLE_CONN_CFG_BASE + 0, /**< BLE GAP specific connection configuration. */ - BLE_CONN_CFG_GATTC = BLE_CONN_CFG_BASE + 1, /**< BLE GATTC specific connection configuration. */ - BLE_CONN_CFG_GATTS = BLE_CONN_CFG_BASE + 2, /**< BLE GATTS specific connection configuration. */ - BLE_CONN_CFG_GATT = BLE_CONN_CFG_BASE + 3, /**< BLE GATT specific connection configuration. */ - BLE_CONN_CFG_L2CAP = BLE_CONN_CFG_BASE + 4, /**< BLE L2CAP specific connection configuration. */ -}; - -/**@brief BLE Common Configuration IDs. - * - * IDs that uniquely identify a common configuration. - */ -enum BLE_COMMON_CFGS { - BLE_COMMON_CFG_VS_UUID = BLE_CFG_BASE, /**< Vendor specific base UUID configuration */ -}; - -/**@brief Common Option IDs. - * IDs that uniquely identify a common option. - */ -enum BLE_COMMON_OPTS { - BLE_COMMON_OPT_PA_LNA = BLE_OPT_BASE + 0, /**< PA and LNA options */ - BLE_COMMON_OPT_CONN_EVT_EXT = BLE_OPT_BASE + 1, /**< Extended connection events option */ - BLE_COMMON_OPT_EXTENDED_RC_CAL = BLE_OPT_BASE + 2, /**< Extended RC calibration option */ -}; - -/** @} */ - -/** @addtogroup BLE_COMMON_DEFINES Defines - * @{ */ - -/** @brief Required pointer alignment for BLE Events. - */ -#define BLE_EVT_PTR_ALIGNMENT 4 - -/** @brief Leaves the maximum of the two arguments. - */ -#define BLE_MAX(a, b) ((a) < (b) ? (b) : (a)) - -/** @brief Maximum possible length for BLE Events. - * @note The highest value used for @ref ble_gatt_conn_cfg_t::att_mtu in any connection configuration shall be used as a - * parameter. If that value has not been configured for any connections then @ref BLE_GATT_ATT_MTU_DEFAULT must be used instead. - */ -#define BLE_EVT_LEN_MAX(ATT_MTU) \ - (offsetof(ble_evt_t, evt.gattc_evt.params.prim_srvc_disc_rsp.services) + ((ATT_MTU)-1) / 4 * sizeof(ble_gattc_service_t)) - -/** @defgroup BLE_USER_MEM_TYPES User Memory Types - * @{ */ -#define BLE_USER_MEM_TYPE_INVALID 0x00 /**< Invalid User Memory Types. */ -#define BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES 0x01 /**< User Memory for GATTS queued writes. */ -/** @} */ - -/** @defgroup BLE_UUID_VS_COUNTS Vendor Specific base UUID counts - * @{ - */ -#define BLE_UUID_VS_COUNT_DEFAULT 10 /**< Default VS UUID count. */ -#define BLE_UUID_VS_COUNT_MAX 254 /**< Maximum VS UUID count. */ -/** @} */ - -/** @defgroup BLE_COMMON_CFG_DEFAULTS Configuration defaults. - * @{ - */ -#define BLE_CONN_CFG_TAG_DEFAULT 0 /**< Default configuration tag, SoftDevice default connection configuration. */ - -/** @} */ - -/** @} */ - -/** @addtogroup BLE_COMMON_STRUCTURES Structures - * @{ */ - -/**@brief User Memory Block. */ -typedef struct { - uint8_t *p_mem; /**< Pointer to the start of the user memory block. */ - uint16_t len; /**< Length in bytes of the user memory block. */ -} ble_user_mem_block_t; - -/**@brief Event structure for @ref BLE_EVT_USER_MEM_REQUEST. */ -typedef struct { - uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ -} ble_evt_user_mem_request_t; - -/**@brief Event structure for @ref BLE_EVT_USER_MEM_RELEASE. */ -typedef struct { - uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ - ble_user_mem_block_t mem_block; /**< User memory block */ -} ble_evt_user_mem_release_t; - -/**@brief Event structure for events not associated with a specific function module. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which this event occurred. */ - union { - ble_evt_user_mem_request_t user_mem_request; /**< User Memory Request Event Parameters. */ - ble_evt_user_mem_release_t user_mem_release; /**< User Memory Release Event Parameters. */ - } params; /**< Event parameter union. */ -} ble_common_evt_t; - -/**@brief BLE Event header. */ -typedef struct { - uint16_t evt_id; /**< Value from a BLE__EVT series. */ - uint16_t evt_len; /**< Length in octets including this header. */ -} ble_evt_hdr_t; - -/**@brief Common BLE Event type, wrapping the module specific event reports. */ -typedef struct { - ble_evt_hdr_t header; /**< Event header. */ - union { - ble_common_evt_t common_evt; /**< Common Event, evt_id in BLE_EVT_* series. */ - ble_gap_evt_t gap_evt; /**< GAP originated event, evt_id in BLE_GAP_EVT_* series. */ - ble_gattc_evt_t gattc_evt; /**< GATT client originated event, evt_id in BLE_GATTC_EVT* series. */ - ble_gatts_evt_t gatts_evt; /**< GATT server originated event, evt_id in BLE_GATTS_EVT* series. */ - ble_l2cap_evt_t l2cap_evt; /**< L2CAP originated event, evt_id in BLE_L2CAP_EVT* series. */ - } evt; /**< Event union. */ -} ble_evt_t; - -/** - * @brief Version Information. - */ -typedef struct { - uint8_t version_number; /**< Link Layer Version number. See - https://www.bluetooth.org/en-us/specification/assigned-numbers/link-layer for assigned values. */ - uint16_t company_id; /**< Company ID, Nordic Semiconductor's company ID is 89 (0x0059) - (https://www.bluetooth.org/apps/content/Default.aspx?doc_id=49708). */ - uint16_t - subversion_number; /**< Link Layer Sub Version number, corresponds to the SoftDevice Config ID or Firmware ID (FWID). */ -} ble_version_t; - -/** - * @brief Configuration parameters for the PA and LNA. - */ -typedef struct { - uint8_t enable : 1; /**< Enable toggling for this amplifier */ - uint8_t active_high : 1; /**< Set the pin to be active high */ - uint8_t gpio_pin : 6; /**< The GPIO pin to toggle for this amplifier */ -} ble_pa_lna_cfg_t; - -/** - * @brief PA & LNA GPIO toggle configuration - * - * This option configures the SoftDevice to toggle pins when the radio is active for use with a power amplifier and/or - * a low noise amplifier. - * - * Toggling the pins is achieved by using two PPI channels and a GPIOTE channel. The hardware channel IDs are provided - * by the application and should be regarded as reserved as long as any PA/LNA toggling is enabled. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * @note Setting this option while the radio is in use (i.e. any of the roles are active) may have undefined consequences - * and must be avoided by the application. - */ -typedef struct { - ble_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */ - ble_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */ - - uint8_t ppi_ch_id_set; /**< PPI channel used for radio pin setting */ - uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */ - uint8_t gpiote_ch_id; /**< GPIOTE channel used for radio pin toggling */ -} ble_common_opt_pa_lna_t; - -/** - * @brief Configuration of extended BLE connection events. - * - * When enabled the SoftDevice will dynamically extend the connection event when possible. - * - * The connection event length is controlled by the connection configuration as set by @ref ble_gap_conn_cfg_t::event_length. - * The connection event can be extended if there is time to send another packet pair before the start of the next connection - * interval, and if there are no conflicts with other BLE roles requesting radio time. - * - * @note @ref sd_ble_opt_get is not supported for this option. - */ -typedef struct { - uint8_t enable : 1; /**< Enable extended BLE connection events, disabled by default. */ -} ble_common_opt_conn_evt_ext_t; - -/** - * @brief Enable/disable extended RC calibration. - * - * If extended RC calibration is enabled and the internal RC oscillator (@ref NRF_CLOCK_LF_SRC_RC) is used as the SoftDevice - * LFCLK source, the SoftDevice as a peripheral will by default try to increase the receive window if two consecutive packets - * are not received. If it turns out that the packets were not received due to clock drift, the RC calibration is started. - * This calibration comes in addition to the periodic calibration that is configured by @ref sd_softdevice_enable(). When - * using only peripheral connections, the periodic calibration can therefore be configured with a much longer interval as the - * peripheral will be able to detect and adjust automatically to clock drift, and calibrate on demand. - * - * If extended RC calibration is disabled and the internal RC oscillator is used as the SoftDevice LFCLK source, the - * RC oscillator is calibrated periodically as configured by @ref sd_softdevice_enable(). - * - * @note @ref sd_ble_opt_get is not supported for this option. - */ -typedef struct { - uint8_t enable : 1; /**< Enable extended RC calibration, enabled by default. */ -} ble_common_opt_extended_rc_cal_t; - -/**@brief Option structure for common options. */ -typedef union { - ble_common_opt_pa_lna_t pa_lna; /**< Parameters for controlling PA and LNA pin toggling. */ - ble_common_opt_conn_evt_ext_t conn_evt_ext; /**< Parameters for enabling extended connection events. */ - ble_common_opt_extended_rc_cal_t extended_rc_cal; /**< Parameters for enabling extended RC calibration. */ -} ble_common_opt_t; - -/**@brief Common BLE Option type, wrapping the module specific options. */ -typedef union { - ble_common_opt_t common_opt; /**< COMMON options, opt_id in @ref BLE_COMMON_OPTS series. */ - ble_gap_opt_t gap_opt; /**< GAP option, opt_id in @ref BLE_GAP_OPTS series. */ - ble_gattc_opt_t gattc_opt; /**< GATTC option, opt_id in @ref BLE_GATTC_OPTS series. */ -} ble_opt_t; - -/**@brief BLE connection configuration type, wrapping the module specific configurations, set with - * @ref sd_ble_cfg_set. - * - * @note Connection configurations don't have to be set. - * In the case that no configurations has been set, or fewer connection configurations has been set than enabled connections, - * the default connection configuration will be automatically added for the remaining connections. - * When creating connections with the default configuration, @ref BLE_CONN_CFG_TAG_DEFAULT should be used in - * place of @ref ble_conn_cfg_t::conn_cfg_tag. - * - * @sa sd_ble_gap_adv_start() - * @sa sd_ble_gap_connect() - * - * @mscs - * @mmsc{@ref BLE_CONN_CFG} - * @endmscs - - */ -typedef struct { - uint8_t conn_cfg_tag; /**< The application chosen tag it can use with the - @ref sd_ble_gap_adv_start() and @ref sd_ble_gap_connect() calls - to select this configuration when creating a connection. - Must be different for all connection configurations added and not @ref BLE_CONN_CFG_TAG_DEFAULT. */ - union { - ble_gap_conn_cfg_t gap_conn_cfg; /**< GAP connection configuration, cfg_id is @ref BLE_CONN_CFG_GAP. */ - ble_gattc_conn_cfg_t gattc_conn_cfg; /**< GATTC connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTC. */ - ble_gatts_conn_cfg_t gatts_conn_cfg; /**< GATTS connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTS. */ - ble_gatt_conn_cfg_t gatt_conn_cfg; /**< GATT connection configuration, cfg_id is @ref BLE_CONN_CFG_GATT. */ - ble_l2cap_conn_cfg_t l2cap_conn_cfg; /**< L2CAP connection configuration, cfg_id is @ref BLE_CONN_CFG_L2CAP. */ - } params; /**< Connection configuration union. */ -} ble_conn_cfg_t; - -/** - * @brief Configuration of Vendor Specific base UUIDs, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_PARAM Too many UUIDs configured. - */ -typedef struct { - uint8_t vs_uuid_count; /**< Number of 128-bit Vendor Specific base UUID bases to allocate memory for. - Default value is @ref BLE_UUID_VS_COUNT_DEFAULT. Maximum value is - @ref BLE_UUID_VS_COUNT_MAX. */ -} ble_common_cfg_vs_uuid_t; - -/**@brief Common BLE Configuration type, wrapping the common configurations. */ -typedef union { - ble_common_cfg_vs_uuid_t vs_uuid_cfg; /**< Vendor Specific base UUID configuration, cfg_id is @ref BLE_COMMON_CFG_VS_UUID. */ -} ble_common_cfg_t; - -/**@brief BLE Configuration type, wrapping the module specific configurations. */ -typedef union { - ble_conn_cfg_t conn_cfg; /**< Connection specific configurations, cfg_id in @ref BLE_CONN_CFGS series. */ - ble_common_cfg_t common_cfg; /**< Global common configurations, cfg_id in @ref BLE_COMMON_CFGS series. */ - ble_gap_cfg_t gap_cfg; /**< Global GAP configurations, cfg_id in @ref BLE_GAP_CFGS series. */ - ble_gatts_cfg_t gatts_cfg; /**< Global GATTS configuration, cfg_id in @ref BLE_GATTS_CFGS series. */ -} ble_cfg_t; - -/** @} */ - -/** @addtogroup BLE_COMMON_FUNCTIONS Functions - * @{ */ - -/**@brief Enable the BLE stack - * - * @param[in, out] p_app_ram_base Pointer to a variable containing the start address of the - * application RAM region (APP_RAM_BASE). On return, this will - * contain the minimum start address of the application RAM region - * required by the SoftDevice for this configuration. - * @warning After this call, the SoftDevice may generate several events. The list of events provided - * below require the application to initiate a SoftDevice API call. The corresponding API call - * is referenced in the event documentation. - * If the application fails to do so, the BLE connection may timeout, or the SoftDevice may stop - * communicating with the peer device. - * - @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST - * - @ref BLE_GAP_EVT_SEC_INFO_REQUEST - * - @ref BLE_GAP_EVT_SEC_REQUEST - * - @ref BLE_GAP_EVT_AUTH_KEY_REQUEST - * - @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST - * - @ref BLE_EVT_USER_MEM_REQUEST - * - @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST - * - * @note The memory requirement for a specific configuration will not increase between SoftDevices - * with the same major version number. - * - * @note At runtime the IC's RAM is split into 2 regions: The SoftDevice RAM region is located - * between 0x20000000 and APP_RAM_BASE-1 and the application's RAM region is located between - * APP_RAM_BASE and the start of the call stack. - * - * @details This call initializes the BLE stack, no BLE related function other than @ref - * sd_ble_cfg_set can be called before this one. - * - * @mscs - * @mmsc{@ref BLE_COMMON_ENABLE} - * @endmscs - * - * @retval ::NRF_SUCCESS The BLE stack has been initialized successfully. - * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized and cannot be reinitialized. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_NO_MEM One or more of the following is true: - * - The amount of memory assigned to the SoftDevice by *p_app_ram_base is not - * large enough to fit this configuration's memory requirement. Check *p_app_ram_base - * and set the start address of the application RAM region accordingly. - * - Dynamic part of the SoftDevice RAM region is larger then 64 kB which - * is currently not supported. - * @retval ::NRF_ERROR_RESOURCES The total number of L2CAP Channels configured using @ref sd_ble_cfg_set is too large. - */ -SVCALL(SD_BLE_ENABLE, uint32_t, sd_ble_enable(uint32_t *p_app_ram_base)); - -/**@brief Add configurations for the BLE stack - * - * @param[in] cfg_id Config ID, see @ref BLE_CONN_CFGS, @ref BLE_COMMON_CFGS, @ref - * BLE_GAP_CFGS or @ref BLE_GATTS_CFGS. - * @param[in] p_cfg Pointer to a ble_cfg_t structure containing the configuration value. - * @param[in] app_ram_base The start address of the application RAM region (APP_RAM_BASE). - * See @ref sd_ble_enable for details about APP_RAM_BASE. - * - * @note The memory requirement for a specific configuration will not increase between SoftDevices - * with the same major version number. - * - * @note If a configuration is set more than once, the last one set is the one that takes effect on - * @ref sd_ble_enable. - * - * @note Any part of the BLE stack that is NOT configured with @ref sd_ble_cfg_set will have default - * configuration. - * - * @note @ref sd_ble_cfg_set may be called at any time when the SoftDevice is enabled (see @ref - * sd_softdevice_enable) while the BLE part of the SoftDevice is not enabled (see @ref - * sd_ble_enable). - * - * @note Error codes for the configurations are described in the configuration structs. - * - * @mscs - * @mmsc{@ref BLE_COMMON_ENABLE} - * @endmscs - * - * @retval ::NRF_SUCCESS The configuration has been added successfully. - * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid cfg_id supplied. - * @retval ::NRF_ERROR_NO_MEM The amount of memory assigned to the SoftDevice by app_ram_base is not - * large enough to fit this configuration's memory requirement. - */ -SVCALL(SD_BLE_CFG_SET, uint32_t, sd_ble_cfg_set(uint32_t cfg_id, ble_cfg_t const *p_cfg, uint32_t app_ram_base)); - -/**@brief Get an event from the pending events queue. - * - * @param[out] p_dest Pointer to buffer to be filled in with an event, or NULL to retrieve the event length. - * This buffer must be aligned to the extend defined by @ref BLE_EVT_PTR_ALIGNMENT. - * The buffer should be interpreted as a @ref ble_evt_t struct. - * @param[in, out] p_len Pointer the length of the buffer, on return it is filled with the event length. - * - * @details This call allows the application to pull a BLE event from the BLE stack. The application is signaled that - * an event is available from the BLE stack by the triggering of the SD_EVT_IRQn interrupt. - * The application is free to choose whether to call this function from thread mode (main context) or directly from the - * Interrupt Service Routine that maps to SD_EVT_IRQn. In any case however, and because the BLE stack runs at a higher - * priority than the application, this function should be called in a loop (until @ref NRF_ERROR_NOT_FOUND is returned) - * every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the BLE stack. Failure to do so - * could potentially leave events in the internal queue without the application being aware of this fact. - * - * Sizing the p_dest buffer is equally important, since the application needs to provide all the memory necessary for the event to - * be copied into application memory. If the buffer provided is not large enough to fit the entire contents of the event, - * @ref NRF_ERROR_DATA_SIZE will be returned and the application can then call again with a larger buffer size. - * The maximum possible event length is defined by @ref BLE_EVT_LEN_MAX. The application may also "peek" the event length - * by providing p_dest as a NULL pointer and inspecting the value of *p_len upon return: - * - * \code - * uint16_t len; - * errcode = sd_ble_evt_get(NULL, &len); - * \endcode - * - * @mscs - * @mmsc{@ref BLE_COMMON_IRQ_EVT_MSC} - * @mmsc{@ref BLE_COMMON_THREAD_EVT_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Event pulled and stored into the supplied buffer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_NOT_FOUND No events ready to be pulled. - * @retval ::NRF_ERROR_DATA_SIZE Event ready but could not fit into the supplied buffer. - */ -SVCALL(SD_BLE_EVT_GET, uint32_t, sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len)); - -/**@brief Add a Vendor Specific base UUID. - * - * @details This call enables the application to add a Vendor Specific base UUID to the BLE stack's table, for later - * use with all other modules and APIs. This then allows the application to use the shorter, 24-bit @ref ble_uuid_t - * format when dealing with both 16-bit and 128-bit UUIDs without having to check for lengths and having split code - * paths. This is accomplished by extending the grouping mechanism that the Bluetooth SIG standard base UUID uses - * for all other 128-bit UUIDs. The type field in the @ref ble_uuid_t structure is an index (relative to - * @ref BLE_UUID_TYPE_VENDOR_BEGIN) to the table populated by multiple calls to this function, and the UUID field - * in the same structure contains the 2 bytes at indexes 12 and 13. The number of possible 128-bit UUIDs available to - * the application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536, - * although restricted to modifying bytes 12 and 13 for each of the entries in the supplied array. - * - * @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by - * the 16-bit uuid field in @ref ble_uuid_t. - * - * @note If a UUID is already present in the BLE stack's internal table, the corresponding index will be returned in - * p_uuid_type along with an @ref NRF_SUCCESS error code. - * - * @param[in] p_vs_uuid Pointer to a 16-octet (128-bit) little endian Vendor Specific base UUID disregarding - * bytes 12 and 13. - * @param[out] p_uuid_type Pointer to a uint8_t where the type field in @ref ble_uuid_t corresponding to this UUID will be - * stored. - * - * @retval ::NRF_SUCCESS Successfully added the Vendor Specific base UUID. - * @retval ::NRF_ERROR_INVALID_ADDR If p_vs_uuid or p_uuid_type is NULL or invalid. - * @retval ::NRF_ERROR_NO_MEM If there are no more free slots for VS UUIDs. - */ -SVCALL(SD_BLE_UUID_VS_ADD, uint32_t, sd_ble_uuid_vs_add(ble_uuid128_t const *p_vs_uuid, uint8_t *p_uuid_type)); - -/**@brief Remove a Vendor Specific base UUID. - * - * @details This call removes a Vendor Specific base UUID. This function allows - * the application to reuse memory allocated for Vendor Specific base UUIDs. - * - * @note Currently this function can only be called with a p_uuid_type set to @ref BLE_UUID_TYPE_UNKNOWN or the last added UUID - * type. - * - * @param[inout] p_uuid_type Pointer to a uint8_t where its value matches the UUID type in @ref ble_uuid_t::type to be removed. - * If the type is set to @ref BLE_UUID_TYPE_UNKNOWN, or the pointer is NULL, the last Vendor Specific - * base UUID will be removed. If the function returns successfully, the UUID type that was removed will - * be written back to @p p_uuid_type. If function returns with a failure, it contains the last type that - * is in use by the ATT Server. - * - * @retval ::NRF_SUCCESS Successfully removed the Vendor Specific base UUID. - * @retval ::NRF_ERROR_INVALID_ADDR If p_uuid_type is invalid. - * @retval ::NRF_ERROR_INVALID_PARAM If p_uuid_type points to a non-valid UUID type. - * @retval ::NRF_ERROR_FORBIDDEN If the Vendor Specific base UUID is in use by the ATT Server. - */ -SVCALL(SD_BLE_UUID_VS_REMOVE, uint32_t, sd_ble_uuid_vs_remove(uint8_t *p_uuid_type)); - -/** @brief Decode little endian raw UUID bytes (16-bit or 128-bit) into a 24 bit @ref ble_uuid_t structure. - * - * @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared - * to the corresponding ones in each entry of the table of Vendor Specific base UUIDs - * to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index - * relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type. - * - * @note If the UUID length supplied is 2, then the type set by this call will always be @ref BLE_UUID_TYPE_BLE. - * - * @param[in] uuid_le_len Length in bytes of the buffer pointed to by p_uuid_le (must be 2 or 16 bytes). - * @param[in] p_uuid_le Pointer pointing to little endian raw UUID bytes. - * @param[out] p_uuid Pointer to a @ref ble_uuid_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Successfully decoded into the @ref ble_uuid_t structure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid UUID length. - * @retval ::NRF_ERROR_NOT_FOUND For a 128-bit UUID, no match in the populated table of UUIDs. - */ -SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uint8_t const *p_uuid_le, ble_uuid_t *p_uuid)); - -/** @brief Encode a @ref ble_uuid_t structure into little endian raw UUID bytes (16-bit or 128-bit). - * - * @note The pointer to the destination buffer p_uuid_le may be NULL, in which case only the validity and size of p_uuid is - * computed. - * - * @param[in] p_uuid Pointer to a @ref ble_uuid_t structure that will be encoded into bytes. - * @param[out] p_uuid_le_len Pointer to a uint8_t that will be filled with the encoded length (2 or 16 bytes). - * @param[out] p_uuid_le Pointer to a buffer where the little endian raw UUID bytes (2 or 16) will be stored. - * - * @retval ::NRF_SUCCESS Successfully encoded into the buffer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid UUID type. - */ -SVCALL(SD_BLE_UUID_ENCODE, uint32_t, sd_ble_uuid_encode(ble_uuid_t const *p_uuid, uint8_t *p_uuid_le_len, uint8_t *p_uuid_le)); - -/**@brief Get Version Information. - * - * @details This call allows the application to get the BLE stack version information. - * - * @param[out] p_version Pointer to a ble_version_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Version information stored successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy (typically doing a locally-initiated disconnection procedure). - */ -SVCALL(SD_BLE_VERSION_GET, uint32_t, sd_ble_version_get(ble_version_t *p_version)); - -/**@brief Provide a user memory block. - * - * @note This call can only be used as a response to a @ref BLE_EVT_USER_MEM_REQUEST event issued to the application. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_block Pointer to a user memory block structure or NULL if memory is managed by the application. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully queued a response to the peer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid user memory block length supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection state or no user memory request pending. - */ -SVCALL(SD_BLE_USER_MEM_REPLY, uint32_t, sd_ble_user_mem_reply(uint16_t conn_handle, ble_user_mem_block_t const *p_block)); - -/**@brief Set a BLE option. - * - * @details This call allows the application to set the value of an option. - * - * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS, @ref BLE_GAP_OPTS, and @ref BLE_GATTC_OPTS. - * @param[in] p_opt Pointer to a @ref ble_opt_t structure containing the option value. - * - * @retval ::NRF_SUCCESS Option set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Unable to set the parameter at this time. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. - */ -SVCALL(SD_BLE_OPT_SET, uint32_t, sd_ble_opt_set(uint32_t opt_id, ble_opt_t const *p_opt)); - -/**@brief Get a BLE option. - * - * @details This call allows the application to retrieve the value of an option. - * - * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS and @ref BLE_GAP_OPTS. - * @param[out] p_opt Pointer to a ble_opt_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Option retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Unable to retrieve the parameter at this time. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. - * @retval ::NRF_ERROR_NOT_SUPPORTED This option is not supported. - * - */ -SVCALL(SD_BLE_OPT_GET, uint32_t, sd_ble_opt_get(uint32_t opt_id, ble_opt_t *p_opt)); - -/** @} */ -#ifdef __cplusplus -} -#endif -#endif /* BLE_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_err.h b/variants/wio-tracker-wm1110/softdevice/ble_err.h deleted file mode 100644 index d20f6d1416..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_err.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @addtogroup nrf_error - @{ - @ingroup BLE_COMMON - @} - - @defgroup ble_err General error codes - @{ - - @brief General error code definitions for the BLE API. - - @ingroup BLE_COMMON -*/ -#ifndef NRF_BLE_ERR_H__ -#define NRF_BLE_ERR_H__ - -#include "nrf_error.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* @defgroup BLE_ERRORS Error Codes - * @{ */ -#define BLE_ERROR_NOT_ENABLED (NRF_ERROR_STK_BASE_NUM + 0x001) /**< @ref sd_ble_enable has not been called. */ -#define BLE_ERROR_INVALID_CONN_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x002) /**< Invalid connection handle. */ -#define BLE_ERROR_INVALID_ATTR_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x003) /**< Invalid attribute handle. */ -#define BLE_ERROR_INVALID_ADV_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x004) /**< Invalid advertising handle. */ -#define BLE_ERROR_INVALID_ROLE (NRF_ERROR_STK_BASE_NUM + 0x005) /**< Invalid role. */ -#define BLE_ERROR_BLOCKED_BY_OTHER_LINKS \ - (NRF_ERROR_STK_BASE_NUM + 0x006) /**< The attempt to change link settings failed due to the scheduling of other links. */ -/** @} */ - -/** @defgroup BLE_ERROR_SUBRANGES Module specific error code subranges - * @brief Assignment of subranges for module specific error codes. - * @note For specific error codes, see ble_.h or ble_error_.h. - * @{ */ -#define NRF_L2CAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x100) /**< L2CAP specific errors. */ -#define NRF_GAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x200) /**< GAP specific errors. */ -#define NRF_GATTC_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x300) /**< GATT client specific errors. */ -#define NRF_GATTS_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x400) /**< GATT server specific errors. */ -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif - -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gap.h b/variants/wio-tracker-wm1110/softdevice/ble_gap.h deleted file mode 100644 index 8ebdfa82b0..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_gap.h +++ /dev/null @@ -1,2895 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GAP Generic Access Profile (GAP) - @{ - @brief Definitions and prototypes for the GAP interface. - */ - -#ifndef BLE_GAP_H__ -#define BLE_GAP_H__ - -#include "ble_err.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup BLE_GAP_ENUMERATIONS Enumerations - * @{ */ - -/**@brief GAP API SVC numbers. - */ -enum BLE_GAP_SVCS { - SD_BLE_GAP_ADDR_SET = BLE_GAP_SVC_BASE, /**< Set own Bluetooth Address. */ - SD_BLE_GAP_ADDR_GET = BLE_GAP_SVC_BASE + 1, /**< Get own Bluetooth Address. */ - SD_BLE_GAP_WHITELIST_SET = BLE_GAP_SVC_BASE + 2, /**< Set active whitelist. */ - SD_BLE_GAP_DEVICE_IDENTITIES_SET = BLE_GAP_SVC_BASE + 3, /**< Set device identity list. */ - SD_BLE_GAP_PRIVACY_SET = BLE_GAP_SVC_BASE + 4, /**< Set Privacy settings*/ - SD_BLE_GAP_PRIVACY_GET = BLE_GAP_SVC_BASE + 5, /**< Get Privacy settings*/ - SD_BLE_GAP_ADV_SET_CONFIGURE = BLE_GAP_SVC_BASE + 6, /**< Configure an advertising set. */ - SD_BLE_GAP_ADV_START = BLE_GAP_SVC_BASE + 7, /**< Start Advertising. */ - SD_BLE_GAP_ADV_STOP = BLE_GAP_SVC_BASE + 8, /**< Stop Advertising. */ - SD_BLE_GAP_CONN_PARAM_UPDATE = BLE_GAP_SVC_BASE + 9, /**< Connection Parameter Update. */ - SD_BLE_GAP_DISCONNECT = BLE_GAP_SVC_BASE + 10, /**< Disconnect. */ - SD_BLE_GAP_TX_POWER_SET = BLE_GAP_SVC_BASE + 11, /**< Set TX Power. */ - SD_BLE_GAP_APPEARANCE_SET = BLE_GAP_SVC_BASE + 12, /**< Set Appearance. */ - SD_BLE_GAP_APPEARANCE_GET = BLE_GAP_SVC_BASE + 13, /**< Get Appearance. */ - SD_BLE_GAP_PPCP_SET = BLE_GAP_SVC_BASE + 14, /**< Set PPCP. */ - SD_BLE_GAP_PPCP_GET = BLE_GAP_SVC_BASE + 15, /**< Get PPCP. */ - SD_BLE_GAP_DEVICE_NAME_SET = BLE_GAP_SVC_BASE + 16, /**< Set Device Name. */ - SD_BLE_GAP_DEVICE_NAME_GET = BLE_GAP_SVC_BASE + 17, /**< Get Device Name. */ - SD_BLE_GAP_AUTHENTICATE = BLE_GAP_SVC_BASE + 18, /**< Initiate Pairing/Bonding. */ - SD_BLE_GAP_SEC_PARAMS_REPLY = BLE_GAP_SVC_BASE + 19, /**< Reply with Security Parameters. */ - SD_BLE_GAP_AUTH_KEY_REPLY = BLE_GAP_SVC_BASE + 20, /**< Reply with an authentication key. */ - SD_BLE_GAP_LESC_DHKEY_REPLY = BLE_GAP_SVC_BASE + 21, /**< Reply with an LE Secure Connections DHKey. */ - SD_BLE_GAP_KEYPRESS_NOTIFY = BLE_GAP_SVC_BASE + 22, /**< Notify of a keypress during an authentication procedure. */ - SD_BLE_GAP_LESC_OOB_DATA_GET = BLE_GAP_SVC_BASE + 23, /**< Get the local LE Secure Connections OOB data. */ - SD_BLE_GAP_LESC_OOB_DATA_SET = BLE_GAP_SVC_BASE + 24, /**< Set the remote LE Secure Connections OOB data. */ - SD_BLE_GAP_ENCRYPT = BLE_GAP_SVC_BASE + 25, /**< Initiate encryption procedure. */ - SD_BLE_GAP_SEC_INFO_REPLY = BLE_GAP_SVC_BASE + 26, /**< Reply with Security Information. */ - SD_BLE_GAP_CONN_SEC_GET = BLE_GAP_SVC_BASE + 27, /**< Obtain connection security level. */ - SD_BLE_GAP_RSSI_START = BLE_GAP_SVC_BASE + 28, /**< Start reporting of changes in RSSI. */ - SD_BLE_GAP_RSSI_STOP = BLE_GAP_SVC_BASE + 29, /**< Stop reporting of changes in RSSI. */ - SD_BLE_GAP_SCAN_START = BLE_GAP_SVC_BASE + 30, /**< Start Scanning. */ - SD_BLE_GAP_SCAN_STOP = BLE_GAP_SVC_BASE + 31, /**< Stop Scanning. */ - SD_BLE_GAP_CONNECT = BLE_GAP_SVC_BASE + 32, /**< Connect. */ - SD_BLE_GAP_CONNECT_CANCEL = BLE_GAP_SVC_BASE + 33, /**< Cancel ongoing connection procedure. */ - SD_BLE_GAP_RSSI_GET = BLE_GAP_SVC_BASE + 34, /**< Get the last RSSI sample. */ - SD_BLE_GAP_PHY_UPDATE = BLE_GAP_SVC_BASE + 35, /**< Initiate or respond to a PHY Update Procedure. */ - SD_BLE_GAP_DATA_LENGTH_UPDATE = BLE_GAP_SVC_BASE + 36, /**< Initiate or respond to a Data Length Update Procedure. */ - SD_BLE_GAP_QOS_CHANNEL_SURVEY_START = BLE_GAP_SVC_BASE + 37, /**< Start Quality of Service (QoS) channel survey module. */ - SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP = BLE_GAP_SVC_BASE + 38, /**< Stop Quality of Service (QoS) channel survey module. */ - SD_BLE_GAP_ADV_ADDR_GET = BLE_GAP_SVC_BASE + 39, /**< Get the Address used on air while Advertising. */ - SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET = BLE_GAP_SVC_BASE + 40, /**< Get the next connection event counter. */ - SD_BLE_GAP_CONN_EVT_TRIGGER_START = BLE_GAP_SVC_BASE + 41, /** Start triggering a given task on connection event start. */ - SD_BLE_GAP_CONN_EVT_TRIGGER_STOP = - BLE_GAP_SVC_BASE + 42, /** Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. */ -}; - -/**@brief GAP Event IDs. - * IDs that uniquely identify an event coming from the stack to the application. - */ -enum BLE_GAP_EVTS { - BLE_GAP_EVT_CONNECTED = - BLE_GAP_EVT_BASE, /**< Connected to peer. \n See @ref ble_gap_evt_connected_t */ - BLE_GAP_EVT_DISCONNECTED = - BLE_GAP_EVT_BASE + 1, /**< Disconnected from peer. \n See @ref ble_gap_evt_disconnected_t. */ - BLE_GAP_EVT_CONN_PARAM_UPDATE = - BLE_GAP_EVT_BASE + 2, /**< Connection Parameters updated. \n See @ref ble_gap_evt_conn_param_update_t. */ - BLE_GAP_EVT_SEC_PARAMS_REQUEST = - BLE_GAP_EVT_BASE + 3, /**< Request to provide security parameters. \n Reply with @ref sd_ble_gap_sec_params_reply. - \n See @ref ble_gap_evt_sec_params_request_t. */ - BLE_GAP_EVT_SEC_INFO_REQUEST = - BLE_GAP_EVT_BASE + 4, /**< Request to provide security information. \n Reply with @ref sd_ble_gap_sec_info_reply. - \n See @ref ble_gap_evt_sec_info_request_t. */ - BLE_GAP_EVT_PASSKEY_DISPLAY = - BLE_GAP_EVT_BASE + 5, /**< Request to display a passkey to the user. \n In LESC Numeric Comparison, reply with @ref - sd_ble_gap_auth_key_reply. \n See @ref ble_gap_evt_passkey_display_t. */ - BLE_GAP_EVT_KEY_PRESSED = - BLE_GAP_EVT_BASE + 6, /**< Notification of a keypress on the remote device.\n See @ref ble_gap_evt_key_pressed_t */ - BLE_GAP_EVT_AUTH_KEY_REQUEST = - BLE_GAP_EVT_BASE + 7, /**< Request to provide an authentication key. \n Reply with @ref sd_ble_gap_auth_key_reply. - \n See @ref ble_gap_evt_auth_key_request_t. */ - BLE_GAP_EVT_LESC_DHKEY_REQUEST = - BLE_GAP_EVT_BASE + 8, /**< Request to calculate an LE Secure Connections DHKey. \n Reply with @ref - sd_ble_gap_lesc_dhkey_reply. \n See @ref ble_gap_evt_lesc_dhkey_request_t */ - BLE_GAP_EVT_AUTH_STATUS = - BLE_GAP_EVT_BASE + 9, /**< Authentication procedure completed with status. \n See @ref ble_gap_evt_auth_status_t. */ - BLE_GAP_EVT_CONN_SEC_UPDATE = - BLE_GAP_EVT_BASE + 10, /**< Connection security updated. \n See @ref ble_gap_evt_conn_sec_update_t. */ - BLE_GAP_EVT_TIMEOUT = - BLE_GAP_EVT_BASE + 11, /**< Timeout expired. \n See @ref ble_gap_evt_timeout_t. */ - BLE_GAP_EVT_RSSI_CHANGED = - BLE_GAP_EVT_BASE + 12, /**< RSSI report. \n See @ref ble_gap_evt_rssi_changed_t. */ - BLE_GAP_EVT_ADV_REPORT = - BLE_GAP_EVT_BASE + 13, /**< Advertising report. \n See @ref ble_gap_evt_adv_report_t. */ - BLE_GAP_EVT_SEC_REQUEST = - BLE_GAP_EVT_BASE + 14, /**< Security Request. \n Reply with @ref sd_ble_gap_authenticate -\n or with @ref sd_ble_gap_encrypt if required security information is available -. \n See @ref ble_gap_evt_sec_request_t. */ - BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 15, /**< Connection Parameter Update Request. \n Reply with @ref - sd_ble_gap_conn_param_update. \n See @ref ble_gap_evt_conn_param_update_request_t. */ - BLE_GAP_EVT_SCAN_REQ_REPORT = - BLE_GAP_EVT_BASE + 16, /**< Scan request report. \n See @ref ble_gap_evt_scan_req_report_t. */ - BLE_GAP_EVT_PHY_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 17, /**< PHY Update Request. \n Reply with @ref sd_ble_gap_phy_update. \n - See @ref ble_gap_evt_phy_update_request_t. */ - BLE_GAP_EVT_PHY_UPDATE = - BLE_GAP_EVT_BASE + 18, /**< PHY Update Procedure is complete. \n See @ref ble_gap_evt_phy_update_t. */ - BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 19, /**< Data Length Update Request. \n Reply with @ref - sd_ble_gap_data_length_update. \n See @ref ble_gap_evt_data_length_update_request_t. */ - BLE_GAP_EVT_DATA_LENGTH_UPDATE = - BLE_GAP_EVT_BASE + - 20, /**< LL Data Channel PDU payload length updated. \n See @ref ble_gap_evt_data_length_update_t. */ - BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT = - BLE_GAP_EVT_BASE + - 21, /**< Channel survey report. \n See @ref ble_gap_evt_qos_channel_survey_report_t. */ - BLE_GAP_EVT_ADV_SET_TERMINATED = - BLE_GAP_EVT_BASE + - 22, /**< Advertising set terminated. \n See @ref ble_gap_evt_adv_set_terminated_t. */ -}; - -/**@brief GAP Option IDs. - * IDs that uniquely identify a GAP option. - */ -enum BLE_GAP_OPTS { - BLE_GAP_OPT_CH_MAP = BLE_GAP_OPT_BASE, /**< Channel Map. @ref ble_gap_opt_ch_map_t */ - BLE_GAP_OPT_LOCAL_CONN_LATENCY = BLE_GAP_OPT_BASE + 1, /**< Local connection latency. @ref ble_gap_opt_local_conn_latency_t */ - BLE_GAP_OPT_PASSKEY = BLE_GAP_OPT_BASE + 2, /**< Set passkey. @ref ble_gap_opt_passkey_t */ - BLE_GAP_OPT_COMPAT_MODE_1 = BLE_GAP_OPT_BASE + 3, /**< Compatibility mode. @ref ble_gap_opt_compat_mode_1_t */ - BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT = - BLE_GAP_OPT_BASE + 4, /**< Set Authenticated payload timeout. @ref ble_gap_opt_auth_payload_timeout_t */ - BLE_GAP_OPT_SLAVE_LATENCY_DISABLE = - BLE_GAP_OPT_BASE + 5, /**< Disable slave latency. @ref ble_gap_opt_slave_latency_disable_t */ -}; - -/**@brief GAP Configuration IDs. - * - * IDs that uniquely identify a GAP configuration. - */ -enum BLE_GAP_CFGS { - BLE_GAP_CFG_ROLE_COUNT = BLE_GAP_CFG_BASE, /**< Role count configuration. */ - BLE_GAP_CFG_DEVICE_NAME = BLE_GAP_CFG_BASE + 1, /**< Device name configuration. */ - BLE_GAP_CFG_PPCP_INCL_CONFIG = BLE_GAP_CFG_BASE + 2, /**< Peripheral Preferred Connection Parameters characteristic - inclusion configuration. */ - BLE_GAP_CFG_CAR_INCL_CONFIG = BLE_GAP_CFG_BASE + 3, /**< Central Address Resolution characteristic - inclusion configuration. */ -}; - -/**@brief GAP TX Power roles. - */ -enum BLE_GAP_TX_POWER_ROLES { - BLE_GAP_TX_POWER_ROLE_ADV = 1, /**< Advertiser role. */ - BLE_GAP_TX_POWER_ROLE_SCAN_INIT = 2, /**< Scanner and initiator role. */ - BLE_GAP_TX_POWER_ROLE_CONN = 3, /**< Connection role. */ -}; - -/** @} */ - -/**@addtogroup BLE_GAP_DEFINES Defines - * @{ */ - -/**@defgroup BLE_ERRORS_GAP SVC return values specific to GAP - * @{ */ -#define BLE_ERROR_GAP_UUID_LIST_MISMATCH \ - (NRF_GAP_ERR_BASE + 0x000) /**< UUID list does not contain an integral number of UUIDs. */ -#define BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST \ - (NRF_GAP_ERR_BASE + 0x001) /**< Use of Whitelist not permitted with discoverable advertising. */ -#define BLE_ERROR_GAP_INVALID_BLE_ADDR \ - (NRF_GAP_ERR_BASE + 0x002) /**< The upper two bits of the address do not correspond to the specified address type. */ -#define BLE_ERROR_GAP_WHITELIST_IN_USE \ - (NRF_GAP_ERR_BASE + 0x003) /**< Attempt to modify the whitelist while already in use by another operation. */ -#define BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE \ - (NRF_GAP_ERR_BASE + 0x004) /**< Attempt to modify the device identity list while already in use by another operation. */ -#define BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE \ - (NRF_GAP_ERR_BASE + 0x005) /**< The device identity list contains entries with duplicate identity addresses. */ -/**@} */ - -/**@defgroup BLE_GAP_ROLES GAP Roles - * @{ */ -#define BLE_GAP_ROLE_INVALID 0x0 /**< Invalid Role. */ -#define BLE_GAP_ROLE_PERIPH 0x1 /**< Peripheral Role. */ -#define BLE_GAP_ROLE_CENTRAL 0x2 /**< Central Role. */ -/**@} */ - -/**@defgroup BLE_GAP_TIMEOUT_SOURCES GAP Timeout sources - * @{ */ -#define BLE_GAP_TIMEOUT_SRC_SCAN 0x01 /**< Scanning timeout. */ -#define BLE_GAP_TIMEOUT_SRC_CONN 0x02 /**< Connection timeout. */ -#define BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD 0x03 /**< Authenticated payload timeout. */ -/**@} */ - -/**@defgroup BLE_GAP_ADDR_TYPES GAP Address types - * @{ */ -#define BLE_GAP_ADDR_TYPE_PUBLIC 0x00 /**< Public (identity) address.*/ -#define BLE_GAP_ADDR_TYPE_RANDOM_STATIC 0x01 /**< Random static (identity) address. */ -#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE 0x02 /**< Random private resolvable address. */ -#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE 0x03 /**< Random private non-resolvable address. */ -#define BLE_GAP_ADDR_TYPE_ANONYMOUS \ - 0x7F /**< An advertiser may advertise without its address. \ - This type of advertising is called anonymous. */ -/**@} */ - -/**@brief The default interval in seconds at which a private address is refreshed. */ -#define BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S (900) /* 15 minutes. */ -/**@brief The maximum interval in seconds at which a private address can be refreshed. */ -#define BLE_GAP_MAX_PRIVATE_ADDR_CYCLE_INTERVAL_S (41400) /* 11 hours 30 minutes. */ - -/** @brief BLE address length. */ -#define BLE_GAP_ADDR_LEN (6) - -/**@defgroup BLE_GAP_PRIVACY_MODES Privacy modes - * @{ */ -#define BLE_GAP_PRIVACY_MODE_OFF 0x00 /**< Device will send and accept its identity address for its own address. */ -#define BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY 0x01 /**< Device will send and accept only private addresses for its own address. */ -#define BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY \ - 0x02 /**< Device will send and accept only private addresses for its own address, \ - and will not accept a peer using identity address as sender address when \ - the peer IRK is exchanged, non-zero and added to the identity list. */ -/**@} */ - -/** @brief Invalid power level. */ -#define BLE_GAP_POWER_LEVEL_INVALID 127 - -/** @brief Advertising set handle not set. */ -#define BLE_GAP_ADV_SET_HANDLE_NOT_SET (0xFF) - -/** @brief The default number of advertising sets. */ -#define BLE_GAP_ADV_SET_COUNT_DEFAULT (1) - -/** @brief The maximum number of advertising sets supported by this SoftDevice. */ -#define BLE_GAP_ADV_SET_COUNT_MAX (1) - -/**@defgroup BLE_GAP_ADV_SET_DATA_SIZES Advertising data sizes. - * @{ */ -#define BLE_GAP_ADV_SET_DATA_SIZE_MAX \ - (31) /**< Maximum data length for an advertising set. \ - If more advertising data is required, use extended advertising instead. */ -#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED \ - (255) /**< Maximum supported data length for an extended advertising set. */ - -#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED \ - (238) /**< Maximum supported data length for an extended connectable advertising set. */ -/**@}. */ - -/** @brief Set ID not available in advertising report. */ -#define BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE 0xFF - -/**@defgroup BLE_GAP_EVT_ADV_SET_TERMINATED_REASON GAP Advertising Set Terminated reasons - * @{ */ -#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT 0x01 /**< Timeout value reached. */ -#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED 0x02 /**< @ref ble_gap_adv_params_t::max_adv_evts was reached. */ -/**@} */ - -/**@defgroup BLE_GAP_AD_TYPE_DEFINITIONS GAP Advertising and Scan Response Data format - * @note Found at https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm - * @{ */ -#define BLE_GAP_AD_TYPE_FLAGS 0x01 /**< Flags for discoverability. */ -#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 /**< Partial list of 16 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 /**< Complete list of 16 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 /**< Partial list of 32 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 /**< Complete list of 32 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 /**< Partial list of 128 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 /**< Complete list of 128 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 /**< Short local device name. */ -#define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 /**< Complete local device name. */ -#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A /**< Transmit power level. */ -#define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D /**< Class of device. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E /**< Simple Pairing Hash C. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F /**< Simple Pairing Randomizer R. */ -#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 /**< Security Manager TK Value. */ -#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 /**< Security Manager Out Of Band Flags. */ -#define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 /**< Slave Connection Interval Range. */ -#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 /**< List of 16-bit Service Solicitation UUIDs. */ -#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 /**< List of 128-bit Service Solicitation UUIDs. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 /**< Service Data - 16-bit UUID. */ -#define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 /**< Public Target Address. */ -#define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 /**< Random Target Address. */ -#define BLE_GAP_AD_TYPE_APPEARANCE 0x19 /**< Appearance. */ -#define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A /**< Advertising Interval. */ -#define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B /**< LE Bluetooth Device Address. */ -#define BLE_GAP_AD_TYPE_LE_ROLE 0x1C /**< LE Role. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D /**< Simple Pairing Hash C-256. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E /**< Simple Pairing Randomizer R-256. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 /**< Service Data - 32-bit UUID. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 /**< Service Data - 128-bit UUID. */ -#define BLE_GAP_AD_TYPE_LESC_CONFIRMATION_VALUE 0x22 /**< LE Secure Connections Confirmation Value */ -#define BLE_GAP_AD_TYPE_LESC_RANDOM_VALUE 0x23 /**< LE Secure Connections Random Value */ -#define BLE_GAP_AD_TYPE_URI 0x24 /**< URI */ -#define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D /**< 3D Information Data. */ -#define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF /**< Manufacturer Specific Data. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_FLAGS GAP Advertisement Flags - * @{ */ -#define BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE (0x01) /**< LE Limited Discoverable Mode. */ -#define BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) /**< LE General Discoverable Mode. */ -#define BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) /**< BR/EDR not supported. */ -#define BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER (0x08) /**< Simultaneous LE and BR/EDR, Controller. */ -#define BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST (0x10) /**< Simultaneous LE and BR/EDR, Host. */ -#define BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE \ - (BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE | \ - BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE Limited Discoverable Mode, BR/EDR not supported. */ -#define BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE \ - (BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | \ - BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE General Discoverable Mode, BR/EDR not supported. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_INTERVALS GAP Advertising interval max and min - * @{ */ -#define BLE_GAP_ADV_INTERVAL_MIN 0x000020 /**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */ -#define BLE_GAP_ADV_INTERVAL_MAX 0x004000 /**< Maximum Advertising interval in 625 us units, i.e. 10.24 s. */ - /**@} */ - -/**@defgroup BLE_GAP_SCAN_INTERVALS GAP Scan interval max and min - * @{ */ -#define BLE_GAP_SCAN_INTERVAL_MIN 0x0004 /**< Minimum Scan interval in 625 us units, i.e. 2.5 ms. */ -#define BLE_GAP_SCAN_INTERVAL_MAX 0xFFFF /**< Maximum Scan interval in 625 us units, i.e. 40,959.375 s. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_WINDOW GAP Scan window max and min - * @{ */ -#define BLE_GAP_SCAN_WINDOW_MIN 0x0004 /**< Minimum Scan window in 625 us units, i.e. 2.5 ms. */ -#define BLE_GAP_SCAN_WINDOW_MAX 0xFFFF /**< Maximum Scan window in 625 us units, i.e. 40,959.375 s. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_TIMEOUT GAP Scan timeout max and min - * @{ */ -#define BLE_GAP_SCAN_TIMEOUT_MIN 0x0001 /**< Minimum Scan timeout in 10 ms units, i.e 10 ms. */ -#define BLE_GAP_SCAN_TIMEOUT_UNLIMITED 0x0000 /**< Continue to scan forever. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_BUFFER_SIZE GAP Minimum scanner buffer size - * - * Scan buffers are used for storing advertising data received from an advertiser. - * If ble_gap_scan_params_t::extended is set to 0, @ref BLE_GAP_SCAN_BUFFER_MIN is the minimum scan buffer length. - * else the minimum scan buffer size is @ref BLE_GAP_SCAN_BUFFER_EXTENDED_MIN. - * @{ */ -#define BLE_GAP_SCAN_BUFFER_MIN \ - (31) /**< Minimum data length for an \ - advertising set. */ -#define BLE_GAP_SCAN_BUFFER_MAX \ - (31) /**< Maximum data length for an \ - advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MIN \ - (255) /**< Minimum data length for an \ - extended advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX \ - (1650) /**< Maximum data length for an \ - extended advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED \ - (255) /**< Maximum supported data length for \ - an extended advertising set. */ -/** @} */ - -/**@defgroup BLE_GAP_ADV_TYPES GAP Advertising types - * - * Advertising types defined in Bluetooth Core Specification v5.0, Vol 6, Part B, Section 4.4.2. - * - * The maximum advertising data length is defined by @ref BLE_GAP_ADV_SET_DATA_SIZE_MAX. - * The maximum supported data length for an extended advertiser is defined by - * @ref BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED - * Note that some of the advertising types do not support advertising data. Non-scannable types do not support - * scan response data. - * - * @{ */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x01 /**< Connectable and scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE \ - 0x02 /**< Connectable non-scannable directed advertising \ - events. Advertising interval is less that 3.75 ms. \ - Use this type for fast reconnections. \ - @note Advertising data is not supported. */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x03 /**< Connectable non-scannable directed advertising \ - events. \ - @note Advertising data is not supported. */ -#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x04 /**< Non-connectable scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x05 /**< Non-connectable non-scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x06 /**< Connectable non-scannable undirected advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x07 /**< Connectable non-scannable directed advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x08 /**< Non-connectable scannable undirected advertising \ - events using extended advertising PDUs. \ - @note Only scan response data is supported. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED \ - 0x09 /**< Non-connectable scannable directed advertising \ - events using extended advertising PDUs. \ - @note Only scan response data is supported. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x0A /**< Non-connectable non-scannable undirected advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x0B /**< Non-connectable non-scannable directed advertising \ - events using extended advertising PDUs. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_FILTER_POLICIES GAP Advertising filter policies - * @{ */ -#define BLE_GAP_ADV_FP_ANY 0x00 /**< Allow scan requests and connect requests from any device. */ -#define BLE_GAP_ADV_FP_FILTER_SCANREQ 0x01 /**< Filter scan requests with whitelist. */ -#define BLE_GAP_ADV_FP_FILTER_CONNREQ 0x02 /**< Filter connect requests with whitelist. */ -#define BLE_GAP_ADV_FP_FILTER_BOTH 0x03 /**< Filter both scan and connect requests with whitelist. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_DATA_STATUS GAP Advertising data status - * @{ */ -#define BLE_GAP_ADV_DATA_STATUS_COMPLETE 0x00 /**< All data in the advertising event have been received. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA \ - 0x01 /**< More data to be received. \ - @note This value will only be used if \ - @ref ble_gap_scan_params_t::report_incomplete_evts and \ - @ref ble_gap_adv_report_type_t::extended_pdu are set to true. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED \ - 0x02 /**< Incomplete data. Buffer size insufficient to receive more. \ - @note This value will only be used if \ - @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MISSED \ - 0x03 /**< Failed to receive the remaining data. \ - @note This value will only be used if \ - @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ -/**@} */ - -/**@defgroup BLE_GAP_SCAN_FILTER_POLICIES GAP Scanner filter policies - * @{ */ -#define BLE_GAP_SCAN_FP_ACCEPT_ALL \ - 0x00 /**< Accept all advertising packets except directed advertising packets \ - not addressed to this device. */ -#define BLE_GAP_SCAN_FP_WHITELIST \ - 0x01 /**< Accept advertising packets from devices in the whitelist except directed \ - packets not addressed to this device. */ -#define BLE_GAP_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED \ - 0x02 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL. \ - In addition, accept directed advertising packets, where the advertiser's \ - address is a resolvable private address that cannot be resolved. */ -#define BLE_GAP_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED \ - 0x03 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST. \ - In addition, accept directed advertising packets, where the advertiser's \ - address is a resolvable private address that cannot be resolved. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_TIMEOUT_VALUES GAP Advertising timeout values in 10 ms units - * @{ */ -#define BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX \ - (128) /**< Maximum high duty advertising time in 10 ms units. Corresponds to 1.28 s. \ - */ -#define BLE_GAP_ADV_TIMEOUT_LIMITED_MAX \ - (18000) /**< Maximum advertising time in 10 ms units corresponding to TGAP(lim_adv_timeout) = 180 s in limited discoverable \ - mode. */ -#define BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED \ - (0) /**< Unlimited advertising in general discoverable mode. \ - For high duty cycle advertising, this corresponds to @ref BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX. */ -/**@} */ - -/**@defgroup BLE_GAP_DISC_MODES GAP Discovery modes - * @{ */ -#define BLE_GAP_DISC_MODE_NOT_DISCOVERABLE 0x00 /**< Not discoverable discovery Mode. */ -#define BLE_GAP_DISC_MODE_LIMITED 0x01 /**< Limited Discovery Mode. */ -#define BLE_GAP_DISC_MODE_GENERAL 0x02 /**< General Discovery Mode. */ -/**@} */ - -/**@defgroup BLE_GAP_IO_CAPS GAP IO Capabilities - * @{ */ -#define BLE_GAP_IO_CAPS_DISPLAY_ONLY 0x00 /**< Display Only. */ -#define BLE_GAP_IO_CAPS_DISPLAY_YESNO 0x01 /**< Display and Yes/No entry. */ -#define BLE_GAP_IO_CAPS_KEYBOARD_ONLY 0x02 /**< Keyboard Only. */ -#define BLE_GAP_IO_CAPS_NONE 0x03 /**< No I/O capabilities. */ -#define BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY 0x04 /**< Keyboard and Display. */ -/**@} */ - -/**@defgroup BLE_GAP_AUTH_KEY_TYPES GAP Authentication Key Types - * @{ */ -#define BLE_GAP_AUTH_KEY_TYPE_NONE 0x00 /**< No key (may be used to reject). */ -#define BLE_GAP_AUTH_KEY_TYPE_PASSKEY 0x01 /**< 6-digit Passkey. */ -#define BLE_GAP_AUTH_KEY_TYPE_OOB 0x02 /**< Out Of Band data. */ -/**@} */ - -/**@defgroup BLE_GAP_KP_NOT_TYPES GAP Keypress Notification Types - * @{ */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_START 0x00 /**< Passkey entry started. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_IN 0x01 /**< Passkey digit entered. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_OUT 0x02 /**< Passkey digit erased. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_CLEAR 0x03 /**< Passkey cleared. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_END 0x04 /**< Passkey entry completed. */ -/**@} */ - -/**@defgroup BLE_GAP_SEC_STATUS GAP Security status - * @{ */ -#define BLE_GAP_SEC_STATUS_SUCCESS 0x00 /**< Procedure completed with success. */ -#define BLE_GAP_SEC_STATUS_TIMEOUT 0x01 /**< Procedure timed out. */ -#define BLE_GAP_SEC_STATUS_PDU_INVALID 0x02 /**< Invalid PDU received. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE1_BEGIN 0x03 /**< Reserved for Future Use range #1 begin. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE1_END 0x80 /**< Reserved for Future Use range #1 end. */ -#define BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED 0x81 /**< Passkey entry failed (user canceled or other). */ -#define BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE 0x82 /**< Out of Band Key not available. */ -#define BLE_GAP_SEC_STATUS_AUTH_REQ 0x83 /**< Authentication requirements not met. */ -#define BLE_GAP_SEC_STATUS_CONFIRM_VALUE 0x84 /**< Confirm value failed. */ -#define BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP 0x85 /**< Pairing not supported. */ -#define BLE_GAP_SEC_STATUS_ENC_KEY_SIZE 0x86 /**< Encryption key size. */ -#define BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED 0x87 /**< Unsupported SMP command. */ -#define BLE_GAP_SEC_STATUS_UNSPECIFIED 0x88 /**< Unspecified reason. */ -#define BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS 0x89 /**< Too little time elapsed since last attempt. */ -#define BLE_GAP_SEC_STATUS_INVALID_PARAMS 0x8A /**< Invalid parameters. */ -#define BLE_GAP_SEC_STATUS_DHKEY_FAILURE 0x8B /**< DHKey check failure. */ -#define BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE 0x8C /**< Numeric Comparison failure. */ -#define BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG 0x8D /**< BR/EDR pairing in progress. */ -#define BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED 0x8E /**< BR/EDR Link Key cannot be used for LE keys. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE2_BEGIN 0x8F /**< Reserved for Future Use range #2 begin. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE2_END 0xFF /**< Reserved for Future Use range #2 end. */ -/**@} */ - -/**@defgroup BLE_GAP_SEC_STATUS_SOURCES GAP Security status sources - * @{ */ -#define BLE_GAP_SEC_STATUS_SOURCE_LOCAL 0x00 /**< Local failure. */ -#define BLE_GAP_SEC_STATUS_SOURCE_REMOTE 0x01 /**< Remote failure. */ -/**@} */ - -/**@defgroup BLE_GAP_CP_LIMITS GAP Connection Parameters Limits - * @{ */ -#define BLE_GAP_CP_MIN_CONN_INTVL_NONE 0xFFFF /**< No new minimum connection interval specified in connect parameters. */ -#define BLE_GAP_CP_MIN_CONN_INTVL_MIN \ - 0x0006 /**< Lowest minimum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ -#define BLE_GAP_CP_MIN_CONN_INTVL_MAX \ - 0x0C80 /**< Highest minimum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ - */ -#define BLE_GAP_CP_MAX_CONN_INTVL_NONE 0xFFFF /**< No new maximum connection interval specified in connect parameters. */ -#define BLE_GAP_CP_MAX_CONN_INTVL_MIN \ - 0x0006 /**< Lowest maximum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ -#define BLE_GAP_CP_MAX_CONN_INTVL_MAX \ - 0x0C80 /**< Highest maximum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ - */ -#define BLE_GAP_CP_SLAVE_LATENCY_MAX 0x01F3 /**< Highest slave latency permitted, in connection events. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_NONE 0xFFFF /**< No new supervision timeout specified in connect parameters. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN 0x000A /**< Lowest supervision timeout permitted, in units of 10 ms, i.e. 100 ms. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX 0x0C80 /**< Highest supervision timeout permitted, in units of 10 ms, i.e. 32 s. */ -/**@} */ - -/**@defgroup BLE_GAP_DEVNAME GAP device name defines. - * @{ */ -#define BLE_GAP_DEVNAME_DEFAULT "nRF5x" /**< Default device name value. */ -#define BLE_GAP_DEVNAME_DEFAULT_LEN 31 /**< Default number of octets in device name. */ -#define BLE_GAP_DEVNAME_MAX_LEN 248 /**< Maximum number of octets in device name. */ -/**@} */ - -/**@brief Disable RSSI events for connections */ -#define BLE_GAP_RSSI_THRESHOLD_INVALID 0xFF - -/**@defgroup BLE_GAP_PHYS GAP PHYs - * @{ */ -#define BLE_GAP_PHY_AUTO 0x00 /**< Automatic PHY selection. Refer @ref sd_ble_gap_phy_update for more information.*/ -#define BLE_GAP_PHY_1MBPS 0x01 /**< 1 Mbps PHY. */ -#define BLE_GAP_PHY_2MBPS 0x02 /**< 2 Mbps PHY. */ -#define BLE_GAP_PHY_CODED 0x04 /**< Coded PHY. */ -#define BLE_GAP_PHY_NOT_SET 0xFF /**< PHY is not configured. */ - -/**@brief Supported PHYs in connections, for scanning, and for advertising. */ -#define BLE_GAP_PHYS_SUPPORTED (BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_CODED) /**< All PHYs are supported. */ - -/**@} */ - -/**@defgroup BLE_GAP_CONN_SEC_MODE_SET_MACROS GAP attribute security requirement setters - * - * See @ref ble_gap_conn_sec_mode_t. - * @{ */ -/**@brief Set sec_mode pointed to by ptr to have no access rights.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(ptr) \ - do { \ - (ptr)->sm = 0; \ - (ptr)->lv = 0; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require no protection, open link.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_OPEN(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 1; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require encryption, but no MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 2; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require encryption and MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 3; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require LESC encryption and MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 4; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require signing or encryption, no MITM protection needed.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(ptr) \ - do { \ - (ptr)->sm = 2; \ - (ptr)->lv = 1; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require signing or encryption with MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 2; \ - (ptr)->lv = 2; \ - } while (0) -/**@} */ - -/**@brief GAP Security Random Number Length. */ -#define BLE_GAP_SEC_RAND_LEN 8 - -/**@brief GAP Security Key Length. */ -#define BLE_GAP_SEC_KEY_LEN 16 - -/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key Length. */ -#define BLE_GAP_LESC_P256_PK_LEN 64 - -/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman DHKey Length. */ -#define BLE_GAP_LESC_DHKEY_LEN 32 - -/**@brief GAP Passkey Length. */ -#define BLE_GAP_PASSKEY_LEN 6 - -/**@brief Maximum amount of addresses in the whitelist. */ -#define BLE_GAP_WHITELIST_ADDR_MAX_COUNT (8) - -/**@brief Maximum amount of identities in the device identities list. */ -#define BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT (8) - -/**@brief Default connection count for a configuration. */ -#define BLE_GAP_CONN_COUNT_DEFAULT (1) - -/**@defgroup BLE_GAP_EVENT_LENGTH GAP event length defines. - * @{ */ -#define BLE_GAP_EVENT_LENGTH_MIN (2) /**< Minimum event length, in 1.25 ms units. */ -#define BLE_GAP_EVENT_LENGTH_CODED_PHY_MIN (6) /**< The shortest event length in 1.25 ms units supporting LE Coded PHY. */ -#define BLE_GAP_EVENT_LENGTH_DEFAULT (3) /**< Default event length, in 1.25 ms units. */ -/**@} */ - -/**@defgroup BLE_GAP_ROLE_COUNT GAP concurrent connection count defines. - * @{ */ -#define BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT (1) /**< Default maximum number of connections concurrently acting as peripherals. */ -#define BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT (3) /**< Default maximum number of connections concurrently acting as centrals. */ -#define BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT \ - (1) /**< Default number of SMP instances shared between all connections acting as centrals. */ -#define BLE_GAP_ROLE_COUNT_COMBINED_MAX \ - (20) /**< Maximum supported number of concurrent connections in the peripheral and central roles combined. */ - -/**@} */ - -/**@brief Automatic data length parameter. */ -#define BLE_GAP_DATA_LENGTH_AUTO 0 - -/**@defgroup BLE_GAP_AUTH_PAYLOAD_TIMEOUT Authenticated payload timeout defines. - * @{ */ -#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX (48000) /**< Maximum authenticated payload timeout in 10 ms units, i.e. 8 minutes. */ -#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MIN (1) /**< Minimum authenticated payload timeout in 10 ms units, i.e. 10 ms. */ -/**@} */ - -/**@defgroup GAP_SEC_MODES GAP Security Modes - * @{ */ -#define BLE_GAP_SEC_MODE 0x00 /**< No key (may be used to reject). */ -/**@} */ - -/**@brief The total number of channels in Bluetooth Low Energy. */ -#define BLE_GAP_CHANNEL_COUNT (40) - -/**@defgroup BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS Quality of Service (QoS) Channel survey interval defines - * @{ */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS (0) /**< Continuous channel survey. */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MIN_US (7500) /**< Minimum channel survey interval in microseconds (7.5 ms). */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MAX_US (4000000) /**< Maximum channel survey interval in microseconds (4 s). */ - /**@} */ - -/** @} */ - -/** @defgroup BLE_GAP_CHAR_INCL_CONFIG GAP Characteristic inclusion configurations - * @{ - */ -#define BLE_GAP_CHAR_INCL_CONFIG_INCLUDE (0) /**< Include the characteristic in the Attribute Table */ -#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITH_SPACE \ - (1) /**< Do not include the characteristic in the Attribute table. \ - The SoftDevice will reserve the attribute handles \ - which are otherwise used for this characteristic. \ - By reserving the attribute handles it will be possible \ - to upgrade the SoftDevice without changing handle of the \ - Service Changed characteristic. */ -#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITHOUT_SPACE \ - (2) /**< Do not include the characteristic in the Attribute table. \ - The SoftDevice will not reserve the attribute handles \ - which are otherwise used for this characteristic. */ -/**@} */ - -/** @defgroup BLE_GAP_CHAR_INCL_CONFIG_DEFAULTS Characteristic inclusion default values - * @{ */ -#define BLE_GAP_PPCP_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ -#define BLE_GAP_CAR_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ -/**@} */ - -/** @defgroup BLE_GAP_SLAVE_LATENCY Slave latency configuration options - * @{ */ -#define BLE_GAP_SLAVE_LATENCY_ENABLE \ - (0) /**< Slave latency is enabled. When slave latency is enabled, \ - the slave will wake up every time it has data to send, \ - and/or every slave latency number of connection events. */ -#define BLE_GAP_SLAVE_LATENCY_DISABLE \ - (1) /**< Disable slave latency. The slave will wake up every connection event \ - regardless of the requested slave latency. \ - This option consumes the most power. */ -#define BLE_GAP_SLAVE_LATENCY_WAIT_FOR_ACK \ - (2) /**< The slave will wake up every connection event if it has not received \ - an ACK from the master for at least slave latency events. This \ - configuration may increase the power consumption in environments \ - with a lot of radio activity. */ -/**@} */ - -/**@addtogroup BLE_GAP_STRUCTURES Structures - * @{ */ - -/**@brief Advertising event properties. */ -typedef struct { - uint8_t type; /**< Advertising type. See @ref BLE_GAP_ADV_TYPES. */ - uint8_t anonymous : 1; /**< Omit advertiser's address from all PDUs. - @note Anonymous advertising is only available for - @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED and - @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED. */ - uint8_t include_tx_power : 1; /**< This feature is not supported on this SoftDevice. */ -} ble_gap_adv_properties_t; - -/**@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 Advertising Auxiliary Pointer. */ -typedef struct { - uint16_t aux_offset; /**< Time offset from the beginning of advertising packet to the auxiliary packet in 100 us units. */ - uint8_t aux_phy; /**< Indicates the PHY on which the auxiliary advertising packet is sent. See @ref BLE_GAP_PHYS. */ -} ble_gap_aux_pointer_t; - -/**@brief Bluetooth Low Energy address. */ -typedef struct { - uint8_t - addr_id_peer : 1; /**< Only valid for peer addresses. - This bit is set by the SoftDevice to indicate whether the address has been resolved from - a Resolvable Private Address (when the peer is using privacy). - If set to 1, @ref addr and @ref addr_type refer to the identity address of the resolved address. - - This bit is ignored when a variable of type @ref ble_gap_addr_t is used as input to API functions. - */ - uint8_t addr_type : 7; /**< See @ref BLE_GAP_ADDR_TYPES. */ - uint8_t addr[BLE_GAP_ADDR_LEN]; /**< 48-bit address, LSB format. - @ref addr is not used if @ref addr_type is @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. */ -} ble_gap_addr_t; - -/**@brief GAP connection parameters. - * - * @note When ble_conn_params_t is received in an event, both min_conn_interval and - * max_conn_interval will be equal to the connection interval set by the central. - * - * @note If both conn_sup_timeout and max_conn_interval are specified, then the following constraint applies: - * conn_sup_timeout * 4 > (1 + slave_latency) * max_conn_interval - * that corresponds to the following Bluetooth Spec requirement: - * The Supervision_Timeout in milliseconds shall be larger than - * (1 + Conn_Latency) * Conn_Interval_Max * 2, where Conn_Interval_Max is given in milliseconds. - */ -typedef struct { - uint16_t min_conn_interval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t max_conn_interval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t slave_latency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t conn_sup_timeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ -} ble_gap_conn_params_t; - -/**@brief GAP connection security modes. - * - * Security Mode 0 Level 0: No access permissions at all (this level is not defined by the Bluetooth Core specification).\n - * Security Mode 1 Level 1: No security is needed (aka open link).\n - * Security Mode 1 Level 2: Encrypted link required, MITM protection not necessary.\n - * Security Mode 1 Level 3: MITM protected encrypted link required.\n - * Security Mode 1 Level 4: LESC MITM protected encrypted link using a 128-bit strength encryption key required.\n - * Security Mode 2 Level 1: Signing or encryption required, MITM protection not necessary.\n - * Security Mode 2 Level 2: MITM protected signing required, unless link is MITM protected encrypted.\n - */ -typedef struct { - uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ - uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */ - -} ble_gap_conn_sec_mode_t; - -/**@brief GAP connection security status.*/ -typedef struct { - ble_gap_conn_sec_mode_t sec_mode; /**< Currently active security mode for this connection.*/ - uint8_t - encr_key_size; /**< Length of currently active encryption key, 7 to 16 octets (only applicable for bonding procedures). */ -} ble_gap_conn_sec_t; - -/**@brief Identity Resolving Key. */ -typedef struct { - uint8_t irk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing IRK. */ -} ble_gap_irk_t; - -/**@brief Channel mask (40 bits). - * Every channel is represented with a bit positioned as per channel index defined in Bluetooth Core Specification v5.0, - * Vol 6, Part B, Section 1.4.1. The LSB contained in array element 0 represents channel index 0, and bit 39 represents - * channel index 39. If a bit is set to 1, the channel is not used. - */ -typedef uint8_t ble_gap_ch_mask_t[5]; - -/**@brief GAP advertising parameters. */ -typedef struct { - ble_gap_adv_properties_t properties; /**< The properties of the advertising events. */ - ble_gap_addr_t const *p_peer_addr; /**< Address of a known peer. - @note ble_gap_addr_t::addr_type cannot be - @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. - - When privacy is enabled and the local device uses - @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE addresses, - the device identity list is searched for a matching entry. If - the local IRK for that device identity is set, the local IRK - for that device will be used to generate the advertiser address - field in the advertising packet. - - If @ref ble_gap_adv_properties_t::type is directed, this must be - set to the targeted scanner or initiator. If the peer address is - in the device identity list, the peer IRK for that device will be - used to generate @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE - target addresses used in the advertising event PDUs. */ - uint32_t interval; /**< Advertising interval in 625 us units. @sa BLE_GAP_ADV_INTERVALS. - @note If @ref ble_gap_adv_properties_t::type is set to - @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE - advertising, this parameter is ignored. */ - uint16_t duration; /**< Advertising duration in 10 ms units. When timeout is reached, - an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. - @sa BLE_GAP_ADV_TIMEOUT_VALUES. - @note The SoftDevice will always complete at least one advertising - event even if the duration is set too low. */ - uint8_t max_adv_evts; /**< Maximum advertising events that shall be sent prior to disabling - advertising. Setting the value to 0 disables the limitation. When - the count of advertising events specified by this parameter - (if not 0) is reached, advertising will be automatically stopped - and an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised - @note If @ref ble_gap_adv_properties_t::type is set to - @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE, - this parameter is ignored. */ - ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. - At least one of the primary channels, that is channel index 37-39, must be used. - Masking away secondary advertising channels is not supported. */ - uint8_t filter_policy; /**< Filter Policy. @sa BLE_GAP_ADV_FILTER_POLICIES. */ - uint8_t primary_phy; /**< Indicates the PHY on which the primary advertising channel packets - are transmitted. If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS - will be used. - Valid values are @ref BLE_GAP_PHY_1MBPS and @ref BLE_GAP_PHY_CODED. - @note The primary_phy shall indicate @ref BLE_GAP_PHY_1MBPS if - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t secondary_phy; /**< Indicates the PHY on which the secondary advertising channel packets - are transmitted. - If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS will be used. - Valid values are - @ref BLE_GAP_PHY_1MBPS, @ref BLE_GAP_PHY_2MBPS, and @ref BLE_GAP_PHY_CODED. - If @ref ble_gap_adv_properties_t::type is an extended advertising type - and connectable, this is the PHY that will be used to establish a - connection and send AUX_ADV_IND packets on. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t set_id : 4; /**< The advertising set identifier distinguishes this advertising set from other - advertising sets transmitted by this and other devices. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t scan_req_notification : 1; /**< Enable scan request notifications for this advertising set. When a - scan request is received and the scanner address is allowed - by the filter policy, @ref BLE_GAP_EVT_SCAN_REQ_REPORT is raised. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is a non-scannable - advertising type. */ -} ble_gap_adv_params_t; - -/**@brief GAP advertising data buffers. - * - * The application must provide the buffers for advertisement. The memory shall reside in application RAM, and - * shall never be modified while advertising. The data shall be kept alive until either: - * - @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. - * - @ref BLE_GAP_EVT_CONNECTED is raised with @ref ble_gap_evt_connected_t::adv_handle set to the corresponding - * advertising handle. - * - Advertising is stopped. - * - Advertising data is changed. - * To update advertising data while advertising, provide new buffers to @ref sd_ble_gap_adv_set_configure. */ -typedef struct { - ble_data_t adv_data; /**< Advertising data. - @note - Advertising data can only be specified for a @ref ble_gap_adv_properties_t::type - that is allowed to contain advertising data. */ - ble_data_t scan_rsp_data; /**< Scan response data. - @note - Scan response data can only be specified for a @ref ble_gap_adv_properties_t::type - that is scannable. */ -} ble_gap_adv_data_t; - -/**@brief GAP scanning parameters. */ -typedef struct { - uint8_t extended : 1; /**< If 1, the scanner will accept extended advertising packets. - If set to 0, the scanner will not receive advertising packets - on secondary advertising channels, and will not be able - to receive long advertising PDUs. */ - uint8_t report_incomplete_evts : 1; /**< If 1, events of type @ref ble_gap_evt_adv_report_t may have - @ref ble_gap_adv_report_type_t::status set to - @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. - This parameter is ignored when used with @ref sd_ble_gap_connect - @note This may be used to abort receiving more packets from an extended - advertising event, and is only available for extended - scanning, see @ref sd_ble_gap_scan_start. - @note This feature is not supported by this SoftDevice. */ - uint8_t active : 1; /**< If 1, perform active scanning by sending scan requests. - This parameter is ignored when used with @ref sd_ble_gap_connect. */ - uint8_t filter_policy : 2; /**< Scanning filter policy. @sa BLE_GAP_SCAN_FILTER_POLICIES. - @note Only @ref BLE_GAP_SCAN_FP_ACCEPT_ALL and - @ref BLE_GAP_SCAN_FP_WHITELIST are valid when used with - @ref sd_ble_gap_connect */ - uint8_t scan_phys; /**< Bitfield of PHYs to scan on. If set to @ref BLE_GAP_PHY_AUTO, - scan_phys will default to @ref BLE_GAP_PHY_1MBPS. - - If @ref ble_gap_scan_params_t::extended is set to 0, the only - supported PHY is @ref BLE_GAP_PHY_1MBPS. - - When used with @ref sd_ble_gap_scan_start, - the bitfield indicates the PHYs the scanner will use for scanning - on primary advertising channels. The scanner will accept - @ref BLE_GAP_PHYS_SUPPORTED as secondary advertising channel PHYs. - - When used with @ref sd_ble_gap_connect, the bitfield indicates - the PHYs the initiator will use for scanning on primary advertising - channels. The initiator will accept connections initiated on either - of the @ref BLE_GAP_PHYS_SUPPORTED PHYs. - If scan_phys contains @ref BLE_GAP_PHY_1MBPS and/or @ref BLE_GAP_PHY_2MBPS, - the primary scan PHY is @ref BLE_GAP_PHY_1MBPS. - If scan_phys also contains @ref BLE_GAP_PHY_CODED, the primary scan - PHY will also contain @ref BLE_GAP_PHY_CODED. If the only scan PHY is - @ref BLE_GAP_PHY_CODED, the primary scan PHY is - @ref BLE_GAP_PHY_CODED only. */ - uint16_t interval; /**< Scan interval in 625 us units. @sa BLE_GAP_SCAN_INTERVALS. */ - uint16_t window; /**< Scan window in 625 us units. @sa BLE_GAP_SCAN_WINDOW. - If scan_phys contains both @ref BLE_GAP_PHY_1MBPS and - @ref BLE_GAP_PHY_CODED interval shall be larger than or - equal to twice the scan window. */ - uint16_t timeout; /**< Scan timeout in 10 ms units. @sa BLE_GAP_SCAN_TIMEOUT. */ - ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. - At least one of the primary channels, that is channel index 37-39, must be - set to 0. - Masking away secondary channels is not supported. */ -} ble_gap_scan_params_t; - -/**@brief Privacy. - * - * The privacy feature provides a way for the device to avoid being tracked over a period of time. - * The privacy feature, when enabled, hides the local device identity and replaces it with a private address - * that is automatically refreshed at a specified interval. - * - * If a device still wants to be recognized by other peers, it needs to share it's Identity Resolving Key (IRK). - * With this key, a device can generate a random private address that can only be recognized by peers in possession of that - * key, and devices can establish connections without revealing their real identities. - * - * Both network privacy (@ref BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY) and device privacy (@ref - * BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY) are supported. - * - * @note If the device IRK is updated, the new IRK becomes the one to be distributed in all - * bonding procedures performed after @ref sd_ble_gap_privacy_set returns. - * The IRK distributed during bonding procedure is the device IRK that is active when @ref sd_ble_gap_sec_params_reply is - * called. - */ -typedef struct { - uint8_t privacy_mode; /**< Privacy mode, see @ref BLE_GAP_PRIVACY_MODES. Default is @ref BLE_GAP_PRIVACY_MODE_OFF. */ - uint8_t private_addr_type; /**< The private address type must be either @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE or - @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE. */ - uint16_t private_addr_cycle_s; /**< Private address cycle interval in seconds. Providing an address cycle value of 0 will use - the default value defined by @ref BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S. */ - ble_gap_irk_t - *p_device_irk; /**< When used as input, pointer to IRK structure that will be used as the default IRK. If NULL, the device - default IRK will be used. When used as output, pointer to IRK structure where the current default IRK - will be written to. If NULL, this argument is ignored. By default, the default IRK is used to generate - random private resolvable addresses for the local device unless instructed otherwise. */ -} ble_gap_privacy_params_t; - -/**@brief PHY preferences for TX and RX - * @note tx_phys and rx_phys are bit fields. Multiple bits can be set in them to indicate multiple preferred PHYs for each - * direction. - * @code - * p_gap_phys->tx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; - * p_gap_phys->rx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; - * @endcode - * - */ -typedef struct { - uint8_t tx_phys; /**< Preferred transmit PHYs, see @ref BLE_GAP_PHYS. */ - uint8_t rx_phys; /**< Preferred receive PHYs, see @ref BLE_GAP_PHYS. */ -} ble_gap_phys_t; - -/** @brief Keys that can be exchanged during a bonding procedure. */ -typedef struct { - uint8_t enc : 1; /**< Long Term Key and Master Identification. */ - uint8_t id : 1; /**< Identity Resolving Key and Identity Address Information. */ - uint8_t sign : 1; /**< Connection Signature Resolving Key. */ - uint8_t link : 1; /**< Derive the Link Key from the LTK. */ -} ble_gap_sec_kdist_t; - -/**@brief GAP security parameters. */ -typedef struct { - uint8_t bond : 1; /**< Perform bonding. */ - uint8_t mitm : 1; /**< Enable Man In The Middle protection. */ - uint8_t lesc : 1; /**< Enable LE Secure Connection pairing. */ - uint8_t keypress : 1; /**< Enable generation of keypress notifications. */ - uint8_t io_caps : 3; /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */ - uint8_t oob : 1; /**< The OOB data flag. - - In LE legacy pairing, this flag is set if a device has out of band authentication data. - The OOB method is used if both of the devices have out of band authentication data. - - In LE Secure Connections pairing, this flag is set if a device has the peer device's out of band - authentication data. The OOB method is used if at least one device has the peer device's OOB data - available. */ - uint8_t - min_key_size; /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */ - uint8_t max_key_size; /**< Maximum encryption key size in octets between min_key_size and 16. */ - ble_gap_sec_kdist_t kdist_own; /**< Key distribution bitmap: keys that the local device will distribute. */ - ble_gap_sec_kdist_t kdist_peer; /**< Key distribution bitmap: keys that the remote device will distribute. */ -} ble_gap_sec_params_t; - -/**@brief GAP Encryption Information. */ -typedef struct { - uint8_t ltk[BLE_GAP_SEC_KEY_LEN]; /**< Long Term Key. */ - uint8_t lesc : 1; /**< Key generated using LE Secure Connections. */ - uint8_t auth : 1; /**< Authenticated Key. */ - uint8_t ltk_len : 6; /**< LTK length in octets. */ -} ble_gap_enc_info_t; - -/**@brief GAP Master Identification. */ -typedef struct { - uint16_t ediv; /**< Encrypted Diversifier. */ - uint8_t rand[BLE_GAP_SEC_RAND_LEN]; /**< Random Number. */ -} ble_gap_master_id_t; - -/**@brief GAP Signing Information. */ -typedef struct { - uint8_t csrk[BLE_GAP_SEC_KEY_LEN]; /**< Connection Signature Resolving Key. */ -} ble_gap_sign_info_t; - -/**@brief GAP LE Secure Connections P-256 Public Key. */ -typedef struct { - uint8_t pk[BLE_GAP_LESC_P256_PK_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key. Stored in the - standard SMP protocol format: {X,Y} both in little-endian. */ -} ble_gap_lesc_p256_pk_t; - -/**@brief GAP LE Secure Connections DHKey. */ -typedef struct { - uint8_t key[BLE_GAP_LESC_DHKEY_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman Key. Stored in little-endian. */ -} ble_gap_lesc_dhkey_t; - -/**@brief GAP LE Secure Connections OOB data. */ -typedef struct { - ble_gap_addr_t addr; /**< Bluetooth address of the device. */ - uint8_t r[BLE_GAP_SEC_KEY_LEN]; /**< Random Number. */ - uint8_t c[BLE_GAP_SEC_KEY_LEN]; /**< Confirm Value. */ -} ble_gap_lesc_oob_data_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONNECTED. */ -typedef struct { - ble_gap_addr_t - peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref - ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ - uint8_t role; /**< BLE role for this connection, see @ref BLE_GAP_ROLES */ - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ - uint8_t adv_handle; /**< Advertising handle in which advertising has ended. - This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ - ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated - advertising set. The advertising buffers provided in - @ref sd_ble_gap_adv_set_configure are now released. - This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ -} ble_gap_evt_connected_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DISCONNECTED. */ -typedef struct { - uint8_t reason; /**< HCI error code, see @ref BLE_HCI_STATUS_CODES. */ -} ble_gap_evt_disconnected_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE. */ -typedef struct { - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ -} ble_gap_evt_conn_param_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST. */ -typedef struct { - ble_gap_phys_t peer_preferred_phys; /**< The PHYs the peer prefers to use. */ -} ble_gap_evt_phy_update_request_t; - -/**@brief Event Structure for @ref BLE_GAP_EVT_PHY_UPDATE. */ -typedef struct { - uint8_t status; /**< Status of the procedure, see @ref BLE_HCI_STATUS_CODES.*/ - uint8_t tx_phy; /**< TX PHY for this connection, see @ref BLE_GAP_PHYS. */ - uint8_t rx_phy; /**< RX PHY for this connection, see @ref BLE_GAP_PHYS. */ -} ble_gap_evt_phy_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. */ -typedef struct { - ble_gap_sec_params_t peer_params; /**< Initiator Security Parameters. */ -} ble_gap_evt_sec_params_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_INFO_REQUEST. */ -typedef struct { - ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. */ - ble_gap_master_id_t master_id; /**< Master Identification for LTK lookup. */ - uint8_t enc_info : 1; /**< If 1, Encryption Information required. */ - uint8_t id_info : 1; /**< If 1, Identity Information required. */ - uint8_t sign_info : 1; /**< If 1, Signing Information required. */ -} ble_gap_evt_sec_info_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_PASSKEY_DISPLAY. */ -typedef struct { - uint8_t passkey[BLE_GAP_PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */ - uint8_t match_request : 1; /**< If 1 requires the application to report the match using @ref sd_ble_gap_auth_key_reply - with either @ref BLE_GAP_AUTH_KEY_TYPE_NONE if there is no match or - @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY if there is a match. */ -} ble_gap_evt_passkey_display_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_KEY_PRESSED. */ -typedef struct { - uint8_t kp_not; /**< Keypress notification type, see @ref BLE_GAP_KP_NOT_TYPES. */ -} ble_gap_evt_key_pressed_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_KEY_REQUEST. */ -typedef struct { - uint8_t key_type; /**< See @ref BLE_GAP_AUTH_KEY_TYPES. */ -} ble_gap_evt_auth_key_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST. */ -typedef struct { - ble_gap_lesc_p256_pk_t - *p_pk_peer; /**< LE Secure Connections remote P-256 Public Key. This will point to the application-supplied memory - inside the keyset during the call to @ref sd_ble_gap_sec_params_reply. */ - uint8_t oobd_req : 1; /**< LESC OOB data required. A call to @ref sd_ble_gap_lesc_oob_data_set is required to complete the - procedure. */ -} ble_gap_evt_lesc_dhkey_request_t; - -/**@brief Security levels supported. - * @note See Bluetooth Specification Version 4.2 Volume 3, Part C, Chapter 10, Section 10.2.1. - */ -typedef struct { - uint8_t lv1 : 1; /**< If 1: Level 1 is supported. */ - uint8_t lv2 : 1; /**< If 1: Level 2 is supported. */ - uint8_t lv3 : 1; /**< If 1: Level 3 is supported. */ - uint8_t lv4 : 1; /**< If 1: Level 4 is supported. */ -} ble_gap_sec_levels_t; - -/**@brief Encryption Key. */ -typedef struct { - ble_gap_enc_info_t enc_info; /**< Encryption Information. */ - ble_gap_master_id_t master_id; /**< Master Identification. */ -} ble_gap_enc_key_t; - -/**@brief Identity Key. */ -typedef struct { - ble_gap_irk_t id_info; /**< Identity Resolving Key. */ - ble_gap_addr_t id_addr_info; /**< Identity Address. */ -} ble_gap_id_key_t; - -/**@brief Security Keys. */ -typedef struct { - ble_gap_enc_key_t *p_enc_key; /**< Encryption Key, or NULL. */ - ble_gap_id_key_t *p_id_key; /**< Identity Key, or NULL. */ - ble_gap_sign_info_t *p_sign_key; /**< Signing Key, or NULL. */ - ble_gap_lesc_p256_pk_t *p_pk; /**< LE Secure Connections P-256 Public Key. When in debug mode the application must use the - value defined in the Core Bluetooth Specification v4.2 Vol.3, Part H, Section 2.3.5.6.1 */ -} ble_gap_sec_keys_t; - -/**@brief Security key set for both local and peer keys. */ -typedef struct { - ble_gap_sec_keys_t keys_own; /**< Keys distributed by the local device. For LE Secure Connections the encryption key will be - generated locally and will always be stored if bonding. */ - ble_gap_sec_keys_t - keys_peer; /**< Keys distributed by the remote device. For LE Secure Connections, p_enc_key must always be NULL. */ -} ble_gap_sec_keyset_t; - -/**@brief Data Length Update Procedure parameters. */ -typedef struct { - uint16_t max_tx_octets; /**< Maximum number of payload octets that a Controller supports for transmission of a single Link - Layer Data Channel PDU. */ - uint16_t max_rx_octets; /**< Maximum number of payload octets that a Controller supports for reception of a single Link Layer - Data Channel PDU. */ - uint16_t max_tx_time_us; /**< Maximum time, in microseconds, that a Controller supports for transmission of a single Link - Layer Data Channel PDU. */ - uint16_t max_rx_time_us; /**< Maximum time, in microseconds, that a Controller supports for reception of a single Link Layer - Data Channel PDU. */ -} ble_gap_data_length_params_t; - -/**@brief Data Length Update Procedure local limitation. */ -typedef struct { - uint16_t tx_payload_limited_octets; /**< If > 0, the requested TX packet length is too long by this many octets. */ - uint16_t rx_payload_limited_octets; /**< If > 0, the requested RX packet length is too long by this many octets. */ - uint16_t tx_rx_time_limited_us; /**< If > 0, the requested combination of TX and RX packet lengths is too long by this many - microseconds. */ -} ble_gap_data_length_limitation_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_STATUS. */ -typedef struct { - uint8_t auth_status; /**< Authentication status, see @ref BLE_GAP_SEC_STATUS. */ - uint8_t error_src : 2; /**< On error, source that caused the failure, see @ref BLE_GAP_SEC_STATUS_SOURCES. */ - uint8_t bonded : 1; /**< Procedure resulted in a bond. */ - uint8_t lesc : 1; /**< Procedure resulted in a LE Secure Connection. */ - ble_gap_sec_levels_t sm1_levels; /**< Levels supported in Security Mode 1. */ - ble_gap_sec_levels_t sm2_levels; /**< Levels supported in Security Mode 2. */ - ble_gap_sec_kdist_t kdist_own; /**< Bitmap stating which keys were exchanged (distributed) by the local device. If bonding - with LE Secure Connections, the enc bit will be always set. */ - ble_gap_sec_kdist_t kdist_peer; /**< Bitmap stating which keys were exchanged (distributed) by the remote device. If bonding - with LE Secure Connections, the enc bit will never be set. */ -} ble_gap_evt_auth_status_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_SEC_UPDATE. */ -typedef struct { - ble_gap_conn_sec_t conn_sec; /**< Connection security level. */ -} ble_gap_evt_conn_sec_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Source of timeout event, see @ref BLE_GAP_TIMEOUT_SOURCES. */ - union { - ble_data_t adv_report_buffer; /**< If source is set to @ref BLE_GAP_TIMEOUT_SRC_SCAN, the released - scan buffer is contained in this field. */ - } params; /**< Event Parameters. */ -} ble_gap_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_RSSI_CHANGED. */ -typedef struct { - int8_t rssi; /**< Received Signal Strength Indication in dBm. - @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature - measurement. */ - uint8_t ch_index; /**< Data Channel Index on which the Signal Strength is measured (0-36). */ -} ble_gap_evt_rssi_changed_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_ADV_SET_TERMINATED */ -typedef struct { - uint8_t reason; /**< Reason for why the advertising set terminated. See - @ref BLE_GAP_EVT_ADV_SET_TERMINATED_REASON. */ - uint8_t adv_handle; /**< Advertising handle in which advertising has ended. */ - uint8_t num_completed_adv_events; /**< If @ref ble_gap_adv_params_t::max_adv_evts was not set to 0, - this field indicates the number of completed advertising events. */ - ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated - advertising set. The advertising buffers provided in - @ref sd_ble_gap_adv_set_configure are now released. */ -} ble_gap_evt_adv_set_terminated_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; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_REQUEST. */ -typedef struct { - uint8_t bond : 1; /**< Perform bonding. */ - uint8_t mitm : 1; /**< Man In The Middle protection requested. */ - uint8_t lesc : 1; /**< LE Secure Connections requested. */ - uint8_t keypress : 1; /**< Generation of keypress notifications requested. */ -} ble_gap_evt_sec_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST. */ -typedef struct { - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ -} ble_gap_evt_conn_param_update_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SCAN_REQ_REPORT. */ -typedef struct { - uint8_t adv_handle; /**< Advertising handle for the advertising set which received the Scan Request */ - int8_t rssi; /**< Received Signal Strength Indication in dBm. - @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature - measurement. */ - ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref - ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ -} ble_gap_evt_scan_req_report_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST. */ -typedef struct { - ble_gap_data_length_params_t peer_params; /**< Peer data length parameters. */ -} ble_gap_evt_data_length_update_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE. - * - * @note This event may also be raised after a PHY Update procedure. - */ -typedef struct { - ble_gap_data_length_params_t effective_params; /**< The effective data length parameters. */ -} ble_gap_evt_data_length_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT. */ -typedef struct { - int8_t - channel_energy[BLE_GAP_CHANNEL_COUNT]; /**< The measured energy on the Bluetooth Low Energy - channels, in dBm, indexed by Channel Index. - If no measurement is available for the given channel, channel_energy is set to - @ref BLE_GAP_POWER_LEVEL_INVALID. */ -} ble_gap_evt_qos_channel_survey_report_t; - -/**@brief GAP event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which event occurred. */ - union /**< union alternative identified by evt_id in enclosing struct. */ - { - ble_gap_evt_connected_t connected; /**< Connected Event Parameters. */ - ble_gap_evt_disconnected_t disconnected; /**< Disconnected Event Parameters. */ - ble_gap_evt_conn_param_update_t conn_param_update; /**< Connection Parameter Update Parameters. */ - ble_gap_evt_sec_params_request_t sec_params_request; /**< Security Parameters Request Event Parameters. */ - ble_gap_evt_sec_info_request_t sec_info_request; /**< Security Information Request Event Parameters. */ - ble_gap_evt_passkey_display_t passkey_display; /**< Passkey Display Event Parameters. */ - ble_gap_evt_key_pressed_t key_pressed; /**< Key Pressed Event Parameters. */ - ble_gap_evt_auth_key_request_t auth_key_request; /**< Authentication Key Request Event Parameters. */ - ble_gap_evt_lesc_dhkey_request_t lesc_dhkey_request; /**< LE Secure Connections DHKey calculation request. */ - ble_gap_evt_auth_status_t auth_status; /**< Authentication Status Event Parameters. */ - ble_gap_evt_conn_sec_update_t conn_sec_update; /**< Connection Security Update Event Parameters. */ - ble_gap_evt_timeout_t timeout; /**< Timeout Event Parameters. */ - ble_gap_evt_rssi_changed_t rssi_changed; /**< RSSI Event Parameters. */ - ble_gap_evt_adv_report_t adv_report; /**< Advertising Report Event Parameters. */ - ble_gap_evt_adv_set_terminated_t adv_set_terminated; /**< Advertising Set Terminated Event Parameters. */ - ble_gap_evt_sec_request_t sec_request; /**< Security Request Event Parameters. */ - ble_gap_evt_conn_param_update_request_t conn_param_update_request; /**< Connection Parameter Update Parameters. */ - ble_gap_evt_scan_req_report_t scan_req_report; /**< Scan Request Report Parameters. */ - ble_gap_evt_phy_update_request_t phy_update_request; /**< PHY Update Request Event Parameters. */ - ble_gap_evt_phy_update_t phy_update; /**< PHY Update Parameters. */ - ble_gap_evt_data_length_update_request_t data_length_update_request; /**< Data Length Update Request Event Parameters. */ - ble_gap_evt_data_length_update_t data_length_update; /**< Data Length Update Event Parameters. */ - ble_gap_evt_qos_channel_survey_report_t - qos_channel_survey_report; /**< Quality of Service (QoS) Channel Survey Report Parameters. */ - } params; /**< Event Parameters. */ -} ble_gap_evt_t; - -/** - * @brief BLE GAP connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_CONN_COUNT The connection count for the connection configurations is zero. - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - The sum of conn_count for all connection configurations combined exceeds UINT8_MAX. - * - The event length is smaller than @ref BLE_GAP_EVENT_LENGTH_MIN. - */ -typedef struct { - uint8_t conn_count; /**< The number of concurrent connections the application can create with this configuration. - The default and minimum value is @ref BLE_GAP_CONN_COUNT_DEFAULT. */ - uint16_t event_length; /**< The time set aside for this connection on every connection interval in 1.25 ms units. - The default value is @ref BLE_GAP_EVENT_LENGTH_DEFAULT, the minimum value is @ref - BLE_GAP_EVENT_LENGTH_MIN. The event length and the connection interval are the primary parameters - for setting the throughput of a connection. - See the SoftDevice Specification for details on throughput. */ -} ble_gap_conn_cfg_t; - -/** - * @brief Configuration of maximum concurrent connections in the different connected roles, set with - * @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_CONN_COUNT The sum of periph_role_count and central_role_count is too - * large. The maximum supported sum of concurrent connections is - * @ref BLE_GAP_ROLE_COUNT_COMBINED_MAX. - * @retval ::NRF_ERROR_INVALID_PARAM central_sec_count is larger than central_role_count. - * @retval ::NRF_ERROR_RESOURCES The adv_set_count is too large. The maximum - * supported advertising handles is - * @ref BLE_GAP_ADV_SET_COUNT_MAX. - */ -typedef struct { - uint8_t adv_set_count; /**< Maximum number of advertising sets. Default value is @ref BLE_GAP_ADV_SET_COUNT_DEFAULT. */ - uint8_t periph_role_count; /**< Maximum number of connections concurrently acting as a peripheral. Default value is @ref - BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT. */ - uint8_t central_role_count; /**< Maximum number of connections concurrently acting as a central. Default value is @ref - BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT. */ - uint8_t central_sec_count; /**< Number of SMP instances shared between all connections acting as a central. Default value is - @ref BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT. */ - uint8_t qos_channel_survey_role_available : 1; /**< If set, the Quality of Service (QoS) channel survey module is available to - the application using @ref sd_ble_gap_qos_channel_survey_start. */ -} ble_gap_cfg_role_count_t; - -/** - * @brief Device name and its properties, set with @ref sd_ble_cfg_set. - * - * @note If the device name is not configured, the default device name will be - * @ref BLE_GAP_DEVNAME_DEFAULT, the maximum device name length will be - * @ref BLE_GAP_DEVNAME_DEFAULT_LEN, vloc will be set to @ref BLE_GATTS_VLOC_STACK and the device name - * will have no write access. - * - * @note If @ref max_len is more than @ref BLE_GAP_DEVNAME_DEFAULT_LEN and vloc is set to @ref BLE_GATTS_VLOC_STACK, - * the attribute table size must be increased to have room for the longer device name (see - * @ref sd_ble_cfg_set and @ref ble_gatts_cfg_attr_tab_size_t). - * - * @note If vloc is @ref BLE_GATTS_VLOC_STACK : - * - p_value must point to non-volatile memory (flash) or be NULL. - * - If p_value is NULL, the device name will initially be empty. - * - * @note If vloc is @ref BLE_GATTS_VLOC_USER : - * - p_value cannot be NULL. - * - If the device name is writable, p_value must point to volatile memory (RAM). - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - Invalid device name location (vloc). - * - Invalid device name security mode. - * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: - * - The device name length is invalid (must be between 0 and @ref BLE_GAP_DEVNAME_MAX_LEN). - * - The device name length is too long for the given Attribute Table. - * @retval ::NRF_ERROR_NOT_SUPPORTED Device name security mode is not supported. - */ -typedef struct { - ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ - uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ - uint8_t *p_value; /**< Pointer to where the value (device name) is stored or will be stored. */ - uint16_t current_len; /**< Current length in bytes of the memory pointed to by p_value.*/ - uint16_t max_len; /**< Maximum length in bytes of the memory pointed to by p_value.*/ -} ble_gap_cfg_device_name_t; - -/**@brief Peripheral Preferred Connection Parameters include configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t include_cfg; /**< Inclusion configuration of the Peripheral Preferred Connection Parameters characteristic. - See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_PPCP_INCL_CONFIG_DEFAULT. */ -} ble_gap_cfg_ppcp_incl_cfg_t; - -/**@brief Central Address Resolution include configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t include_cfg; /**< Inclusion configuration of the Central Address Resolution characteristic. - See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_CAR_INCL_CONFIG_DEFAULT. */ -} ble_gap_cfg_car_incl_cfg_t; - -/**@brief Configuration structure for GAP configurations. */ -typedef union { - ble_gap_cfg_role_count_t role_count_cfg; /**< Role count configuration, cfg_id is @ref BLE_GAP_CFG_ROLE_COUNT. */ - ble_gap_cfg_device_name_t device_name_cfg; /**< Device name configuration, cfg_id is @ref BLE_GAP_CFG_DEVICE_NAME. */ - ble_gap_cfg_ppcp_incl_cfg_t ppcp_include_cfg; /**< Peripheral Preferred Connection Parameters characteristic include - configuration, cfg_id is @ref BLE_GAP_CFG_PPCP_INCL_CONFIG. */ - ble_gap_cfg_car_incl_cfg_t car_include_cfg; /**< Central Address Resolution characteristic include configuration, - cfg_id is @ref BLE_GAP_CFG_CAR_INCL_CONFIG. */ -} ble_gap_cfg_t; - -/**@brief Channel Map option. - * - * @details Used with @ref sd_ble_opt_get to get the current channel map - * or @ref sd_ble_opt_set to set a new channel map. When setting the - * channel map, it applies to all current and future connections. When getting the - * current channel map, it applies to a single connection and the connection handle - * must be supplied. - * - * @note Setting the channel map may take some time, depending on connection parameters. - * The time taken may be different for each connection and the get operation will - * return the previous channel map until the new one has taken effect. - * - * @note After setting the channel map, by spec it can not be set again until at least 1 s has passed. - * See Bluetooth Specification Version 4.1 Volume 2, Part E, Section 7.3.46. - * - * @retval ::NRF_SUCCESS Get or set successful. - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - Less then two bits in @ref ch_map are set. - * - Bits for primary advertising channels (37-39) are set. - * @retval ::NRF_ERROR_BUSY Channel map was set again before enough time had passed. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied for get. - * - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle (only applicable for get) */ - uint8_t ch_map[5]; /**< Channel Map (37-bit). */ -} ble_gap_opt_ch_map_t; - -/**@brief Local connection latency option. - * - * @details Local connection latency is a feature which enables the slave to improve - * current consumption by ignoring the slave latency set by the peer. The - * local connection latency can only be set to a multiple of the slave latency, - * and cannot be longer than half of the supervision timeout. - * - * @details Used with @ref sd_ble_opt_set to set the local connection latency. The - * @ref sd_ble_opt_get is not supported for this option, but the actual - * local connection latency (unless set to NULL) is set as a return parameter - * when setting the option. - * - * @note The latency set will be truncated down to the closest slave latency event - * multiple, or the nearest multiple before half of the supervision timeout. - * - * @note The local connection latency is disabled by default, and needs to be enabled for new - * connections and whenever the connection is updated. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint16_t requested_latency; /**< Requested local connection latency. */ - uint16_t *p_actual_latency; /**< Pointer to storage for the actual local connection latency (can be set to NULL to skip return - value). */ -} ble_gap_opt_local_conn_latency_t; - -/**@brief Disable slave latency - * - * @details Used with @ref sd_ble_opt_set to temporarily disable slave latency of a peripheral connection - * (see @ref ble_gap_conn_params_t::slave_latency). And to re-enable it again. When disabled, the - * peripheral will ignore the slave_latency set by the central. - * - * @note Shall only be called on peripheral links. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint8_t disable; /**< For allowed values see @ref BLE_GAP_SLAVE_LATENCY */ -} ble_gap_opt_slave_latency_disable_t; - -/**@brief Passkey Option. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} - * @endmscs - * - * @details Structure containing the passkey to be used during pairing. This can be used with @ref - * sd_ble_opt_set to make the SoftDevice use a preprogrammed passkey for authentication - * instead of generating a random one. - * - * @note Repeated pairing attempts using the same preprogrammed passkey makes pairing vulnerable to MITM attacks. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * - */ -typedef struct { - uint8_t const *p_passkey; /**< Pointer to 6-digit ASCII string (digit 0..9 only, no NULL termination) passkey to be used - during pairing. If this is NULL, the SoftDevice will generate a random passkey if required.*/ -} ble_gap_opt_passkey_t; - -/**@brief Compatibility mode 1 option. - * - * @details This can be used with @ref sd_ble_opt_set to enable and disable - * compatibility mode 1. Compatibility mode 1 is disabled by default. - * - * @note Compatibility mode 1 enables interoperability with devices that do not support a value of - * 0 for the WinOffset parameter in the Link Layer CONNECT_IND packet. This applies to a - * limited set of legacy peripheral devices from another vendor. Enabling this compatibility - * mode will only have an effect if the local device will act as a central device and - * initiate a connection to a peripheral device. In that case it may lead to the connection - * creation taking up to one connection interval longer to complete for all connections. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_INVALID_STATE When connection creation is ongoing while mode 1 is set. - */ -typedef struct { - uint8_t enable : 1; /**< Enable compatibility mode 1.*/ -} ble_gap_opt_compat_mode_1_t; - -/**@brief Authenticated payload timeout option. - * - * @details This can be used with @ref sd_ble_opt_set to change the Authenticated payload timeout to a value other - * than the default of @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX. - * - * @note The authenticated payload timeout event ::BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD will be generated - * if auth_payload_timeout time has elapsed without receiving a packet with a valid MIC on an encrypted - * link. - * - * @note The LE ping procedure will be initiated before the timer expires to give the peer a chance - * to reset the timer. In addition the stack will try to prioritize running of LE ping over other - * activities to increase chances of finishing LE ping before timer expires. To avoid side-effects - * on other activities, it is recommended to use high timeout values. - * Recommended timeout > 2*(connInterval * (6 + connSlaveLatency)). - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. auth_payload_timeout was outside of allowed range. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint16_t auth_payload_timeout; /**< Requested timeout in 10 ms unit, see @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT. */ -} ble_gap_opt_auth_payload_timeout_t; - -/**@brief Option structure for GAP options. */ -typedef union { - ble_gap_opt_ch_map_t ch_map; /**< Parameters for the Channel Map option. */ - ble_gap_opt_local_conn_latency_t local_conn_latency; /**< Parameters for the Local connection latency option */ - ble_gap_opt_passkey_t passkey; /**< Parameters for the Passkey option.*/ - ble_gap_opt_compat_mode_1_t compat_mode_1; /**< Parameters for the compatibility mode 1 option.*/ - ble_gap_opt_auth_payload_timeout_t auth_payload_timeout; /**< Parameters for the authenticated payload timeout option.*/ - ble_gap_opt_slave_latency_disable_t slave_latency_disable; /**< Parameters for the Disable slave latency option */ -} ble_gap_opt_t; - -/**@brief Connection event triggering parameters. */ -typedef struct { - uint8_t ppi_ch_id; /**< PPI channel to use. This channel should be regarded as reserved until - connection event PPI task triggering is stopped. - The PPI channel ID can not be one of the PPI channels reserved by - the SoftDevice. See @ref NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK. */ - uint32_t task_endpoint; /**< Task Endpoint to trigger. */ - uint16_t conn_evt_counter_start; /**< The connection event on which the task triggering should start. */ - uint16_t period_in_events; /**< Trigger period. Valid range is [1, 32767]. - If the device is in slave role and slave latency is enabled, - this parameter should be set to a multiple of (slave latency + 1) - to ensure low power operation. */ -} ble_gap_conn_event_trigger_t; -/**@} */ - -/**@addtogroup BLE_GAP_FUNCTIONS Functions - * @{ */ - -/**@brief Set the local Bluetooth identity address. - * - * The local Bluetooth identity address is the address that identifies this device to other peers. - * The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. - * - * @note The identity address cannot be changed while advertising, scanning or creating a connection. - * - * @note This address will be distributed to the peer during bonding. - * If the address changes, the address stored in the peer device will not be valid and the ability to - * reconnect using the old address will be lost. - * - * @note By default the SoftDevice will set an address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC upon being - * enabled. The address is a random number populated during the IC manufacturing process and remains unchanged - * for the lifetime of each IC. - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @endmscs - * - * @param[in] p_addr Pointer to address structure. - * - * @retval ::NRF_SUCCESS Address successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_STATE The identity address cannot be changed while advertising, - * scanning or creating a connection. - */ -SVCALL(SD_BLE_GAP_ADDR_SET, uint32_t, sd_ble_gap_addr_set(ble_gap_addr_t const *p_addr)); - -/**@brief Get local Bluetooth identity address. - * - * @note This will always return the identity address irrespective of the privacy settings, - * i.e. the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. - * - * @param[out] p_addr Pointer to address structure to be filled in. - * - * @retval ::NRF_SUCCESS Address successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - */ -SVCALL(SD_BLE_GAP_ADDR_GET, uint32_t, sd_ble_gap_addr_get(ble_gap_addr_t *p_addr)); - -/**@brief Get the Bluetooth device address used by the advertiser. - * - * @note This function will return the local Bluetooth address used in advertising PDUs. When - * using privacy, the SoftDevice will generate a new private address every - * @ref ble_gap_privacy_params_t::private_addr_cycle_s configured using - * @ref sd_ble_gap_privacy_set. Hence depending on when the application calls this API, the - * address returned may not be the latest address that is used in the advertising PDUs. - * - * @param[in] adv_handle The advertising handle to get the address from. - * @param[out] p_addr Pointer to address structure to be filled in. - * - * @retval ::NRF_SUCCESS Address successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. - * @retval ::NRF_ERROR_INVALID_STATE The advertising set is currently not advertising. - */ -SVCALL(SD_BLE_GAP_ADV_ADDR_GET, uint32_t, sd_ble_gap_adv_addr_get(uint8_t adv_handle, ble_gap_addr_t *p_addr)); - -/**@brief Set the active whitelist in the SoftDevice. - * - * @note Only one whitelist can be used at a time and the whitelist is shared between the BLE roles. - * The whitelist cannot be set if a BLE role is using the whitelist. - * - * @note If an address is resolved using the information in the device identity list, then the whitelist - * filter policy applies to the peer identity address and not the resolvable address sent on air. - * - * @mscs - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} - * @endmscs - * - * @param[in] pp_wl_addrs Pointer to a whitelist of peer addresses, if NULL the whitelist will be cleared. - * @param[in] len Length of the whitelist, maximum @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT. - * - * @retval ::NRF_SUCCESS The whitelist is successfully set/cleared. - * @retval ::NRF_ERROR_INVALID_ADDR The whitelist (or one of its entries) provided is invalid. - * @retval ::BLE_ERROR_GAP_WHITELIST_IN_USE The whitelist is in use by a BLE role and cannot be set or cleared. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_DATA_SIZE The given whitelist size is invalid (zero or too large); this can only return when - * pp_wl_addrs is not NULL. - */ -SVCALL(SD_BLE_GAP_WHITELIST_SET, uint32_t, sd_ble_gap_whitelist_set(ble_gap_addr_t const *const *pp_wl_addrs, uint8_t len)); - -/**@brief Set device identity list. - * - * @note Only one device identity list can be used at a time and the list is shared between the BLE roles. - * The device identity list cannot be set if a BLE role is using the list. - * - * @param[in] pp_id_keys Pointer to an array of peer identity addresses and peer IRKs, if NULL the device identity list will - * be cleared. - * @param[in] pp_local_irks Pointer to an array of local IRKs. Each entry in the array maps to the entry in pp_id_keys at the - * same index. To fill in the list with the currently set device IRK for all peers, set to NULL. - * @param[in] len Length of the device identity list, maximum @ref BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT. - * - * @mscs - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS The device identity list successfully set/cleared. - * @retval ::NRF_ERROR_INVALID_ADDR The device identity list (or one of its entries) provided is invalid. - * This code may be returned if the local IRK list also has an invalid entry. - * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE The device identity list is in use and cannot be set or cleared. - * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE The device identity list contains multiple entries with the same identity - * address. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_DATA_SIZE The given device identity list size invalid (zero or too large); this can - * only return when pp_id_keys is not NULL. - */ -SVCALL(SD_BLE_GAP_DEVICE_IDENTITIES_SET, uint32_t, - sd_ble_gap_device_identities_set(ble_gap_id_key_t const *const *pp_id_keys, ble_gap_irk_t const *const *pp_local_irks, - uint8_t len)); - -/**@brief Set privacy settings. - * - * @note Privacy settings cannot be changed while advertising, scanning or creating a connection. - * - * @param[in] p_privacy_params Privacy settings. - * - * @mscs - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_INVALID_ADDR The pointer to privacy settings is NULL or invalid. - * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. - * @retval ::NRF_ERROR_INVALID_PARAM Out of range parameters are provided. - * @retval ::NRF_ERROR_NOT_SUPPORTED The SoftDevice does not support privacy if the Central Address Resolution - characteristic is not configured to be included and the SoftDevice is configured - to support central roles. - See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - * @retval ::NRF_ERROR_INVALID_STATE Privacy settings cannot be changed while advertising, scanning - * or creating a connection. - */ -SVCALL(SD_BLE_GAP_PRIVACY_SET, uint32_t, sd_ble_gap_privacy_set(ble_gap_privacy_params_t const *p_privacy_params)); - -/**@brief Get privacy settings. - * - * @note ::ble_gap_privacy_params_t::p_device_irk must be initialized to NULL or a valid address before this function is called. - * If it is initialized to a valid address, the address pointed to will contain the current device IRK on return. - * - * @param[in,out] p_privacy_params Privacy settings. - * - * @retval ::NRF_SUCCESS Privacy settings read. - * @retval ::NRF_ERROR_INVALID_ADDR The pointer given for returning the privacy settings may be NULL or invalid. - * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. - */ -SVCALL(SD_BLE_GAP_PRIVACY_GET, uint32_t, sd_ble_gap_privacy_get(ble_gap_privacy_params_t *p_privacy_params)); - -/**@brief Configure an advertising set. Set, clear or update advertising and scan response data. - * - * @note The format of the advertising data will be checked by this call to ensure interoperability. - * Limitations imposed by this API call to the data provided include having a flags data type in the scan response data and - * duplicating the local name in the advertising data and scan response data. - * - * @note In order to update advertising data while advertising, new advertising buffers must be provided. - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in,out] p_adv_handle Provide a pointer to a handle containing @ref - * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising set. On success, a new handle is then returned through the - * pointer. Provide a pointer to an existing advertising handle to configure an existing advertising set. - * @param[in] p_adv_data Advertising data. If set to NULL, no advertising data will be used. See - * @ref ble_gap_adv_data_t. - * @param[in] p_adv_params Advertising parameters. When this function is used to update advertising - * data while advertising, this parameter must be NULL. See @ref ble_gap_adv_params_t. - * - * @retval ::NRF_SUCCESS Advertising set successfully configured. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: - * - Invalid advertising data configuration specified. See @ref - * ble_gap_adv_data_t. - * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. - * - Use of whitelist requested but whitelist has not been set, - * see @ref sd_ble_gap_whitelist_set. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR ble_gap_adv_params_t::p_peer_addr is invalid. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - It is invalid to provide non-NULL advertising set parameters while - * advertising. - * - It is invalid to provide the same data buffers while advertising. To - * update advertising data, provide new advertising buffers. - * @retval ::BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST Discoverable mode and whitelist incompatible. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. Use @ref - * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_FLAGS Invalid combination of advertising flags supplied. - * @retval ::NRF_ERROR_INVALID_DATA Invalid data type(s) supplied. Check the advertising data format - * specification given in Bluetooth Specification Version 5.0, Volume 3, Part C, Chapter 11. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid data length(s) supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported data length or advertising parameter configuration. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to configure a new advertising handle. Update an - * existing advertising handle instead. - * @retval ::BLE_ERROR_GAP_UUID_LIST_MISMATCH Invalid UUID list supplied. - */ -SVCALL(SD_BLE_GAP_ADV_SET_CONFIGURE, uint32_t, - sd_ble_gap_adv_set_configure(uint8_t *p_adv_handle, ble_gap_adv_data_t const *p_adv_data, - ble_gap_adv_params_t const *p_adv_params)); - -/**@brief Start advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). - * - * @note Only one advertiser may be active at any time. - * - * @note If privacy is enabled, the advertiser's private address will be refreshed when this function is called. - * See @ref sd_ble_gap_privacy_set(). - * - * @events - * @event{@ref BLE_GAP_EVT_CONNECTED, Generated after connection has been established through connectable advertising.} - * @event{@ref BLE_GAP_EVT_ADV_SET_TERMINATED, Advertising set has terminated.} - * @event{@ref BLE_GAP_EVT_SCAN_REQ_REPORT, A scan request was received.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] adv_handle Advertising handle to advertise on, received from @ref sd_ble_gap_adv_set_configure. - * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or - * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. For non-connectable - * advertising, this is ignored. - * - * @retval ::NRF_SUCCESS The BLE stack has started advertising. - * @retval ::NRF_ERROR_INVALID_STATE adv_handle is not configured or already advertising. - * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration - * tag has been reached; connectable advertiser cannot be started. - * To increase the number of available connections, - * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. Configure a new adveriting handle with @ref - sd_ble_gap_adv_set_configure. - * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: - * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. - * - Use of whitelist requested but whitelist has not been set, see @ref - sd_ble_gap_whitelist_set. - * @retval ::NRF_ERROR_RESOURCES Either: - * - adv_handle is configured with connectable advertising, but the event_length parameter - * associated with conn_cfg_tag is too small to be able to establish a connection on - * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. - * - Not enough BLE role slots available. - Stop one or more currently active roles (Central, Peripheral, Broadcaster or Observer) - and try again. - * - p_adv_params is configured with connectable advertising, but the event_length - parameter - * associated with conn_cfg_tag is too small to be able to establish a connection on - * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. - */ -SVCALL(SD_BLE_GAP_ADV_START, uint32_t, sd_ble_gap_adv_start(uint8_t adv_handle, uint8_t conn_cfg_tag)); - -/**@brief Stop advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] adv_handle The advertising handle that should stop advertising. - * - * @retval ::NRF_SUCCESS The BLE stack has stopped advertising. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Invalid advertising handle. - * @retval ::NRF_ERROR_INVALID_STATE The advertising handle is not advertising. - */ -SVCALL(SD_BLE_GAP_ADV_STOP, uint32_t, sd_ble_gap_adv_stop(uint8_t adv_handle)); - -/**@brief Update connection parameters. - * - * @details In the central role this will initiate a Link Layer connection parameter update procedure, - * otherwise in the peripheral role, this will send the corresponding L2CAP request and wait for - * the central to perform the procedure. In both cases, and regardless of success or failure, the application - * will be informed of the result with a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE event. - * - * @details This function can be used as a central both to reply to a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST or to start the - * procedure unrequested. - * - * @events - * @event{@ref BLE_GAP_EVT_CONN_PARAM_UPDATE, Result of the connection parameter update procedure.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CPU_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CPU_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CPU_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_conn_params Pointer to desired connection parameters. If NULL is provided on a peripheral role, - * the parameters in the PPCP characteristic of the GAP service will be used instead. - * If NULL is provided on a central role and in response to a @ref - * BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST, the peripheral request will be rejected - * - * @retval ::NRF_SUCCESS The Connection Update procedure has been started successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. - * @retval ::NRF_ERROR_BUSY Procedure already in progress, wait for pending procedures to complete and retry. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GAP_CONN_PARAM_UPDATE, uint32_t, - sd_ble_gap_conn_param_update(uint16_t conn_handle, ble_gap_conn_params_t const *p_conn_params)); - -/**@brief Disconnect (GAP Link Termination). - * - * @details This call initiates the disconnection procedure, and its completion will be communicated to the application - * with a @ref BLE_GAP_EVT_DISCONNECTED event. - * - * @events - * @event{@ref BLE_GAP_EVT_DISCONNECTED, Generated when disconnection procedure is complete.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CONN_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] hci_status_code HCI status code, see @ref BLE_HCI_STATUS_CODES (accepted values are @ref - * BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION and @ref BLE_HCI_CONN_INTERVAL_UNACCEPTABLE). - * - * @retval ::NRF_SUCCESS The disconnection procedure has been started successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. - */ -SVCALL(SD_BLE_GAP_DISCONNECT, uint32_t, sd_ble_gap_disconnect(uint16_t conn_handle, uint8_t hci_status_code)); - -/**@brief Set the radio's transmit power. - * - * @param[in] role The role to set the transmit power for, see @ref BLE_GAP_TX_POWER_ROLES for - * possible roles. - * @param[in] handle The handle parameter is interpreted depending on role: - * - If role is @ref BLE_GAP_TX_POWER_ROLE_CONN, this value is the specific connection handle. - * - If role is @ref BLE_GAP_TX_POWER_ROLE_ADV, the advertising set identified with the advertising handle, - * will use the specified transmit power, and include it in the advertising packet headers if - * @ref ble_gap_adv_properties_t::include_tx_power set. - * - For all other roles handle is ignored. - * @param[in] tx_power Radio transmit power in dBm (see note for accepted values). - * - * @note Supported tx_power values: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm and +4dBm. - * In addition, on some chips following values are supported: +2dBm, +5dBm, +6dBm, +7dBm and +8dBm. - * Setting these values on a chip that does not support them will result in undefined behaviour. - * @note The initiator will have the same transmit power as the scanner. - * @note When a connection is created it will inherit the transmit power from the initiator or - * advertiser leading to the connection. - * - * @retval ::NRF_SUCCESS Successfully changed the transmit power. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_TX_POWER_SET, uint32_t, sd_ble_gap_tx_power_set(uint8_t role, uint16_t handle, int8_t tx_power)); - -/**@brief Set GAP Appearance value. - * - * @param[in] appearance Appearance (16-bit), see @ref BLE_APPEARANCES. - * - * @retval ::NRF_SUCCESS Appearance value set successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - */ -SVCALL(SD_BLE_GAP_APPEARANCE_SET, uint32_t, sd_ble_gap_appearance_set(uint16_t appearance)); - -/**@brief Get GAP Appearance value. - * - * @param[out] p_appearance Pointer to appearance (16-bit) to be filled in, see @ref BLE_APPEARANCES. - * - * @retval ::NRF_SUCCESS Appearance value retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GAP_APPEARANCE_GET, uint32_t, sd_ble_gap_appearance_get(uint16_t *p_appearance)); - -/**@brief Set GAP Peripheral Preferred Connection Parameters. - * - * @param[in] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure with the desired parameters. - * - * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, - see @ref ble_gap_cfg_ppcp_incl_cfg_t. - */ -SVCALL(SD_BLE_GAP_PPCP_SET, uint32_t, sd_ble_gap_ppcp_set(ble_gap_conn_params_t const *p_conn_params)); - -/**@brief Get GAP Peripheral Preferred Connection Parameters. - * - * @param[out] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure where the parameters will be stored. - * - * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, - see @ref ble_gap_cfg_ppcp_incl_cfg_t. - */ -SVCALL(SD_BLE_GAP_PPCP_GET, uint32_t, sd_ble_gap_ppcp_get(ble_gap_conn_params_t *p_conn_params)); - -/**@brief Set GAP device name. - * - * @note If the device name is located in application flash memory (see @ref ble_gap_cfg_device_name_t), - * it cannot be changed. Then @ref NRF_ERROR_FORBIDDEN will be returned. - * - * @param[in] p_write_perm Write permissions for the Device Name characteristic, see @ref ble_gap_conn_sec_mode_t. - * @param[in] p_dev_name Pointer to a UTF-8 encoded, non NULL-terminated string. - * @param[in] len Length of the UTF-8, non NULL-terminated string pointed to by p_dev_name in octets (must be smaller or - * equal than @ref BLE_GAP_DEVNAME_MAX_LEN). - * - * @retval ::NRF_SUCCESS GAP device name and permissions set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_FORBIDDEN Device name is not writable. - */ -SVCALL(SD_BLE_GAP_DEVICE_NAME_SET, uint32_t, - sd_ble_gap_device_name_set(ble_gap_conn_sec_mode_t const *p_write_perm, uint8_t const *p_dev_name, uint16_t len)); - -/**@brief Get GAP device name. - * - * @note If the device name is longer than the size of the supplied buffer, - * p_len will return the complete device name length, - * and not the number of bytes actually returned in p_dev_name. - * The application may use this information to allocate a suitable buffer size. - * - * @param[out] p_dev_name Pointer to an empty buffer where the UTF-8 non NULL-terminated string will be placed. Set to - * NULL to obtain the complete device name length. - * @param[in,out] p_len Length of the buffer pointed by p_dev_name, complete device name length on output. - * - * @retval ::NRF_SUCCESS GAP device name retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - */ -SVCALL(SD_BLE_GAP_DEVICE_NAME_GET, uint32_t, sd_ble_gap_device_name_get(uint8_t *p_dev_name, uint16_t *p_len)); - -/**@brief Initiate the GAP Authentication procedure. - * - * @details In the central role, this function will send an SMP Pairing Request (or an SMP Pairing Failed if rejected), - * otherwise in the peripheral role, an SMP Security Request will be sent. - * - * @events - * @event{Depending on the security parameters set and the packet exchanges with the peer\, the following events may be - * generated:} - * @event{@ref BLE_GAP_EVT_SEC_PARAMS_REQUEST} - * @event{@ref BLE_GAP_EVT_SEC_INFO_REQUEST} - * @event{@ref BLE_GAP_EVT_PASSKEY_DISPLAY} - * @event{@ref BLE_GAP_EVT_KEY_PRESSED} - * @event{@ref BLE_GAP_EVT_AUTH_KEY_REQUEST} - * @event{@ref BLE_GAP_EVT_LESC_DHKEY_REQUEST} - * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE} - * @event{@ref BLE_GAP_EVT_AUTH_STATUS} - * @event{@ref BLE_GAP_EVT_TIMEOUT} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_SEC_REQ_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_sec_params Pointer to the @ref ble_gap_sec_params_t structure with the security parameters to be used during the - * pairing or bonding procedure. In the peripheral role, only the bond, mitm, lesc and keypress fields of this structure are used. - * In the central role, this pointer may be NULL to reject a Security Request. - * - * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - No link has been established. - * - An encryption is already executing or queued. - * @retval ::NRF_ERROR_NO_MEM The maximum number of authentication procedures that can run in parallel for the given role is - * reached. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. - * Distribution of own Identity Information is only supported if the Central - * Address Resolution characteristic is configured to be included or - * the Softdevice is configured to support peripheral roles only. - * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - * @retval ::NRF_ERROR_TIMEOUT A SMP timeout has occurred, and further SMP operations on this link is prohibited. - */ -SVCALL(SD_BLE_GAP_AUTHENTICATE, uint32_t, - sd_ble_gap_authenticate(uint16_t conn_handle, ble_gap_sec_params_t const *p_sec_params)); - -/**@brief Reply with GAP security parameters. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST, calling it at other times will result in - * an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_CONFIRM_FAIL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_KS_TOO_SMALL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_APP_ERROR_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_REMOTE_PAIRING_FAIL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_TIMEOUT_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] sec_status Security status, see @ref BLE_GAP_SEC_STATUS. - * @param[in] p_sec_params Pointer to a @ref ble_gap_sec_params_t security parameters structure. In the central role this must be - * set to NULL, as the parameters have already been provided during a previous call to @ref sd_ble_gap_authenticate. - * @param[in,out] p_sec_keyset Pointer to a @ref ble_gap_sec_keyset_t security keyset structure. Any keys generated and/or - * distributed as a result of the ongoing security procedure will be stored into the memory referenced by the pointers inside this - * structure. The keys will be stored and available to the application upon reception of a @ref BLE_GAP_EVT_AUTH_STATUS event. - * Note that the SoftDevice expects the application to provide memory for storing the - * peer's keys. So it must be ensured that the relevant pointers inside this structure are not NULL. The - * pointers to the local key can, however, be NULL, in which case, the local key data will not be available to the application - * upon reception of the - * @ref BLE_GAP_EVT_AUTH_STATUS event. - * - * @retval ::NRF_SUCCESS Successfully accepted security parameter from the application. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Security parameters has not been requested. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. - * Distribution of own Identity Information is only supported if the Central - * Address Resolution characteristic is configured to be included or - * the Softdevice is configured to support peripheral roles only. - * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - */ -SVCALL(SD_BLE_GAP_SEC_PARAMS_REPLY, uint32_t, - sd_ble_gap_sec_params_reply(uint16_t conn_handle, uint8_t sec_status, ble_gap_sec_params_t const *p_sec_params, - ble_gap_sec_keyset_t const *p_sec_keyset)); - -/**@brief Reply with an authentication key. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_AUTH_KEY_REQUEST or a @ref BLE_GAP_EVT_PASSKEY_DISPLAY, - * calling it at other times will result in an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] key_type See @ref BLE_GAP_AUTH_KEY_TYPES. - * @param[in] p_key If key type is @ref BLE_GAP_AUTH_KEY_TYPE_NONE, then NULL. - * If key type is @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY, then a 6-byte ASCII string (digit 0..9 only, no NULL - * termination) or NULL when confirming LE Secure Connections Numeric Comparison. If key type is @ref BLE_GAP_AUTH_KEY_TYPE_OOB, - * then a 16-byte OOB key value in little-endian format. - * - * @retval ::NRF_SUCCESS Authentication key successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Authentication key has not been requested. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_AUTH_KEY_REPLY, uint32_t, - sd_ble_gap_auth_key_reply(uint16_t conn_handle, uint8_t key_type, uint8_t const *p_key)); - -/**@brief Reply with an LE Secure connections DHKey. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST, calling it at other times will result in - * an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_dhkey LE Secure Connections DHKey. - * - * @retval ::NRF_SUCCESS DHKey successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - The peer is not authenticated. - * - The application has not pulled a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_DHKEY_REPLY, uint32_t, - sd_ble_gap_lesc_dhkey_reply(uint16_t conn_handle, ble_gap_lesc_dhkey_t const *p_dhkey)); - -/**@brief Notify the peer of a local keypress. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] kp_not See @ref BLE_GAP_KP_NOT_TYPES. - * - * @retval ::NRF_SUCCESS Keypress notification successfully queued for transmission. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Authentication key not requested. - * - Passkey has not been entered. - * - Keypresses have not been enabled by both peers. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy. Retry at later time. - */ -SVCALL(SD_BLE_GAP_KEYPRESS_NOTIFY, uint32_t, sd_ble_gap_keypress_notify(uint16_t conn_handle, uint8_t kp_not)); - -/**@brief Generate a set of OOB data to send to a peer out of band. - * - * @note The @ref ble_gap_addr_t included in the OOB data returned will be the currently active one (or, if a connection has - * already been established, the one used during connection setup). The application may manually overwrite it with an updated - * value. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. Can be @ref BLE_CONN_HANDLE_INVALID if a BLE connection has not been established yet. - * @param[in] p_pk_own LE Secure Connections local P-256 Public Key. - * @param[out] p_oobd_own The OOB data to be sent out of band to a peer. - * - * @retval ::NRF_SUCCESS OOB data successfully generated. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_OOB_DATA_GET, uint32_t, - sd_ble_gap_lesc_oob_data_get(uint16_t conn_handle, ble_gap_lesc_p256_pk_t const *p_pk_own, - ble_gap_lesc_oob_data_t *p_oobd_own)); - -/**@brief Provide the OOB data sent/received out of band. - * - * @note An authentication procedure with OOB selected as an algorithm must be in progress when calling this function. - * @note A @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event with the oobd_req set to 1 must have been received prior to calling this - * function. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_oobd_own The OOB data sent out of band to a peer or NULL if the peer has not received OOB data. - * Must correspond to @ref ble_gap_sec_params_t::oob flag in @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. - * @param[in] p_oobd_peer The OOB data received out of band from a peer or NULL if none received. - * Must correspond to @ref ble_gap_sec_params_t::oob flag - * in @ref sd_ble_gap_authenticate in the central role or - * in @ref sd_ble_gap_sec_params_reply in the peripheral role. - * - * @retval ::NRF_SUCCESS OOB data accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Authentication key not requested - * - Not expecting LESC OOB data - * - Have not actually exchanged passkeys. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_OOB_DATA_SET, uint32_t, - sd_ble_gap_lesc_oob_data_set(uint16_t conn_handle, ble_gap_lesc_oob_data_t const *p_oobd_own, - ble_gap_lesc_oob_data_t const *p_oobd_peer)); - -/**@brief Initiate GAP Encryption procedure. - * - * @details In the central role, this function will initiate the encryption procedure using the encryption information provided. - * - * @events - * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE, The connection security has been updated.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_master_id Pointer to a @ref ble_gap_master_id_t master identification structure. - * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. - * - * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::BLE_ERROR_INVALID_ROLE Operation is not supported in the Peripheral role. - * @retval ::NRF_ERROR_BUSY Procedure already in progress or not allowed at this time, wait for pending procedures to complete and - * retry. - */ -SVCALL(SD_BLE_GAP_ENCRYPT, uint32_t, - sd_ble_gap_encrypt(uint16_t conn_handle, ble_gap_master_id_t const *p_master_id, ble_gap_enc_info_t const *p_enc_info)); - -/**@brief Reply with GAP security information. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_INFO_REQUEST, calling it at other times will result in - * @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * @note Data signing is not yet supported, and p_sign_info must therefore be NULL. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_ENC_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. May be NULL to signal none is - * available. - * @param[in] p_id_info Pointer to a @ref ble_gap_irk_t identity information structure. May be NULL to signal none is available. - * @param[in] p_sign_info Pointer to a @ref ble_gap_sign_info_t signing information structure. May be NULL to signal none is - * available. - * - * @retval ::NRF_SUCCESS Successfully accepted security information. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - No link has been established. - * - No @ref BLE_GAP_EVT_SEC_INFO_REQUEST pending. - * - Encryption information provided by the app without being requested. See @ref - * ble_gap_evt_sec_info_request_t::enc_info. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_SEC_INFO_REPLY, uint32_t, - sd_ble_gap_sec_info_reply(uint16_t conn_handle, ble_gap_enc_info_t const *p_enc_info, ble_gap_irk_t const *p_id_info, - ble_gap_sign_info_t const *p_sign_info)); - -/**@brief Get the current connection security. - * - * @param[in] conn_handle Connection handle. - * @param[out] p_conn_sec Pointer to a @ref ble_gap_conn_sec_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Current connection security successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_CONN_SEC_GET, uint32_t, sd_ble_gap_conn_sec_get(uint16_t conn_handle, ble_gap_conn_sec_t *p_conn_sec)); - -/**@brief Start reporting the received signal strength to the application. - * - * A new event is reported whenever the RSSI value changes, until @ref sd_ble_gap_rssi_stop is called. - * - * @events - * @event{@ref BLE_GAP_EVT_RSSI_CHANGED, New RSSI data available. How often the event is generated is - * dependent on the settings of the threshold_dbm - * and skip_count input parameters.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] threshold_dbm Minimum change in dBm before triggering the @ref BLE_GAP_EVT_RSSI_CHANGED event. Events are - * disabled if threshold_dbm equals @ref BLE_GAP_RSSI_THRESHOLD_INVALID. - * @param[in] skip_count Number of RSSI samples with a change of threshold_dbm or more before sending a new @ref - * BLE_GAP_EVT_RSSI_CHANGED event. - * - * @retval ::NRF_SUCCESS Successfully activated RSSI reporting. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is already ongoing. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_RSSI_START, uint32_t, sd_ble_gap_rssi_start(uint16_t conn_handle, uint8_t threshold_dbm, uint8_t skip_count)); - -/**@brief Stop reporting the received signal strength. - * - * @note An RSSI change detected before the call but not yet received by the application - * may be reported after @ref sd_ble_gap_rssi_stop has been called. - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * - * @retval ::NRF_SUCCESS Successfully deactivated RSSI reporting. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_RSSI_STOP, uint32_t, sd_ble_gap_rssi_stop(uint16_t conn_handle)); - -/**@brief Get the received signal strength for the last connection event. - * - * @ref sd_ble_gap_rssi_start must be called to start reporting RSSI before using this function. @ref NRF_ERROR_NOT_FOUND - * will be returned until RSSI was sampled for the first time after calling @ref sd_ble_gap_rssi_start. - * @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature measurement. - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[out] p_rssi Pointer to the location where the RSSI measurement shall be stored. - * @param[out] p_ch_index Pointer to the location where Channel Index for the RSSI measurement shall be stored. - * - * @retval ::NRF_SUCCESS Successfully read the RSSI. - * @retval ::NRF_ERROR_NOT_FOUND No sample is available. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. - */ -SVCALL(SD_BLE_GAP_RSSI_GET, uint32_t, sd_ble_gap_rssi_get(uint16_t conn_handle, int8_t *p_rssi, uint8_t *p_ch_index)); - -/**@brief Start or continue scanning (GAP Discovery procedure, Observer Procedure). - * - * @note A call to this function will require the application to keep the memory pointed by - * p_adv_report_buffer alive until the buffer is released. The buffer is released when the scanner is stopped - * or when this function is called with another buffer. - * - * @note The scanner will automatically stop in the following cases: - * - @ref sd_ble_gap_scan_stop is called. - * - @ref sd_ble_gap_connect is called. - * - A @ref BLE_GAP_EVT_TIMEOUT with source set to @ref BLE_GAP_TIMEOUT_SRC_SCAN is received. - * - When a @ref BLE_GAP_EVT_ADV_REPORT event is received and @ref ble_gap_adv_report_type_t::status is not set to - * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. In this case scanning is only paused to let the application - * access received data. The application must call this function to continue scanning, or call @ref - * sd_ble_gap_scan_stop to stop scanning. - * - * @note If a @ref BLE_GAP_EVT_ADV_REPORT event is received with @ref ble_gap_adv_report_type_t::status set to - * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the scanner will continue scanning, and the application will - * receive more reports from this advertising event. The following reports will include the old and new received data. - * - * @events - * @event{@ref BLE_GAP_EVT_ADV_REPORT, An advertising or scan response packet has been received.} - * @event{@ref BLE_GAP_EVT_TIMEOUT, Scanner has timed out.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_SCAN_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] p_scan_params Pointer to scan parameters structure. When this function is used to continue - * scanning, this parameter must be NULL. - * @param[in] p_adv_report_buffer Pointer to buffer used to store incoming advertising data. - * The memory pointed to should be kept alive until the scanning is stopped. - * See @ref BLE_GAP_SCAN_BUFFER_SIZE for minimum and maximum buffer size. - * If the scanner receives advertising data larger than can be stored in the buffer, - * a @ref BLE_GAP_EVT_ADV_REPORT will be raised with @ref ble_gap_adv_report_type_t::status - * set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED. - * - * @retval ::NRF_SUCCESS Successfully initiated scanning procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Scanning is already ongoing and p_scan_params was not NULL - * - Scanning is not running and p_scan_params was NULL. - * - The scanner has timed out when this function is called to continue scanning. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. See @ref ble_gap_scan_params_t. - * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported parameters supplied. See @ref ble_gap_scan_params_t. - * @retval ::NRF_ERROR_INVALID_LENGTH The provided buffer length is invalid. See @ref BLE_GAP_SCAN_BUFFER_MIN. - * @retval ::NRF_ERROR_RESOURCES Not enough BLE role slots available. - * Stop one or more currently active roles (Central, Peripheral or Broadcaster) and try again - */ -SVCALL(SD_BLE_GAP_SCAN_START, uint32_t, - sd_ble_gap_scan_start(ble_gap_scan_params_t const *p_scan_params, ble_data_t const *p_adv_report_buffer)); - -/**@brief Stop scanning (GAP Discovery procedure, Observer Procedure). - * - * @note The buffer provided in @ref sd_ble_gap_scan_start is released. - * - * @mscs - * @mmsc{@ref BLE_GAP_SCAN_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully stopped scanning procedure. - * @retval ::NRF_ERROR_INVALID_STATE Not in the scanning state. - */ -SVCALL(SD_BLE_GAP_SCAN_STOP, uint32_t, sd_ble_gap_scan_stop(void)); - -/**@brief Create a connection (GAP Link Establishment). - * - * @note If a scanning procedure is currently in progress it will be automatically stopped when calling this function. - * The scanning procedure will be stopped even if the function returns an error. - * - * @events - * @event{@ref BLE_GAP_EVT_CONNECTED, A connection was established.} - * @event{@ref BLE_GAP_EVT_TIMEOUT, Failed to establish a connection.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} - * @endmscs - * - * @param[in] p_peer_addr Pointer to peer identity address. If @ref ble_gap_scan_params_t::filter_policy is set to use - * whitelist, then p_peer_addr is ignored. - * @param[in] p_scan_params Pointer to scan parameters structure. - * @param[in] p_conn_params Pointer to desired connection parameters. - * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or - * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. - * - * @retval ::NRF_SUCCESS Successfully initiated connection procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid parameter(s) pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * - Invalid parameter(s) in p_scan_params or p_conn_params. - * - Use of whitelist requested but whitelist has not been set, see @ref - * sd_ble_gap_whitelist_set. - * - Peer address was not present in the device identity list, see @ref - * sd_ble_gap_device_identities_set. - * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. - * @retval ::NRF_ERROR_INVALID_STATE The SoftDevice is in an invalid state to perform this operation. This may be due to an - * existing locally initiated connect procedure, which must complete before initiating again. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid Peer address. - * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration tag has been reached. - * To increase the number of available connections, - * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. - * @retval ::NRF_ERROR_RESOURCES Either: - * - Not enough BLE role slots available. - * Stop one or more currently active roles (Central, Peripheral or Observer) and try again. - * - The event_length parameter associated with conn_cfg_tag is too small to be able to - * establish a connection on the selected @ref ble_gap_scan_params_t::scan_phys. - * Use @ref sd_ble_cfg_set to increase the event length. - */ -SVCALL(SD_BLE_GAP_CONNECT, uint32_t, - sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params, - ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag)); - -/**@brief Cancel a connection establishment. - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully canceled an ongoing connection procedure. - * @retval ::NRF_ERROR_INVALID_STATE No locally initiated connect procedure started or connection - * completed occurred. - */ -SVCALL(SD_BLE_GAP_CONNECT_CANCEL, uint32_t, sd_ble_gap_connect_cancel(void)); - -/**@brief Initiate or respond to a PHY Update Procedure - * - * @details This function is used to initiate or respond to a PHY Update Procedure. It will always - * generate a @ref BLE_GAP_EVT_PHY_UPDATE event if successfully executed. - * If this function is used to initiate a PHY Update procedure and the only option - * provided in @ref ble_gap_phys_t::tx_phys and @ref ble_gap_phys_t::rx_phys is the - * currently active PHYs in the respective directions, the SoftDevice will generate a - * @ref BLE_GAP_EVT_PHY_UPDATE with the current PHYs set and will not initiate the - * procedure in the Link Layer. - * - * If @ref ble_gap_phys_t::tx_phys or @ref ble_gap_phys_t::rx_phys is @ref BLE_GAP_PHY_AUTO, - * then the stack will select PHYs based on the peer's PHY preferences and the local link - * configuration. The PHY Update procedure will for this case result in a PHY combination - * that respects the time constraints configured with @ref sd_ble_cfg_set and the current - * link layer data length. - * - * When acting as a central, the SoftDevice will select the fastest common PHY in each direction. - * - * If the peer does not support the PHY Update Procedure, then the resulting - * @ref BLE_GAP_EVT_PHY_UPDATE event will have a status set to - * @ref BLE_HCI_UNSUPPORTED_REMOTE_FEATURE. - * - * If the PHY Update procedure was rejected by the peer due to a procedure collision, the status - * will be @ref BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION or - * @ref BLE_HCI_DIFFERENT_TRANSACTION_COLLISION. - * If the peer responds to the PHY Update procedure with invalid parameters, the status - * will be @ref BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS. - * If the PHY Update procedure was rejected by the peer for a different reason, the status will - * contain the reason as specified by the peer. - * - * @events - * @event{@ref BLE_GAP_EVT_PHY_UPDATE, Result of the PHY Update Procedure.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_PHY_UPDATE} - * @mmsc{@ref BLE_GAP_PERIPHERAL_PHY_UPDATE} - * @endmscs - * - * @param[in] conn_handle Connection handle to indicate the connection for which the PHY Update is requested. - * @param[in] p_gap_phys Pointer to PHY structure. - * - * @retval ::NRF_SUCCESS Successfully requested a PHY Update. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the combination of - * @ref ble_gap_phys_t::tx_phys, @ref ble_gap_phys_t::rx_phys, and @ref - * ble_gap_data_length_params_t. The connection event length is configured with @ref BLE_CONN_CFG_GAP using @ref sd_ble_cfg_set. - * @retval ::NRF_ERROR_BUSY Procedure is already in progress or not allowed at this time. Process pending events and wait for the - * pending procedure to complete and retry. - * - */ -SVCALL(SD_BLE_GAP_PHY_UPDATE, uint32_t, sd_ble_gap_phy_update(uint16_t conn_handle, ble_gap_phys_t const *p_gap_phys)); - -/**@brief Initiate or respond to a Data Length Update Procedure. - * - * @note If the application uses @ref BLE_GAP_DATA_LENGTH_AUTO for one or more members of - * p_dl_params, the SoftDevice will choose the highest value supported in current - * configuration and connection parameters. - * @note If the link PHY is Coded, the SoftDevice will ensure that the MaxTxTime and/or MaxRxTime - * used in the Data Length Update procedure is at least 2704 us. Otherwise, MaxTxTime and - * MaxRxTime will be limited to maximum 2120 us. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_dl_params Pointer to local parameters to be used in Data Length Update - * Procedure. Set any member to @ref BLE_GAP_DATA_LENGTH_AUTO to let - * the SoftDevice automatically decide the value for that member. - * Set to NULL to use automatic values for all members. - * @param[out] p_dl_limitation Pointer to limitation to be written when local device does not - * have enough resources or does not support the requested Data Length - * Update parameters. Ignored if NULL. - * - * @mscs - * @mmsc{@ref BLE_GAP_DATA_LENGTH_UPDATE_PROCEDURE_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully set Data Length Extension initiation/response parameters. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The requested parameters are not supported by the SoftDevice. Inspect - * p_dl_limitation to see which parameter is not supported. - * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the requested - * parameters. Use @ref sd_ble_cfg_set with @ref BLE_CONN_CFG_GAP to increase the connection event length. Inspect p_dl_limitation - * to see where the limitation is. - * @retval ::NRF_ERROR_BUSY Peer has already initiated a Data Length Update Procedure. Process the - * pending @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event to respond. - */ -SVCALL(SD_BLE_GAP_DATA_LENGTH_UPDATE, uint32_t, - sd_ble_gap_data_length_update(uint16_t conn_handle, ble_gap_data_length_params_t const *p_dl_params, - ble_gap_data_length_limitation_t *p_dl_limitation)); - -/**@brief Start the Quality of Service (QoS) channel survey module. - * - * @details The channel survey module provides measurements of the energy levels on - * the Bluetooth Low Energy channels. When the module is enabled, @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT - * events will periodically report the measured energy levels for each channel. - * - * @note The measurements are scheduled with lower priority than other Bluetooth Low Energy roles, - * Radio Timeslot API events and Flash API events. - * - * @note The channel survey module will attempt to do measurements so that the average interval - * between measurements will be interval_us. However due to the channel survey module - * having the lowest priority of all roles and modules, this may not be possible. In that - * case fewer than expected channel survey reports may be given. - * - * @note In order to use the channel survey module, @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available - * must be set. This is done using @ref sd_ble_cfg_set. - * - * @param[in] interval_us Requested average interval for the measurements and reports. See - * @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS for valid ranges. If set - * to @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS, the channel - * survey role will be scheduled at every available opportunity. - * - * @retval ::NRF_SUCCESS The module is successfully started. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. interval_us is out of the - * allowed range. - * @retval ::NRF_ERROR_INVALID_STATE Trying to start the module when already running. - * @retval ::NRF_ERROR_RESOURCES The channel survey module is not available to the application. - * Set @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available using - * @ref sd_ble_cfg_set. - */ -SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_START, uint32_t, sd_ble_gap_qos_channel_survey_start(uint32_t interval_us)); - -/**@brief Stop the Quality of Service (QoS) channel survey module. - * - * @note The SoftDevice may generate one @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT event after this - * function is called. - * - * @retval ::NRF_SUCCESS The module is successfully stopped. - * @retval ::NRF_ERROR_INVALID_STATE Trying to stop the module when it is not running. - */ -SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP, uint32_t, sd_ble_gap_qos_channel_survey_stop(void)); - -/**@brief Obtain the next connection event counter value. - * - * @details The connection event counter is initialized to zero on the first connection event. The value is incremented - * by one for each connection event. For more information see Bluetooth Core Specification v5.0, Vol 6, Part B, - * Section 4.5.1. - * - * @note The connection event counter obtained through this API will be outdated if this API is called - * at the same time as the connection event counter is incremented. - * - * @note This API will always return the last connection event counter + 1. - * The actual connection event may be multiple connection events later if: - * - Slave latency is enabled and there is no data to transmit or receive. - * - Another role is scheduled with a higher priority at the same time as the next connection event. - * - * @param[in] conn_handle Connection handle. - * @param[out] p_counter Pointer to the variable where the next connection event counter will be written. - * - * @retval ::NRF_SUCCESS The connection event counter was successfully retrieved. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET, uint32_t, - sd_ble_gap_next_conn_evt_counter_get(uint16_t conn_handle, uint16_t *p_counter)); - -/**@brief Start triggering a given task on connection event start. - * - * @details When enabled, this feature will trigger a PPI task at the start of connection events. - * The application can configure the SoftDevice to trigger every N connection events starting from - * a given connection event counter. See also @ref ble_gap_conn_event_trigger_t. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_params Connection event trigger parameters. - * - * @retval ::NRF_SUCCESS Success. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. See @ref ble_gap_conn_event_trigger_t. - * @retval ::NRF_ERROR_INVALID_STATE Either: - * - Trying to start connection event triggering when it is already ongoing. - * - @ref ble_gap_conn_event_trigger_t::conn_evt_counter_start is in the past. - * Use @ref sd_ble_gap_next_conn_evt_counter_get to find a new value - to be used as ble_gap_conn_event_trigger_t::conn_evt_counter_start. - */ -SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_START, uint32_t, - sd_ble_gap_conn_evt_trigger_start(uint16_t conn_handle, ble_gap_conn_event_trigger_t const *p_params)); - -/**@brief Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. - * - * @param[in] conn_handle Connection handle. - * - * @retval ::NRF_SUCCESS Success. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE Trying to stop connection event triggering when it is not enabled. - */ -SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_STOP, uint32_t, sd_ble_gap_conn_evt_trigger_stop(uint16_t conn_handle)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GAP_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gatt.h b/variants/wio-tracker-wm1110/softdevice/ble_gatt.h deleted file mode 100644 index df0d728fc8..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_gatt.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATT Generic Attribute Profile (GATT) Common - @{ - @brief Common definitions and prototypes for the GATT interfaces. - */ - -#ifndef BLE_GATT_H__ -#define BLE_GATT_H__ - -#include "ble_err.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATT_DEFINES Defines - * @{ */ - -/** @brief Default ATT MTU, in bytes. */ -#define BLE_GATT_ATT_MTU_DEFAULT 23 - -/**@brief Invalid Attribute Handle. */ -#define BLE_GATT_HANDLE_INVALID 0x0000 - -/**@brief First Attribute Handle. */ -#define BLE_GATT_HANDLE_START 0x0001 - -/**@brief Last Attribute Handle. */ -#define BLE_GATT_HANDLE_END 0xFFFF - -/** @defgroup BLE_GATT_TIMEOUT_SOURCES GATT Timeout sources - * @{ */ -#define BLE_GATT_TIMEOUT_SRC_PROTOCOL 0x00 /**< ATT Protocol timeout. */ -/** @} */ - -/** @defgroup BLE_GATT_WRITE_OPS GATT Write operations - * @{ */ -#define BLE_GATT_OP_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATT_OP_WRITE_REQ 0x01 /**< Write Request. */ -#define BLE_GATT_OP_WRITE_CMD 0x02 /**< Write Command. */ -#define BLE_GATT_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ -#define BLE_GATT_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ -#define BLE_GATT_OP_EXEC_WRITE_REQ 0x05 /**< Execute Write Request. */ -/** @} */ - -/** @defgroup BLE_GATT_EXEC_WRITE_FLAGS GATT Execute Write flags - * @{ */ -#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL 0x00 /**< Cancel prepared write. */ -#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE 0x01 /**< Execute prepared write. */ -/** @} */ - -/** @defgroup BLE_GATT_HVX_TYPES GATT Handle Value operations - * @{ */ -#define BLE_GATT_HVX_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATT_HVX_NOTIFICATION 0x01 /**< Handle Value Notification. */ -#define BLE_GATT_HVX_INDICATION 0x02 /**< Handle Value Indication. */ -/** @} */ - -/** @defgroup BLE_GATT_STATUS_CODES GATT Status Codes - * @{ */ -#define BLE_GATT_STATUS_SUCCESS 0x0000 /**< Success. */ -#define BLE_GATT_STATUS_UNKNOWN 0x0001 /**< Unknown or not applicable status. */ -#define BLE_GATT_STATUS_ATTERR_INVALID 0x0100 /**< ATT Error: Invalid Error Code. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_HANDLE 0x0101 /**< ATT Error: Invalid Attribute Handle. */ -#define BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED 0x0102 /**< ATT Error: Read not permitted. */ -#define BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED 0x0103 /**< ATT Error: Write not permitted. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_PDU 0x0104 /**< ATT Error: Used in ATT as Invalid PDU. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION 0x0105 /**< ATT Error: Authenticated link required. */ -#define BLE_GATT_STATUS_ATTERR_REQUEST_NOT_SUPPORTED 0x0106 /**< ATT Error: Used in ATT as Request Not Supported. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_OFFSET 0x0107 /**< ATT Error: Offset specified was past the end of the attribute. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION 0x0108 /**< ATT Error: Used in ATT as Insufficient Authorization. */ -#define BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL 0x0109 /**< ATT Error: Used in ATT as Prepare Queue Full. */ -#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND 0x010A /**< ATT Error: Used in ATT as Attribute not found. */ -#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_LONG \ - 0x010B /**< ATT Error: Attribute cannot be read or written using read/write blob requests. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_ENC_KEY_SIZE 0x010C /**< ATT Error: Encryption key size used is insufficient. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH 0x010D /**< ATT Error: Invalid value size. */ -#define BLE_GATT_STATUS_ATTERR_UNLIKELY_ERROR 0x010E /**< ATT Error: Very unlikely error. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION 0x010F /**< ATT Error: Encrypted link required. */ -#define BLE_GATT_STATUS_ATTERR_UNSUPPORTED_GROUP_TYPE \ - 0x0110 /**< ATT Error: Attribute type is not a supported grouping attribute. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_RESOURCES 0x0111 /**< ATT Error: Insufficient resources. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_BEGIN 0x0112 /**< ATT Error: Reserved for Future Use range #1 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_END 0x017F /**< ATT Error: Reserved for Future Use range #1 end. */ -#define BLE_GATT_STATUS_ATTERR_APP_BEGIN 0x0180 /**< ATT Error: Application range begin. */ -#define BLE_GATT_STATUS_ATTERR_APP_END 0x019F /**< ATT Error: Application range end. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_BEGIN 0x01A0 /**< ATT Error: Reserved for Future Use range #2 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_END 0x01DF /**< ATT Error: Reserved for Future Use range #2 end. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_BEGIN 0x01E0 /**< ATT Error: Reserved for Future Use range #3 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_END 0x01FC /**< ATT Error: Reserved for Future Use range #3 end. */ -#define BLE_GATT_STATUS_ATTERR_CPS_WRITE_REQ_REJECTED \ - 0x01FC /**< ATT Common Profile and Service Error: Write request rejected. \ - */ -#define BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR \ - 0x01FD /**< ATT Common Profile and Service Error: Client Characteristic Configuration Descriptor improperly configured. */ -#define BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG \ - 0x01FE /**< ATT Common Profile and Service Error: Procedure Already in Progress. */ -#define BLE_GATT_STATUS_ATTERR_CPS_OUT_OF_RANGE 0x01FF /**< ATT Common Profile and Service Error: Out Of Range. */ -/** @} */ - -/** @defgroup BLE_GATT_CPF_FORMATS Characteristic Presentation Formats - * @note Found at - * http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml - * @{ */ -#define BLE_GATT_CPF_FORMAT_RFU 0x00 /**< Reserved For Future Use. */ -#define BLE_GATT_CPF_FORMAT_BOOLEAN 0x01 /**< Boolean. */ -#define BLE_GATT_CPF_FORMAT_2BIT 0x02 /**< Unsigned 2-bit integer. */ -#define BLE_GATT_CPF_FORMAT_NIBBLE 0x03 /**< Unsigned 4-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT8 0x04 /**< Unsigned 8-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT12 0x05 /**< Unsigned 12-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT16 0x06 /**< Unsigned 16-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT24 0x07 /**< Unsigned 24-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT32 0x08 /**< Unsigned 32-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT48 0x09 /**< Unsigned 48-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT64 0x0A /**< Unsigned 64-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT128 0x0B /**< Unsigned 128-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT8 0x0C /**< Signed 2-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT12 0x0D /**< Signed 12-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT16 0x0E /**< Signed 16-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT24 0x0F /**< Signed 24-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT32 0x10 /**< Signed 32-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT48 0x11 /**< Signed 48-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT64 0x12 /**< Signed 64-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT128 0x13 /**< Signed 128-bit integer. */ -#define BLE_GATT_CPF_FORMAT_FLOAT32 0x14 /**< IEEE-754 32-bit floating point. */ -#define BLE_GATT_CPF_FORMAT_FLOAT64 0x15 /**< IEEE-754 64-bit floating point. */ -#define BLE_GATT_CPF_FORMAT_SFLOAT 0x16 /**< IEEE-11073 16-bit SFLOAT. */ -#define BLE_GATT_CPF_FORMAT_FLOAT 0x17 /**< IEEE-11073 32-bit FLOAT. */ -#define BLE_GATT_CPF_FORMAT_DUINT16 0x18 /**< IEEE-20601 format. */ -#define BLE_GATT_CPF_FORMAT_UTF8S 0x19 /**< UTF-8 string. */ -#define BLE_GATT_CPF_FORMAT_UTF16S 0x1A /**< UTF-16 string. */ -#define BLE_GATT_CPF_FORMAT_STRUCT 0x1B /**< Opaque Structure. */ -/** @} */ - -/** @defgroup BLE_GATT_CPF_NAMESPACES GATT Bluetooth Namespaces - * @{ - */ -#define BLE_GATT_CPF_NAMESPACE_BTSIG 0x01 /**< Bluetooth SIG defined Namespace. */ -#define BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN 0x0000 /**< Namespace Description Unknown. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATT_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATT connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_PARAM att_mtu is smaller than @ref BLE_GATT_ATT_MTU_DEFAULT. - */ -typedef struct { - uint16_t att_mtu; /**< Maximum size of ATT packet the SoftDevice can send or receive. - The default and minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - @mscs - @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} - @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} - @endmscs - */ -} ble_gatt_conn_cfg_t; - -/**@brief GATT Characteristic Properties. */ -typedef struct { - /* Standard properties */ - uint8_t broadcast : 1; /**< Broadcasting of the value permitted. */ - uint8_t read : 1; /**< Reading the value permitted. */ - uint8_t write_wo_resp : 1; /**< Writing the value with Write Command permitted. */ - uint8_t write : 1; /**< Writing the value with Write Request permitted. */ - uint8_t notify : 1; /**< Notification of the value permitted. */ - uint8_t indicate : 1; /**< Indications of the value permitted. */ - uint8_t auth_signed_wr : 1; /**< Writing the value with Signed Write Command permitted. */ -} ble_gatt_char_props_t; - -/**@brief GATT Characteristic Extended Properties. */ -typedef struct { - /* Extended properties */ - uint8_t reliable_wr : 1; /**< Writing the value with Queued Write operations permitted. */ - uint8_t wr_aux : 1; /**< Writing the Characteristic User Description descriptor permitted. */ -} ble_gatt_char_ext_props_t; - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GATT_H__ - -/** @} */ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gattc.h b/variants/wio-tracker-wm1110/softdevice/ble_gattc.h deleted file mode 100644 index f1df1782ca..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_gattc.h +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATTC Generic Attribute Profile (GATT) Client - @{ - @brief Definitions and prototypes for the GATT Client interface. - */ - -#ifndef BLE_GATTC_H__ -#define BLE_GATTC_H__ - -#include "ble_err.h" -#include "ble_gatt.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATTC_ENUMERATIONS Enumerations - * @{ */ - -/**@brief GATTC API SVC numbers. */ -enum BLE_GATTC_SVCS { - SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER = BLE_GATTC_SVC_BASE, /**< Primary Service Discovery. */ - SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, /**< Relationship Discovery. */ - SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, /**< Characteristic Discovery. */ - SD_BLE_GATTC_DESCRIPTORS_DISCOVER, /**< Characteristic Descriptor Discovery. */ - SD_BLE_GATTC_ATTR_INFO_DISCOVER, /**< Attribute Information Discovery. */ - SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, /**< Read Characteristic Value by UUID. */ - SD_BLE_GATTC_READ, /**< Generic read. */ - SD_BLE_GATTC_CHAR_VALUES_READ, /**< Read multiple Characteristic Values. */ - SD_BLE_GATTC_WRITE, /**< Generic write. */ - SD_BLE_GATTC_HV_CONFIRM, /**< Handle Value Confirmation. */ - SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. */ -}; - -/** - * @brief GATT Client Event IDs. - */ -enum BLE_GATTC_EVTS { - BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP = BLE_GATTC_EVT_BASE, /**< Primary Service Discovery Response event. \n See @ref - ble_gattc_evt_prim_srvc_disc_rsp_t. */ - BLE_GATTC_EVT_REL_DISC_RSP, /**< Relationship Discovery Response event. \n See @ref ble_gattc_evt_rel_disc_rsp_t. - */ - BLE_GATTC_EVT_CHAR_DISC_RSP, /**< Characteristic Discovery Response event. \n See @ref - ble_gattc_evt_char_disc_rsp_t. */ - BLE_GATTC_EVT_DESC_DISC_RSP, /**< Descriptor Discovery Response event. \n See @ref - ble_gattc_evt_desc_disc_rsp_t. */ - BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, /**< Attribute Information Response event. \n See @ref - ble_gattc_evt_attr_info_disc_rsp_t. */ - BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP, /**< Read By UUID Response event. \n See @ref - ble_gattc_evt_char_val_by_uuid_read_rsp_t. */ - BLE_GATTC_EVT_READ_RSP, /**< Read Response event. \n See @ref ble_gattc_evt_read_rsp_t. */ - BLE_GATTC_EVT_CHAR_VALS_READ_RSP, /**< Read multiple Response event. \n See @ref - ble_gattc_evt_char_vals_read_rsp_t. */ - BLE_GATTC_EVT_WRITE_RSP, /**< Write Response event. \n See @ref ble_gattc_evt_write_rsp_t. */ - BLE_GATTC_EVT_HVX, /**< Handle Value Notification or Indication event. \n Confirm indication with @ref - sd_ble_gattc_hv_confirm. \n See @ref ble_gattc_evt_hvx_t. */ - BLE_GATTC_EVT_EXCHANGE_MTU_RSP, /**< Exchange MTU Response event. \n See @ref - ble_gattc_evt_exchange_mtu_rsp_t. */ - BLE_GATTC_EVT_TIMEOUT, /**< Timeout event. \n See @ref ble_gattc_evt_timeout_t. */ - BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE /**< Write without Response transmission complete. \n See @ref - ble_gattc_evt_write_cmd_tx_complete_t. */ -}; - -/**@brief GATTC Option IDs. - * IDs that uniquely identify a GATTC option. - */ -enum BLE_GATTC_OPTS { - BLE_GATTC_OPT_UUID_DISC = BLE_GATTC_OPT_BASE, /**< UUID discovery. @ref ble_gattc_opt_uuid_disc_t */ -}; - -/** @} */ - -/** @addtogroup BLE_GATTC_DEFINES Defines - * @{ */ - -/** @defgroup BLE_ERRORS_GATTC SVC return values specific to GATTC - * @{ */ -#define BLE_ERROR_GATTC_PROC_NOT_PERMITTED (NRF_GATTC_ERR_BASE + 0x000) /**< Procedure not Permitted. */ -/** @} */ - -/** @defgroup BLE_GATTC_ATTR_INFO_FORMAT Attribute Information Formats - * @{ */ -#define BLE_GATTC_ATTR_INFO_FORMAT_16BIT 1 /**< 16-bit Attribute Information Format. */ -#define BLE_GATTC_ATTR_INFO_FORMAT_128BIT 2 /**< 128-bit Attribute Information Format. */ -/** @} */ - -/** @defgroup BLE_GATTC_DEFAULTS GATT Client defaults - * @{ */ -#define BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT \ - 1 /**< Default number of Write without Response that can be queued for transmission. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATTC_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATTC connection configuration parameters, set with @ref sd_ble_cfg_set. - */ -typedef struct { - uint8_t write_cmd_tx_queue_size; /**< The guaranteed minimum number of Write without Response that can be queued for - transmission. The default value is @ref BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT */ -} ble_gattc_conn_cfg_t; - -/**@brief Operation Handle Range. */ -typedef struct { - uint16_t start_handle; /**< Start Handle. */ - uint16_t end_handle; /**< End Handle. */ -} ble_gattc_handle_range_t; - -/**@brief GATT service. */ -typedef struct { - ble_uuid_t uuid; /**< Service UUID. */ - ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */ -} ble_gattc_service_t; - -/**@brief GATT include. */ -typedef struct { - uint16_t handle; /**< Include Handle. */ - ble_gattc_service_t included_srvc; /**< Handle of the included service. */ -} ble_gattc_include_t; - -/**@brief GATT characteristic. */ -typedef struct { - ble_uuid_t uuid; /**< Characteristic UUID. */ - ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ - uint8_t char_ext_props : 1; /**< Extended properties present. */ - uint16_t handle_decl; /**< Handle of the Characteristic Declaration. */ - uint16_t handle_value; /**< Handle of the Characteristic Value. */ -} ble_gattc_char_t; - -/**@brief GATT descriptor. */ -typedef struct { - uint16_t handle; /**< Descriptor Handle. */ - ble_uuid_t uuid; /**< Descriptor UUID. */ -} ble_gattc_desc_t; - -/**@brief Write Parameters. */ -typedef struct { - uint8_t write_op; /**< Write Operation to be performed, see @ref BLE_GATT_WRITE_OPS. */ - uint8_t flags; /**< Flags, see @ref BLE_GATT_EXEC_WRITE_FLAGS. */ - uint16_t handle; /**< Handle to the attribute to be written. */ - uint16_t offset; /**< Offset in bytes. @note For WRITE_CMD and WRITE_REQ, offset must be 0. */ - uint16_t len; /**< Length of data in bytes. */ - uint8_t const *p_value; /**< Pointer to the value data. */ -} ble_gattc_write_params_t; - -/**@brief Attribute Information for 16-bit Attribute UUID. */ -typedef struct { - uint16_t handle; /**< Attribute handle. */ - ble_uuid_t uuid; /**< 16-bit Attribute UUID. */ -} ble_gattc_attr_info16_t; - -/**@brief Attribute Information for 128-bit Attribute UUID. */ -typedef struct { - uint16_t handle; /**< Attribute handle. */ - ble_uuid128_t uuid; /**< 128-bit Attribute UUID. */ -} ble_gattc_attr_info128_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Service count. */ - ble_gattc_service_t services[1]; /**< Service data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use - event structures with variable length array members. */ -} ble_gattc_evt_prim_srvc_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_REL_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Include count. */ - ble_gattc_include_t includes[1]; /**< Include data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use - event structures with variable length array members. */ -} ble_gattc_evt_rel_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Characteristic count. */ - ble_gattc_char_t chars[1]; /**< Characteristic data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event - structures with variable length array members. */ -} ble_gattc_evt_char_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_DESC_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Descriptor count. */ - ble_gattc_desc_t descs[1]; /**< Descriptor data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event - structures with variable length array members. */ -} ble_gattc_evt_desc_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Attribute count. */ - uint8_t format; /**< Attribute information format, see @ref BLE_GATTC_ATTR_INFO_FORMAT. */ - union { - ble_gattc_attr_info16_t attr_info16[1]; /**< Attribute information for 16-bit Attribute UUID. - @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on - how to use event structures with variable length array members. */ - ble_gattc_attr_info128_t attr_info128[1]; /**< Attribute information for 128-bit Attribute UUID. - @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on - how to use event structures with variable length array members. */ - } info; /**< Attribute information union. */ -} ble_gattc_evt_attr_info_disc_rsp_t; - -/**@brief GATT read by UUID handle value pair. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint8_t *p_value; /**< Pointer to the Attribute Value, length is available in @ref - ble_gattc_evt_char_val_by_uuid_read_rsp_t::value_len. */ -} ble_gattc_handle_value_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP. */ -typedef struct { - uint16_t count; /**< Handle-Value Pair Count. */ - uint16_t value_len; /**< Length of the value in Handle-Value(s) list. */ - uint8_t handle_value[1]; /**< Handle-Value(s) list. To iterate through the list use @ref - sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter. - @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with - variable length array members. */ -} ble_gattc_evt_char_val_by_uuid_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_READ_RSP. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint16_t offset; /**< Offset of the attribute data. */ - uint16_t len; /**< Attribute data length. */ - uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP. */ -typedef struct { - uint16_t len; /**< Concatenated Attribute values length. */ - uint8_t values[1]; /**< Attribute values. @note This is a variable length array. The size of 1 indicated is only a placeholder - for compilation. See @ref sd_ble_evt_get for more information on how to use event structures with - variable length array members. */ -} ble_gattc_evt_char_vals_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_RSP. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint8_t write_op; /**< Type of write operation, see @ref BLE_GATT_WRITE_OPS. */ - uint16_t offset; /**< Data offset. */ - uint16_t len; /**< Data length. */ - uint8_t data[1]; /**< Data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_write_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_HVX. */ -typedef struct { - uint16_t handle; /**< Handle to which the HVx operation applies. */ - uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ - uint16_t len; /**< Attribute data length. */ - uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_hvx_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. */ -typedef struct { - uint16_t server_rx_mtu; /**< Server RX MTU size. */ -} ble_gattc_evt_exchange_mtu_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ -} ble_gattc_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE. */ -typedef struct { - uint8_t count; /**< Number of write without response transmissions completed. */ -} ble_gattc_evt_write_cmd_tx_complete_t; - -/**@brief GATTC event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which event occurred. */ - uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ - uint16_t - error_handle; /**< In case of error: The handle causing the error. In all other cases @ref BLE_GATT_HANDLE_INVALID. */ - union { - ble_gattc_evt_prim_srvc_disc_rsp_t prim_srvc_disc_rsp; /**< Primary Service Discovery Response Event Parameters. */ - ble_gattc_evt_rel_disc_rsp_t rel_disc_rsp; /**< Relationship Discovery Response Event Parameters. */ - ble_gattc_evt_char_disc_rsp_t char_disc_rsp; /**< Characteristic Discovery Response Event Parameters. */ - ble_gattc_evt_desc_disc_rsp_t desc_disc_rsp; /**< Descriptor Discovery Response Event Parameters. */ - ble_gattc_evt_char_val_by_uuid_read_rsp_t - char_val_by_uuid_read_rsp; /**< Characteristic Value Read by UUID Response Event Parameters. */ - ble_gattc_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. */ - ble_gattc_evt_char_vals_read_rsp_t char_vals_read_rsp; /**< Characteristic Values Read Response Event Parameters. */ - ble_gattc_evt_write_rsp_t write_rsp; /**< Write Response Event Parameters. */ - ble_gattc_evt_hvx_t hvx; /**< Handle Value Notification/Indication Event Parameters. */ - ble_gattc_evt_exchange_mtu_rsp_t exchange_mtu_rsp; /**< Exchange MTU Response Event Parameters. */ - ble_gattc_evt_timeout_t timeout; /**< Timeout Event Parameters. */ - ble_gattc_evt_attr_info_disc_rsp_t attr_info_disc_rsp; /**< Attribute Information Discovery Event Parameters. */ - ble_gattc_evt_write_cmd_tx_complete_t - write_cmd_tx_complete; /**< Write without Response transmission complete Event Parameters. */ - } params; /**< Event Parameters. @note Only valid if @ref gatt_status == @ref BLE_GATT_STATUS_SUCCESS. */ -} ble_gattc_evt_t; - -/**@brief UUID discovery option. - * - * @details Used with @ref sd_ble_opt_set to enable and disable automatic insertion of discovered 128-bit UUIDs to the - * Vendor Specific UUID table. Disabled by default. - * - When disabled, if a procedure initiated by - * @ref sd_ble_gattc_primary_services_discover, - * @ref sd_ble_gattc_relationships_discover, - * @ref sd_ble_gattc_characteristics_discover, - * @ref sd_ble_gattc_descriptors_discover - * finds a 128-bit UUID which was not added by @ref sd_ble_uuid_vs_add, @ref ble_uuid_t::type will be set - * to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. - * - When enabled, all found 128-bit UUIDs will be automatically added. The application can use - * @ref sd_ble_uuid_encode to retrieve the 128-bit UUID from @ref ble_uuid_t received in the corresponding - * event. If the total number of Vendor Specific UUIDs exceeds the table capacity, @ref ble_uuid_t::type will - * be set to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. - * See also @ref ble_common_cfg_vs_uuid_t, @ref sd_ble_uuid_vs_remove. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * - * @retval ::NRF_SUCCESS Set successfully. - * - */ -typedef struct { - uint8_t auto_add_vs_enable : 1; /**< Set to 1 to enable (or 0 to disable) automatic insertion of discovered 128-bit UUIDs. */ -} ble_gattc_opt_uuid_disc_t; - -/**@brief Option structure for GATTC options. */ -typedef union { - ble_gattc_opt_uuid_disc_t uuid_disc; /**< Parameters for the UUID discovery option. */ -} ble_gattc_opt_t; - -/** @} */ - -/** @addtogroup BLE_GATTC_FUNCTIONS Functions - * @{ */ - -/**@brief Initiate or continue a GATT Primary Service Discovery procedure. - * - * @details This function initiates or resumes a Primary Service discovery procedure, starting from the supplied handle. - * If the last service has not been reached, this function must be called again with an updated start handle value to - * continue the search. See also @ref ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_PRIM_SRVC_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] start_handle Handle to start searching from. - * @param[in] p_srvc_uuid Pointer to the service UUID to be found. If it is NULL, all primary services will be returned. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Primary Service Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER, uint32_t, - sd_ble_gattc_primary_services_discover(uint16_t conn_handle, uint16_t start_handle, ble_uuid_t const *p_srvc_uuid)); - -/**@brief Initiate or continue a GATT Relationship Discovery procedure. - * - * @details This function initiates or resumes the Find Included Services sub-procedure. If the last included service has not been - * reached, this must be called again with an updated handle range to continue the search. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_REL_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_REL_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Relationship Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, uint32_t, - sd_ble_gattc_relationships_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Characteristic Discovery procedure. - * - * @details This function initiates or resumes a Characteristic discovery procedure. If the last Characteristic has not been - * reached, this must be called again with an updated handle range to continue the discovery. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_CHAR_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Characteristic Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, uint32_t, - sd_ble_gattc_characteristics_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Characteristic Descriptor Discovery procedure. - * - * @details This function initiates or resumes a Characteristic Descriptor discovery procedure. If the last Descriptor has not - * been reached, this must be called again with an updated handle range to continue the discovery. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_DESC_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_DESC_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Characteristic to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Descriptor Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t, - sd_ble_gattc_descriptors_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Read using Characteristic UUID procedure. - * - * @details This function initiates or resumes a Read using Characteristic UUID procedure. If the last Characteristic has not been - * reached, this must be called again with an updated handle range to continue the discovery. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_READ_UUID_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_uuid Pointer to a Characteristic value UUID to read. - * @param[in] p_handle_range A pointer to the range of handles to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Read using Characteristic UUID procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, uint32_t, - sd_ble_gattc_char_value_by_uuid_read(uint16_t conn_handle, ble_uuid_t const *p_uuid, - ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Read (Long) Characteristic or Descriptor procedure. - * - * @details This function initiates or resumes a GATT Read (Long) Characteristic or Descriptor procedure. If the Characteristic or - * Descriptor to be read is longer than ATT_MTU - 1, this function must be called multiple times with appropriate offset to read - * the complete value. - * - * @events - * @event{@ref BLE_GATTC_EVT_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_VALUE_READ_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] handle The handle of the attribute to be read. - * @param[in] offset Offset into the attribute value to be read. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Read (Long) procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_READ, uint32_t, sd_ble_gattc_read(uint16_t conn_handle, uint16_t handle, uint16_t offset)); - -/**@brief Initiate a GATT Read Multiple Characteristic Values procedure. - * - * @details This function initiates a GATT Read Multiple Characteristic Values procedure. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_READ_MULT_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handles A pointer to the handle(s) of the attribute(s) to be read. - * @param[in] handle_count The number of handles in p_handles. - * - * @retval ::NRF_SUCCESS Successfully started the Read Multiple Characteristic Values procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t, - sd_ble_gattc_char_values_read(uint16_t conn_handle, uint16_t const *p_handles, uint16_t handle_count)); - -/**@brief Perform a Write (Characteristic Value or Descriptor, with or without response, signed or not, long or reliable) - * procedure. - * - * @details This function can perform all write procedures described in GATT. - * - * @note Only one write with response procedure can be ongoing per connection at a time. - * If the application tries to write with response while another write with response procedure is ongoing, - * the function call will return @ref NRF_ERROR_BUSY. - * A @ref BLE_GATTC_EVT_WRITE_RSP event will be issued as soon as the write response arrives from the peer. - * - * @note The number of Write without Response that can be queued is configured by @ref - * ble_gattc_conn_cfg_t::write_cmd_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. - * A @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event will be issued as soon as the transmission of the write without - * response is complete. - * - * @note The application can keep track of the available queue element count for writes without responses by following the - * procedure below: - * - Store initial queue element count in a variable. - * - Decrement the variable, which stores the currently available queue element count, by one when a call to this - * function returns @ref NRF_SUCCESS. - * - Increment the variable, which stores the current available queue element count, by the count variable in @ref - * BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event. - * - * @events - * @event{@ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE, Write without response transmission complete.} - * @event{@ref BLE_GATTC_EVT_WRITE_RSP, Write response received from the peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_VALUE_WRITE_WITHOUT_RESP_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_WRITE_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_LONG_WRITE_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_RELIABLE_WRITE_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_write_params A pointer to a write parameters structure. - * - * @retval ::NRF_SUCCESS Successfully started the Write procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_BUSY For write with response, procedure already in progress. Wait for a @ref BLE_GATTC_EVT_WRITE_RSP event - * and retry. - * @retval ::NRF_ERROR_RESOURCES Too many writes without responses queued. - * Wait for a @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event and retry. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_WRITE, uint32_t, sd_ble_gattc_write(uint16_t conn_handle, ble_gattc_write_params_t const *p_write_params)); - -/**@brief Send a Handle Value Confirmation to the GATT Server. - * - * @mscs - * @mmsc{@ref BLE_GATTC_HVI_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] handle The handle of the attribute in the indication. - * - * @retval ::NRF_SUCCESS Successfully queued the Handle Value Confirmation for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no Indication pending to be confirmed. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_HV_CONFIRM, uint32_t, sd_ble_gattc_hv_confirm(uint16_t conn_handle, uint16_t handle)); - -/**@brief Discovers information about a range of attributes on a GATT server. - * - * @events - * @event{@ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, Generated when information about a range of attributes has been received.} - * @endevents - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range The range of handles to request information about. - * - * @retval ::NRF_SUCCESS Successfully started an attribute information discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t, - sd_ble_gattc_attr_info_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Start an ATT_MTU exchange by sending an Exchange MTU Request to the server. - * - * @details The SoftDevice sets ATT_MTU to the minimum of: - * - The Client RX MTU value, and - * - The Server RX MTU value from @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. - * - * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. - * - * @events - * @event{@ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] client_rx_mtu Client RX MTU size. - * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration - used for this connection. - * - The value must be equal to Server RX MTU size given in @ref sd_ble_gatts_exchange_mtu_reply - * if an ATT_MTU exchange has already been performed in the other direction. - * - * @retval ::NRF_SUCCESS Successfully sent request to the server. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state or an ATT_MTU exchange was already requested once. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid Client RX MTU size supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, uint32_t, - sd_ble_gattc_exchange_mtu_request(uint16_t conn_handle, uint16_t client_rx_mtu)); - -/**@brief Iterate through Handle-Value(s) list in @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. - * - * @param[in] p_gattc_evt Pointer to event buffer containing @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. - * @note If the buffer contains different event, behavior is undefined. - * @param[in,out] p_iter Iterator, points to @ref ble_gattc_handle_value_t structure that will be filled in with - * the next Handle-Value pair in each iteration. If the function returns other than - * @ref NRF_SUCCESS, it will not be changed. - * - To start iteration, initialize the structure to zero. - * - To continue, pass the value from previous iteration. - * - * \code - * ble_gattc_handle_value_t iter; - * memset(&iter, 0, sizeof(ble_gattc_handle_value_t)); - * while (sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(&ble_evt.evt.gattc_evt, &iter) == NRF_SUCCESS) - * { - * app_handle = iter.handle; - * memcpy(app_value, iter.p_value, ble_evt.evt.gattc_evt.params.char_val_by_uuid_read_rsp.value_len); - * } - * \endcode - * - * @retval ::NRF_SUCCESS Successfully retrieved the next Handle-Value pair. - * @retval ::NRF_ERROR_NOT_FOUND No more Handle-Value pairs available in the list. - */ -__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, - ble_gattc_handle_value_t *p_iter); - -/** @} */ - -#ifndef SUPPRESS_INLINE_IMPLEMENTATION - -__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, - ble_gattc_handle_value_t *p_iter) -{ - uint32_t value_len = p_gattc_evt->params.char_val_by_uuid_read_rsp.value_len; - uint8_t *p_first = p_gattc_evt->params.char_val_by_uuid_read_rsp.handle_value; - uint8_t *p_next = p_iter->p_value ? p_iter->p_value + value_len : p_first; - - if ((p_next - p_first) / (sizeof(uint16_t) + value_len) < p_gattc_evt->params.char_val_by_uuid_read_rsp.count) { - p_iter->handle = (uint16_t)p_next[1] << 8 | p_next[0]; - p_iter->p_value = p_next + sizeof(uint16_t); - return NRF_SUCCESS; - } else { - return NRF_ERROR_NOT_FOUND; - } -} - -#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ - -#ifdef __cplusplus -} -#endif -#endif /* BLE_GATTC_H__ */ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_gatts.h b/variants/wio-tracker-wm1110/softdevice/ble_gatts.h deleted file mode 100644 index dc94957cd1..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_gatts.h +++ /dev/null @@ -1,904 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATTS Generic Attribute Profile (GATT) Server - @{ - @brief Definitions and prototypes for the GATTS interface. - */ - -#ifndef BLE_GATTS_H__ -#define BLE_GATTS_H__ - -#include "ble_err.h" -#include "ble_gap.h" -#include "ble_gatt.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATTS_ENUMERATIONS Enumerations - * @{ */ - -/** - * @brief GATTS API SVC numbers. - */ -enum BLE_GATTS_SVCS { - SD_BLE_GATTS_SERVICE_ADD = BLE_GATTS_SVC_BASE, /**< Add a service. */ - SD_BLE_GATTS_INCLUDE_ADD, /**< Add an included service. */ - SD_BLE_GATTS_CHARACTERISTIC_ADD, /**< Add a characteristic. */ - SD_BLE_GATTS_DESCRIPTOR_ADD, /**< Add a generic attribute. */ - SD_BLE_GATTS_VALUE_SET, /**< Set an attribute value. */ - SD_BLE_GATTS_VALUE_GET, /**< Get an attribute value. */ - SD_BLE_GATTS_HVX, /**< Handle Value Notification or Indication. */ - SD_BLE_GATTS_SERVICE_CHANGED, /**< Perform a Service Changed Indication to one or more peers. */ - SD_BLE_GATTS_RW_AUTHORIZE_REPLY, /**< Reply to an authorization request for a read or write operation on one or more - attributes. */ - SD_BLE_GATTS_SYS_ATTR_SET, /**< Set the persistent system attributes for a connection. */ - SD_BLE_GATTS_SYS_ATTR_GET, /**< Retrieve the persistent system attributes. */ - SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, /**< Retrieve the first valid user handle. */ - SD_BLE_GATTS_ATTR_GET, /**< Retrieve the UUID and/or metadata of an attribute. */ - SD_BLE_GATTS_EXCHANGE_MTU_REPLY /**< Reply to Exchange MTU Request. */ -}; - -/** - * @brief GATT Server Event IDs. - */ -enum BLE_GATTS_EVTS { - BLE_GATTS_EVT_WRITE = BLE_GATTS_EVT_BASE, /**< Write operation performed. \n See - @ref ble_gatts_evt_write_t. */ - BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST, /**< Read/Write Authorization request. \n Reply with - @ref sd_ble_gatts_rw_authorize_reply. \n See @ref ble_gatts_evt_rw_authorize_request_t. - */ - BLE_GATTS_EVT_SYS_ATTR_MISSING, /**< A persistent system attribute access is pending. \n Respond with @ref - sd_ble_gatts_sys_attr_set. \n See @ref ble_gatts_evt_sys_attr_missing_t. */ - BLE_GATTS_EVT_HVC, /**< Handle Value Confirmation. \n See @ref ble_gatts_evt_hvc_t. - */ - BLE_GATTS_EVT_SC_CONFIRM, /**< Service Changed Confirmation. \n No additional event - structure applies. */ - BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. \n Reply with - @ref sd_ble_gatts_exchange_mtu_reply. \n See @ref ble_gatts_evt_exchange_mtu_request_t. - */ - BLE_GATTS_EVT_TIMEOUT, /**< Peer failed to respond to an ATT request in time. \n See @ref - ble_gatts_evt_timeout_t. */ - BLE_GATTS_EVT_HVN_TX_COMPLETE /**< Handle Value Notification transmission complete. \n See @ref - ble_gatts_evt_hvn_tx_complete_t. */ -}; - -/**@brief GATTS Configuration IDs. - * - * IDs that uniquely identify a GATTS configuration. - */ -enum BLE_GATTS_CFGS { - BLE_GATTS_CFG_SERVICE_CHANGED = BLE_GATTS_CFG_BASE, /**< Service changed configuration. */ - BLE_GATTS_CFG_ATTR_TAB_SIZE, /**< Attribute table size configuration. */ - BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM, /**< Service changed CCCD permission configuration. */ -}; - -/** @} */ - -/** @addtogroup BLE_GATTS_DEFINES Defines - * @{ */ - -/** @defgroup BLE_ERRORS_GATTS SVC return values specific to GATTS - * @{ */ -#define BLE_ERROR_GATTS_INVALID_ATTR_TYPE (NRF_GATTS_ERR_BASE + 0x000) /**< Invalid attribute type. */ -#define BLE_ERROR_GATTS_SYS_ATTR_MISSING (NRF_GATTS_ERR_BASE + 0x001) /**< System Attributes missing. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_LENS_MAX Maximum attribute lengths - * @{ */ -#define BLE_GATTS_FIX_ATTR_LEN_MAX (510) /**< Maximum length for fixed length Attribute Values. */ -#define BLE_GATTS_VAR_ATTR_LEN_MAX (512) /**< Maximum length for variable length Attribute Values. */ -/** @} */ - -/** @defgroup BLE_GATTS_SRVC_TYPES GATT Server Service Types - * @{ */ -#define BLE_GATTS_SRVC_TYPE_INVALID 0x00 /**< Invalid Service Type. */ -#define BLE_GATTS_SRVC_TYPE_PRIMARY 0x01 /**< Primary Service. */ -#define BLE_GATTS_SRVC_TYPE_SECONDARY 0x02 /**< Secondary Type. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_TYPES GATT Server Attribute Types - * @{ */ -#define BLE_GATTS_ATTR_TYPE_INVALID 0x00 /**< Invalid Attribute Type. */ -#define BLE_GATTS_ATTR_TYPE_PRIM_SRVC_DECL 0x01 /**< Primary Service Declaration. */ -#define BLE_GATTS_ATTR_TYPE_SEC_SRVC_DECL 0x02 /**< Secondary Service Declaration. */ -#define BLE_GATTS_ATTR_TYPE_INC_DECL 0x03 /**< Include Declaration. */ -#define BLE_GATTS_ATTR_TYPE_CHAR_DECL 0x04 /**< Characteristic Declaration. */ -#define BLE_GATTS_ATTR_TYPE_CHAR_VAL 0x05 /**< Characteristic Value. */ -#define BLE_GATTS_ATTR_TYPE_DESC 0x06 /**< Descriptor. */ -#define BLE_GATTS_ATTR_TYPE_OTHER 0x07 /**< Other, non-GATT specific type. */ -/** @} */ - -/** @defgroup BLE_GATTS_OPS GATT Server Operations - * @{ */ -#define BLE_GATTS_OP_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATTS_OP_WRITE_REQ 0x01 /**< Write Request. */ -#define BLE_GATTS_OP_WRITE_CMD 0x02 /**< Write Command. */ -#define BLE_GATTS_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ -#define BLE_GATTS_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ -#define BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL 0x05 /**< Execute Write Request: Cancel all prepared writes. */ -#define BLE_GATTS_OP_EXEC_WRITE_REQ_NOW 0x06 /**< Execute Write Request: Immediately execute all prepared writes. */ -/** @} */ - -/** @defgroup BLE_GATTS_VLOCS GATT Value Locations - * @{ */ -#define BLE_GATTS_VLOC_INVALID 0x00 /**< Invalid Location. */ -#define BLE_GATTS_VLOC_STACK 0x01 /**< Attribute Value is located in stack memory, no user memory is required. */ -#define BLE_GATTS_VLOC_USER \ - 0x02 /**< Attribute Value is located in user memory. This requires the user to maintain a valid buffer through the lifetime \ - of the attribute, since the stack will read and write directly to the memory using the pointer provided in the APIs. \ - There are no alignment requirements for the buffer. */ -/** @} */ - -/** @defgroup BLE_GATTS_AUTHORIZE_TYPES GATT Server Authorization Types - * @{ */ -#define BLE_GATTS_AUTHORIZE_TYPE_INVALID 0x00 /**< Invalid Type. */ -#define BLE_GATTS_AUTHORIZE_TYPE_READ 0x01 /**< Authorize a Read Operation. */ -#define BLE_GATTS_AUTHORIZE_TYPE_WRITE 0x02 /**< Authorize a Write Request Operation. */ -/** @} */ - -/** @defgroup BLE_GATTS_SYS_ATTR_FLAGS System Attribute Flags - * @{ */ -#define BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS (1 << 0) /**< Restrict system attributes to system services only. */ -#define BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS (1 << 1) /**< Restrict system attributes to user services only. */ -/** @} */ - -/** @defgroup BLE_GATTS_SERVICE_CHANGED Service Changed Inclusion Values - * @{ - */ -#define BLE_GATTS_SERVICE_CHANGED_DEFAULT \ - (1) /**< Default is to include the Service Changed characteristic in the Attribute Table. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_TAB_SIZE Attribute Table size - * @{ - */ -#define BLE_GATTS_ATTR_TAB_SIZE_MIN (248) /**< Minimum Attribute Table size */ -#define BLE_GATTS_ATTR_TAB_SIZE_DEFAULT (1408) /**< Default Attribute Table size. */ -/** @} */ - -/** @defgroup BLE_GATTS_DEFAULTS GATT Server defaults - * @{ - */ -#define BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT \ - 1 /**< Default number of Handle Value Notifications that can be queued for transmission. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATTS_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATTS connection configuration parameters, set with @ref sd_ble_cfg_set. - */ -typedef struct { - uint8_t hvn_tx_queue_size; /**< Minimum guaranteed number of Handle Value Notifications that can be queued for transmission. - The default value is @ref BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT */ -} ble_gatts_conn_cfg_t; - -/**@brief Attribute metadata. */ -typedef struct { - ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */ - ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ - uint8_t vlen : 1; /**< Variable length attribute. */ - uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ - uint8_t rd_auth : 1; /**< Read authorization and value will be requested from the application on every read operation. */ - uint8_t wr_auth : 1; /**< Write authorization will be requested from the application on every Write Request operation (but not - Write Command). */ -} ble_gatts_attr_md_t; - -/**@brief GATT Attribute. */ -typedef struct { - ble_uuid_t const *p_uuid; /**< Pointer to the attribute UUID. */ - ble_gatts_attr_md_t const *p_attr_md; /**< Pointer to the attribute metadata structure. */ - uint16_t init_len; /**< Initial attribute value length in bytes. */ - uint16_t init_offs; /**< Initial attribute value offset in bytes. If different from zero, the first init_offs bytes of the - attribute value will be left uninitialized. */ - uint16_t max_len; /**< Maximum attribute value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */ - uint8_t *p_value; /**< Pointer to the attribute data. Please note that if the @ref BLE_GATTS_VLOC_USER value location is - selected in the attribute metadata, this will have to point to a buffer that remains valid through the - lifetime of the attribute. This excludes usage of automatic variables that may go out of scope or any - other temporary location. The stack may access that memory directly without the application's - knowledge. For writable characteristics, this value must not be a location in flash memory.*/ -} ble_gatts_attr_t; - -/**@brief GATT Attribute Value. */ -typedef struct { - uint16_t len; /**< Length in bytes to be written or read. Length in bytes written or read after successful return.*/ - uint16_t offset; /**< Attribute value offset. */ - uint8_t *p_value; /**< Pointer to where value is stored or will be stored. - If value is stored in user memory, only the attribute length is updated when p_value == NULL. - Set to NULL when reading to obtain the complete length of the attribute value */ -} ble_gatts_value_t; - -/**@brief GATT Characteristic Presentation Format. */ -typedef struct { - uint8_t format; /**< Format of the value, see @ref BLE_GATT_CPF_FORMATS. */ - int8_t exponent; /**< Exponent for integer data types. */ - uint16_t unit; /**< Unit from Bluetooth Assigned Numbers. */ - uint8_t name_space; /**< Namespace from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ - uint16_t desc; /**< Namespace description from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ -} ble_gatts_char_pf_t; - -/**@brief GATT Characteristic metadata. */ -typedef struct { - ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ - ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic Extended Properties. */ - uint8_t const * - p_char_user_desc; /**< Pointer to a UTF-8 encoded string (non-NULL terminated), NULL if the descriptor is not required. */ - uint16_t char_user_desc_max_size; /**< The maximum size in bytes of the user description descriptor. */ - uint16_t char_user_desc_size; /**< The size of the user description, must be smaller or equal to char_user_desc_max_size. */ - ble_gatts_char_pf_t const - *p_char_pf; /**< Pointer to a presentation format structure or NULL if the CPF descriptor is not required. */ - ble_gatts_attr_md_t const - *p_user_desc_md; /**< Attribute metadata for the User Description descriptor, or NULL for default values. */ - ble_gatts_attr_md_t const - *p_cccd_md; /**< Attribute metadata for the Client Characteristic Configuration Descriptor, or NULL for default values. */ - ble_gatts_attr_md_t const - *p_sccd_md; /**< Attribute metadata for the Server Characteristic Configuration Descriptor, or NULL for default values. */ -} ble_gatts_char_md_t; - -/**@brief GATT Characteristic Definition Handles. */ -typedef struct { - uint16_t value_handle; /**< Handle to the characteristic value. */ - uint16_t user_desc_handle; /**< Handle to the User Description descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */ - uint16_t cccd_handle; /**< Handle to the Client Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if - not present. */ - uint16_t sccd_handle; /**< Handle to the Server Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if - not present. */ -} ble_gatts_char_handles_t; - -/**@brief GATT HVx parameters. */ -typedef struct { - uint16_t handle; /**< Characteristic Value Handle. */ - uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ - uint16_t offset; /**< Offset within the attribute value. */ - uint16_t *p_len; /**< Length in bytes to be written, length in bytes written after return. */ - uint8_t const *p_data; /**< Actual data content, use NULL to use the current attribute value. */ -} ble_gatts_hvx_params_t; - -/**@brief GATT Authorization parameters. */ -typedef struct { - uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ - uint8_t update : 1; /**< If set, data supplied in p_data will be used to update the attribute value. - Please note that for @ref BLE_GATTS_AUTHORIZE_TYPE_WRITE operations this bit must always be set, - as the data to be written needs to be stored and later provided by the application. */ - uint16_t offset; /**< Offset of the attribute value being updated. */ - uint16_t len; /**< Length in bytes of the value in p_data pointer, see @ref BLE_GATTS_ATTR_LENS_MAX. */ - uint8_t const *p_data; /**< Pointer to new value used to update the attribute value. */ -} ble_gatts_authorize_params_t; - -/**@brief GATT Read or Write Authorize Reply parameters. */ -typedef struct { - uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ - union { - ble_gatts_authorize_params_t read; /**< Read authorization parameters. */ - ble_gatts_authorize_params_t write; /**< Write authorization parameters. */ - } params; /**< Reply Parameters. */ -} ble_gatts_rw_authorize_reply_params_t; - -/**@brief Service Changed Inclusion configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t service_changed : 1; /**< If 1, include the Service Changed characteristic in the Attribute Table. Default is @ref - BLE_GATTS_SERVICE_CHANGED_DEFAULT. */ -} ble_gatts_cfg_service_changed_t; - -/**@brief Service Changed CCCD permission configuration parameters, set with @ref sd_ble_cfg_set. - * - * @note @ref ble_gatts_attr_md_t::vlen is ignored and should be set to 0. - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - @ref ble_gatts_attr_md_t::write_perm is out of range. - * - @ref ble_gatts_attr_md_t::write_perm is @ref BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS, that is - * not allowed by the Bluetooth Specification. - * - wrong @ref ble_gatts_attr_md_t::read_perm, only @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN is - * allowed by the Bluetooth Specification. - * - wrong @ref ble_gatts_attr_md_t::vloc, only @ref BLE_GATTS_VLOC_STACK is allowed. - * @retval ::NRF_ERROR_NOT_SUPPORTED Security Mode 2 not supported - */ -typedef struct { - ble_gatts_attr_md_t - perm; /**< Permission for Service Changed CCCD. Default is @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN, no authorization. */ -} ble_gatts_cfg_service_changed_cccd_perm_t; - -/**@brief Attribute table size configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: - * - The specified Attribute Table size is too small. - * The minimum acceptable size is defined by @ref BLE_GATTS_ATTR_TAB_SIZE_MIN. - * - The specified Attribute Table size is not a multiple of 4. - */ -typedef struct { - uint32_t attr_tab_size; /**< Attribute table size. Default is @ref BLE_GATTS_ATTR_TAB_SIZE_DEFAULT, minimum is @ref - BLE_GATTS_ATTR_TAB_SIZE_MIN. */ -} ble_gatts_cfg_attr_tab_size_t; - -/**@brief Config structure for GATTS configurations. */ -typedef union { - ble_gatts_cfg_service_changed_t - service_changed; /**< Include service changed characteristic, cfg_id is @ref BLE_GATTS_CFG_SERVICE_CHANGED. */ - ble_gatts_cfg_service_changed_cccd_perm_t service_changed_cccd_perm; /**< Service changed CCCD permission, cfg_id is @ref - BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM. */ - ble_gatts_cfg_attr_tab_size_t attr_tab_size; /**< Attribute table size, cfg_id is @ref BLE_GATTS_CFG_ATTR_TAB_SIZE. */ -} ble_gatts_cfg_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_WRITE. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - ble_uuid_t uuid; /**< Attribute UUID. */ - uint8_t op; /**< Type of write operation, see @ref BLE_GATTS_OPS. */ - uint8_t auth_required; /**< Writing operation deferred due to authorization requirement. Application may use @ref - sd_ble_gatts_value_set to finalize the writing operation. */ - uint16_t offset; /**< Offset for the write operation. */ - uint16_t len; /**< Length of the received data. */ - uint8_t data[1]; /**< Received data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gatts_evt_write_t; - -/**@brief Event substructure for authorized read requests, see @ref ble_gatts_evt_rw_authorize_request_t. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - ble_uuid_t uuid; /**< Attribute UUID. */ - uint16_t offset; /**< Offset for the read operation. */ -} ble_gatts_evt_read_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST. */ -typedef struct { - uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ - union { - ble_gatts_evt_read_t read; /**< Attribute Read Parameters. */ - ble_gatts_evt_write_t write; /**< Attribute Write Parameters. */ - } request; /**< Request Parameters. */ -} ble_gatts_evt_rw_authorize_request_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. */ -typedef struct { - uint8_t hint; /**< Hint (currently unused). */ -} ble_gatts_evt_sys_attr_missing_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_HVC. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ -} ble_gatts_evt_hvc_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST. */ -typedef struct { - uint16_t client_rx_mtu; /**< Client RX MTU size. */ -} ble_gatts_evt_exchange_mtu_request_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ -} ble_gatts_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_HVN_TX_COMPLETE. */ -typedef struct { - uint8_t count; /**< Number of notification transmissions completed. */ -} ble_gatts_evt_hvn_tx_complete_t; - -/**@brief GATTS event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which the event occurred. */ - union { - ble_gatts_evt_write_t write; /**< Write Event Parameters. */ - ble_gatts_evt_rw_authorize_request_t authorize_request; /**< Read or Write Authorize Request Parameters. */ - ble_gatts_evt_sys_attr_missing_t sys_attr_missing; /**< System attributes missing. */ - ble_gatts_evt_hvc_t hvc; /**< Handle Value Confirmation Event Parameters. */ - ble_gatts_evt_exchange_mtu_request_t exchange_mtu_request; /**< Exchange MTU Request Event Parameters. */ - ble_gatts_evt_timeout_t timeout; /**< Timeout Event. */ - ble_gatts_evt_hvn_tx_complete_t hvn_tx_complete; /**< Handle Value Notification transmission complete Event Parameters. */ - } params; /**< Event Parameters. */ -} ble_gatts_evt_t; - -/** @} */ - -/** @addtogroup BLE_GATTS_FUNCTIONS Functions - * @{ */ - -/**@brief Add a service declaration to the Attribute Table. - * - * @note Secondary Services are only relevant in the context of the entity that references them, it is therefore forbidden to - * add a secondary service declaration that is not referenced by another service later in the Attribute Table. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] type Toggles between primary and secondary services, see @ref BLE_GATTS_SRVC_TYPES. - * @param[in] p_uuid Pointer to service UUID. - * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a service declaration. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, Vendor Specific UUIDs need to be present in the table. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type, ble_uuid_t const *p_uuid, uint16_t *p_handle)); - -/**@brief Add an include declaration to the Attribute Table. - * - * @note It is currently only possible to add an include declaration to the last added service (i.e. only sequential population is - * supported at this time). - * - * @note The included service must already be present in the Attribute Table prior to this call. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] service_handle Handle of the service where the included service is to be placed, if @ref BLE_GATT_HANDLE_INVALID - * is used, it will be placed sequentially. - * @param[in] inc_srvc_handle Handle of the included service. - * @param[out] p_include_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added an include declaration. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, handle values need to match previously added services. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. - * @retval ::NRF_ERROR_NOT_SUPPORTED Feature is not supported, service_handle must be that of the last added service. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, self inclusions are not allowed. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - */ -SVCALL(SD_BLE_GATTS_INCLUDE_ADD, uint32_t, - sd_ble_gatts_include_add(uint16_t service_handle, uint16_t inc_srvc_handle, uint16_t *p_include_handle)); - -/**@brief Add a characteristic declaration, a characteristic value declaration and optional characteristic descriptor declarations - * to the Attribute Table. - * - * @note It is currently only possible to add a characteristic to the last added service (i.e. only sequential population is - * supported at this time). - * - * @note Several restrictions apply to the parameters, such as matching permissions between the user description descriptor and - * the writable auxiliaries bits, readable (no security) and writable (selectable) CCCDs and SCCDs and valid presentation format - * values. - * - * @note If no metadata is provided for the optional descriptors, their permissions will be derived from the characteristic - * permissions. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] service_handle Handle of the service where the characteristic is to be placed, if @ref BLE_GATT_HANDLE_INVALID is - * used, it will be placed sequentially. - * @param[in] p_char_md Characteristic metadata. - * @param[in] p_attr_char_value Pointer to the attribute structure corresponding to the characteristic value. - * @param[out] p_handles Pointer to the structure where the assigned handles will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a characteristic. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, service handle, Vendor Specific UUIDs, lengths, and - * permissions need to adhere to the constraints. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - */ -SVCALL(SD_BLE_GATTS_CHARACTERISTIC_ADD, uint32_t, - sd_ble_gatts_characteristic_add(uint16_t service_handle, ble_gatts_char_md_t const *p_char_md, - ble_gatts_attr_t const *p_attr_char_value, ble_gatts_char_handles_t *p_handles)); - -/**@brief Add a descriptor to the Attribute Table. - * - * @note It is currently only possible to add a descriptor to the last added characteristic (i.e. only sequential population is - * supported at this time). - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] char_handle Handle of the characteristic where the descriptor is to be placed, if @ref BLE_GATT_HANDLE_INVALID is - * used, it will be placed sequentially. - * @param[in] p_attr Pointer to the attribute structure. - * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a descriptor. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, characteristic handle, Vendor Specific UUIDs, lengths, and - * permissions need to adhere to the constraints. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a characteristic context is required. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - */ -SVCALL(SD_BLE_GATTS_DESCRIPTOR_ADD, uint32_t, - sd_ble_gatts_descriptor_add(uint16_t char_handle, ble_gatts_attr_t const *p_attr, uint16_t *p_handle)); - -/**@brief Set the value of a given attribute. - * - * @note Values other than system attributes can be set at any time, regardless of whether any active connections exist. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. - * @param[in] handle Attribute handle. - * @param[in,out] p_value Attribute value information. - * - * @retval ::NRF_SUCCESS Successfully set the value of the attribute. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden handle supplied, certain attributes are not modifiable by the application. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. - */ -SVCALL(SD_BLE_GATTS_VALUE_SET, uint32_t, - sd_ble_gatts_value_set(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); - -/**@brief Get the value of a given attribute. - * - * @note If the attribute value is longer than the size of the supplied buffer, - * @ref ble_gatts_value_t::len will return the total attribute value length (excluding offset), - * and not the number of bytes actually returned in @ref ble_gatts_value_t::p_value. - * The application may use this information to allocate a suitable buffer size. - * - * @note When retrieving system attribute values with this function, the connection handle - * may refer to an already disconnected connection. Refer to the documentation of - * @ref sd_ble_gatts_sys_attr_get for further information. - * - * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. - * @param[in] handle Attribute handle. - * @param[in,out] p_value Attribute value information. - * - * @retval ::NRF_SUCCESS Successfully retrieved the value of the attribute. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid attribute offset supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - */ -SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, - sd_ble_gatts_value_get(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); - -/**@brief Notify or Indicate an attribute value. - * - * @details This function checks for the relevant Client Characteristic Configuration descriptor value to verify that the relevant - * operation (notification or indication) has been enabled by the client. It is also able to update the attribute value before - * issuing the PDU, so that the application can atomically perform a value update and a server initiated transaction with a single - * API call. - * - * @note The local attribute value may be updated even if an outgoing packet is not sent to the peer due to an error during - * execution. The Attribute Table has been updated if one of the following error codes is returned: @ref NRF_ERROR_INVALID_STATE, - * @ref NRF_ERROR_BUSY, - * @ref NRF_ERROR_FORBIDDEN, @ref BLE_ERROR_GATTS_SYS_ATTR_MISSING and @ref NRF_ERROR_RESOURCES. - * The caller can check whether the value has been updated by looking at the contents of *(@ref - * ble_gatts_hvx_params_t::p_len). - * - * @note Only one indication procedure can be ongoing per connection at a time. - * If the application tries to indicate an attribute value while another indication procedure is ongoing, - * the function call will return @ref NRF_ERROR_BUSY. - * A @ref BLE_GATTS_EVT_HVC event will be issued as soon as the confirmation arrives from the peer. - * - * @note The number of Handle Value Notifications that can be queued is configured by @ref - * ble_gatts_conn_cfg_t::hvn_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. A @ref - * BLE_GATTS_EVT_HVN_TX_COMPLETE event will be issued as soon as the transmission of the notification is complete. - * - * @note The application can keep track of the available queue element count for notifications by following the procedure - * below: - * - Store initial queue element count in a variable. - * - Decrement the variable, which stores the currently available queue element count, by one when a call to this - * function returns @ref NRF_SUCCESS. - * - Increment the variable, which stores the current available queue element count, by the count variable in @ref - * BLE_GATTS_EVT_HVN_TX_COMPLETE event. - * - * @events - * @event{@ref BLE_GATTS_EVT_HVN_TX_COMPLETE, Notification transmission complete.} - * @event{@ref BLE_GATTS_EVT_HVC, Confirmation received from the peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} - * @mmsc{@ref BLE_GATTS_HVN_MSC} - * @mmsc{@ref BLE_GATTS_HVI_MSC} - * @mmsc{@ref BLE_GATTS_HVX_DISABLED_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in,out] p_hvx_params Pointer to an HVx parameters structure. If @ref ble_gatts_hvx_params_t::p_data - * contains a non-NULL pointer the attribute value will be updated with the contents - * pointed by it before sending the notification or indication. If the attribute value - * is updated, @ref ble_gatts_hvx_params_t::p_len is updated by the SoftDevice to - * contain the number of actual bytes written, else it will be set to 0. - * - * @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute - * value. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: - * - Invalid Connection State - * - Notifications and/or indications not enabled in the CCCD - * - An ATT_MTU exchange is ongoing - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application - * are available to notify and indicate. - * @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and - * indicated. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_FORBIDDEN The connection's current security level is lower than the one required by the write permissions - * of the CCCD associated with this characteristic. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC - * event and retry. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - * @retval ::NRF_ERROR_RESOURCES Too many notifications queued. - * Wait for a @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event and retry. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_gatts_hvx_params_t const *p_hvx_params)); - -/**@brief Indicate the Service Changed attribute value. - * - * @details This call will send a Handle Value Indication to one or more peers connected to inform them that the Attribute - * Table layout has changed. As soon as the peer has confirmed the indication, a @ref BLE_GATTS_EVT_SC_CONFIRM event will - * be issued. - * - * @note Some of the restrictions and limitations that apply to @ref sd_ble_gatts_hvx also apply here. - * - * @events - * @event{@ref BLE_GATTS_EVT_SC_CONFIRM, Confirmation of attribute table change received from peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTS_SC_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] start_handle Start of affected attribute handle range. - * @param[in] end_handle End of affected attribute handle range. - * - * @retval ::NRF_SUCCESS Successfully queued the Service Changed indication for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_NOT_SUPPORTED Service Changed not enabled at initialization. See @ref - * sd_ble_cfg_set and @ref ble_gatts_cfg_service_changed_t. - * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: - * - Invalid Connection State - * - Notifications and/or indications not enabled in the CCCD - * - An ATT_MTU exchange is ongoing - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied, handles must be in the range populated by the - * application. - * @retval ::NRF_ERROR_BUSY Procedure already in progress. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t, - sd_ble_gatts_service_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle)); - -/**@brief Respond to a Read/Write authorization request. - * - * @note This call should only be used as a response to a @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event issued to the application. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_READ_REQ_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_WRITE_REQ_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_rw_authorize_reply_params Pointer to a structure with the attribute provided by the application. - * - * @note @ref ble_gatts_authorize_params_t::p_data is ignored when this function is used to respond - * to a @ref BLE_GATTS_AUTHORIZE_TYPE_READ event if @ref ble_gatts_authorize_params_t::update - * is set to 0. - * - * @retval ::NRF_SUCCESS Successfully queued a response to the peer, and in the case of a write operation, Attribute - * Table updated. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no authorization request pending. - * @retval ::NRF_ERROR_INVALID_PARAM Authorization op invalid, - * handle supplied does not match requested handle, - * or invalid data to be written provided by the application. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_RW_AUTHORIZE_REPLY, uint32_t, - sd_ble_gatts_rw_authorize_reply(uint16_t conn_handle, - ble_gatts_rw_authorize_reply_params_t const *p_rw_authorize_reply_params)); - -/**@brief Update persistent system attribute information. - * - * @details Supply information about persistent system attributes to the stack, - * previously obtained using @ref sd_ble_gatts_sys_attr_get. - * This call is only allowed for active connections, and is usually - * made immediately after a connection is established with an known bonded device, - * often as a response to a @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. - * - * p_sysattrs may point directly to the application's stored copy of the system attributes - * obtained using @ref sd_ble_gatts_sys_attr_get. - * If the pointer is NULL, the system attribute info is initialized, assuming that - * the application does not have any previously saved system attribute data for this device. - * - * @note The state of persistent system attributes is reset upon connection establishment and then remembered for its duration. - * - * @note If this call returns with an error code different from @ref NRF_SUCCESS, the storage of persistent system attributes may - * have been completed only partially. This means that the state of the attribute table is undefined, and the application should - * either provide a new set of attributes using this same call or reset the SoftDevice to return to a known state. - * - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system - * services will be modified. - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user - * services will be modified. - * - * @mscs - * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_UNK_PEER_MSC} - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_sys_attr_data Pointer to a saved copy of system attributes supplied to the stack, or NULL. - * @param[in] len Size of data pointed by p_sys_attr_data, in octets. - * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS - * - * @retval ::NRF_SUCCESS Successfully set the system attribute information. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. - * @retval ::NRF_ERROR_INVALID_DATA Invalid data supplied, the data should be exactly the same as retrieved with @ref - * sd_ble_gatts_sys_attr_get. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GATTS_SYS_ATTR_SET, uint32_t, - sd_ble_gatts_sys_attr_set(uint16_t conn_handle, uint8_t const *p_sys_attr_data, uint16_t len, uint32_t flags)); - -/**@brief Retrieve persistent system attribute information from the stack. - * - * @details This call is used to retrieve information about values to be stored persistently by the application - * during the lifetime of a connection or after it has been terminated. When a new connection is established with the - * same bonded device, the system attribute information retrieved with this function should be restored using using @ref - * sd_ble_gatts_sys_attr_set. If retrieved after disconnection, the data should be read before a new connection established. The - * connection handle for the previous, now disconnected, connection will remain valid until a new one is created to allow this API - * call to refer to it. Connection handles belonging to active connections can be used as well, but care should be taken since the - * system attributes may be written to at any time by the peer during a connection's lifetime. - * - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system - * services will be returned. - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user - * services will be returned. - * - * @mscs - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle of the recently terminated connection. - * @param[out] p_sys_attr_data Pointer to a buffer where updated information about system attributes will be filled in. The - * format of the data is described in @ref BLE_GATTS_SYS_ATTRS_FORMAT. NULL can be provided to obtain the length of the data. - * @param[in,out] p_len Size of application buffer if p_sys_attr_data is not NULL. Unconditionally updated to actual - * length of system attribute data. - * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS - * - * @retval ::NRF_SUCCESS Successfully retrieved the system attribute information. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. - * @retval ::NRF_ERROR_DATA_SIZE The system attribute information did not fit into the provided buffer. - * @retval ::NRF_ERROR_NOT_FOUND No system attributes found. - */ -SVCALL(SD_BLE_GATTS_SYS_ATTR_GET, uint32_t, - sd_ble_gatts_sys_attr_get(uint16_t conn_handle, uint8_t *p_sys_attr_data, uint16_t *p_len, uint32_t flags)); - -/**@brief Retrieve the first valid user attribute handle. - * - * @param[out] p_handle Pointer to an integer where the handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully retrieved the handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, uint32_t, sd_ble_gatts_initial_user_handle_get(uint16_t *p_handle)); - -/**@brief Retrieve the attribute UUID and/or metadata. - * - * @param[in] handle Attribute handle - * @param[out] p_uuid UUID of the attribute. Use NULL to omit this field. - * @param[out] p_md Metadata of the attribute. Use NULL to omit this field. - * - * @retval ::NRF_SUCCESS Successfully retrieved the attribute metadata, - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. Returned when both @c p_uuid and @c p_md are NULL. - * @retval ::NRF_ERROR_NOT_FOUND Attribute was not found. - */ -SVCALL(SD_BLE_GATTS_ATTR_GET, uint32_t, sd_ble_gatts_attr_get(uint16_t handle, ble_uuid_t *p_uuid, ble_gatts_attr_md_t *p_md)); - -/**@brief Reply to an ATT_MTU exchange request by sending an Exchange MTU Response to the client. - * - * @details This function is only used to reply to a @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event. - * - * @details The SoftDevice sets ATT_MTU to the minimum of: - * - The Client RX MTU value from @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, and - * - The Server RX MTU value. - * - * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. - * - * @mscs - * @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] server_rx_mtu Server RX MTU size. - * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration - * used for this connection. - * - The value must be equal to Client RX MTU size given in @ref sd_ble_gattc_exchange_mtu_request - * if an ATT_MTU exchange has already been performed in the other direction. - * - * @retval ::NRF_SUCCESS Successfully sent response to the client. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no ATT_MTU exchange request pending. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid Server RX MTU size supplied. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_EXCHANGE_MTU_REPLY, uint32_t, sd_ble_gatts_exchange_mtu_reply(uint16_t conn_handle, uint16_t server_rx_mtu)); -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GATTS_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_hci.h b/variants/wio-tracker-wm1110/softdevice/ble_hci.h deleted file mode 100644 index 27f85d52ea..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_hci.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ -*/ - -#ifndef BLE_HCI_H__ -#define BLE_HCI_H__ -#ifdef __cplusplus -extern "C" { -#endif - -/** @defgroup BLE_HCI_STATUS_CODES Bluetooth status codes - * @{ */ - -#define BLE_HCI_STATUS_CODE_SUCCESS 0x00 /**< Success. */ -#define BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND 0x01 /**< Unknown BLE Command. */ -#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02 /**< Unknown Connection Identifier. */ -/*0x03 Hardware Failure -0x04 Page Timeout -*/ -#define BLE_HCI_AUTHENTICATION_FAILURE 0x05 /**< Authentication Failure. */ -#define BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING 0x06 /**< Pin or Key missing. */ -#define BLE_HCI_MEMORY_CAPACITY_EXCEEDED 0x07 /**< Memory Capacity Exceeded. */ -#define BLE_HCI_CONNECTION_TIMEOUT 0x08 /**< Connection Timeout. */ -/*0x09 Connection Limit Exceeded -0x0A Synchronous Connection Limit To A Device Exceeded -0x0B ACL Connection Already Exists*/ -#define BLE_HCI_STATUS_CODE_COMMAND_DISALLOWED 0x0C /**< Command Disallowed. */ -/*0x0D Connection Rejected due to Limited Resources -0x0E Connection Rejected Due To Security Reasons -0x0F Connection Rejected due to Unacceptable BD_ADDR -0x10 Connection Accept Timeout Exceeded -0x11 Unsupported Feature or Parameter Value*/ -#define BLE_HCI_STATUS_CODE_INVALID_BTLE_COMMAND_PARAMETERS 0x12 /**< Invalid BLE Command Parameters. */ -#define BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION 0x13 /**< Remote User Terminated Connection. */ -#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES \ - 0x14 /**< Remote Device Terminated Connection due to low \ - resources.*/ -#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF 0x15 /**< Remote Device Terminated Connection due to power off. */ -#define BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION 0x16 /**< Local Host Terminated Connection. */ -/* -0x17 Repeated Attempts -0x18 Pairing Not Allowed -0x19 Unknown LMP PDU -*/ -#define BLE_HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A /**< Unsupported Remote Feature. */ -/* -0x1B SCO Offset Rejected -0x1C SCO Interval Rejected -0x1D SCO Air Mode Rejected*/ -#define BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS 0x1E /**< Invalid LMP Parameters. */ -#define BLE_HCI_STATUS_CODE_UNSPECIFIED_ERROR 0x1F /**< Unspecified Error. */ -/*0x20 Unsupported LMP Parameter Value -0x21 Role Change Not Allowed -*/ -#define BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT 0x22 /**< LMP Response Timeout. */ -#define BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION 0x23 /**< LMP Error Transaction Collision/LL Procedure Collision. */ -#define BLE_HCI_STATUS_CODE_LMP_PDU_NOT_ALLOWED 0x24 /**< LMP PDU Not Allowed. */ -/*0x25 Encryption Mode Not Acceptable -0x26 Link Key Can Not be Changed -0x27 Requested QoS Not Supported -*/ -#define BLE_HCI_INSTANT_PASSED 0x28 /**< Instant Passed. */ -#define BLE_HCI_PAIRING_WITH_UNIT_KEY_UNSUPPORTED 0x29 /**< Pairing with Unit Key Unsupported. */ -#define BLE_HCI_DIFFERENT_TRANSACTION_COLLISION 0x2A /**< Different Transaction Collision. */ -/* -0x2B Reserved -0x2C QoS Unacceptable Parameter -0x2D QoS Rejected -0x2E Channel Classification Not Supported -0x2F Insufficient Security -*/ -#define BLE_HCI_PARAMETER_OUT_OF_MANDATORY_RANGE 0x30 /**< Parameter Out Of Mandatory Range. */ -/* -0x31 Reserved -0x32 Role Switch Pending -0x33 Reserved -0x34 Reserved Slot Violation -0x35 Role Switch Failed -0x36 Extended Inquiry Response Too Large -0x37 Secure Simple Pairing Not Supported By Host. -0x38 Host Busy - Pairing -0x39 Connection Rejected due to No Suitable Channel Found*/ -#define BLE_HCI_CONTROLLER_BUSY 0x3A /**< Controller Busy. */ -#define BLE_HCI_CONN_INTERVAL_UNACCEPTABLE 0x3B /**< Connection Interval Unacceptable. */ -#define BLE_HCI_DIRECTED_ADVERTISER_TIMEOUT 0x3C /**< Directed Advertisement Timeout. */ -#define BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE 0x3D /**< Connection Terminated due to MIC Failure. */ -#define BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED 0x3E /**< Connection Failed to be Established. */ - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_HCI_H__ - -/** @} */ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h b/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h deleted file mode 100644 index 5f4bd277d3..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_l2cap.h +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_L2CAP Logical Link Control and Adaptation Protocol (L2CAP) - @{ - @brief Definitions and prototypes for the L2CAP interface. - */ - -#ifndef BLE_L2CAP_H__ -#define BLE_L2CAP_H__ - -#include "ble_err.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup BLE_L2CAP_TERMINOLOGY Terminology - * @{ - * @details - * - * L2CAP SDU - * - A data unit that the application can send/receive to/from a peer. - * - * L2CAP PDU - * - A data unit that is exchanged between local and remote L2CAP entities. - * It consists of L2CAP protocol control information and payload fields. - * The payload field can contain an L2CAP SDU or a part of an L2CAP SDU. - * - * L2CAP MTU - * - The maximum length of an L2CAP SDU. - * - * L2CAP MPS - * - The maximum length of an L2CAP PDU payload field. - * - * Credits - * - A value indicating the number of L2CAP PDUs that the receiver of the credit can send to the peer. - * @} */ - -/**@addtogroup BLE_L2CAP_ENUMERATIONS Enumerations - * @{ */ - -/**@brief L2CAP API SVC numbers. */ -enum BLE_L2CAP_SVCS { - SD_BLE_L2CAP_CH_SETUP = BLE_L2CAP_SVC_BASE + 0, /**< Set up an L2CAP channel. */ - SD_BLE_L2CAP_CH_RELEASE = BLE_L2CAP_SVC_BASE + 1, /**< Release an L2CAP channel. */ - SD_BLE_L2CAP_CH_RX = BLE_L2CAP_SVC_BASE + 2, /**< Receive an SDU on an L2CAP channel. */ - SD_BLE_L2CAP_CH_TX = BLE_L2CAP_SVC_BASE + 3, /**< Transmit an SDU on an L2CAP channel. */ - SD_BLE_L2CAP_CH_FLOW_CONTROL = BLE_L2CAP_SVC_BASE + 4, /**< Advanced SDU reception flow control. */ -}; - -/**@brief L2CAP Event IDs. */ -enum BLE_L2CAP_EVTS { - BLE_L2CAP_EVT_CH_SETUP_REQUEST = BLE_L2CAP_EVT_BASE + 0, /**< L2CAP Channel Setup Request event. - \n Reply with @ref sd_ble_l2cap_ch_setup. - \n See @ref ble_l2cap_evt_ch_setup_request_t. */ - BLE_L2CAP_EVT_CH_SETUP_REFUSED = BLE_L2CAP_EVT_BASE + 1, /**< L2CAP Channel Setup Refused event. - \n See @ref ble_l2cap_evt_ch_setup_refused_t. */ - BLE_L2CAP_EVT_CH_SETUP = BLE_L2CAP_EVT_BASE + 2, /**< L2CAP Channel Setup Completed event. - \n See @ref ble_l2cap_evt_ch_setup_t. */ - BLE_L2CAP_EVT_CH_RELEASED = BLE_L2CAP_EVT_BASE + 3, /**< L2CAP Channel Released event. - \n No additional event structure applies. */ - BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED = BLE_L2CAP_EVT_BASE + 4, /**< L2CAP Channel SDU data buffer released event. - \n See @ref ble_l2cap_evt_ch_sdu_buf_released_t. */ - BLE_L2CAP_EVT_CH_CREDIT = BLE_L2CAP_EVT_BASE + 5, /**< L2CAP Channel Credit received. - \n See @ref ble_l2cap_evt_ch_credit_t. */ - BLE_L2CAP_EVT_CH_RX = BLE_L2CAP_EVT_BASE + 6, /**< L2CAP Channel SDU received. - \n See @ref ble_l2cap_evt_ch_rx_t. */ - BLE_L2CAP_EVT_CH_TX = BLE_L2CAP_EVT_BASE + 7, /**< L2CAP Channel SDU transmitted. - \n See @ref ble_l2cap_evt_ch_tx_t. */ -}; - -/** @} */ - -/**@addtogroup BLE_L2CAP_DEFINES Defines - * @{ */ - -/**@brief Maximum number of L2CAP channels per connection. */ -#define BLE_L2CAP_CH_COUNT_MAX (64) - -/**@brief Minimum L2CAP MTU, in bytes. */ -#define BLE_L2CAP_MTU_MIN (23) - -/**@brief Minimum L2CAP MPS, in bytes. */ -#define BLE_L2CAP_MPS_MIN (23) - -/**@brief Invalid CID. */ -#define BLE_L2CAP_CID_INVALID (0x0000) - -/**@brief Default number of credits for @ref sd_ble_l2cap_ch_flow_control. */ -#define BLE_L2CAP_CREDITS_DEFAULT (1) - -/**@defgroup BLE_L2CAP_CH_SETUP_REFUSED_SRCS L2CAP channel setup refused sources - * @{ */ -#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_LOCAL (0x01) /**< Local. */ -#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_REMOTE (0x02) /**< Remote. */ - /** @} */ - -/** @defgroup BLE_L2CAP_CH_STATUS_CODES L2CAP channel status codes - * @{ */ -#define BLE_L2CAP_CH_STATUS_CODE_SUCCESS (0x0000) /**< Success. */ -#define BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED (0x0002) /**< LE_PSM not supported. */ -#define BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES (0x0004) /**< No resources available. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHENTICATION (0x0005) /**< Insufficient authentication. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHORIZATION (0x0006) /**< Insufficient authorization. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC_KEY_SIZE (0x0007) /**< Insufficient encryption key size. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC (0x0008) /**< Insufficient encryption. */ -#define BLE_L2CAP_CH_STATUS_CODE_INVALID_SCID (0x0009) /**< Invalid Source CID. */ -#define BLE_L2CAP_CH_STATUS_CODE_SCID_ALLOCATED (0x000A) /**< Source CID already allocated. */ -#define BLE_L2CAP_CH_STATUS_CODE_UNACCEPTABLE_PARAMS (0x000B) /**< Unacceptable parameters. */ -#define BLE_L2CAP_CH_STATUS_CODE_NOT_UNDERSTOOD \ - (0x8000) /**< Command Reject received instead of LE Credit Based Connection Response. */ -#define BLE_L2CAP_CH_STATUS_CODE_TIMEOUT (0xC000) /**< Operation timed out. */ -/** @} */ - -/** @} */ - -/**@addtogroup BLE_L2CAP_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE L2CAP connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @note These parameters are set per connection, so all L2CAP channels created on this connection - * will have the same parameters. - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - rx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. - * - tx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. - * - ch_count is greater than @ref BLE_L2CAP_CH_COUNT_MAX. - * @retval ::NRF_ERROR_NO_MEM rx_mps or tx_mps is set too high. - */ -typedef struct { - uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall - be able to receive on L2CAP channels on connections with this - configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ - uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall - be able to transmit on L2CAP channels on connections with this - configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ - uint8_t rx_queue_size; /**< Number of SDU data buffers that can be queued for reception per - L2CAP channel. The minimum value is one. */ - uint8_t tx_queue_size; /**< Number of SDU data buffers that can be queued for transmission - per L2CAP channel. The minimum value is one. */ - uint8_t ch_count; /**< Number of L2CAP channels the application can create per connection - with this configuration. The default value is zero, the maximum - value is @ref BLE_L2CAP_CH_COUNT_MAX. - @note if this parameter is set to zero, all other parameters in - @ref ble_l2cap_conn_cfg_t are ignored. */ -} ble_l2cap_conn_cfg_t; - -/**@brief L2CAP channel RX parameters. */ -typedef struct { - uint16_t rx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP shall be able to - receive on this L2CAP channel. - - Must be equal to or greater than @ref BLE_L2CAP_MTU_MIN. */ - uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall be - able to receive on this L2CAP channel. - - Must be equal to or greater than @ref BLE_L2CAP_MPS_MIN. - - Must be equal to or less than @ref ble_l2cap_conn_cfg_t::rx_mps. */ - ble_data_t sdu_buf; /**< SDU data buffer for reception. - - If @ref ble_data_t::p_data is non-NULL, initial credits are - issued to the peer. - - If @ref ble_data_t::p_data is NULL, no initial credits are - issued to the peer. */ -} ble_l2cap_ch_rx_params_t; - -/**@brief L2CAP channel setup parameters. */ -typedef struct { - ble_l2cap_ch_rx_params_t rx_params; /**< L2CAP channel RX parameters. */ - uint16_t le_psm; /**< LE Protocol/Service Multiplexer. Used when requesting - setup of an L2CAP channel, ignored otherwise. */ - uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES. - Used when replying to a setup request of an L2CAP - channel, ignored otherwise. */ -} ble_l2cap_ch_setup_params_t; - -/**@brief L2CAP channel TX parameters. */ -typedef struct { - uint16_t tx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP is able to - transmit on this L2CAP channel. */ - uint16_t peer_mps; /**< The maximum L2CAP PDU payload size, in bytes, that the peer is - able to receive on this L2CAP channel. */ - uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP is able - to transmit on this L2CAP channel. This is effective tx_mps, - selected by the SoftDevice as - MIN( @ref ble_l2cap_ch_tx_params_t::peer_mps, @ref ble_l2cap_conn_cfg_t::tx_mps ) */ - uint16_t credits; /**< Initial credits given by the peer. */ -} ble_l2cap_ch_tx_params_t; - -/**@brief L2CAP Channel Setup Request event. */ -typedef struct { - ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ - uint16_t le_psm; /**< LE Protocol/Service Multiplexer. */ -} ble_l2cap_evt_ch_setup_request_t; - -/**@brief L2CAP Channel Setup Refused event. */ -typedef struct { - uint8_t source; /**< Source, see @ref BLE_L2CAP_CH_SETUP_REFUSED_SRCS */ - uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES */ -} ble_l2cap_evt_ch_setup_refused_t; - -/**@brief L2CAP Channel Setup Completed event. */ -typedef struct { - ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ -} ble_l2cap_evt_ch_setup_t; - -/**@brief L2CAP Channel SDU Data Buffer Released event. */ -typedef struct { - ble_data_t sdu_buf; /**< Returned reception or transmission SDU data buffer. The SoftDevice - returns SDU data buffers supplied by the application, which have - not yet been returned previously via a @ref BLE_L2CAP_EVT_CH_RX or - @ref BLE_L2CAP_EVT_CH_TX event. */ -} ble_l2cap_evt_ch_sdu_buf_released_t; - -/**@brief L2CAP Channel Credit received event. */ -typedef struct { - uint16_t credits; /**< Additional credits given by the peer. */ -} ble_l2cap_evt_ch_credit_t; - -/**@brief L2CAP Channel received SDU event. */ -typedef struct { - uint16_t sdu_len; /**< Total SDU length, in bytes. */ - ble_data_t sdu_buf; /**< SDU data buffer. - @note If there is not enough space in the buffer - (sdu_buf.len < sdu_len) then the rest of the SDU will be - silently discarded by the SoftDevice. */ -} ble_l2cap_evt_ch_rx_t; - -/**@brief L2CAP Channel transmitted SDU event. */ -typedef struct { - ble_data_t sdu_buf; /**< SDU data buffer. */ -} ble_l2cap_evt_ch_tx_t; - -/**@brief L2CAP event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which the event occured. */ - uint16_t local_cid; /**< Local Channel ID of the L2CAP channel, or - @ref BLE_L2CAP_CID_INVALID if not present. */ - union { - ble_l2cap_evt_ch_setup_request_t ch_setup_request; /**< L2CAP Channel Setup Request Event Parameters. */ - ble_l2cap_evt_ch_setup_refused_t ch_setup_refused; /**< L2CAP Channel Setup Refused Event Parameters. */ - ble_l2cap_evt_ch_setup_t ch_setup; /**< L2CAP Channel Setup Completed Event Parameters. */ - ble_l2cap_evt_ch_sdu_buf_released_t ch_sdu_buf_released; /**< L2CAP Channel SDU Data Buffer Released Event Parameters. */ - ble_l2cap_evt_ch_credit_t credit; /**< L2CAP Channel Credit Received Event Parameters. */ - ble_l2cap_evt_ch_rx_t rx; /**< L2CAP Channel SDU Received Event Parameters. */ - ble_l2cap_evt_ch_tx_t tx; /**< L2CAP Channel SDU Transmitted Event Parameters. */ - } params; /**< Event Parameters. */ -} ble_l2cap_evt_t; - -/** @} */ - -/**@addtogroup BLE_L2CAP_FUNCTIONS Functions - * @{ */ - -/**@brief Set up an L2CAP channel. - * - * @details This function is used to: - * - Request setup of an L2CAP channel: sends an LE Credit Based Connection Request packet to a peer. - * - Reply to a setup request of an L2CAP channel (if called in response to a - * @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST event): sends an LE Credit Based Connection - * Response packet to a peer. - * - * @note A call to this function will require the application to keep the SDU data buffer alive - * until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX or - * @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_SETUP, Setup successful.} - * @event{@ref BLE_L2CAP_EVT_CH_SETUP_REFUSED, Setup failed.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_SETUP_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in,out] p_local_cid Pointer to a uint16_t containing Local Channel ID of the L2CAP channel: - * - As input: @ref BLE_L2CAP_CID_INVALID when requesting setup of an L2CAP - * channel or local_cid provided in the @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST - * event when replying to a setup request of an L2CAP channel. - * - As output: local_cid for this channel. - * @param[in] p_params L2CAP channel parameters. - * - * @retval ::NRF_SUCCESS Successfully queued request or response for transmission. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_LENGTH Supplied higher rx_mps than has been configured on this link. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (L2CAP channel already set up). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_RESOURCES The limit has been reached for available L2CAP channels, - * see @ref ble_l2cap_conn_cfg_t::ch_count. - */ -SVCALL(SD_BLE_L2CAP_CH_SETUP, uint32_t, - sd_ble_l2cap_ch_setup(uint16_t conn_handle, uint16_t *p_local_cid, ble_l2cap_ch_setup_params_t const *p_params)); - -/**@brief Release an L2CAP channel. - * - * @details This sends a Disconnection Request packet to a peer. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_RELEASED, Release complete.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_RELEASE_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * - * @retval ::NRF_SUCCESS Successfully queued request for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for the L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - */ -SVCALL(SD_BLE_L2CAP_CH_RELEASE, uint32_t, sd_ble_l2cap_ch_release(uint16_t conn_handle, uint16_t local_cid)); - -/**@brief Receive an SDU on an L2CAP channel. - * - * @details This may issue additional credits to the peer using an LE Flow Control Credit packet. - * - * @note A call to this function will require the application to keep the memory pointed by - * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX - * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::rx_queue_size SDU data buffers - * for reception per L2CAP channel. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_RX, The SDU is received.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_RX_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * @param[in] p_sdu_buf Pointer to the SDU data buffer. - * - * @retval ::NRF_SUCCESS Buffer accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for an L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_RESOURCES Too many SDU data buffers supplied. Wait for a - * @ref BLE_L2CAP_EVT_CH_RX event and retry. - */ -SVCALL(SD_BLE_L2CAP_CH_RX, uint32_t, sd_ble_l2cap_ch_rx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); - -/**@brief Transmit an SDU on an L2CAP channel. - * - * @note A call to this function will require the application to keep the memory pointed by - * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_TX - * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::tx_queue_size SDUs for - * transmission per L2CAP channel. - * - * @note The application can keep track of the available credits for transmission by following - * the procedure below: - * - Store initial credits given by the peer in a variable. - * (Initial credits are provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) - * - Decrement the variable, which stores the currently available credits, by - * ceiling((@ref ble_data_t::len + 2) / tx_mps) when a call to this function returns - * @ref NRF_SUCCESS. (tx_mps is provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) - * - Increment the variable, which stores the currently available credits, by additional - * credits given by the peer in a @ref BLE_L2CAP_EVT_CH_CREDIT event. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_TX, The SDU is transmitted.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_TX_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * @param[in] p_sdu_buf Pointer to the SDU data buffer. - * - * @retval ::NRF_SUCCESS Successfully queued L2CAP SDU for transmission. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for the L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_DATA_SIZE Invalid SDU length supplied, must not be more than - * @ref ble_l2cap_ch_tx_params_t::tx_mtu provided in - * @ref BLE_L2CAP_EVT_CH_SETUP event. - * @retval ::NRF_ERROR_RESOURCES Too many SDUs queued for transmission. Wait for a - * @ref BLE_L2CAP_EVT_CH_TX event and retry. - */ -SVCALL(SD_BLE_L2CAP_CH_TX, uint32_t, sd_ble_l2cap_ch_tx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); - -/**@brief Advanced SDU reception flow control. - * - * @details Adjust the way the SoftDevice issues credits to the peer. - * This may issue additional credits to the peer using an LE Flow Control Credit packet. - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_FLOW_CONTROL_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel or @ref BLE_L2CAP_CID_INVALID to set - * the value that will be used for newly created channels. - * @param[in] credits Number of credits that the SoftDevice will make sure the peer has every - * time it starts using a new reception buffer. - * - @ref BLE_L2CAP_CREDITS_DEFAULT is the default value the SoftDevice will - * use if this function is not called. - * - If set to zero, the SoftDevice will stop issuing credits for new reception - * buffers the application provides or has provided. SDU reception that is - * currently ongoing will be allowed to complete. - * @param[out] p_credits NULL or pointer to a uint16_t. If a valid pointer is provided, it will be - * written by the SoftDevice with the number of credits that is or will be - * available to the peer. If the value written by the SoftDevice is 0 when - * credits parameter was set to 0, the peer will not be able to send more - * data until more credits are provided by calling this function again with - * credits > 0. This parameter is ignored when local_cid is set to - * @ref BLE_L2CAP_CID_INVALID. - * - * @note Application should take care when setting number of credits higher than default value. In - * this case the application must make sure that the SoftDevice always has reception buffers - * available (see @ref sd_ble_l2cap_ch_rx) for that channel. If the SoftDevice does not have - * such buffers available, packets may be NACKed on the Link Layer and all Bluetooth traffic - * on the connection handle may be stalled until the SoftDevice again has an available - * reception buffer. This applies even if the application has used this call to set the - * credits back to default, or zero. - * - * @retval ::NRF_SUCCESS Flow control parameters accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for an L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - */ -SVCALL(SD_BLE_L2CAP_CH_FLOW_CONTROL, uint32_t, - sd_ble_l2cap_ch_flow_control(uint16_t conn_handle, uint16_t local_cid, uint16_t credits, uint16_t *p_credits)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_L2CAP_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_ranges.h b/variants/wio-tracker-wm1110/softdevice/ble_ranges.h deleted file mode 100644 index 2768e49967..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_ranges.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @defgroup ble_ranges Module specific SVC, event and option number subranges - @{ - - @brief Definition of SVC, event and option number subranges for each API module. - - @note - SVCs, event and option numbers are split into subranges for each API module. - Each module receives its entire allocated range of SVC calls, whether implemented or not, - but return BLE_ERROR_NOT_SUPPORTED for unimplemented or undefined calls in its range. - - Note that the symbols BLE__SVC_LAST is the end of the allocated SVC range, - rather than the last SVC function call actually defined and implemented. - - Specific SVC, event and option values are defined in each module's ble_.h file, - which defines names of each individual SVC code based on the range start value. -*/ - -#ifndef BLE_RANGES_H__ -#define BLE_RANGES_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#define BLE_SVC_BASE 0x60 /**< Common BLE SVC base. */ -#define BLE_SVC_LAST 0x6B /**< Common BLE SVC last. */ - -#define BLE_GAP_SVC_BASE 0x6C /**< GAP BLE SVC base. */ -#define BLE_GAP_SVC_LAST 0x9A /**< GAP BLE SVC last. */ - -#define BLE_GATTC_SVC_BASE 0x9B /**< GATTC BLE SVC base. */ -#define BLE_GATTC_SVC_LAST 0xA7 /**< GATTC BLE SVC last. */ - -#define BLE_GATTS_SVC_BASE 0xA8 /**< GATTS BLE SVC base. */ -#define BLE_GATTS_SVC_LAST 0xB7 /**< GATTS BLE SVC last. */ - -#define BLE_L2CAP_SVC_BASE 0xB8 /**< L2CAP BLE SVC base. */ -#define BLE_L2CAP_SVC_LAST 0xBF /**< L2CAP BLE SVC last. */ - -#define BLE_EVT_INVALID 0x00 /**< Invalid BLE Event. */ - -#define BLE_EVT_BASE 0x01 /**< Common BLE Event base. */ -#define BLE_EVT_LAST 0x0F /**< Common BLE Event last. */ - -#define BLE_GAP_EVT_BASE 0x10 /**< GAP BLE Event base. */ -#define BLE_GAP_EVT_LAST 0x2F /**< GAP BLE Event last. */ - -#define BLE_GATTC_EVT_BASE 0x30 /**< GATTC BLE Event base. */ -#define BLE_GATTC_EVT_LAST 0x4F /**< GATTC BLE Event last. */ - -#define BLE_GATTS_EVT_BASE 0x50 /**< GATTS BLE Event base. */ -#define BLE_GATTS_EVT_LAST 0x6F /**< GATTS BLE Event last. */ - -#define BLE_L2CAP_EVT_BASE 0x70 /**< L2CAP BLE Event base. */ -#define BLE_L2CAP_EVT_LAST 0x8F /**< L2CAP BLE Event last. */ - -#define BLE_OPT_INVALID 0x00 /**< Invalid BLE Option. */ - -#define BLE_OPT_BASE 0x01 /**< Common BLE Option base. */ -#define BLE_OPT_LAST 0x1F /**< Common BLE Option last. */ - -#define BLE_GAP_OPT_BASE 0x20 /**< GAP BLE Option base. */ -#define BLE_GAP_OPT_LAST 0x3F /**< GAP BLE Option last. */ - -#define BLE_GATT_OPT_BASE 0x40 /**< GATT BLE Option base. */ -#define BLE_GATT_OPT_LAST 0x5F /**< GATT BLE Option last. */ - -#define BLE_GATTC_OPT_BASE 0x60 /**< GATTC BLE Option base. */ -#define BLE_GATTC_OPT_LAST 0x7F /**< GATTC BLE Option last. */ - -#define BLE_GATTS_OPT_BASE 0x80 /**< GATTS BLE Option base. */ -#define BLE_GATTS_OPT_LAST 0x9F /**< GATTS BLE Option last. */ - -#define BLE_L2CAP_OPT_BASE 0xA0 /**< L2CAP BLE Option base. */ -#define BLE_L2CAP_OPT_LAST 0xBF /**< L2CAP BLE Option last. */ - -#define BLE_CFG_INVALID 0x00 /**< Invalid BLE configuration. */ - -#define BLE_CFG_BASE 0x01 /**< Common BLE configuration base. */ -#define BLE_CFG_LAST 0x1F /**< Common BLE configuration last. */ - -#define BLE_CONN_CFG_BASE 0x20 /**< BLE connection configuration base. */ -#define BLE_CONN_CFG_LAST 0x3F /**< BLE connection configuration last. */ - -#define BLE_GAP_CFG_BASE 0x40 /**< GAP BLE configuration base. */ -#define BLE_GAP_CFG_LAST 0x5F /**< GAP BLE configuration last. */ - -#define BLE_GATT_CFG_BASE 0x60 /**< GATT BLE configuration base. */ -#define BLE_GATT_CFG_LAST 0x7F /**< GATT BLE configuration last. */ - -#define BLE_GATTC_CFG_BASE 0x80 /**< GATTC BLE configuration base. */ -#define BLE_GATTC_CFG_LAST 0x9F /**< GATTC BLE configuration last. */ - -#define BLE_GATTS_CFG_BASE 0xA0 /**< GATTS BLE configuration base. */ -#define BLE_GATTS_CFG_LAST 0xBF /**< GATTS BLE configuration last. */ - -#define BLE_L2CAP_CFG_BASE 0xC0 /**< L2CAP BLE configuration base. */ -#define BLE_L2CAP_CFG_LAST 0xDF /**< L2CAP BLE configuration last. */ - -#ifdef __cplusplus -} -#endif -#endif /* BLE_RANGES_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/ble_types.h b/variants/wio-tracker-wm1110/softdevice/ble_types.h deleted file mode 100644 index db3656cfdd..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/ble_types.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @defgroup ble_types Common types and macro definitions - @{ - - @brief Common types and macro definitions for the BLE SoftDevice. - */ - -#ifndef BLE_TYPES_H__ -#define BLE_TYPES_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_TYPES_DEFINES Defines - * @{ */ - -/** @defgroup BLE_CONN_HANDLES BLE Connection Handles - * @{ */ -#define BLE_CONN_HANDLE_INVALID 0xFFFF /**< Invalid Connection Handle. */ -#define BLE_CONN_HANDLE_ALL 0xFFFE /**< Applies to all Connection Handles. */ -/** @} */ - -/** @defgroup BLE_UUID_VALUES Assigned Values for BLE UUIDs - * @{ */ -/* Generic UUIDs, applicable to all services */ -#define BLE_UUID_UNKNOWN 0x0000 /**< Reserved UUID. */ -#define BLE_UUID_SERVICE_PRIMARY 0x2800 /**< Primary Service. */ -#define BLE_UUID_SERVICE_SECONDARY 0x2801 /**< Secondary Service. */ -#define BLE_UUID_SERVICE_INCLUDE 0x2802 /**< Include. */ -#define BLE_UUID_CHARACTERISTIC 0x2803 /**< Characteristic. */ -#define BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP 0x2900 /**< Characteristic Extended Properties Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_USER_DESC 0x2901 /**< Characteristic User Description Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG 0x2902 /**< Client Characteristic Configuration Descriptor. */ -#define BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG 0x2903 /**< Server Characteristic Configuration Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT 0x2904 /**< Characteristic Presentation Format Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_AGGREGATE_FORMAT 0x2905 /**< Characteristic Aggregate Format Descriptor. */ -/* GATT specific UUIDs */ -#define BLE_UUID_GATT 0x1801 /**< Generic Attribute Profile. */ -#define BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED 0x2A05 /**< Service Changed Characteristic. */ -/* GAP specific UUIDs */ -#define BLE_UUID_GAP 0x1800 /**< Generic Access Profile. */ -#define BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME 0x2A00 /**< Device Name Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_APPEARANCE 0x2A01 /**< Appearance Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_RECONN_ADDR 0x2A03 /**< Reconnection Address Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_PPCP 0x2A04 /**< Peripheral Preferred Connection Parameters Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_CAR 0x2AA6 /**< Central Address Resolution Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_RPA_ONLY 0x2AC9 /**< Resolvable Private Address Only Characteristic. */ -/** @} */ - -/** @defgroup BLE_UUID_TYPES Types of UUID - * @{ */ -#define BLE_UUID_TYPE_UNKNOWN 0x00 /**< Invalid UUID type. */ -#define BLE_UUID_TYPE_BLE 0x01 /**< Bluetooth SIG UUID (16-bit). */ -#define BLE_UUID_TYPE_VENDOR_BEGIN 0x02 /**< Vendor UUID types start at this index (128-bit). */ -/** @} */ - -/** @defgroup BLE_APPEARANCES Bluetooth Appearance values - * @note Retrieved from - * http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml - * @{ */ -#define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */ -#define BLE_APPEARANCE_GENERIC_PHONE 64 /**< Generic Phone. */ -#define BLE_APPEARANCE_GENERIC_COMPUTER 128 /**< Generic Computer. */ -#define BLE_APPEARANCE_GENERIC_WATCH 192 /**< Generic Watch. */ -#define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /**< Watch: Sports Watch. */ -#define BLE_APPEARANCE_GENERIC_CLOCK 256 /**< Generic Clock. */ -#define BLE_APPEARANCE_GENERIC_DISPLAY 320 /**< Generic Display. */ -#define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /**< Generic Remote Control. */ -#define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /**< Generic Eye-glasses. */ -#define BLE_APPEARANCE_GENERIC_TAG 512 /**< Generic Tag. */ -#define BLE_APPEARANCE_GENERIC_KEYRING 576 /**< Generic Keyring. */ -#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /**< Generic Media Player. */ -#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /**< Generic Barcode Scanner. */ -#define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /**< Generic Thermometer. */ -#define BLE_APPEARANCE_THERMOMETER_EAR 769 /**< Thermometer: Ear. */ -#define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /**< Generic Heart rate Sensor. */ -#define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /**< Heart Rate Sensor: Heart Rate Belt. */ -#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /**< Generic Blood Pressure. */ -#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /**< Blood Pressure: Arm. */ -#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /**< Blood Pressure: Wrist. */ -#define BLE_APPEARANCE_GENERIC_HID 960 /**< Human Interface Device (HID). */ -#define BLE_APPEARANCE_HID_KEYBOARD 961 /**< Keyboard (HID Subtype). */ -#define BLE_APPEARANCE_HID_MOUSE 962 /**< Mouse (HID Subtype). */ -#define BLE_APPEARANCE_HID_JOYSTICK 963 /**< Joystick (HID Subtype). */ -#define BLE_APPEARANCE_HID_GAMEPAD 964 /**< Gamepad (HID Subtype). */ -#define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /**< Digitizer Tablet (HID Subtype). */ -#define BLE_APPEARANCE_HID_CARD_READER 966 /**< Card Reader (HID Subtype). */ -#define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /**< Digital Pen (HID Subtype). */ -#define BLE_APPEARANCE_HID_BARCODE 968 /**< Barcode Scanner (HID Subtype). */ -#define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /**< Generic Glucose Meter. */ -#define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /**< Generic Running Walking Sensor. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /**< Running Walking Sensor: In-Shoe. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /**< Running Walking Sensor: On-Shoe. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /**< Running Walking Sensor: On-Hip. */ -#define BLE_APPEARANCE_GENERIC_CYCLING 1152 /**< Generic Cycling. */ -#define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /**< Cycling: Cycling Computer. */ -#define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /**< Cycling: Speed Sensor. */ -#define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /**< Cycling: Cadence Sensor. */ -#define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /**< Cycling: Power Sensor. */ -#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /**< Cycling: Speed and Cadence Sensor. */ -#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /**< Generic Pulse Oximeter. */ -#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /**< Fingertip (Pulse Oximeter subtype). */ -#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /**< Wrist Worn(Pulse Oximeter subtype). */ -#define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /**< Generic Weight Scale. */ -#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /**< Generic Outdoor Sports Activity. */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /**< Location Display Device (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP \ - 5186 /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /**< Location Pod (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD \ - 5188 /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */ -/** @} */ - -/** @brief Set .type and .uuid fields of ble_uuid_struct to specified UUID value. */ -#define BLE_UUID_BLE_ASSIGN(instance, value) \ - do { \ - instance.type = BLE_UUID_TYPE_BLE; \ - instance.uuid = value; \ - } while (0) - -/** @brief Copy type and uuid members from src to dst ble_uuid_t pointer. Both pointers must be valid/non-null. */ -#define BLE_UUID_COPY_PTR(dst, src) \ - do { \ - (dst)->type = (src)->type; \ - (dst)->uuid = (src)->uuid; \ - } while (0) - -/** @brief Copy type and uuid members from src to dst ble_uuid_t struct. */ -#define BLE_UUID_COPY_INST(dst, src) \ - do { \ - (dst).type = (src).type; \ - (dst).uuid = (src).uuid; \ - } while (0) - -/** @brief Compare for equality both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ -#define BLE_UUID_EQ(p_uuid1, p_uuid2) (((p_uuid1)->type == (p_uuid2)->type) && ((p_uuid1)->uuid == (p_uuid2)->uuid)) - -/** @brief Compare for difference both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ -#define BLE_UUID_NEQ(p_uuid1, p_uuid2) (((p_uuid1)->type != (p_uuid2)->type) || ((p_uuid1)->uuid != (p_uuid2)->uuid)) - -/** @} */ - -/** @addtogroup BLE_TYPES_STRUCTURES Structures - * @{ */ - -/** @brief 128 bit UUID values. */ -typedef struct { - uint8_t uuid128[16]; /**< Little-Endian UUID bytes. */ -} ble_uuid128_t; - -/** @brief Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */ -typedef struct { - uint16_t uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */ - uint8_t - type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is @ref BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */ -} ble_uuid_t; - -/**@brief Data structure. */ -typedef struct { - uint8_t *p_data; /**< Pointer to the data buffer provided to/from the application. */ - uint16_t len; /**< Length of the data buffer, in bytes. */ -} ble_data_t; - -/** @} */ -#ifdef __cplusplus -} -#endif - -#endif /* BLE_TYPES_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h b/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h deleted file mode 100644 index 4e0bd752ab..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf52/nrf_mbr.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2014 - 2017, Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_mbr_api Master Boot Record API - @{ - - @brief APIs for updating SoftDevice and BootLoader - -*/ - -#ifndef NRF_MBR_H__ -#define NRF_MBR_H__ - -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup NRF_MBR_DEFINES Defines - * @{ */ - -/**@brief MBR SVC Base number. */ -#define MBR_SVC_BASE (0x18) - -/**@brief Page size in words. */ -#define MBR_PAGE_SIZE_IN_WORDS (1024) - -/** @brief The size that must be reserved for the MBR when a SoftDevice is written to flash. -This is the offset where the first byte of the SoftDevice hex file is written. */ -#define MBR_SIZE (0x1000) - -/** @brief Location (in the flash memory) of the bootloader address. */ -#define MBR_BOOTLOADER_ADDR (0xFF8) - -/** @brief Location (in UICR) of the bootloader address. */ -#define MBR_UICR_BOOTLOADER_ADDR (&(NRF_UICR->NRFFW[0])) - -/** @brief Location (in the flash memory) of the address of the MBR parameter page. */ -#define MBR_PARAM_PAGE_ADDR (0xFFC) - -/** @brief Location (in UICR) of the address of the MBR parameter page. */ -#define MBR_UICR_PARAM_PAGE_ADDR (&(NRF_UICR->NRFFW[1])) - -/** @} */ - -/** @addtogroup NRF_MBR_ENUMS Enumerations - * @{ */ - -/**@brief nRF Master Boot Record API SVC numbers. */ -enum NRF_MBR_SVCS { - SD_MBR_COMMAND = MBR_SVC_BASE, /**< ::sd_mbr_command */ -}; - -/**@brief Possible values for ::sd_mbr_command_t.command */ -enum NRF_MBR_COMMANDS { - SD_MBR_COMMAND_COPY_BL, /**< Copy a new BootLoader. @see ::sd_mbr_command_copy_bl_t*/ - SD_MBR_COMMAND_COPY_SD, /**< Copy a new SoftDevice. @see ::sd_mbr_command_copy_sd_t*/ - SD_MBR_COMMAND_INIT_SD, /**< Initialize forwarding interrupts to SD, and run reset function in SD. Does not require any - parameters in ::sd_mbr_command_t params.*/ - SD_MBR_COMMAND_COMPARE, /**< This command works like memcmp. @see ::sd_mbr_command_compare_t*/ - SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET, /**< Change the address the MBR starts after a reset. @see - ::sd_mbr_command_vector_table_base_set_t*/ - SD_MBR_COMMAND_RESERVED, - SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET, /**< Start forwarding all interrupts to this address. @see - ::sd_mbr_command_irq_forward_address_set_t*/ -}; - -/** @} */ - -/** @addtogroup NRF_MBR_TYPES Types - * @{ */ - -/**@brief This command copies part of a new SoftDevice - * - * The destination area is erased before copying. - * If dst is in the middle of a flash page, that whole flash page will be erased. - * If (dst+len) is in the middle of a flash page, that whole flash page will be erased. - * - * The user of this function is responsible for setting the BPROT registers. - * - * @retval ::NRF_SUCCESS indicates that the contents of the memory blocks where copied correctly. - * @retval ::NRF_ERROR_INTERNAL indicates that the contents of the memory blocks where not verified correctly after copying. - */ -typedef struct { - uint32_t *src; /**< Pointer to the source of data to be copied.*/ - uint32_t *dst; /**< Pointer to the destination where the content is to be copied.*/ - uint32_t len; /**< Number of 32 bit words to copy. Must be a multiple of @ref MBR_PAGE_SIZE_IN_WORDS words.*/ -} sd_mbr_command_copy_sd_t; - -/**@brief This command works like memcmp, but takes the length in words. - * - * @retval ::NRF_SUCCESS indicates that the contents of both memory blocks are equal. - * @retval ::NRF_ERROR_NULL indicates that the contents of the memory blocks are not equal. - */ -typedef struct { - uint32_t *ptr1; /**< Pointer to block of memory. */ - uint32_t *ptr2; /**< Pointer to block of memory. */ - uint32_t len; /**< Number of 32 bit words to compare.*/ -} sd_mbr_command_compare_t; - -/**@brief This command copies a new BootLoader. - * - * The MBR assumes that either @ref MBR_BOOTLOADER_ADDR or @ref MBR_UICR_BOOTLOADER_ADDR is set to - * the address where the bootloader will be copied. If both addresses are set, the MBR will prioritize - * @ref MBR_BOOTLOADER_ADDR. - * - * The bootloader destination is erased by this function. - * If (destination+bl_len) is in the middle of a flash page, that whole flash page will be erased. - * - * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, - * see @ref sd_mbr_command. - * - * This command will use the flash protect peripheral (BPROT or ACL) to protect the flash that is - * not intended to be written. - * - * On success, this function will not return. It will start the new bootloader from reset-vector as normal. - * - * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. - * @retval ::NRF_ERROR_FORBIDDEN if the bootloader address is not set. - * @retval ::NRF_ERROR_INVALID_LENGTH if parameters attempts to read or write outside flash area. - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. - */ -typedef struct { - uint32_t *bl_src; /**< Pointer to the source of the bootloader to be be copied.*/ - uint32_t bl_len; /**< Number of 32 bit words to copy for BootLoader. */ -} sd_mbr_command_copy_bl_t; - -/**@brief Change the address the MBR starts after a reset - * - * Once this function has been called, this address is where the MBR will start to forward - * interrupts to after a reset. - * - * To restore default forwarding, this function should be called with @ref address set to 0. If a - * bootloader is present, interrupts will be forwarded to the bootloader. If not, interrupts will - * be forwarded to the SoftDevice. - * - * The location of a bootloader can be specified in @ref MBR_BOOTLOADER_ADDR or - * @ref MBR_UICR_BOOTLOADER_ADDR. If both addresses are set, the MBR will prioritize - * @ref MBR_BOOTLOADER_ADDR. - * - * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, - * see @ref sd_mbr_command. - * - * On success, this function will not return. It will reset the device. - * - * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. - * @retval ::NRF_ERROR_INVALID_ADDR if parameter address is outside of the flash size. - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. - */ -typedef struct { - uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ -} sd_mbr_command_vector_table_base_set_t; - -/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the MBR - * - * Unlike sd_mbr_command_vector_table_base_set_t, this function does not reset, and it does not - * change where the MBR starts after reset. - * - * @retval ::NRF_SUCCESS - */ -typedef struct { - uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ -} sd_mbr_command_irq_forward_address_set_t; - -/**@brief Input structure containing data used when calling ::sd_mbr_command - * - * Depending on what command value that is set, the corresponding params value type must also be - * set. See @ref NRF_MBR_COMMANDS for command types and corresponding params value type. If command - * @ref SD_MBR_COMMAND_INIT_SD is set, it is not necessary to set any values under params. - */ -typedef struct { - uint32_t command; /**< Type of command to be issued. See @ref NRF_MBR_COMMANDS. */ - union { - sd_mbr_command_copy_sd_t copy_sd; /**< Parameters for copy SoftDevice.*/ - sd_mbr_command_compare_t compare; /**< Parameters for verify.*/ - sd_mbr_command_copy_bl_t copy_bl; /**< Parameters for copy BootLoader. Requires parameter page. */ - sd_mbr_command_vector_table_base_set_t base_set; /**< Parameters for vector table base set. Requires parameter page.*/ - sd_mbr_command_irq_forward_address_set_t irq_forward_address_set; /**< Parameters for irq forward address set*/ - } params; /**< Command parameters. */ -} sd_mbr_command_t; - -/** @} */ - -/** @addtogroup NRF_MBR_FUNCTIONS Functions - * @{ */ - -/**@brief Issue Master Boot Record commands - * - * Commands used when updating a SoftDevice and bootloader. - * - * The @ref SD_MBR_COMMAND_COPY_BL and @ref SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET requires - * parameters to be retained by the MBR when resetting the IC. This is done in a separate flash - * page. The location of the flash page should be provided by the application in either - * @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR. If both addresses are set, the MBR - * will prioritize @ref MBR_PARAM_PAGE_ADDR. This page will be cleared by the MBR and is used to - * store the command before reset. When an address is specified, the page it refers to must not be - * used by the application. If no address is provided by the application, i.e. both - * @ref MBR_PARAM_PAGE_ADDR and @ref MBR_UICR_PARAM_PAGE_ADDR is 0xFFFFFFFF, MBR commands which use - * flash will be unavailable and return @ref NRF_ERROR_NO_MEM. - * - * @param[in] param Pointer to a struct describing the command. - * - * @note For a complete set of return values, see ::sd_mbr_command_copy_sd_t, - * ::sd_mbr_command_copy_bl_t, ::sd_mbr_command_compare_t, - * ::sd_mbr_command_vector_table_base_set_t, ::sd_mbr_command_irq_forward_address_set_t - * - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page provided - * @retval ::NRF_ERROR_INVALID_PARAM if an invalid command is given. - */ -SVCALL(SD_MBR_COMMAND, uint32_t, sd_mbr_command(sd_mbr_command_t *param)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_MBR_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error.h b/variants/wio-tracker-wm1110/softdevice/nrf_error.h deleted file mode 100644 index fb2831e191..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_error.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_error SoftDevice Global Error Codes - @{ - - @brief Global Error definitions -*/ - -/* Header guard */ -#ifndef NRF_ERROR_H__ -#define NRF_ERROR_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** @defgroup NRF_ERRORS_BASE Error Codes Base number definitions - * @{ */ -#define NRF_ERROR_BASE_NUM (0x0) ///< Global error base -#define NRF_ERROR_SDM_BASE_NUM (0x1000) ///< SDM error base -#define NRF_ERROR_SOC_BASE_NUM (0x2000) ///< SoC error base -#define NRF_ERROR_STK_BASE_NUM (0x3000) ///< STK error base -/** @} */ - -#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command -#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing -#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled -#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error -#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation -#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found -#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported -#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter -#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state -#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length -#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags -#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data -#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Invalid Data size -#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out -#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer -#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation -#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address -#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy -#define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded. -#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h b/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h deleted file mode 100644 index 2fd6210576..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_error_sdm.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup nrf_sdm_api - @{ - @defgroup nrf_sdm_error SoftDevice Manager Error Codes - @{ - - @brief Error definitions for the SDM API -*/ - -/* Header guard */ -#ifndef NRF_ERROR_SDM_H__ -#define NRF_ERROR_SDM_H__ - -#include "nrf_error.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN (NRF_ERROR_SDM_BASE_NUM + 0) ///< Unknown LFCLK source. -#define NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION \ - (NRF_ERROR_SDM_BASE_NUM + 1) ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having - ///< enabled SoftDevice interrupts). -#define NRF_ERROR_SDM_INCORRECT_CLENR0 \ - (NRF_ERROR_SDM_BASE_NUM + 2) ///< Incorrect CLENR0 (can be caused by erroneous SoftDevice flashing). - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_SDM_H__ - -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h b/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h deleted file mode 100644 index cbd0ba8ac4..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_error_soc.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup nrf_soc_api - @{ - @defgroup nrf_soc_error SoC Library Error Codes - @{ - - @brief Error definitions for the SoC library - -*/ - -/* Header guard */ -#ifndef NRF_ERROR_SOC_H__ -#define NRF_ERROR_SOC_H__ - -#include "nrf_error.h" -#ifdef __cplusplus -extern "C" { -#endif - -/* Mutex Errors */ -#define NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN (NRF_ERROR_SOC_BASE_NUM + 0) ///< Mutex already taken - -/* NVIC errors */ -#define NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE (NRF_ERROR_SOC_BASE_NUM + 1) ///< NVIC interrupt not available -#define NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED (NRF_ERROR_SOC_BASE_NUM + 2) ///< NVIC interrupt priority not allowed -#define NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 3) ///< NVIC should not return - -/* Power errors */ -#define NRF_ERROR_SOC_POWER_MODE_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 4) ///< Power mode unknown -#define NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 5) ///< Power POF threshold unknown -#define NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 6) ///< Power off should not return - -/* Rand errors */ -#define NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES (NRF_ERROR_SOC_BASE_NUM + 7) ///< RAND not enough values - -/* PPI errors */ -#define NRF_ERROR_SOC_PPI_INVALID_CHANNEL (NRF_ERROR_SOC_BASE_NUM + 8) ///< Invalid PPI Channel -#define NRF_ERROR_SOC_PPI_INVALID_GROUP (NRF_ERROR_SOC_BASE_NUM + 9) ///< Invalid PPI Group - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_SOC_H__ -/** - @} - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h b/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h deleted file mode 100644 index d4ab204d96..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_nvic.h +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @defgroup nrf_nvic_api SoftDevice NVIC API - * @{ - * - * @note In order to use this module, the following code has to be added to a .c file: - * \code - * nrf_nvic_state_t nrf_nvic_state = {0}; - * \endcode - * - * @note Definitions and declarations starting with __ (double underscore) in this header file are - * not intended for direct use by the application. - * - * @brief APIs for the accessing NVIC when using a SoftDevice. - * - */ - -#ifndef NRF_NVIC_H__ -#define NRF_NVIC_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup NRF_NVIC_DEFINES Defines - * @{ */ - -/**@defgroup NRF_NVIC_ISER_DEFINES SoftDevice NVIC internal definitions - * @{ */ - -#define __NRF_NVIC_NVMC_IRQn \ - (30) /**< The peripheral ID of the NVMC. IRQ numbers are used to identify peripherals, but the NVMC doesn't have an IRQ \ - number in the MDK. */ - -#define __NRF_NVIC_ISER_COUNT (2) /**< The number of ISER/ICER registers in the NVIC that are used. */ - -/**@brief Interrupt priority levels used by the SoftDevice. */ -#define __NRF_NVIC_SD_IRQ_PRIOS \ - ((uint8_t)((1U << 0) /**< Priority level high .*/ \ - | (1U << 1) /**< Priority level medium. */ \ - | (1U << 4) /**< Priority level low. */ \ - )) - -/**@brief Interrupt priority levels available to the application. */ -#define __NRF_NVIC_APP_IRQ_PRIOS ((uint8_t)~__NRF_NVIC_SD_IRQ_PRIOS) - -/**@brief Interrupts used by the SoftDevice, with IRQn in the range 0-31. */ -#define __NRF_NVIC_SD_IRQS_0 \ - ((uint32_t)((1U << POWER_CLOCK_IRQn) | (1U << RADIO_IRQn) | (1U << RTC0_IRQn) | (1U << TIMER0_IRQn) | (1U << RNG_IRQn) | \ - (1U << ECB_IRQn) | (1U << CCM_AAR_IRQn) | (1U << TEMP_IRQn) | (1U << __NRF_NVIC_NVMC_IRQn) | \ - (1U << (uint32_t)SWI5_IRQn))) - -/**@brief Interrupts used by the SoftDevice, with IRQn in the range 32-63. */ -#define __NRF_NVIC_SD_IRQS_1 ((uint32_t)0) - -/**@brief Interrupts available for to application, with IRQn in the range 0-31. */ -#define __NRF_NVIC_APP_IRQS_0 (~__NRF_NVIC_SD_IRQS_0) - -/**@brief Interrupts available for to application, with IRQn in the range 32-63. */ -#define __NRF_NVIC_APP_IRQS_1 (~__NRF_NVIC_SD_IRQS_1) - -/**@} */ - -/**@} */ - -/**@addtogroup NRF_NVIC_VARIABLES Variables - * @{ */ - -/**@brief Type representing the state struct for the SoftDevice NVIC module. */ -typedef struct { - uint32_t volatile __irq_masks[__NRF_NVIC_ISER_COUNT]; /**< IRQs enabled by the application in the NVIC. */ - uint32_t volatile __cr_flag; /**< Non-zero if already in a critical region */ -} nrf_nvic_state_t; - -/**@brief Variable keeping the state for the SoftDevice NVIC module. This must be declared in an - * application source file. */ -extern nrf_nvic_state_t nrf_nvic_state; - -/**@} */ - -/**@addtogroup NRF_NVIC_INTERNAL_FUNCTIONS SoftDevice NVIC internal functions - * @{ */ - -/**@brief Disables IRQ interrupts globally, including the SoftDevice's interrupts. - * - * @retval The value of PRIMASK prior to disabling the interrupts. - */ -__STATIC_INLINE int __sd_nvic_irq_disable(void); - -/**@brief Enables IRQ interrupts globally, including the SoftDevice's interrupts. - */ -__STATIC_INLINE void __sd_nvic_irq_enable(void); - -/**@brief Checks if IRQn is available to application - * @param[in] IRQn IRQ to check - * - * @retval 1 (true) if the IRQ to check is available to the application - */ -__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn); - -/**@brief Checks if priority is available to application - * @param[in] priority priority to check - * - * @retval 1 (true) if the priority to check is available to the application - */ -__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority); - -/**@} */ - -/**@addtogroup NRF_NVIC_FUNCTIONS SoftDevice NVIC public functions - * @{ */ - -/**@brief Enable External Interrupt. - * @note Corresponds to NVIC_EnableIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_EnableIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt was enabled. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt has a priority not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn); - -/**@brief Disable External Interrupt. - * @note Corresponds to NVIC_DisableIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_DisableIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt was disabled. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn); - -/**@brief Get Pending Interrupt. - * @note Corresponds to NVIC_GetPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_GetPendingIRQ documentation in CMSIS. - * @param[out] p_pending_irq Return value from NVIC_GetPendingIRQ. - * - * @retval ::NRF_SUCCESS The interrupt is available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq); - -/**@brief Set Pending Interrupt. - * @note Corresponds to NVIC_SetPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_SetPendingIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt is set pending. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn); - -/**@brief Clear Pending Interrupt. - * @note Corresponds to NVIC_ClearPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_ClearPendingIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt pending flag is cleared. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn); - -/**@brief Set Interrupt Priority. - * @note Corresponds to NVIC_SetPriority in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * @pre Priority is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_SetPriority documentation in CMSIS. - * @param[in] priority A valid IRQ priority for use by the application. - * - * @retval ::NRF_SUCCESS The interrupt and priority level is available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt priority is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority); - -/**@brief Get Interrupt Priority. - * @note Corresponds to NVIC_GetPriority in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_GetPriority documentation in CMSIS. - * @param[out] p_priority Return value from NVIC_GetPriority. - * - * @retval ::NRF_SUCCESS The interrupt priority is returned in p_priority. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE - IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority); - -/**@brief System Reset. - * @note Corresponds to NVIC_SystemReset in CMSIS. - * - * @retval ::NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN - */ -__STATIC_INLINE uint32_t sd_nvic_SystemReset(void); - -/**@brief Enter critical region. - * - * @post Application interrupts will be disabled. - * @note sd_nvic_critical_region_enter() and ::sd_nvic_critical_region_exit() must be called in matching pairs inside each - * execution context - * @sa sd_nvic_critical_region_exit - * - * @param[out] p_is_nested_critical_region If 1, the application is now in a nested critical region. - * - * @retval ::NRF_SUCCESS - */ -__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region); - -/**@brief Exit critical region. - * - * @pre Application has entered a critical region using ::sd_nvic_critical_region_enter. - * @post If not in a nested critical region, the application interrupts will restored to the state before - * ::sd_nvic_critical_region_enter was called. - * - * @param[in] is_nested_critical_region If this is set to 1, the critical region won't be exited. @sa - * sd_nvic_critical_region_enter. - * - * @retval ::NRF_SUCCESS - */ -__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region); - -/**@} */ - -#ifndef SUPPRESS_INLINE_IMPLEMENTATION - -__STATIC_INLINE int __sd_nvic_irq_disable(void) -{ - int pm = __get_PRIMASK(); - __disable_irq(); - return pm; -} - -__STATIC_INLINE void __sd_nvic_irq_enable(void) -{ - __enable_irq(); -} - -__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn) -{ - if (IRQn < 32) { - return ((1UL << IRQn) & __NRF_NVIC_APP_IRQS_0) != 0; - } else if (IRQn < 64) { - return ((1UL << (IRQn - 32)) & __NRF_NVIC_APP_IRQS_1) != 0; - } else { - return 1; - } -} - -__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority) -{ - if ((priority >= (1 << __NVIC_PRIO_BITS)) || (((1 << priority) & __NRF_NVIC_APP_IRQ_PRIOS) == 0)) { - return 0; - } - return 1; -} - -__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - if (!__sd_nvic_is_app_accessible_priority(NVIC_GetPriority(IRQn))) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; - } - - if (nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] |= - (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F)); - } else { - NVIC_EnableIRQ(IRQn); - } - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - - if (nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] &= ~(1UL << ((uint32_t)(IRQn)&0x1F)); - } else { - NVIC_DisableIRQ(IRQn); - } - - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - *p_pending_irq = NVIC_GetPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - NVIC_SetPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - NVIC_ClearPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - - if (!__sd_nvic_is_app_accessible_priority(priority)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; - } - - NVIC_SetPriority(IRQn, (uint32_t)priority); - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - *p_priority = (NVIC_GetPriority(IRQn) & 0xFF); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SystemReset(void) -{ - NVIC_SystemReset(); - return NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN; -} - -__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region) -{ - int was_masked = __sd_nvic_irq_disable(); - if (!nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__cr_flag = 1; - nrf_nvic_state.__irq_masks[0] = (NVIC->ICER[0] & __NRF_NVIC_APP_IRQS_0); - NVIC->ICER[0] = __NRF_NVIC_APP_IRQS_0; - nrf_nvic_state.__irq_masks[1] = (NVIC->ICER[1] & __NRF_NVIC_APP_IRQS_1); - NVIC->ICER[1] = __NRF_NVIC_APP_IRQS_1; - *p_is_nested_critical_region = 0; - } else { - *p_is_nested_critical_region = 1; - } - if (!was_masked) { - __sd_nvic_irq_enable(); - } - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region) -{ - if (nrf_nvic_state.__cr_flag && (is_nested_critical_region == 0)) { - int was_masked = __sd_nvic_irq_disable(); - NVIC->ISER[0] = nrf_nvic_state.__irq_masks[0]; - NVIC->ISER[1] = nrf_nvic_state.__irq_masks[1]; - nrf_nvic_state.__cr_flag = 0; - if (!was_masked) { - __sd_nvic_irq_enable(); - } - } - - return NRF_SUCCESS; -} - -#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ - -#ifdef __cplusplus -} -#endif - -#endif // NRF_NVIC_H__ - -/**@} */ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h b/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h deleted file mode 100644 index 2786a86a45..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_sdm.h +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_sdm_api SoftDevice Manager API - @{ - - @brief APIs for SoftDevice management. - -*/ - -#ifndef NRF_SDM_H__ -#define NRF_SDM_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_sdm.h" -#include "nrf_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup NRF_SDM_DEFINES Defines - * @{ */ -#ifdef NRFSOC_DOXYGEN -/// Declared in nrf_mbr.h -#define MBR_SIZE 0 -#warning test -#endif - -/** @brief The major version for the SoftDevice binary distributed with this header file. */ -#define SD_MAJOR_VERSION (7) - -/** @brief The minor version for the SoftDevice binary distributed with this header file. */ -#define SD_MINOR_VERSION (3) - -/** @brief The bugfix version for the SoftDevice binary distributed with this header file. */ -#define SD_BUGFIX_VERSION (0) - -/** @brief The SoftDevice variant of this firmware. */ -#define SD_VARIANT_ID 140 - -/** @brief The full version number for the SoftDevice binary this header file was distributed - * with, as a decimal number in the form Mmmmbbb, where: - * - M is major version (one or more digits) - * - mmm is minor version (three digits) - * - bbb is bugfix version (three digits). */ -#define SD_VERSION (SD_MAJOR_VERSION * 1000000 + SD_MINOR_VERSION * 1000 + SD_BUGFIX_VERSION) - -/** @brief SoftDevice Manager SVC Base number. */ -#define SDM_SVC_BASE 0x10 - -/** @brief SoftDevice unique string size in bytes. */ -#define SD_UNIQUE_STR_SIZE 20 - -/** @brief Invalid info field. Returned when an info field does not exist. */ -#define SDM_INFO_FIELD_INVALID (0) - -/** @brief Defines the SoftDevice Information Structure location (address) as an offset from -the start of the SoftDevice (without MBR)*/ -#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000) - -/** @brief Defines the absolute SoftDevice Information Structure location (address) when the - * SoftDevice is installed just above the MBR (the usual case). */ -#define SOFTDEVICE_INFO_STRUCT_ADDRESS (SOFTDEVICE_INFO_STRUCT_OFFSET + MBR_SIZE) - -/** @brief Defines the offset for the SoftDevice Information Structure size value relative to the - * SoftDevice base address. The size value is of type uint8_t. */ -#define SD_INFO_STRUCT_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET) - -/** @brief Defines the offset for the SoftDevice size value relative to the SoftDevice base address. - * The size value is of type uint32_t. */ -#define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08) - -/** @brief Defines the offset for FWID value relative to the SoftDevice base address. The FWID value - * is of type uint16_t. */ -#define SD_FWID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x0C) - -/** @brief Defines the offset for the SoftDevice ID relative to the SoftDevice base address. The ID - * is of type uint32_t. */ -#define SD_ID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x10) - -/** @brief Defines the offset for the SoftDevice version relative to the SoftDevice base address in - * the same format as @ref SD_VERSION, stored as an uint32_t. */ -#define SD_VERSION_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x14) - -/** @brief Defines the offset for the SoftDevice unique string relative to the SoftDevice base address. - * The SD_UNIQUE_STR is stored as an array of uint8_t. The size of array is @ref SD_UNIQUE_STR_SIZE. - */ -#define SD_UNIQUE_STR_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x18) - -/** @brief Defines a macro for retrieving the actual SoftDevice Information Structure size value - * from a given base address. Use @ref MBR_SIZE as the argument when the SoftDevice is - * installed just above the MBR (the usual case). */ -#define SD_INFO_STRUCT_SIZE_GET(baseaddr) (*((uint8_t *)((baseaddr) + SD_INFO_STRUCT_SIZE_OFFSET))) - -/** @brief Defines a macro for retrieving the actual SoftDevice size value from a given base - * address. Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above - * the MBR (the usual case). */ -#define SD_SIZE_GET(baseaddr) (*((uint32_t *)((baseaddr) + SD_SIZE_OFFSET))) - -/** @brief Defines the amount of flash that is used by the SoftDevice. - * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed - * just above the MBR (the usual case). - */ -#define SD_FLASH_SIZE 0x26000 - -/** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use - * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual - * case). */ -#define SD_FWID_GET(baseaddr) (*((uint16_t *)((baseaddr) + SD_FWID_OFFSET))) - -/** @brief Defines a macro for retrieving the actual SoftDevice ID from a given base address. Use - * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the - * usual case). */ -#define SD_ID_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_ID_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (*((uint32_t *)((baseaddr) + SD_ID_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/** @brief Defines a macro for retrieving the actual SoftDevice version from a given base address. - * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR - * (the usual case). */ -#define SD_VERSION_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_VERSION_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (*((uint32_t *)((baseaddr) + SD_VERSION_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/** @brief Defines a macro for retrieving the address of SoftDevice unique str based on a given base address. - * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR - * (the usual case). */ -#define SD_UNIQUE_STR_ADDR_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_UNIQUE_STR_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (((uint8_t *)((baseaddr) + SD_UNIQUE_STR_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/**@defgroup NRF_FAULT_ID_RANGES Fault ID ranges - * @{ */ -#define NRF_FAULT_ID_SD_RANGE_START 0x00000000 /**< SoftDevice ID range start. */ -#define NRF_FAULT_ID_APP_RANGE_START 0x00001000 /**< Application ID range start. */ -/**@} */ - -/**@defgroup NRF_FAULT_IDS Fault ID types - * @{ */ -#define NRF_FAULT_ID_SD_ASSERT \ - (NRF_FAULT_ID_SD_RANGE_START + 1) /**< SoftDevice assertion. The info parameter is reserved for future used. */ -#define NRF_FAULT_ID_APP_MEMACC \ - (NRF_FAULT_ID_APP_RANGE_START + 1) /**< Application invalid memory access. The info parameter will contain 0x00000000, \ - in case of SoftDevice RAM access violation. In case of SoftDevice peripheral \ - register violation the info parameter will contain the sub-region number of \ - PREGION[0], on whose address range the disallowed write access caused the \ - memory access fault. */ -/**@} */ - -/** @} */ - -/** @addtogroup NRF_SDM_ENUMS Enumerations - * @{ */ - -/**@brief nRF SoftDevice Manager API SVC numbers. */ -enum NRF_SD_SVCS { - SD_SOFTDEVICE_ENABLE = SDM_SVC_BASE, /**< ::sd_softdevice_enable */ - SD_SOFTDEVICE_DISABLE, /**< ::sd_softdevice_disable */ - SD_SOFTDEVICE_IS_ENABLED, /**< ::sd_softdevice_is_enabled */ - SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, /**< ::sd_softdevice_vector_table_base_set */ - SVC_SDM_LAST /**< Placeholder for last SDM SVC */ -}; - -/** @} */ - -/** @addtogroup NRF_SDM_DEFINES Defines - * @{ */ - -/**@defgroup NRF_CLOCK_LF_ACCURACY Clock accuracy - * @{ */ - -#define NRF_CLOCK_LF_ACCURACY_250_PPM (0) /**< Default: 250 ppm */ -#define NRF_CLOCK_LF_ACCURACY_500_PPM (1) /**< 500 ppm */ -#define NRF_CLOCK_LF_ACCURACY_150_PPM (2) /**< 150 ppm */ -#define NRF_CLOCK_LF_ACCURACY_100_PPM (3) /**< 100 ppm */ -#define NRF_CLOCK_LF_ACCURACY_75_PPM (4) /**< 75 ppm */ -#define NRF_CLOCK_LF_ACCURACY_50_PPM (5) /**< 50 ppm */ -#define NRF_CLOCK_LF_ACCURACY_30_PPM (6) /**< 30 ppm */ -#define NRF_CLOCK_LF_ACCURACY_20_PPM (7) /**< 20 ppm */ -#define NRF_CLOCK_LF_ACCURACY_10_PPM (8) /**< 10 ppm */ -#define NRF_CLOCK_LF_ACCURACY_5_PPM (9) /**< 5 ppm */ -#define NRF_CLOCK_LF_ACCURACY_2_PPM (10) /**< 2 ppm */ -#define NRF_CLOCK_LF_ACCURACY_1_PPM (11) /**< 1 ppm */ - -/** @} */ - -/**@defgroup NRF_CLOCK_LF_SRC Possible LFCLK oscillator sources - * @{ */ - -#define NRF_CLOCK_LF_SRC_RC (0) /**< LFCLK RC oscillator. */ -#define NRF_CLOCK_LF_SRC_XTAL (1) /**< LFCLK crystal oscillator. */ -#define NRF_CLOCK_LF_SRC_SYNTH (2) /**< LFCLK Synthesized from HFCLK. */ - -/** @} */ - -/** @} */ - -/** @addtogroup NRF_SDM_TYPES Types - * @{ */ - -/**@brief Type representing LFCLK oscillator source. */ -typedef struct { - uint8_t source; /**< LF oscillator clock source, see @ref NRF_CLOCK_LF_SRC. */ - uint8_t rc_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: Calibration timer interval in 1/4 second - units (nRF52: 1-32). - @note To avoid excessive clock drift, 0.5 degrees Celsius is the - maximum temperature change allowed in one calibration timer - interval. The interval should be selected to ensure this. - - @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. */ - uint8_t rc_temp_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: How often (in number of calibration - intervals) the RC oscillator shall be calibrated if the temperature - hasn't changed. - 0: Always calibrate even if the temperature hasn't changed. - 1: Only calibrate if the temperature has changed (legacy - nRF51 only). - 2-33: Check the temperature and only calibrate if it has changed, - however calibration will take place every rc_temp_ctiv - intervals in any case. - - @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. - - @note For nRF52, the application must ensure calibration at least once - every 8 seconds to ensure +/-500 ppm clock stability. The - recommended configuration for ::NRF_CLOCK_LF_SRC_RC on nRF52 is - rc_ctiv=16 and rc_temp_ctiv=2. This will ensure calibration at - least once every 8 seconds and for temperature changes of 0.5 - degrees Celsius every 4 seconds. See the Product Specification - for the nRF52 device being used for more information.*/ - uint8_t accuracy; /**< External clock accuracy used in the LL to compute timing - windows, see @ref NRF_CLOCK_LF_ACCURACY.*/ -} nrf_clock_lf_cfg_t; - -/**@brief Fault Handler type. - * - * When certain unrecoverable errors occur within the application or SoftDevice the fault handler will be called back. - * The protocol stack will be in an undefined state when this happens and the only way to recover will be to - * perform a reset, using e.g. CMSIS NVIC_SystemReset(). - * If the application returns from the fault handler the SoftDevice will call NVIC_SystemReset(). - * - * @note It is recommended to either perform a reset in the fault handler or to let the SoftDevice reset the device. - * Otherwise SoC peripherals may behave in an undefined way. For example, the RADIO peripherial may - * continously transmit packets. - * - * @note This callback is executed in HardFault context, thus SVC functions cannot be called from the fault callback. - * - * @param[in] id Fault identifier. See @ref NRF_FAULT_IDS. - * @param[in] pc The program counter of the instruction that triggered the fault. - * @param[in] info Optional additional information regarding the fault. Refer to each Fault identifier for details. - * - * @note When id is set to @ref NRF_FAULT_ID_APP_MEMACC, pc will contain the address of the instruction being executed at the time - * when the fault is detected by the CPU. The CPU program counter may have advanced up to 2 instructions (no branching) after the - * one that triggered the fault. - */ -typedef void (*nrf_fault_handler_t)(uint32_t id, uint32_t pc, uint32_t info); - -/** @} */ - -/** @addtogroup NRF_SDM_FUNCTIONS Functions - * @{ */ - -/**@brief Enables the SoftDevice and by extension the protocol stack. - * - * @note Some care must be taken if a low frequency clock source is already running when calling this function: - * If the LF clock has a different source then the one currently running, it will be stopped. Then, the new - * clock source will be started. - * - * @note This function has no effect when returning with an error. - * - * @post If return code is ::NRF_SUCCESS - * - SoC library and protocol stack APIs are made available. - * - A portion of RAM will be unavailable (see relevant SDS documentation). - * - Some peripherals will be unavailable or available only through the SoC API (see relevant SDS documentation). - * - Interrupts will not arrive from protected peripherals or interrupts. - * - nrf_nvic_ functions must be used instead of CMSIS NVIC_ functions for reliable usage of the SoftDevice. - * - Interrupt latency may be affected by the SoftDevice (see relevant SDS documentation). - * - Chosen low frequency clock source will be running. - * - * @param p_clock_lf_cfg Low frequency clock source and accuracy. - If NULL the clock will be configured as an RC source with rc_ctiv = 16 and .rc_temp_ctiv = 2 - In the case of XTAL source, the PPM accuracy of the chosen clock source must be greater than or equal to - the actual characteristics of your XTAL clock. - * @param fault_handler Callback to be invoked in case of fault, cannot be NULL. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE SoftDevice is already enabled, and the clock source and fault handler cannot be updated. - * @retval ::NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION SoftDevice interrupt is already enabled, or an enabled interrupt has - an illegal priority level. - * @retval ::NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN Unknown low frequency clock source selected. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid clock source configuration supplied in p_clock_lf_cfg. - */ -SVCALL(SD_SOFTDEVICE_ENABLE, uint32_t, - sd_softdevice_enable(nrf_clock_lf_cfg_t const *p_clock_lf_cfg, nrf_fault_handler_t fault_handler)); - -/**@brief Disables the SoftDevice and by extension the protocol stack. - * - * Idempotent function to disable the SoftDevice. - * - * @post SoC library and protocol stack APIs are made unavailable. - * @post All interrupts that was protected by the SoftDevice will be disabled and initialized to priority 0 (highest). - * @post All peripherals used by the SoftDevice will be reset to default values. - * @post All of RAM become available. - * @post All interrupts are forwarded to the application. - * @post LFCLK source chosen in ::sd_softdevice_enable will be left running. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_DISABLE, uint32_t, sd_softdevice_disable(void)); - -/**@brief Check if the SoftDevice is enabled. - * - * @param[out] p_softdevice_enabled If the SoftDevice is enabled: 1 else 0. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_IS_ENABLED, uint32_t, sd_softdevice_is_enabled(uint8_t *p_softdevice_enabled)); - -/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the SoftDevice - * - * This function is only intended to be called when a bootloader is enabled. - * - * @param[in] address The base address of the interrupt vector table for forwarded interrupts. - - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table_base_set(uint32_t address)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_SDM_H__ - -/** - @} -*/ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_soc.h b/variants/wio-tracker-wm1110/softdevice/nrf_soc.h deleted file mode 100644 index c649ca836d..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_soc.h +++ /dev/null @@ -1,1046 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @defgroup nrf_soc_api SoC Library API - * @{ - * - * @brief APIs for the SoC library. - * - */ - -#ifndef NRF_SOC_H__ -#define NRF_SOC_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup NRF_SOC_DEFINES Defines - * @{ */ - -/**@brief The number of the lowest SVC number reserved for the SoC library. */ -#define SOC_SVC_BASE (0x20) /**< Base value for SVCs that are available when the SoftDevice is disabled. */ -#define SOC_SVC_BASE_NOT_AVAILABLE (0x2C) /**< Base value for SVCs that are not available when the SoftDevice is disabled. */ - -/**@brief Guaranteed time for application to process radio inactive notification. */ -#define NRF_RADIO_NOTIFICATION_INACTIVE_GUARANTEED_TIME_US (62) - -/**@brief The minimum allowed timeslot extension time. */ -#define NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US (200) - -/**@brief The maximum processing time to handle a timeslot extension. */ -#define NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US (20) - -/**@brief The latest time before the end of a timeslot the timeslot can be extended. */ -#define NRF_RADIO_MIN_EXTENSION_MARGIN_US (82) - -#define SOC_ECB_KEY_LENGTH (16) /**< ECB key length. */ -#define SOC_ECB_CLEARTEXT_LENGTH (16) /**< ECB cleartext length. */ -#define SOC_ECB_CIPHERTEXT_LENGTH (SOC_ECB_CLEARTEXT_LENGTH) /**< ECB ciphertext length. */ - -#define SD_EVT_IRQn (SWI2_IRQn) /**< SoftDevice Event IRQ number. Used for both protocol events and SoC events. */ -#define SD_EVT_IRQHandler \ - (SWI2_IRQHandler) /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. \ - The default interrupt priority for this handler is set to 6 */ -#define RADIO_NOTIFICATION_IRQn (SWI1_IRQn) /**< The radio notification IRQ number. */ -#define RADIO_NOTIFICATION_IRQHandler \ - (SWI1_IRQHandler) /**< The radio notification IRQ handler. \ - The default interrupt priority for this handler is set to 6 */ -#define NRF_RADIO_LENGTH_MIN_US (100) /**< The shortest allowed radio timeslot, in microseconds. */ -#define NRF_RADIO_LENGTH_MAX_US (100000) /**< The longest allowed radio timeslot, in microseconds. */ - -#define NRF_RADIO_DISTANCE_MAX_US \ - (128000000UL - 1UL) /**< The longest timeslot distance, in microseconds, allowed for the distance parameter (see @ref \ - nrf_radio_request_normal_t) in the request. */ - -#define NRF_RADIO_EARLIEST_TIMEOUT_MAX_US \ - (128000000UL - 1UL) /**< The longest timeout, in microseconds, allowed when requesting the earliest possible timeslot. */ - -#define NRF_RADIO_START_JITTER_US \ - (2) /**< The maximum jitter in @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START relative to the requested start time. */ - -/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is disabled. */ -#define NRF_SOC_SD_PPI_CHANNELS_SD_DISABLED_MSK ((uint32_t)(0)) - -/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is enabled. */ -#define NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK \ - ((uint32_t)((1U << 17) | (1U << 18) | (1U << 19) | (1U << 20) | (1U << 21) | (1U << 22) | (1U << 23) | (1U << 24) | \ - (1U << 25) | (1U << 26) | (1U << 27) | (1U << 28) | (1U << 29) | (1U << 30) | (1U << 31))) - -/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is disabled. */ -#define NRF_SOC_SD_PPI_GROUPS_SD_DISABLED_MSK ((uint32_t)(0)) - -/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is enabled. */ -#define NRF_SOC_SD_PPI_GROUPS_SD_ENABLED_MSK ((uint32_t)((1U << 4) | (1U << 5))) - -/**@} */ - -/**@addtogroup NRF_SOC_ENUMS Enumerations - * @{ */ - -/**@brief The SVC numbers used by the SVC functions in the SoC library. */ -enum NRF_SOC_SVCS { - SD_PPI_CHANNEL_ENABLE_GET = SOC_SVC_BASE, - SD_PPI_CHANNEL_ENABLE_SET = SOC_SVC_BASE + 1, - SD_PPI_CHANNEL_ENABLE_CLR = SOC_SVC_BASE + 2, - SD_PPI_CHANNEL_ASSIGN = SOC_SVC_BASE + 3, - SD_PPI_GROUP_TASK_ENABLE = SOC_SVC_BASE + 4, - SD_PPI_GROUP_TASK_DISABLE = SOC_SVC_BASE + 5, - SD_PPI_GROUP_ASSIGN = SOC_SVC_BASE + 6, - SD_PPI_GROUP_GET = SOC_SVC_BASE + 7, - SD_FLASH_PAGE_ERASE = SOC_SVC_BASE + 8, - SD_FLASH_WRITE = SOC_SVC_BASE + 9, - SD_PROTECTED_REGISTER_WRITE = SOC_SVC_BASE + 11, - SD_MUTEX_NEW = SOC_SVC_BASE_NOT_AVAILABLE, - SD_MUTEX_ACQUIRE = SOC_SVC_BASE_NOT_AVAILABLE + 1, - SD_MUTEX_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 2, - SD_RAND_APPLICATION_POOL_CAPACITY_GET = SOC_SVC_BASE_NOT_AVAILABLE + 3, - SD_RAND_APPLICATION_BYTES_AVAILABLE_GET = SOC_SVC_BASE_NOT_AVAILABLE + 4, - SD_RAND_APPLICATION_VECTOR_GET = SOC_SVC_BASE_NOT_AVAILABLE + 5, - SD_POWER_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 6, - SD_POWER_SYSTEM_OFF = SOC_SVC_BASE_NOT_AVAILABLE + 7, - SD_POWER_RESET_REASON_GET = SOC_SVC_BASE_NOT_AVAILABLE + 8, - SD_POWER_RESET_REASON_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 9, - SD_POWER_POF_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 10, - SD_POWER_POF_THRESHOLD_SET = SOC_SVC_BASE_NOT_AVAILABLE + 11, - SD_POWER_POF_THRESHOLDVDDH_SET = SOC_SVC_BASE_NOT_AVAILABLE + 12, - SD_POWER_RAM_POWER_SET = SOC_SVC_BASE_NOT_AVAILABLE + 13, - SD_POWER_RAM_POWER_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 14, - SD_POWER_RAM_POWER_GET = SOC_SVC_BASE_NOT_AVAILABLE + 15, - SD_POWER_GPREGRET_SET = SOC_SVC_BASE_NOT_AVAILABLE + 16, - SD_POWER_GPREGRET_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 17, - SD_POWER_GPREGRET_GET = SOC_SVC_BASE_NOT_AVAILABLE + 18, - SD_POWER_DCDC_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 19, - SD_POWER_DCDC0_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 20, - SD_APP_EVT_WAIT = SOC_SVC_BASE_NOT_AVAILABLE + 21, - SD_CLOCK_HFCLK_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 22, - SD_CLOCK_HFCLK_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 23, - SD_CLOCK_HFCLK_IS_RUNNING = SOC_SVC_BASE_NOT_AVAILABLE + 24, - SD_RADIO_NOTIFICATION_CFG_SET = SOC_SVC_BASE_NOT_AVAILABLE + 25, - SD_ECB_BLOCK_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 26, - SD_ECB_BLOCKS_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 27, - SD_RADIO_SESSION_OPEN = SOC_SVC_BASE_NOT_AVAILABLE + 28, - SD_RADIO_SESSION_CLOSE = SOC_SVC_BASE_NOT_AVAILABLE + 29, - SD_RADIO_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 30, - SD_EVT_GET = SOC_SVC_BASE_NOT_AVAILABLE + 31, - SD_TEMP_GET = SOC_SVC_BASE_NOT_AVAILABLE + 32, - SD_POWER_USBPWRRDY_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 33, - SD_POWER_USBDETECTED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 34, - SD_POWER_USBREMOVED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 35, - SD_POWER_USBREGSTATUS_GET = SOC_SVC_BASE_NOT_AVAILABLE + 36, - SVC_SOC_LAST = SOC_SVC_BASE_NOT_AVAILABLE + 37 -}; - -/**@brief Possible values of a ::nrf_mutex_t. */ -enum NRF_MUTEX_VALUES { NRF_MUTEX_FREE, NRF_MUTEX_TAKEN }; - -/**@brief Power modes. */ -enum NRF_POWER_MODES { - NRF_POWER_MODE_CONSTLAT, /**< Constant latency mode. See power management in the reference manual. */ - NRF_POWER_MODE_LOWPWR /**< Low power mode. See power management in the reference manual. */ -}; - -/**@brief Power failure thresholds */ -enum NRF_POWER_THRESHOLDS { - NRF_POWER_THRESHOLD_V17 = 4UL, /**< 1.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V18, /**< 1.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V19, /**< 1.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V20, /**< 2.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V21, /**< 2.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V22, /**< 2.2 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V23, /**< 2.3 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V24, /**< 2.4 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V25, /**< 2.5 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V26, /**< 2.6 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V27, /**< 2.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V28 /**< 2.8 Volts power failure threshold. */ -}; - -/**@brief Power failure thresholds for high voltage */ -enum NRF_POWER_THRESHOLDVDDHS { - NRF_POWER_THRESHOLDVDDH_V27, /**< 2.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V28, /**< 2.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V29, /**< 2.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V30, /**< 3.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V31, /**< 3.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V32, /**< 3.2 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V33, /**< 3.3 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V34, /**< 3.4 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V35, /**< 3.5 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V36, /**< 3.6 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V37, /**< 3.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V38, /**< 3.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V39, /**< 3.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V40, /**< 4.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V41, /**< 4.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V42 /**< 4.2 Volts power failure threshold. */ -}; - -/**@brief DC/DC converter modes. */ -enum NRF_POWER_DCDC_MODES { - NRF_POWER_DCDC_DISABLE, /**< The DCDC is disabled. */ - NRF_POWER_DCDC_ENABLE /**< The DCDC is enabled. */ -}; - -/**@brief Radio notification distances. */ -enum NRF_RADIO_NOTIFICATION_DISTANCES { - NRF_RADIO_NOTIFICATION_DISTANCE_NONE = 0, /**< The event does not have a notification. */ - NRF_RADIO_NOTIFICATION_DISTANCE_800US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_1740US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_2680US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_3620US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_4560US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_5500US /**< The distance from the active notification to start of radio activity. */ -}; - -/**@brief Radio notification types. */ -enum NRF_RADIO_NOTIFICATION_TYPES { - NRF_RADIO_NOTIFICATION_TYPE_NONE = 0, /**< The event does not have a radio notification signal. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, /**< Using interrupt for notification when the radio will be enabled. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, /**< Using interrupt for notification when the radio has been disabled. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, /**< Using interrupt for notification both when the radio will be enabled and - disabled. */ -}; - -/**@brief The Radio signal callback types. */ -enum NRF_RADIO_CALLBACK_SIGNAL_TYPE { - NRF_RADIO_CALLBACK_SIGNAL_TYPE_START, /**< This signal indicates the start of the radio timeslot. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0, /**< This signal indicates the NRF_TIMER0 interrupt. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO, /**< This signal indicates the NRF_RADIO interrupt. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED, /**< This signal indicates extend action failed. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED /**< This signal indicates extend action succeeded. */ -}; - -/**@brief The actions requested by the signal callback. - * - * This code gives the SOC instructions about what action to take when the signal callback has - * returned. - */ -enum NRF_RADIO_SIGNAL_CALLBACK_ACTION { - NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE, /**< Return without action. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND, /**< Request an extension of the current - timeslot. Maximum execution time for this action: - @ref NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US. - This action must be started at least - @ref NRF_RADIO_MIN_EXTENSION_MARGIN_US before - the end of the timeslot. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_END, /**< End the current radio timeslot. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END /**< Request a new radio timeslot and end the current timeslot. */ -}; - -/**@brief Radio timeslot high frequency clock source configuration. */ -enum NRF_RADIO_HFCLK_CFG { - NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED, /**< The SoftDevice will guarantee that the high frequency clock source is the - external crystal for the whole duration of the timeslot. This should be the - preferred option for events that use the radio or require high timing accuracy. - @note The SoftDevice will automatically turn on and off the external crystal, - at the beginning and end of the timeslot, respectively. The crystal may also - intentionally be left running after the timeslot, in cases where it is needed - by the SoftDevice shortly after the end of the timeslot. */ - NRF_RADIO_HFCLK_CFG_NO_GUARANTEE /**< This configuration allows for earlier and tighter scheduling of timeslots. - The RC oscillator may be the clock source in part or for the whole duration of the - timeslot. The RC oscillator's accuracy must therefore be taken into consideration. - @note If the application will use the radio peripheral in timeslots with this - configuration, it must make sure that the crystal is running and stable before - starting the radio. */ -}; - -/**@brief Radio timeslot priorities. */ -enum NRF_RADIO_PRIORITY { - NRF_RADIO_PRIORITY_HIGH, /**< High (equal priority as the normal connection priority of the SoftDevice stack(s)). */ - NRF_RADIO_PRIORITY_NORMAL, /**< Normal (equal priority as the priority of secondary activities of the SoftDevice stack(s)). */ -}; - -/**@brief Radio timeslot request type. */ -enum NRF_RADIO_REQUEST_TYPE { - NRF_RADIO_REQ_TYPE_EARLIEST, /**< Request radio timeslot as early as possible. This should always be used for the first - request in a session. */ - NRF_RADIO_REQ_TYPE_NORMAL /**< Normal radio timeslot request. */ -}; - -/**@brief SoC Events. */ -enum NRF_SOC_EVTS { - NRF_EVT_HFCLKSTARTED, /**< Event indicating that the HFCLK has started. */ - NRF_EVT_POWER_FAILURE_WARNING, /**< Event indicating that a power failure warning has occurred. */ - NRF_EVT_FLASH_OPERATION_SUCCESS, /**< Event indicating that the ongoing flash operation has completed successfully. */ - NRF_EVT_FLASH_OPERATION_ERROR, /**< Event indicating that the ongoing flash operation has timed out with an error. */ - NRF_EVT_RADIO_BLOCKED, /**< Event indicating that a radio timeslot was blocked. */ - NRF_EVT_RADIO_CANCELED, /**< Event indicating that a radio timeslot was canceled by SoftDevice. */ - NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN, /**< Event indicating that a radio timeslot signal callback handler return was - invalid. */ - NRF_EVT_RADIO_SESSION_IDLE, /**< Event indicating that a radio timeslot session is idle. */ - NRF_EVT_RADIO_SESSION_CLOSED, /**< Event indicating that a radio timeslot session is closed. */ - NRF_EVT_POWER_USB_POWER_READY, /**< Event indicating that a USB 3.3 V supply is ready. */ - NRF_EVT_POWER_USB_DETECTED, /**< Event indicating that voltage supply is detected on VBUS. */ - NRF_EVT_POWER_USB_REMOVED, /**< Event indicating that voltage supply is removed from VBUS. */ - NRF_EVT_NUMBER_OF_EVTS -}; - -/**@} */ - -/**@addtogroup NRF_SOC_STRUCTURES Structures - * @{ */ - -/**@brief Represents a mutex for use with the nrf_mutex functions. - * @note Accessing the value directly is not safe, use the mutex functions! - */ -typedef volatile uint8_t nrf_mutex_t; - -/**@brief Parameters for a request for a timeslot as early as possible. */ -typedef struct { - uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ - uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ - uint32_t length_us; /**< The radio timeslot length (in the range 100 to 100,000] microseconds). */ - uint32_t timeout_us; /**< Longest acceptable delay until the start of the requested timeslot (up to @ref - NRF_RADIO_EARLIEST_TIMEOUT_MAX_US microseconds). */ -} nrf_radio_request_earliest_t; - -/**@brief Parameters for a normal radio timeslot request. */ -typedef struct { - uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ - uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ - uint32_t distance_us; /**< Distance from the start of the previous radio timeslot (up to @ref NRF_RADIO_DISTANCE_MAX_US - microseconds). */ - uint32_t length_us; /**< The radio timeslot length (in the range [100..100,000] microseconds). */ -} nrf_radio_request_normal_t; - -/**@brief Radio timeslot request parameters. */ -typedef struct { - uint8_t request_type; /**< Type of request, see @ref NRF_RADIO_REQUEST_TYPE. */ - union { - nrf_radio_request_earliest_t earliest; /**< Parameters for requesting a radio timeslot as early as possible. */ - nrf_radio_request_normal_t normal; /**< Parameters for requesting a normal radio timeslot. */ - } params; /**< Parameter union. */ -} nrf_radio_request_t; - -/**@brief Return parameters of the radio timeslot signal callback. */ -typedef struct { - uint8_t callback_action; /**< The action requested by the application when returning from the signal callback, see @ref - NRF_RADIO_SIGNAL_CALLBACK_ACTION. */ - union { - struct { - nrf_radio_request_t *p_next; /**< The request parameters for the next radio timeslot. */ - } request; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END. */ - struct { - uint32_t length_us; /**< Requested extension of the radio timeslot duration (microseconds) (for minimum time see @ref - NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US). */ - } extend; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND. */ - } params; /**< Parameter union. */ -} nrf_radio_signal_callback_return_param_t; - -/**@brief The radio timeslot signal callback type. - * - * @note In case of invalid return parameters, the radio timeslot will automatically end - * immediately after returning from the signal callback and the - * @ref NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN event will be sent. - * @note The returned struct pointer must remain valid after the signal callback - * function returns. For instance, this means that it must not point to a stack variable. - * - * @param[in] signal_type Type of signal, see @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE. - * - * @return Pointer to structure containing action requested by the application. - */ -typedef nrf_radio_signal_callback_return_param_t *(*nrf_radio_signal_callback_t)(uint8_t signal_type); - -/**@brief AES ECB parameter typedefs */ -typedef uint8_t soc_ecb_key_t[SOC_ECB_KEY_LENGTH]; /**< Encryption key type. */ -typedef uint8_t soc_ecb_cleartext_t[SOC_ECB_CLEARTEXT_LENGTH]; /**< Cleartext data type. */ -typedef uint8_t soc_ecb_ciphertext_t[SOC_ECB_CIPHERTEXT_LENGTH]; /**< Ciphertext data type. */ - -/**@brief AES ECB data structure */ -typedef struct { - soc_ecb_key_t key; /**< Encryption key. */ - soc_ecb_cleartext_t cleartext; /**< Cleartext data. */ - soc_ecb_ciphertext_t ciphertext; /**< Ciphertext data. */ -} nrf_ecb_hal_data_t; - -/**@brief AES ECB block. Used to provide multiple blocks in a single call - to @ref sd_ecb_blocks_encrypt.*/ -typedef struct { - soc_ecb_key_t const *p_key; /**< Pointer to the Encryption key. */ - soc_ecb_cleartext_t const *p_cleartext; /**< Pointer to the Cleartext data. */ - soc_ecb_ciphertext_t *p_ciphertext; /**< Pointer to the Ciphertext data. */ -} nrf_ecb_hal_data_block_t; - -/**@} */ - -/**@addtogroup NRF_SOC_FUNCTIONS Functions - * @{ */ - -/**@brief Initialize a mutex. - * - * @param[in] p_mutex Pointer to the mutex to initialize. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_MUTEX_NEW, uint32_t, sd_mutex_new(nrf_mutex_t *p_mutex)); - -/**@brief Attempt to acquire a mutex. - * - * @param[in] p_mutex Pointer to the mutex to acquire. - * - * @retval ::NRF_SUCCESS The mutex was successfully acquired. - * @retval ::NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN The mutex could not be acquired. - */ -SVCALL(SD_MUTEX_ACQUIRE, uint32_t, sd_mutex_acquire(nrf_mutex_t *p_mutex)); - -/**@brief Release a mutex. - * - * @param[in] p_mutex Pointer to the mutex to release. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_MUTEX_RELEASE, uint32_t, sd_mutex_release(nrf_mutex_t *p_mutex)); - -/**@brief Query the capacity of the application random pool. - * - * @param[out] p_pool_capacity The capacity of the pool. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RAND_APPLICATION_POOL_CAPACITY_GET, uint32_t, sd_rand_application_pool_capacity_get(uint8_t *p_pool_capacity)); - -/**@brief Get number of random bytes available to the application. - * - * @param[out] p_bytes_available The number of bytes currently available in the pool. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RAND_APPLICATION_BYTES_AVAILABLE_GET, uint32_t, sd_rand_application_bytes_available_get(uint8_t *p_bytes_available)); - -/**@brief Get random bytes from the application pool. - * - * @param[out] p_buff Pointer to unit8_t buffer for storing the bytes. - * @param[in] length Number of bytes to take from pool and place in p_buff. - * - * @retval ::NRF_SUCCESS The requested bytes were written to p_buff. - * @retval ::NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES No bytes were written to the buffer, because there were not enough bytes - * available. - */ -SVCALL(SD_RAND_APPLICATION_VECTOR_GET, uint32_t, sd_rand_application_vector_get(uint8_t *p_buff, uint8_t length)); - -/**@brief Gets the reset reason register. - * - * @param[out] p_reset_reason Contents of the NRF_POWER->RESETREAS register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RESET_REASON_GET, uint32_t, sd_power_reset_reason_get(uint32_t *p_reset_reason)); - -/**@brief Clears the bits of the reset reason register. - * - * @param[in] reset_reason_clr_msk Contains the bits to clear from the reset reason register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RESET_REASON_CLR, uint32_t, sd_power_reset_reason_clr(uint32_t reset_reason_clr_msk)); - -/**@brief Sets the power mode when in CPU sleep. - * - * @param[in] power_mode The power mode to use when in CPU sleep, see @ref NRF_POWER_MODES. @sa sd_app_evt_wait - * - * @retval ::NRF_SUCCESS The power mode was set. - * @retval ::NRF_ERROR_SOC_POWER_MODE_UNKNOWN The power mode was unknown. - */ -SVCALL(SD_POWER_MODE_SET, uint32_t, sd_power_mode_set(uint8_t power_mode)); - -/**@brief Puts the chip in System OFF mode. - * - * @retval ::NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN - */ -SVCALL(SD_POWER_SYSTEM_OFF, uint32_t, sd_power_system_off(void)); - -/**@brief Enables or disables the power-fail comparator. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_FAILURE_WARNING) when the power failure warning occurs. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] pof_enable True if the power-fail comparator should be enabled, false if it should be disabled. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_POF_ENABLE, uint32_t, sd_power_pof_enable(uint8_t pof_enable)); - -/**@brief Enables or disables the USB power ready event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_POWER_READY) when a USB 3.3 V supply is ready. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbpwrrdy_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBPWRRDY_ENABLE, uint32_t, sd_power_usbpwrrdy_enable(uint8_t usbpwrrdy_enable)); - -/**@brief Enables or disables the power USB-detected event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_DETECTED) when a voltage supply is detected on VBUS. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbdetected_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBDETECTED_ENABLE, uint32_t, sd_power_usbdetected_enable(uint8_t usbdetected_enable)); - -/**@brief Enables or disables the power USB-removed event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_REMOVED) when a voltage supply is removed from VBUS. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbremoved_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBREMOVED_ENABLE, uint32_t, sd_power_usbremoved_enable(uint8_t usbremoved_enable)); - -/**@brief Get USB supply status register content. - * - * @param[out] usbregstatus The content of USBREGSTATUS register. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBREGSTATUS_GET, uint32_t, sd_power_usbregstatus_get(uint32_t *usbregstatus)); - -/**@brief Sets the power failure comparator threshold value. - * - * @note: Power failure comparator threshold setting. This setting applies both for normal voltage - * mode (supply connected to both VDD and VDDH) and high voltage mode (supply connected to - * VDDH only). - * - * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDS. - * - * @retval ::NRF_SUCCESS The power failure threshold was set. - * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. - */ -SVCALL(SD_POWER_POF_THRESHOLD_SET, uint32_t, sd_power_pof_threshold_set(uint8_t threshold)); - -/**@brief Sets the power failure comparator threshold value for high voltage. - * - * @note: Power failure comparator threshold setting for high voltage mode (supply connected to - * VDDH only). This setting does not apply for normal voltage mode (supply connected to both - * VDD and VDDH). - * - * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDVDDHS. - * - * @retval ::NRF_SUCCESS The power failure threshold was set. - * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. - */ -SVCALL(SD_POWER_POF_THRESHOLDVDDH_SET, uint32_t, sd_power_pof_thresholdvddh_set(uint8_t threshold)); - -/**@brief Writes the NRF_POWER->RAM[index].POWERSET register. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERSET register to write to. - * @param[in] ram_powerset Contains the word to write to the NRF_POWER->RAM[index].POWERSET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_SET, uint32_t, sd_power_ram_power_set(uint8_t index, uint32_t ram_powerset)); - -/**@brief Writes the NRF_POWER->RAM[index].POWERCLR register. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERCLR register to write to. - * @param[in] ram_powerclr Contains the word to write to the NRF_POWER->RAM[index].POWERCLR register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_CLR, uint32_t, sd_power_ram_power_clr(uint8_t index, uint32_t ram_powerclr)); - -/**@brief Get contents of NRF_POWER->RAM[index].POWER register, indicates power status of RAM[index] blocks. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWER register to read from. - * @param[out] p_ram_power Content of NRF_POWER->RAM[index].POWER register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_GET, uint32_t, sd_power_ram_power_get(uint8_t index, uint32_t *p_ram_power)); - -/**@brief Set bits in the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[in] gpregret_msk Bits to be set in the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_SET, uint32_t, sd_power_gpregret_set(uint32_t gpregret_id, uint32_t gpregret_msk)); - -/**@brief Clear bits in the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[in] gpregret_msk Bits to be clear in the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_CLR, uint32_t, sd_power_gpregret_clr(uint32_t gpregret_id, uint32_t gpregret_msk)); - -/**@brief Get contents of the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[out] p_gpregret Contents of the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_GET, uint32_t, sd_power_gpregret_get(uint32_t gpregret_id, uint32_t *p_gpregret)); - -/**@brief Enable or disable the DC/DC regulator for the regulator stage 1 (REG1). - * - * @param[in] dcdc_mode The mode of the DCDC, see @ref NRF_POWER_DCDC_MODES. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_PARAM The DCDC mode is invalid. - */ -SVCALL(SD_POWER_DCDC_MODE_SET, uint32_t, sd_power_dcdc_mode_set(uint8_t dcdc_mode)); - -/**@brief Enable or disable the DC/DC regulator for the regulator stage 0 (REG0). - * - * For more details on the REG0 stage, please see product specification. - * - * @param[in] dcdc_mode The mode of the DCDC0, see @ref NRF_POWER_DCDC_MODES. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_PARAM The dcdc_mode is invalid. - */ -SVCALL(SD_POWER_DCDC0_MODE_SET, uint32_t, sd_power_dcdc0_mode_set(uint8_t dcdc_mode)); - -/**@brief Request the high frequency crystal oscillator. - * - * Will start the high frequency crystal oscillator, the startup time of the crystal varies - * and the ::sd_clock_hfclk_is_running function can be polled to check if it has started. - * - * @see sd_clock_hfclk_is_running - * @see sd_clock_hfclk_release - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_REQUEST, uint32_t, sd_clock_hfclk_request(void)); - -/**@brief Releases the high frequency crystal oscillator. - * - * Will stop the high frequency crystal oscillator, this happens immediately. - * - * @see sd_clock_hfclk_is_running - * @see sd_clock_hfclk_request - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_RELEASE, uint32_t, sd_clock_hfclk_release(void)); - -/**@brief Checks if the high frequency crystal oscillator is running. - * - * @see sd_clock_hfclk_request - * @see sd_clock_hfclk_release - * - * @param[out] p_is_running 1 if the external crystal oscillator is running, 0 if not. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_IS_RUNNING, uint32_t, sd_clock_hfclk_is_running(uint32_t *p_is_running)); - -/**@brief Waits for an application event. - * - * An application event is either an application interrupt or a pended interrupt when the interrupt - * is disabled. - * - * When the application waits for an application event by calling this function, an interrupt that - * is enabled will be taken immediately on pending since this function will wait in thread mode, - * then the execution will return in the application's main thread. - * - * In order to wake up from disabled interrupts, the SEVONPEND flag has to be set in the Cortex-M - * MCU's System Control Register (SCR), CMSIS_SCB. In that case, when a disabled interrupt gets - * pended, this function will return to the application's main thread. - * - * @note The application must ensure that the pended flag is cleared using ::sd_nvic_ClearPendingIRQ - * in order to sleep using this function. This is only necessary for disabled interrupts, as - * the interrupt handler will clear the pending flag automatically for enabled interrupts. - * - * @note If an application interrupt has happened since the last time sd_app_evt_wait was - * called this function will return immediately and not go to sleep. This is to avoid race - * conditions that can occur when a flag is updated in the interrupt handler and processed - * in the main loop. - * - * @post An application interrupt has happened or a interrupt pending flag is set. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_APP_EVT_WAIT, uint32_t, sd_app_evt_wait(void)); - -/**@brief Get PPI channel enable register contents. - * - * @param[out] p_channel_enable The contents of the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_GET, uint32_t, sd_ppi_channel_enable_get(uint32_t *p_channel_enable)); - -/**@brief Set PPI channel enable register. - * - * @param[in] channel_enable_set_msk Mask containing the bits to set in the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_SET, uint32_t, sd_ppi_channel_enable_set(uint32_t channel_enable_set_msk)); - -/**@brief Clear PPI channel enable register. - * - * @param[in] channel_enable_clr_msk Mask containing the bits to clear in the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_CLR, uint32_t, sd_ppi_channel_enable_clr(uint32_t channel_enable_clr_msk)); - -/**@brief Assign endpoints to a PPI channel. - * - * @param[in] channel_num Number of the PPI channel to assign. - * @param[in] evt_endpoint Event endpoint of the PPI channel. - * @param[in] task_endpoint Task endpoint of the PPI channel. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_CHANNEL The channel number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ASSIGN, uint32_t, - sd_ppi_channel_assign(uint8_t channel_num, const volatile void *evt_endpoint, const volatile void *task_endpoint)); - -/**@brief Task to enable a channel group. - * - * @param[in] group_num Number of the channel group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_TASK_ENABLE, uint32_t, sd_ppi_group_task_enable(uint8_t group_num)); - -/**@brief Task to disable a channel group. - * - * @param[in] group_num Number of the PPI group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_TASK_DISABLE, uint32_t, sd_ppi_group_task_disable(uint8_t group_num)); - -/**@brief Assign PPI channels to a channel group. - * - * @param[in] group_num Number of the channel group. - * @param[in] channel_msk Mask of the channels to assign to the group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_ASSIGN, uint32_t, sd_ppi_group_assign(uint8_t group_num, uint32_t channel_msk)); - -/**@brief Gets the PPI channels of a channel group. - * - * @param[in] group_num Number of the channel group. - * @param[out] p_channel_msk Mask of the channels assigned to the group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_GET, uint32_t, sd_ppi_group_get(uint8_t group_num, uint32_t *p_channel_msk)); - -/**@brief Configures the Radio Notification signal. - * - * @note - * - The notification signal latency depends on the interrupt priority settings of SWI used - * for notification signal. - * - To ensure that the radio notification signal behaves in a consistent way, the radio - * notifications must be configured when there is no protocol stack or other SoftDevice - * activity in progress. It is recommended that the radio notification signal is - * configured directly after the SoftDevice has been enabled. - * - In the period between the ACTIVE signal and the start of the Radio Event, the SoftDevice - * will interrupt the application to do Radio Event preparation. - * - Using the Radio Notification feature may limit the bandwidth, as the SoftDevice may have - * to shorten the connection events to have time for the Radio Notification signals. - * - * @param[in] type Type of notification signal, see @ref NRF_RADIO_NOTIFICATION_TYPES. - * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE shall be used to turn off radio - * notification. Using @ref NRF_RADIO_NOTIFICATION_DISTANCE_NONE is - * recommended (but not required) to be used with - * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE. - * - * @param[in] distance Distance between the notification signal and start of radio activity, see @ref - * NRF_RADIO_NOTIFICATION_DISTANCES. This parameter is ignored when @ref NRF_RADIO_NOTIFICATION_TYPE_NONE or - * @ref NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE is used. - * - * @retval ::NRF_ERROR_INVALID_PARAM The group number is invalid. - * @retval ::NRF_ERROR_INVALID_STATE A protocol stack or other SoftDevice is running. Stop all - * running activities and retry. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RADIO_NOTIFICATION_CFG_SET, uint32_t, sd_radio_notification_cfg_set(uint8_t type, uint8_t distance)); - -/**@brief Encrypts a block according to the specified parameters. - * - * 128-bit AES encryption. - * - * @note: - * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while - * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application - * main or low interrupt level. - * - * @param[in, out] p_ecb_data Pointer to the ECB parameters' struct (two input - * parameters and one output parameter). - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_ECB_BLOCK_ENCRYPT, uint32_t, sd_ecb_block_encrypt(nrf_ecb_hal_data_t *p_ecb_data)); - -/**@brief Encrypts multiple data blocks provided as an array of data block structures. - * - * @details: Performs 128-bit AES encryption on multiple data blocks - * - * @note: - * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while - * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application - * main or low interrupt level. - * - * @param[in] block_count Count of blocks in the p_data_blocks array. - * @param[in,out] p_data_blocks Pointer to the first entry in a contiguous array of - * @ref nrf_ecb_hal_data_block_t structures. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_ECB_BLOCKS_ENCRYPT, uint32_t, sd_ecb_blocks_encrypt(uint8_t block_count, nrf_ecb_hal_data_block_t *p_data_blocks)); - -/**@brief Gets any pending events generated by the SoC API. - * - * The application should keep calling this function to get events, until ::NRF_ERROR_NOT_FOUND is returned. - * - * @param[out] p_evt_id Set to one of the values in @ref NRF_SOC_EVTS, if any events are pending. - * - * @retval ::NRF_SUCCESS An event was pending. The event id is written in the p_evt_id parameter. - * @retval ::NRF_ERROR_NOT_FOUND No pending events. - */ -SVCALL(SD_EVT_GET, uint32_t, sd_evt_get(uint32_t *p_evt_id)); - -/**@brief Get the temperature measured on the chip - * - * This function will block until the temperature measurement is done. - * It takes around 50 us from call to return. - * - * @param[out] p_temp Result of temperature measurement. Die temperature in 0.25 degrees Celsius. - * - * @retval ::NRF_SUCCESS A temperature measurement was done, and the temperature was written to temp - */ -SVCALL(SD_TEMP_GET, uint32_t, sd_temp_get(int32_t *p_temp)); - -/**@brief Flash Write - * - * Commands to write a buffer to flash - * - * If the SoftDevice is enabled: - * This call initiates the flash access command, and its completion will be communicated to the - * application with exactly one of the following events: - * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. - * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. - * - * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the - * write has been completed - * - * @note - * - This call takes control over the radio and the CPU during flash erase and write to make sure that - * they will not interfere with the flash access. This means that all interrupts will be blocked - * for a predictable time (depending on the NVMC specification in the device's Product Specification - * and the command parameters). - * - The data in the p_src buffer should not be modified before the @ref NRF_EVT_FLASH_OPERATION_SUCCESS - * or the @ref NRF_EVT_FLASH_OPERATION_ERROR have been received if the SoftDevice is enabled. - * - This call will make the SoftDevice trigger a hardfault when the page is written, if it is - * protected. - * - * - * @param[in] p_dst Pointer to start of flash location to be written. - * @param[in] p_src Pointer to buffer with data to be written. - * @param[in] size Number of 32-bit words to write. Maximum size is the number of words in one - * flash page. See the device's Product Specification for details. - * - * @retval ::NRF_ERROR_INVALID_ADDR Tried to write to a non existing flash address, or p_dst or p_src was unaligned. - * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. - * @retval ::NRF_ERROR_INVALID_LENGTH Size was 0, or higher than the maximum allowed size. - * @retval ::NRF_ERROR_FORBIDDEN Tried to write to an address outside the application flash area. - * @retval ::NRF_SUCCESS The command was accepted. - */ -SVCALL(SD_FLASH_WRITE, uint32_t, sd_flash_write(uint32_t *p_dst, uint32_t const *p_src, uint32_t size)); - -/**@brief Flash Erase page - * - * Commands to erase a flash page - * If the SoftDevice is enabled: - * This call initiates the flash access command, and its completion will be communicated to the - * application with exactly one of the following events: - * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. - * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. - * - * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the - * erase has been completed - * - * @note - * - This call takes control over the radio and the CPU during flash erase and write to make sure that - * they will not interfere with the flash access. This means that all interrupts will be blocked - * for a predictable time (depending on the NVMC specification in the device's Product Specification - * and the command parameters). - * - This call will make the SoftDevice trigger a hardfault when the page is erased, if it is - * protected. - * - * - * @param[in] page_number Page number of the page to erase - * - * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. - * @retval ::NRF_ERROR_INVALID_ADDR Tried to erase to a non existing flash page. - * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. - * @retval ::NRF_ERROR_FORBIDDEN Tried to erase a page outside the application flash area. - * @retval ::NRF_SUCCESS The command was accepted. - */ -SVCALL(SD_FLASH_PAGE_ERASE, uint32_t, sd_flash_page_erase(uint32_t page_number)); - -/**@brief Opens a session for radio timeslot requests. - * - * @note Only one session can be open at a time. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) will be called when the radio timeslot - * starts. From this point the NRF_RADIO and NRF_TIMER0 peripherals can be freely accessed - * by the application. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0) is called whenever the NRF_TIMER0 - * interrupt occurs. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO) is called whenever the NRF_RADIO - * interrupt occurs. - * @note p_radio_signal_callback() will be called at ARM interrupt priority level 0. This - * implies that none of the sd_* API calls can be used from p_radio_signal_callback(). - * - * @param[in] p_radio_signal_callback The signal callback. - * - * @retval ::NRF_ERROR_INVALID_ADDR p_radio_signal_callback is an invalid function pointer. - * @retval ::NRF_ERROR_BUSY If session cannot be opened. - * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_SESSION_OPEN, uint32_t, sd_radio_session_open(nrf_radio_signal_callback_t p_radio_signal_callback)); - -/**@brief Closes a session for radio timeslot requests. - * - * @note Any current radio timeslot will be finished before the session is closed. - * @note If a radio timeslot is scheduled when the session is closed, it will be canceled. - * @note The application cannot consider the session closed until the @ref NRF_EVT_RADIO_SESSION_CLOSED - * event is received. - * - * @retval ::NRF_ERROR_FORBIDDEN If session not opened. - * @retval ::NRF_ERROR_BUSY If session is currently being closed. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_SESSION_CLOSE, uint32_t, sd_radio_session_close(void)); - -/**@brief Requests a radio timeslot. - * - * @note The request type is determined by p_request->request_type, and can be one of @ref NRF_RADIO_REQ_TYPE_EARLIEST - * and @ref NRF_RADIO_REQ_TYPE_NORMAL. The first request in a session must always be of type @ref - * NRF_RADIO_REQ_TYPE_EARLIEST. - * @note For a normal request (@ref NRF_RADIO_REQ_TYPE_NORMAL), the start time of a radio timeslot is specified by - * p_request->distance_us and is given relative to the start of the previous timeslot. - * @note A too small p_request->distance_us will lead to a @ref NRF_EVT_RADIO_BLOCKED event. - * @note Timeslots scheduled too close will lead to a @ref NRF_EVT_RADIO_BLOCKED event. - * @note See the SoftDevice Specification for more on radio timeslot scheduling, distances and lengths. - * @note If an opportunity for the first radio timeslot is not found before 100 ms after the call to this - * function, it is not scheduled, and instead a @ref NRF_EVT_RADIO_BLOCKED event is sent. - * The application may then try to schedule the first radio timeslot again. - * @note Successful requests will result in nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START). - * Unsuccessful requests will result in a @ref NRF_EVT_RADIO_BLOCKED event, see @ref NRF_SOC_EVTS. - * @note The jitter in the start time of the radio timeslots is +/- @ref NRF_RADIO_START_JITTER_US us. - * @note The nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) call has a latency relative to the - * specified radio timeslot start, but this does not affect the actual start time of the timeslot. - * @note NRF_TIMER0 is reset at the start of the radio timeslot, and is clocked at 1MHz from the high frequency - * (16 MHz) clock source. If p_request->hfclk_force_xtal is true, the high frequency clock is - * guaranteed to be clocked from the external crystal. - * @note The SoftDevice will neither access the NRF_RADIO peripheral nor the NRF_TIMER0 peripheral - * during the radio timeslot. - * - * @param[in] p_request Pointer to the request parameters. - * - * @retval ::NRF_ERROR_FORBIDDEN Either: - * - The session is not open. - * - The session is not IDLE. - * - This is the first request and its type is not @ref NRF_RADIO_REQ_TYPE_EARLIEST. - * - The request type was set to @ref NRF_RADIO_REQ_TYPE_NORMAL after a - * @ref NRF_RADIO_REQ_TYPE_EARLIEST request was blocked. - * @retval ::NRF_ERROR_INVALID_ADDR If the p_request pointer is invalid. - * @retval ::NRF_ERROR_INVALID_PARAM If the parameters of p_request are not valid. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_REQUEST, uint32_t, sd_radio_request(nrf_radio_request_t const *p_request)); - -/**@brief Write register protected by the SoftDevice - * - * This function writes to a register that is write-protected by the SoftDevice. Please refer to your - * SoftDevice Specification for more details about which registers that are protected by SoftDevice. - * This function can write to the following protected peripheral: - * - ACL - * - * @note Protected registers may be read directly. - * @note Register that are write-once will return @ref NRF_SUCCESS on second set, even the value in - * the register has not changed. See the Product Specification for more details about register - * properties. - * - * @param[in] p_register Pointer to register to be written. - * @param[in] value Value to be written to the register. - * - * @retval ::NRF_ERROR_INVALID_ADDR This function can not write to the reguested register. - * @retval ::NRF_SUCCESS Value successfully written to register. - * - */ -SVCALL(SD_PROTECTED_REGISTER_WRITE, uint32_t, sd_protected_register_write(volatile uint32_t *p_register, uint32_t value)); - -/**@} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_SOC_H__ - -/**@} */ diff --git a/variants/wio-tracker-wm1110/softdevice/nrf_svc.h b/variants/wio-tracker-wm1110/softdevice/nrf_svc.h deleted file mode 100644 index 1de44656f3..0000000000 --- a/variants/wio-tracker-wm1110/softdevice/nrf_svc.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef NRF_SVC__ -#define NRF_SVC__ - -#include "stdint.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @brief Supervisor call declaration. - * - * A call to a function marked with @ref SVCALL, will trigger a Supervisor Call (SVC) Exception. - * The SVCs with SVC numbers 0x00-0x0F are forwared to the application. All other SVCs are handled by the SoftDevice. - * - * @param[in] number The SVC number to be used. - * @param[in] return_type The return type of the SVC function. - * @param[in] signature Function signature. The function can have at most four arguments. - */ - -#ifdef SVCALL_AS_NORMAL_FUNCTION -#define SVCALL(number, return_type, signature) return_type signature -#else - -#ifndef SVCALL -#if defined(__CC_ARM) -#define SVCALL(number, return_type, signature) return_type __svc(number) signature -#elif defined(__GNUC__) -#ifdef __cplusplus -#define GCC_CAST_CPP (uint16_t) -#else -#define GCC_CAST_CPP -#endif -#define SVCALL(number, return_type, signature) \ - _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") __attribute__((naked)) \ - __attribute__((unused)) static return_type signature \ - { \ - __asm("svc %0\n" \ - "bx r14" \ - : \ - : "I"(GCC_CAST_CPP number) \ - : "r0"); \ - } \ - _Pragma("GCC diagnostic pop") - -#elif defined(__ICCARM__) -#define PRAGMA(x) _Pragma(#x) -#define SVCALL(number, return_type, signature) \ - PRAGMA(swi_number = (number)) \ - __swi return_type signature; -#else -#define SVCALL(number, return_type, signature) return_type signature -#endif -#endif // SVCALL - -#endif // SVCALL_AS_NORMAL_FUNCTION - -#ifdef __cplusplus -} -#endif -#endif // NRF_SVC__ diff --git a/version.properties b/version.properties index 1cb93ac2bf..c9336d539a 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 15 +build = 16 From a04de8c6b3c23d20536f635586c11361d198dcce Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 14 Jul 2024 06:27:16 -0500 Subject: [PATCH 163/211] Add PaxCounter to the mix --- src/modules/esp32/PaxcounterModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index a8fe5c4c5b..8953282345 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -80,7 +80,7 @@ int32_t PaxcounterModule::runOnce() firstTime = false; LOG_DEBUG("Paxcounter starting up with interval of %d seconds\n", Default::getConfiguredOrDefault(moduleConfig.paxcounter.paxcounter_update_interval, - default_broadcast_interval_secs)); + default_telemetry_broadcast_interval_secs)); struct libpax_config_t configuration; libpax_default_config(&configuration); From 0f5fdfbab780e3dcdb3a957efd142d9440f52cf3 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Mon, 15 Jul 2024 20:11:37 +0800 Subject: [PATCH 164/211] Make mergehex executable. (#4290) Previously, we used sudo and chmod to make mergehex executable in our build script. This change attempts to set the executable bit using git properties and remove the dependence on elevated permissions. --- bin/build-nrf52.sh | 1 - bin/mergehex | Bin 2 files changed, 1 deletion(-) mode change 100644 => 100755 bin/mergehex diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index cf4ca60cb2..c0658dad95 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -35,7 +35,6 @@ SRCHEX=.pio/build/$1/firmware.hex # if WM1110 target, merge hex with softdevice 7.3.0 if (echo $1 | grep -q "wio-sdk-wm1110"); then echo "Merging with softdevice" - sudo chmod +x ./bin/mergehex bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/$basename.hex SRCHEX=.pio/build/$1/$basename.hex bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 diff --git a/bin/mergehex b/bin/mergehex old mode 100644 new mode 100755 From 9db3552e5a069c3edb8b4ca9538437ab1160ae2c Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 16 Jul 2024 19:31:25 +0800 Subject: [PATCH 165/211] Remove softdevice folder from wio-sdk-wm1110 (#4295) Recently, softdevice was moved to platform/nrf52. We missed deleting this one. --- variants/wio-sdk-wm1110/softdevice/ble.h | 652 ---- variants/wio-sdk-wm1110/softdevice/ble_err.h | 92 - variants/wio-sdk-wm1110/softdevice/ble_gap.h | 2895 ----------------- variants/wio-sdk-wm1110/softdevice/ble_gatt.h | 232 -- .../wio-sdk-wm1110/softdevice/ble_gattc.h | 764 ----- .../wio-sdk-wm1110/softdevice/ble_gatts.h | 904 ----- variants/wio-sdk-wm1110/softdevice/ble_hci.h | 135 - .../wio-sdk-wm1110/softdevice/ble_l2cap.h | 495 --- .../wio-sdk-wm1110/softdevice/ble_ranges.h | 149 - .../wio-sdk-wm1110/softdevice/ble_types.h | 217 -- .../wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h | 259 -- .../wio-sdk-wm1110/softdevice/nrf_error.h | 90 - .../wio-sdk-wm1110/softdevice/nrf_error_sdm.h | 73 - .../wio-sdk-wm1110/softdevice/nrf_error_soc.h | 85 - variants/wio-sdk-wm1110/softdevice/nrf_nvic.h | 449 --- variants/wio-sdk-wm1110/softdevice/nrf_sdm.h | 380 --- variants/wio-sdk-wm1110/softdevice/nrf_soc.h | 1046 ------ variants/wio-sdk-wm1110/softdevice/nrf_svc.h | 98 - 18 files changed, 9015 deletions(-) delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_err.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gap.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gatt.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gattc.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gatts.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_hci.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_l2cap.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_ranges.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_types.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_nvic.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_sdm.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_soc.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_svc.h diff --git a/variants/wio-sdk-wm1110/softdevice/ble.h b/variants/wio-sdk-wm1110/softdevice/ble.h deleted file mode 100644 index 177b436ad8..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble.h +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON BLE SoftDevice Common - @{ - @defgroup ble_api Events, type definitions and API calls - @{ - - @brief Module independent events, type definitions and API calls for the BLE SoftDevice. - - */ - -#ifndef BLE_H__ -#define BLE_H__ - -#include "ble_err.h" -#include "ble_gap.h" -#include "ble_gatt.h" -#include "ble_gattc.h" -#include "ble_gatts.h" -#include "ble_l2cap.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_COMMON_ENUMERATIONS Enumerations - * @{ */ - -/** - * @brief Common API SVC numbers. - */ -enum BLE_COMMON_SVCS { - SD_BLE_ENABLE = BLE_SVC_BASE, /**< Enable and initialize the BLE stack */ - SD_BLE_EVT_GET, /**< Get an event from the pending events queue. */ - SD_BLE_UUID_VS_ADD, /**< Add a Vendor Specific base UUID. */ - SD_BLE_UUID_DECODE, /**< Decode UUID bytes. */ - SD_BLE_UUID_ENCODE, /**< Encode UUID bytes. */ - SD_BLE_VERSION_GET, /**< Get the local version information (company ID, Link Layer Version, Link Layer Subversion). */ - SD_BLE_USER_MEM_REPLY, /**< User Memory Reply. */ - SD_BLE_OPT_SET, /**< Set a BLE option. */ - SD_BLE_OPT_GET, /**< Get a BLE option. */ - SD_BLE_CFG_SET, /**< Add a configuration to the BLE stack. */ - SD_BLE_UUID_VS_REMOVE, /**< Remove a Vendor Specific base UUID. */ -}; - -/** - * @brief BLE Module Independent Event IDs. - */ -enum BLE_COMMON_EVTS { - BLE_EVT_USER_MEM_REQUEST = BLE_EVT_BASE + 0, /**< User Memory request. See @ref ble_evt_user_mem_request_t - \n Reply with @ref sd_ble_user_mem_reply. */ - BLE_EVT_USER_MEM_RELEASE = BLE_EVT_BASE + 1, /**< User Memory release. See @ref ble_evt_user_mem_release_t */ -}; - -/**@brief BLE Connection Configuration IDs. - * - * IDs that uniquely identify a connection configuration. - */ -enum BLE_CONN_CFGS { - BLE_CONN_CFG_GAP = BLE_CONN_CFG_BASE + 0, /**< BLE GAP specific connection configuration. */ - BLE_CONN_CFG_GATTC = BLE_CONN_CFG_BASE + 1, /**< BLE GATTC specific connection configuration. */ - BLE_CONN_CFG_GATTS = BLE_CONN_CFG_BASE + 2, /**< BLE GATTS specific connection configuration. */ - BLE_CONN_CFG_GATT = BLE_CONN_CFG_BASE + 3, /**< BLE GATT specific connection configuration. */ - BLE_CONN_CFG_L2CAP = BLE_CONN_CFG_BASE + 4, /**< BLE L2CAP specific connection configuration. */ -}; - -/**@brief BLE Common Configuration IDs. - * - * IDs that uniquely identify a common configuration. - */ -enum BLE_COMMON_CFGS { - BLE_COMMON_CFG_VS_UUID = BLE_CFG_BASE, /**< Vendor specific base UUID configuration */ -}; - -/**@brief Common Option IDs. - * IDs that uniquely identify a common option. - */ -enum BLE_COMMON_OPTS { - BLE_COMMON_OPT_PA_LNA = BLE_OPT_BASE + 0, /**< PA and LNA options */ - BLE_COMMON_OPT_CONN_EVT_EXT = BLE_OPT_BASE + 1, /**< Extended connection events option */ - BLE_COMMON_OPT_EXTENDED_RC_CAL = BLE_OPT_BASE + 2, /**< Extended RC calibration option */ -}; - -/** @} */ - -/** @addtogroup BLE_COMMON_DEFINES Defines - * @{ */ - -/** @brief Required pointer alignment for BLE Events. - */ -#define BLE_EVT_PTR_ALIGNMENT 4 - -/** @brief Leaves the maximum of the two arguments. - */ -#define BLE_MAX(a, b) ((a) < (b) ? (b) : (a)) - -/** @brief Maximum possible length for BLE Events. - * @note The highest value used for @ref ble_gatt_conn_cfg_t::att_mtu in any connection configuration shall be used as a - * parameter. If that value has not been configured for any connections then @ref BLE_GATT_ATT_MTU_DEFAULT must be used instead. - */ -#define BLE_EVT_LEN_MAX(ATT_MTU) \ - (offsetof(ble_evt_t, evt.gattc_evt.params.prim_srvc_disc_rsp.services) + ((ATT_MTU)-1) / 4 * sizeof(ble_gattc_service_t)) - -/** @defgroup BLE_USER_MEM_TYPES User Memory Types - * @{ */ -#define BLE_USER_MEM_TYPE_INVALID 0x00 /**< Invalid User Memory Types. */ -#define BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES 0x01 /**< User Memory for GATTS queued writes. */ -/** @} */ - -/** @defgroup BLE_UUID_VS_COUNTS Vendor Specific base UUID counts - * @{ - */ -#define BLE_UUID_VS_COUNT_DEFAULT 10 /**< Default VS UUID count. */ -#define BLE_UUID_VS_COUNT_MAX 254 /**< Maximum VS UUID count. */ -/** @} */ - -/** @defgroup BLE_COMMON_CFG_DEFAULTS Configuration defaults. - * @{ - */ -#define BLE_CONN_CFG_TAG_DEFAULT 0 /**< Default configuration tag, SoftDevice default connection configuration. */ - -/** @} */ - -/** @} */ - -/** @addtogroup BLE_COMMON_STRUCTURES Structures - * @{ */ - -/**@brief User Memory Block. */ -typedef struct { - uint8_t *p_mem; /**< Pointer to the start of the user memory block. */ - uint16_t len; /**< Length in bytes of the user memory block. */ -} ble_user_mem_block_t; - -/**@brief Event structure for @ref BLE_EVT_USER_MEM_REQUEST. */ -typedef struct { - uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ -} ble_evt_user_mem_request_t; - -/**@brief Event structure for @ref BLE_EVT_USER_MEM_RELEASE. */ -typedef struct { - uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ - ble_user_mem_block_t mem_block; /**< User memory block */ -} ble_evt_user_mem_release_t; - -/**@brief Event structure for events not associated with a specific function module. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which this event occurred. */ - union { - ble_evt_user_mem_request_t user_mem_request; /**< User Memory Request Event Parameters. */ - ble_evt_user_mem_release_t user_mem_release; /**< User Memory Release Event Parameters. */ - } params; /**< Event parameter union. */ -} ble_common_evt_t; - -/**@brief BLE Event header. */ -typedef struct { - uint16_t evt_id; /**< Value from a BLE__EVT series. */ - uint16_t evt_len; /**< Length in octets including this header. */ -} ble_evt_hdr_t; - -/**@brief Common BLE Event type, wrapping the module specific event reports. */ -typedef struct { - ble_evt_hdr_t header; /**< Event header. */ - union { - ble_common_evt_t common_evt; /**< Common Event, evt_id in BLE_EVT_* series. */ - ble_gap_evt_t gap_evt; /**< GAP originated event, evt_id in BLE_GAP_EVT_* series. */ - ble_gattc_evt_t gattc_evt; /**< GATT client originated event, evt_id in BLE_GATTC_EVT* series. */ - ble_gatts_evt_t gatts_evt; /**< GATT server originated event, evt_id in BLE_GATTS_EVT* series. */ - ble_l2cap_evt_t l2cap_evt; /**< L2CAP originated event, evt_id in BLE_L2CAP_EVT* series. */ - } evt; /**< Event union. */ -} ble_evt_t; - -/** - * @brief Version Information. - */ -typedef struct { - uint8_t version_number; /**< Link Layer Version number. See - https://www.bluetooth.org/en-us/specification/assigned-numbers/link-layer for assigned values. */ - uint16_t company_id; /**< Company ID, Nordic Semiconductor's company ID is 89 (0x0059) - (https://www.bluetooth.org/apps/content/Default.aspx?doc_id=49708). */ - uint16_t - subversion_number; /**< Link Layer Sub Version number, corresponds to the SoftDevice Config ID or Firmware ID (FWID). */ -} ble_version_t; - -/** - * @brief Configuration parameters for the PA and LNA. - */ -typedef struct { - uint8_t enable : 1; /**< Enable toggling for this amplifier */ - uint8_t active_high : 1; /**< Set the pin to be active high */ - uint8_t gpio_pin : 6; /**< The GPIO pin to toggle for this amplifier */ -} ble_pa_lna_cfg_t; - -/** - * @brief PA & LNA GPIO toggle configuration - * - * This option configures the SoftDevice to toggle pins when the radio is active for use with a power amplifier and/or - * a low noise amplifier. - * - * Toggling the pins is achieved by using two PPI channels and a GPIOTE channel. The hardware channel IDs are provided - * by the application and should be regarded as reserved as long as any PA/LNA toggling is enabled. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * @note Setting this option while the radio is in use (i.e. any of the roles are active) may have undefined consequences - * and must be avoided by the application. - */ -typedef struct { - ble_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */ - ble_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */ - - uint8_t ppi_ch_id_set; /**< PPI channel used for radio pin setting */ - uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */ - uint8_t gpiote_ch_id; /**< GPIOTE channel used for radio pin toggling */ -} ble_common_opt_pa_lna_t; - -/** - * @brief Configuration of extended BLE connection events. - * - * When enabled the SoftDevice will dynamically extend the connection event when possible. - * - * The connection event length is controlled by the connection configuration as set by @ref ble_gap_conn_cfg_t::event_length. - * The connection event can be extended if there is time to send another packet pair before the start of the next connection - * interval, and if there are no conflicts with other BLE roles requesting radio time. - * - * @note @ref sd_ble_opt_get is not supported for this option. - */ -typedef struct { - uint8_t enable : 1; /**< Enable extended BLE connection events, disabled by default. */ -} ble_common_opt_conn_evt_ext_t; - -/** - * @brief Enable/disable extended RC calibration. - * - * If extended RC calibration is enabled and the internal RC oscillator (@ref NRF_CLOCK_LF_SRC_RC) is used as the SoftDevice - * LFCLK source, the SoftDevice as a peripheral will by default try to increase the receive window if two consecutive packets - * are not received. If it turns out that the packets were not received due to clock drift, the RC calibration is started. - * This calibration comes in addition to the periodic calibration that is configured by @ref sd_softdevice_enable(). When - * using only peripheral connections, the periodic calibration can therefore be configured with a much longer interval as the - * peripheral will be able to detect and adjust automatically to clock drift, and calibrate on demand. - * - * If extended RC calibration is disabled and the internal RC oscillator is used as the SoftDevice LFCLK source, the - * RC oscillator is calibrated periodically as configured by @ref sd_softdevice_enable(). - * - * @note @ref sd_ble_opt_get is not supported for this option. - */ -typedef struct { - uint8_t enable : 1; /**< Enable extended RC calibration, enabled by default. */ -} ble_common_opt_extended_rc_cal_t; - -/**@brief Option structure for common options. */ -typedef union { - ble_common_opt_pa_lna_t pa_lna; /**< Parameters for controlling PA and LNA pin toggling. */ - ble_common_opt_conn_evt_ext_t conn_evt_ext; /**< Parameters for enabling extended connection events. */ - ble_common_opt_extended_rc_cal_t extended_rc_cal; /**< Parameters for enabling extended RC calibration. */ -} ble_common_opt_t; - -/**@brief Common BLE Option type, wrapping the module specific options. */ -typedef union { - ble_common_opt_t common_opt; /**< COMMON options, opt_id in @ref BLE_COMMON_OPTS series. */ - ble_gap_opt_t gap_opt; /**< GAP option, opt_id in @ref BLE_GAP_OPTS series. */ - ble_gattc_opt_t gattc_opt; /**< GATTC option, opt_id in @ref BLE_GATTC_OPTS series. */ -} ble_opt_t; - -/**@brief BLE connection configuration type, wrapping the module specific configurations, set with - * @ref sd_ble_cfg_set. - * - * @note Connection configurations don't have to be set. - * In the case that no configurations has been set, or fewer connection configurations has been set than enabled connections, - * the default connection configuration will be automatically added for the remaining connections. - * When creating connections with the default configuration, @ref BLE_CONN_CFG_TAG_DEFAULT should be used in - * place of @ref ble_conn_cfg_t::conn_cfg_tag. - * - * @sa sd_ble_gap_adv_start() - * @sa sd_ble_gap_connect() - * - * @mscs - * @mmsc{@ref BLE_CONN_CFG} - * @endmscs - - */ -typedef struct { - uint8_t conn_cfg_tag; /**< The application chosen tag it can use with the - @ref sd_ble_gap_adv_start() and @ref sd_ble_gap_connect() calls - to select this configuration when creating a connection. - Must be different for all connection configurations added and not @ref BLE_CONN_CFG_TAG_DEFAULT. */ - union { - ble_gap_conn_cfg_t gap_conn_cfg; /**< GAP connection configuration, cfg_id is @ref BLE_CONN_CFG_GAP. */ - ble_gattc_conn_cfg_t gattc_conn_cfg; /**< GATTC connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTC. */ - ble_gatts_conn_cfg_t gatts_conn_cfg; /**< GATTS connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTS. */ - ble_gatt_conn_cfg_t gatt_conn_cfg; /**< GATT connection configuration, cfg_id is @ref BLE_CONN_CFG_GATT. */ - ble_l2cap_conn_cfg_t l2cap_conn_cfg; /**< L2CAP connection configuration, cfg_id is @ref BLE_CONN_CFG_L2CAP. */ - } params; /**< Connection configuration union. */ -} ble_conn_cfg_t; - -/** - * @brief Configuration of Vendor Specific base UUIDs, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_PARAM Too many UUIDs configured. - */ -typedef struct { - uint8_t vs_uuid_count; /**< Number of 128-bit Vendor Specific base UUID bases to allocate memory for. - Default value is @ref BLE_UUID_VS_COUNT_DEFAULT. Maximum value is - @ref BLE_UUID_VS_COUNT_MAX. */ -} ble_common_cfg_vs_uuid_t; - -/**@brief Common BLE Configuration type, wrapping the common configurations. */ -typedef union { - ble_common_cfg_vs_uuid_t vs_uuid_cfg; /**< Vendor Specific base UUID configuration, cfg_id is @ref BLE_COMMON_CFG_VS_UUID. */ -} ble_common_cfg_t; - -/**@brief BLE Configuration type, wrapping the module specific configurations. */ -typedef union { - ble_conn_cfg_t conn_cfg; /**< Connection specific configurations, cfg_id in @ref BLE_CONN_CFGS series. */ - ble_common_cfg_t common_cfg; /**< Global common configurations, cfg_id in @ref BLE_COMMON_CFGS series. */ - ble_gap_cfg_t gap_cfg; /**< Global GAP configurations, cfg_id in @ref BLE_GAP_CFGS series. */ - ble_gatts_cfg_t gatts_cfg; /**< Global GATTS configuration, cfg_id in @ref BLE_GATTS_CFGS series. */ -} ble_cfg_t; - -/** @} */ - -/** @addtogroup BLE_COMMON_FUNCTIONS Functions - * @{ */ - -/**@brief Enable the BLE stack - * - * @param[in, out] p_app_ram_base Pointer to a variable containing the start address of the - * application RAM region (APP_RAM_BASE). On return, this will - * contain the minimum start address of the application RAM region - * required by the SoftDevice for this configuration. - * @warning After this call, the SoftDevice may generate several events. The list of events provided - * below require the application to initiate a SoftDevice API call. The corresponding API call - * is referenced in the event documentation. - * If the application fails to do so, the BLE connection may timeout, or the SoftDevice may stop - * communicating with the peer device. - * - @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST - * - @ref BLE_GAP_EVT_SEC_INFO_REQUEST - * - @ref BLE_GAP_EVT_SEC_REQUEST - * - @ref BLE_GAP_EVT_AUTH_KEY_REQUEST - * - @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST - * - @ref BLE_EVT_USER_MEM_REQUEST - * - @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST - * - * @note The memory requirement for a specific configuration will not increase between SoftDevices - * with the same major version number. - * - * @note At runtime the IC's RAM is split into 2 regions: The SoftDevice RAM region is located - * between 0x20000000 and APP_RAM_BASE-1 and the application's RAM region is located between - * APP_RAM_BASE and the start of the call stack. - * - * @details This call initializes the BLE stack, no BLE related function other than @ref - * sd_ble_cfg_set can be called before this one. - * - * @mscs - * @mmsc{@ref BLE_COMMON_ENABLE} - * @endmscs - * - * @retval ::NRF_SUCCESS The BLE stack has been initialized successfully. - * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized and cannot be reinitialized. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_NO_MEM One or more of the following is true: - * - The amount of memory assigned to the SoftDevice by *p_app_ram_base is not - * large enough to fit this configuration's memory requirement. Check *p_app_ram_base - * and set the start address of the application RAM region accordingly. - * - Dynamic part of the SoftDevice RAM region is larger then 64 kB which - * is currently not supported. - * @retval ::NRF_ERROR_RESOURCES The total number of L2CAP Channels configured using @ref sd_ble_cfg_set is too large. - */ -SVCALL(SD_BLE_ENABLE, uint32_t, sd_ble_enable(uint32_t *p_app_ram_base)); - -/**@brief Add configurations for the BLE stack - * - * @param[in] cfg_id Config ID, see @ref BLE_CONN_CFGS, @ref BLE_COMMON_CFGS, @ref - * BLE_GAP_CFGS or @ref BLE_GATTS_CFGS. - * @param[in] p_cfg Pointer to a ble_cfg_t structure containing the configuration value. - * @param[in] app_ram_base The start address of the application RAM region (APP_RAM_BASE). - * See @ref sd_ble_enable for details about APP_RAM_BASE. - * - * @note The memory requirement for a specific configuration will not increase between SoftDevices - * with the same major version number. - * - * @note If a configuration is set more than once, the last one set is the one that takes effect on - * @ref sd_ble_enable. - * - * @note Any part of the BLE stack that is NOT configured with @ref sd_ble_cfg_set will have default - * configuration. - * - * @note @ref sd_ble_cfg_set may be called at any time when the SoftDevice is enabled (see @ref - * sd_softdevice_enable) while the BLE part of the SoftDevice is not enabled (see @ref - * sd_ble_enable). - * - * @note Error codes for the configurations are described in the configuration structs. - * - * @mscs - * @mmsc{@ref BLE_COMMON_ENABLE} - * @endmscs - * - * @retval ::NRF_SUCCESS The configuration has been added successfully. - * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid cfg_id supplied. - * @retval ::NRF_ERROR_NO_MEM The amount of memory assigned to the SoftDevice by app_ram_base is not - * large enough to fit this configuration's memory requirement. - */ -SVCALL(SD_BLE_CFG_SET, uint32_t, sd_ble_cfg_set(uint32_t cfg_id, ble_cfg_t const *p_cfg, uint32_t app_ram_base)); - -/**@brief Get an event from the pending events queue. - * - * @param[out] p_dest Pointer to buffer to be filled in with an event, or NULL to retrieve the event length. - * This buffer must be aligned to the extend defined by @ref BLE_EVT_PTR_ALIGNMENT. - * The buffer should be interpreted as a @ref ble_evt_t struct. - * @param[in, out] p_len Pointer the length of the buffer, on return it is filled with the event length. - * - * @details This call allows the application to pull a BLE event from the BLE stack. The application is signaled that - * an event is available from the BLE stack by the triggering of the SD_EVT_IRQn interrupt. - * The application is free to choose whether to call this function from thread mode (main context) or directly from the - * Interrupt Service Routine that maps to SD_EVT_IRQn. In any case however, and because the BLE stack runs at a higher - * priority than the application, this function should be called in a loop (until @ref NRF_ERROR_NOT_FOUND is returned) - * every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the BLE stack. Failure to do so - * could potentially leave events in the internal queue without the application being aware of this fact. - * - * Sizing the p_dest buffer is equally important, since the application needs to provide all the memory necessary for the event to - * be copied into application memory. If the buffer provided is not large enough to fit the entire contents of the event, - * @ref NRF_ERROR_DATA_SIZE will be returned and the application can then call again with a larger buffer size. - * The maximum possible event length is defined by @ref BLE_EVT_LEN_MAX. The application may also "peek" the event length - * by providing p_dest as a NULL pointer and inspecting the value of *p_len upon return: - * - * \code - * uint16_t len; - * errcode = sd_ble_evt_get(NULL, &len); - * \endcode - * - * @mscs - * @mmsc{@ref BLE_COMMON_IRQ_EVT_MSC} - * @mmsc{@ref BLE_COMMON_THREAD_EVT_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Event pulled and stored into the supplied buffer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_NOT_FOUND No events ready to be pulled. - * @retval ::NRF_ERROR_DATA_SIZE Event ready but could not fit into the supplied buffer. - */ -SVCALL(SD_BLE_EVT_GET, uint32_t, sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len)); - -/**@brief Add a Vendor Specific base UUID. - * - * @details This call enables the application to add a Vendor Specific base UUID to the BLE stack's table, for later - * use with all other modules and APIs. This then allows the application to use the shorter, 24-bit @ref ble_uuid_t - * format when dealing with both 16-bit and 128-bit UUIDs without having to check for lengths and having split code - * paths. This is accomplished by extending the grouping mechanism that the Bluetooth SIG standard base UUID uses - * for all other 128-bit UUIDs. The type field in the @ref ble_uuid_t structure is an index (relative to - * @ref BLE_UUID_TYPE_VENDOR_BEGIN) to the table populated by multiple calls to this function, and the UUID field - * in the same structure contains the 2 bytes at indexes 12 and 13. The number of possible 128-bit UUIDs available to - * the application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536, - * although restricted to modifying bytes 12 and 13 for each of the entries in the supplied array. - * - * @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by - * the 16-bit uuid field in @ref ble_uuid_t. - * - * @note If a UUID is already present in the BLE stack's internal table, the corresponding index will be returned in - * p_uuid_type along with an @ref NRF_SUCCESS error code. - * - * @param[in] p_vs_uuid Pointer to a 16-octet (128-bit) little endian Vendor Specific base UUID disregarding - * bytes 12 and 13. - * @param[out] p_uuid_type Pointer to a uint8_t where the type field in @ref ble_uuid_t corresponding to this UUID will be - * stored. - * - * @retval ::NRF_SUCCESS Successfully added the Vendor Specific base UUID. - * @retval ::NRF_ERROR_INVALID_ADDR If p_vs_uuid or p_uuid_type is NULL or invalid. - * @retval ::NRF_ERROR_NO_MEM If there are no more free slots for VS UUIDs. - */ -SVCALL(SD_BLE_UUID_VS_ADD, uint32_t, sd_ble_uuid_vs_add(ble_uuid128_t const *p_vs_uuid, uint8_t *p_uuid_type)); - -/**@brief Remove a Vendor Specific base UUID. - * - * @details This call removes a Vendor Specific base UUID. This function allows - * the application to reuse memory allocated for Vendor Specific base UUIDs. - * - * @note Currently this function can only be called with a p_uuid_type set to @ref BLE_UUID_TYPE_UNKNOWN or the last added UUID - * type. - * - * @param[inout] p_uuid_type Pointer to a uint8_t where its value matches the UUID type in @ref ble_uuid_t::type to be removed. - * If the type is set to @ref BLE_UUID_TYPE_UNKNOWN, or the pointer is NULL, the last Vendor Specific - * base UUID will be removed. If the function returns successfully, the UUID type that was removed will - * be written back to @p p_uuid_type. If function returns with a failure, it contains the last type that - * is in use by the ATT Server. - * - * @retval ::NRF_SUCCESS Successfully removed the Vendor Specific base UUID. - * @retval ::NRF_ERROR_INVALID_ADDR If p_uuid_type is invalid. - * @retval ::NRF_ERROR_INVALID_PARAM If p_uuid_type points to a non-valid UUID type. - * @retval ::NRF_ERROR_FORBIDDEN If the Vendor Specific base UUID is in use by the ATT Server. - */ -SVCALL(SD_BLE_UUID_VS_REMOVE, uint32_t, sd_ble_uuid_vs_remove(uint8_t *p_uuid_type)); - -/** @brief Decode little endian raw UUID bytes (16-bit or 128-bit) into a 24 bit @ref ble_uuid_t structure. - * - * @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared - * to the corresponding ones in each entry of the table of Vendor Specific base UUIDs - * to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index - * relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type. - * - * @note If the UUID length supplied is 2, then the type set by this call will always be @ref BLE_UUID_TYPE_BLE. - * - * @param[in] uuid_le_len Length in bytes of the buffer pointed to by p_uuid_le (must be 2 or 16 bytes). - * @param[in] p_uuid_le Pointer pointing to little endian raw UUID bytes. - * @param[out] p_uuid Pointer to a @ref ble_uuid_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Successfully decoded into the @ref ble_uuid_t structure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid UUID length. - * @retval ::NRF_ERROR_NOT_FOUND For a 128-bit UUID, no match in the populated table of UUIDs. - */ -SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uint8_t const *p_uuid_le, ble_uuid_t *p_uuid)); - -/** @brief Encode a @ref ble_uuid_t structure into little endian raw UUID bytes (16-bit or 128-bit). - * - * @note The pointer to the destination buffer p_uuid_le may be NULL, in which case only the validity and size of p_uuid is - * computed. - * - * @param[in] p_uuid Pointer to a @ref ble_uuid_t structure that will be encoded into bytes. - * @param[out] p_uuid_le_len Pointer to a uint8_t that will be filled with the encoded length (2 or 16 bytes). - * @param[out] p_uuid_le Pointer to a buffer where the little endian raw UUID bytes (2 or 16) will be stored. - * - * @retval ::NRF_SUCCESS Successfully encoded into the buffer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid UUID type. - */ -SVCALL(SD_BLE_UUID_ENCODE, uint32_t, sd_ble_uuid_encode(ble_uuid_t const *p_uuid, uint8_t *p_uuid_le_len, uint8_t *p_uuid_le)); - -/**@brief Get Version Information. - * - * @details This call allows the application to get the BLE stack version information. - * - * @param[out] p_version Pointer to a ble_version_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Version information stored successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy (typically doing a locally-initiated disconnection procedure). - */ -SVCALL(SD_BLE_VERSION_GET, uint32_t, sd_ble_version_get(ble_version_t *p_version)); - -/**@brief Provide a user memory block. - * - * @note This call can only be used as a response to a @ref BLE_EVT_USER_MEM_REQUEST event issued to the application. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_block Pointer to a user memory block structure or NULL if memory is managed by the application. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully queued a response to the peer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid user memory block length supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection state or no user memory request pending. - */ -SVCALL(SD_BLE_USER_MEM_REPLY, uint32_t, sd_ble_user_mem_reply(uint16_t conn_handle, ble_user_mem_block_t const *p_block)); - -/**@brief Set a BLE option. - * - * @details This call allows the application to set the value of an option. - * - * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS, @ref BLE_GAP_OPTS, and @ref BLE_GATTC_OPTS. - * @param[in] p_opt Pointer to a @ref ble_opt_t structure containing the option value. - * - * @retval ::NRF_SUCCESS Option set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Unable to set the parameter at this time. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. - */ -SVCALL(SD_BLE_OPT_SET, uint32_t, sd_ble_opt_set(uint32_t opt_id, ble_opt_t const *p_opt)); - -/**@brief Get a BLE option. - * - * @details This call allows the application to retrieve the value of an option. - * - * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS and @ref BLE_GAP_OPTS. - * @param[out] p_opt Pointer to a ble_opt_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Option retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Unable to retrieve the parameter at this time. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. - * @retval ::NRF_ERROR_NOT_SUPPORTED This option is not supported. - * - */ -SVCALL(SD_BLE_OPT_GET, uint32_t, sd_ble_opt_get(uint32_t opt_id, ble_opt_t *p_opt)); - -/** @} */ -#ifdef __cplusplus -} -#endif -#endif /* BLE_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_err.h b/variants/wio-sdk-wm1110/softdevice/ble_err.h deleted file mode 100644 index d20f6d1416..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_err.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @addtogroup nrf_error - @{ - @ingroup BLE_COMMON - @} - - @defgroup ble_err General error codes - @{ - - @brief General error code definitions for the BLE API. - - @ingroup BLE_COMMON -*/ -#ifndef NRF_BLE_ERR_H__ -#define NRF_BLE_ERR_H__ - -#include "nrf_error.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* @defgroup BLE_ERRORS Error Codes - * @{ */ -#define BLE_ERROR_NOT_ENABLED (NRF_ERROR_STK_BASE_NUM + 0x001) /**< @ref sd_ble_enable has not been called. */ -#define BLE_ERROR_INVALID_CONN_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x002) /**< Invalid connection handle. */ -#define BLE_ERROR_INVALID_ATTR_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x003) /**< Invalid attribute handle. */ -#define BLE_ERROR_INVALID_ADV_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x004) /**< Invalid advertising handle. */ -#define BLE_ERROR_INVALID_ROLE (NRF_ERROR_STK_BASE_NUM + 0x005) /**< Invalid role. */ -#define BLE_ERROR_BLOCKED_BY_OTHER_LINKS \ - (NRF_ERROR_STK_BASE_NUM + 0x006) /**< The attempt to change link settings failed due to the scheduling of other links. */ -/** @} */ - -/** @defgroup BLE_ERROR_SUBRANGES Module specific error code subranges - * @brief Assignment of subranges for module specific error codes. - * @note For specific error codes, see ble_.h or ble_error_.h. - * @{ */ -#define NRF_L2CAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x100) /**< L2CAP specific errors. */ -#define NRF_GAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x200) /**< GAP specific errors. */ -#define NRF_GATTC_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x300) /**< GATT client specific errors. */ -#define NRF_GATTS_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x400) /**< GATT server specific errors. */ -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif - -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gap.h b/variants/wio-sdk-wm1110/softdevice/ble_gap.h deleted file mode 100644 index 8ebdfa82b0..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_gap.h +++ /dev/null @@ -1,2895 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GAP Generic Access Profile (GAP) - @{ - @brief Definitions and prototypes for the GAP interface. - */ - -#ifndef BLE_GAP_H__ -#define BLE_GAP_H__ - -#include "ble_err.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup BLE_GAP_ENUMERATIONS Enumerations - * @{ */ - -/**@brief GAP API SVC numbers. - */ -enum BLE_GAP_SVCS { - SD_BLE_GAP_ADDR_SET = BLE_GAP_SVC_BASE, /**< Set own Bluetooth Address. */ - SD_BLE_GAP_ADDR_GET = BLE_GAP_SVC_BASE + 1, /**< Get own Bluetooth Address. */ - SD_BLE_GAP_WHITELIST_SET = BLE_GAP_SVC_BASE + 2, /**< Set active whitelist. */ - SD_BLE_GAP_DEVICE_IDENTITIES_SET = BLE_GAP_SVC_BASE + 3, /**< Set device identity list. */ - SD_BLE_GAP_PRIVACY_SET = BLE_GAP_SVC_BASE + 4, /**< Set Privacy settings*/ - SD_BLE_GAP_PRIVACY_GET = BLE_GAP_SVC_BASE + 5, /**< Get Privacy settings*/ - SD_BLE_GAP_ADV_SET_CONFIGURE = BLE_GAP_SVC_BASE + 6, /**< Configure an advertising set. */ - SD_BLE_GAP_ADV_START = BLE_GAP_SVC_BASE + 7, /**< Start Advertising. */ - SD_BLE_GAP_ADV_STOP = BLE_GAP_SVC_BASE + 8, /**< Stop Advertising. */ - SD_BLE_GAP_CONN_PARAM_UPDATE = BLE_GAP_SVC_BASE + 9, /**< Connection Parameter Update. */ - SD_BLE_GAP_DISCONNECT = BLE_GAP_SVC_BASE + 10, /**< Disconnect. */ - SD_BLE_GAP_TX_POWER_SET = BLE_GAP_SVC_BASE + 11, /**< Set TX Power. */ - SD_BLE_GAP_APPEARANCE_SET = BLE_GAP_SVC_BASE + 12, /**< Set Appearance. */ - SD_BLE_GAP_APPEARANCE_GET = BLE_GAP_SVC_BASE + 13, /**< Get Appearance. */ - SD_BLE_GAP_PPCP_SET = BLE_GAP_SVC_BASE + 14, /**< Set PPCP. */ - SD_BLE_GAP_PPCP_GET = BLE_GAP_SVC_BASE + 15, /**< Get PPCP. */ - SD_BLE_GAP_DEVICE_NAME_SET = BLE_GAP_SVC_BASE + 16, /**< Set Device Name. */ - SD_BLE_GAP_DEVICE_NAME_GET = BLE_GAP_SVC_BASE + 17, /**< Get Device Name. */ - SD_BLE_GAP_AUTHENTICATE = BLE_GAP_SVC_BASE + 18, /**< Initiate Pairing/Bonding. */ - SD_BLE_GAP_SEC_PARAMS_REPLY = BLE_GAP_SVC_BASE + 19, /**< Reply with Security Parameters. */ - SD_BLE_GAP_AUTH_KEY_REPLY = BLE_GAP_SVC_BASE + 20, /**< Reply with an authentication key. */ - SD_BLE_GAP_LESC_DHKEY_REPLY = BLE_GAP_SVC_BASE + 21, /**< Reply with an LE Secure Connections DHKey. */ - SD_BLE_GAP_KEYPRESS_NOTIFY = BLE_GAP_SVC_BASE + 22, /**< Notify of a keypress during an authentication procedure. */ - SD_BLE_GAP_LESC_OOB_DATA_GET = BLE_GAP_SVC_BASE + 23, /**< Get the local LE Secure Connections OOB data. */ - SD_BLE_GAP_LESC_OOB_DATA_SET = BLE_GAP_SVC_BASE + 24, /**< Set the remote LE Secure Connections OOB data. */ - SD_BLE_GAP_ENCRYPT = BLE_GAP_SVC_BASE + 25, /**< Initiate encryption procedure. */ - SD_BLE_GAP_SEC_INFO_REPLY = BLE_GAP_SVC_BASE + 26, /**< Reply with Security Information. */ - SD_BLE_GAP_CONN_SEC_GET = BLE_GAP_SVC_BASE + 27, /**< Obtain connection security level. */ - SD_BLE_GAP_RSSI_START = BLE_GAP_SVC_BASE + 28, /**< Start reporting of changes in RSSI. */ - SD_BLE_GAP_RSSI_STOP = BLE_GAP_SVC_BASE + 29, /**< Stop reporting of changes in RSSI. */ - SD_BLE_GAP_SCAN_START = BLE_GAP_SVC_BASE + 30, /**< Start Scanning. */ - SD_BLE_GAP_SCAN_STOP = BLE_GAP_SVC_BASE + 31, /**< Stop Scanning. */ - SD_BLE_GAP_CONNECT = BLE_GAP_SVC_BASE + 32, /**< Connect. */ - SD_BLE_GAP_CONNECT_CANCEL = BLE_GAP_SVC_BASE + 33, /**< Cancel ongoing connection procedure. */ - SD_BLE_GAP_RSSI_GET = BLE_GAP_SVC_BASE + 34, /**< Get the last RSSI sample. */ - SD_BLE_GAP_PHY_UPDATE = BLE_GAP_SVC_BASE + 35, /**< Initiate or respond to a PHY Update Procedure. */ - SD_BLE_GAP_DATA_LENGTH_UPDATE = BLE_GAP_SVC_BASE + 36, /**< Initiate or respond to a Data Length Update Procedure. */ - SD_BLE_GAP_QOS_CHANNEL_SURVEY_START = BLE_GAP_SVC_BASE + 37, /**< Start Quality of Service (QoS) channel survey module. */ - SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP = BLE_GAP_SVC_BASE + 38, /**< Stop Quality of Service (QoS) channel survey module. */ - SD_BLE_GAP_ADV_ADDR_GET = BLE_GAP_SVC_BASE + 39, /**< Get the Address used on air while Advertising. */ - SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET = BLE_GAP_SVC_BASE + 40, /**< Get the next connection event counter. */ - SD_BLE_GAP_CONN_EVT_TRIGGER_START = BLE_GAP_SVC_BASE + 41, /** Start triggering a given task on connection event start. */ - SD_BLE_GAP_CONN_EVT_TRIGGER_STOP = - BLE_GAP_SVC_BASE + 42, /** Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. */ -}; - -/**@brief GAP Event IDs. - * IDs that uniquely identify an event coming from the stack to the application. - */ -enum BLE_GAP_EVTS { - BLE_GAP_EVT_CONNECTED = - BLE_GAP_EVT_BASE, /**< Connected to peer. \n See @ref ble_gap_evt_connected_t */ - BLE_GAP_EVT_DISCONNECTED = - BLE_GAP_EVT_BASE + 1, /**< Disconnected from peer. \n See @ref ble_gap_evt_disconnected_t. */ - BLE_GAP_EVT_CONN_PARAM_UPDATE = - BLE_GAP_EVT_BASE + 2, /**< Connection Parameters updated. \n See @ref ble_gap_evt_conn_param_update_t. */ - BLE_GAP_EVT_SEC_PARAMS_REQUEST = - BLE_GAP_EVT_BASE + 3, /**< Request to provide security parameters. \n Reply with @ref sd_ble_gap_sec_params_reply. - \n See @ref ble_gap_evt_sec_params_request_t. */ - BLE_GAP_EVT_SEC_INFO_REQUEST = - BLE_GAP_EVT_BASE + 4, /**< Request to provide security information. \n Reply with @ref sd_ble_gap_sec_info_reply. - \n See @ref ble_gap_evt_sec_info_request_t. */ - BLE_GAP_EVT_PASSKEY_DISPLAY = - BLE_GAP_EVT_BASE + 5, /**< Request to display a passkey to the user. \n In LESC Numeric Comparison, reply with @ref - sd_ble_gap_auth_key_reply. \n See @ref ble_gap_evt_passkey_display_t. */ - BLE_GAP_EVT_KEY_PRESSED = - BLE_GAP_EVT_BASE + 6, /**< Notification of a keypress on the remote device.\n See @ref ble_gap_evt_key_pressed_t */ - BLE_GAP_EVT_AUTH_KEY_REQUEST = - BLE_GAP_EVT_BASE + 7, /**< Request to provide an authentication key. \n Reply with @ref sd_ble_gap_auth_key_reply. - \n See @ref ble_gap_evt_auth_key_request_t. */ - BLE_GAP_EVT_LESC_DHKEY_REQUEST = - BLE_GAP_EVT_BASE + 8, /**< Request to calculate an LE Secure Connections DHKey. \n Reply with @ref - sd_ble_gap_lesc_dhkey_reply. \n See @ref ble_gap_evt_lesc_dhkey_request_t */ - BLE_GAP_EVT_AUTH_STATUS = - BLE_GAP_EVT_BASE + 9, /**< Authentication procedure completed with status. \n See @ref ble_gap_evt_auth_status_t. */ - BLE_GAP_EVT_CONN_SEC_UPDATE = - BLE_GAP_EVT_BASE + 10, /**< Connection security updated. \n See @ref ble_gap_evt_conn_sec_update_t. */ - BLE_GAP_EVT_TIMEOUT = - BLE_GAP_EVT_BASE + 11, /**< Timeout expired. \n See @ref ble_gap_evt_timeout_t. */ - BLE_GAP_EVT_RSSI_CHANGED = - BLE_GAP_EVT_BASE + 12, /**< RSSI report. \n See @ref ble_gap_evt_rssi_changed_t. */ - BLE_GAP_EVT_ADV_REPORT = - BLE_GAP_EVT_BASE + 13, /**< Advertising report. \n See @ref ble_gap_evt_adv_report_t. */ - BLE_GAP_EVT_SEC_REQUEST = - BLE_GAP_EVT_BASE + 14, /**< Security Request. \n Reply with @ref sd_ble_gap_authenticate -\n or with @ref sd_ble_gap_encrypt if required security information is available -. \n See @ref ble_gap_evt_sec_request_t. */ - BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 15, /**< Connection Parameter Update Request. \n Reply with @ref - sd_ble_gap_conn_param_update. \n See @ref ble_gap_evt_conn_param_update_request_t. */ - BLE_GAP_EVT_SCAN_REQ_REPORT = - BLE_GAP_EVT_BASE + 16, /**< Scan request report. \n See @ref ble_gap_evt_scan_req_report_t. */ - BLE_GAP_EVT_PHY_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 17, /**< PHY Update Request. \n Reply with @ref sd_ble_gap_phy_update. \n - See @ref ble_gap_evt_phy_update_request_t. */ - BLE_GAP_EVT_PHY_UPDATE = - BLE_GAP_EVT_BASE + 18, /**< PHY Update Procedure is complete. \n See @ref ble_gap_evt_phy_update_t. */ - BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 19, /**< Data Length Update Request. \n Reply with @ref - sd_ble_gap_data_length_update. \n See @ref ble_gap_evt_data_length_update_request_t. */ - BLE_GAP_EVT_DATA_LENGTH_UPDATE = - BLE_GAP_EVT_BASE + - 20, /**< LL Data Channel PDU payload length updated. \n See @ref ble_gap_evt_data_length_update_t. */ - BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT = - BLE_GAP_EVT_BASE + - 21, /**< Channel survey report. \n See @ref ble_gap_evt_qos_channel_survey_report_t. */ - BLE_GAP_EVT_ADV_SET_TERMINATED = - BLE_GAP_EVT_BASE + - 22, /**< Advertising set terminated. \n See @ref ble_gap_evt_adv_set_terminated_t. */ -}; - -/**@brief GAP Option IDs. - * IDs that uniquely identify a GAP option. - */ -enum BLE_GAP_OPTS { - BLE_GAP_OPT_CH_MAP = BLE_GAP_OPT_BASE, /**< Channel Map. @ref ble_gap_opt_ch_map_t */ - BLE_GAP_OPT_LOCAL_CONN_LATENCY = BLE_GAP_OPT_BASE + 1, /**< Local connection latency. @ref ble_gap_opt_local_conn_latency_t */ - BLE_GAP_OPT_PASSKEY = BLE_GAP_OPT_BASE + 2, /**< Set passkey. @ref ble_gap_opt_passkey_t */ - BLE_GAP_OPT_COMPAT_MODE_1 = BLE_GAP_OPT_BASE + 3, /**< Compatibility mode. @ref ble_gap_opt_compat_mode_1_t */ - BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT = - BLE_GAP_OPT_BASE + 4, /**< Set Authenticated payload timeout. @ref ble_gap_opt_auth_payload_timeout_t */ - BLE_GAP_OPT_SLAVE_LATENCY_DISABLE = - BLE_GAP_OPT_BASE + 5, /**< Disable slave latency. @ref ble_gap_opt_slave_latency_disable_t */ -}; - -/**@brief GAP Configuration IDs. - * - * IDs that uniquely identify a GAP configuration. - */ -enum BLE_GAP_CFGS { - BLE_GAP_CFG_ROLE_COUNT = BLE_GAP_CFG_BASE, /**< Role count configuration. */ - BLE_GAP_CFG_DEVICE_NAME = BLE_GAP_CFG_BASE + 1, /**< Device name configuration. */ - BLE_GAP_CFG_PPCP_INCL_CONFIG = BLE_GAP_CFG_BASE + 2, /**< Peripheral Preferred Connection Parameters characteristic - inclusion configuration. */ - BLE_GAP_CFG_CAR_INCL_CONFIG = BLE_GAP_CFG_BASE + 3, /**< Central Address Resolution characteristic - inclusion configuration. */ -}; - -/**@brief GAP TX Power roles. - */ -enum BLE_GAP_TX_POWER_ROLES { - BLE_GAP_TX_POWER_ROLE_ADV = 1, /**< Advertiser role. */ - BLE_GAP_TX_POWER_ROLE_SCAN_INIT = 2, /**< Scanner and initiator role. */ - BLE_GAP_TX_POWER_ROLE_CONN = 3, /**< Connection role. */ -}; - -/** @} */ - -/**@addtogroup BLE_GAP_DEFINES Defines - * @{ */ - -/**@defgroup BLE_ERRORS_GAP SVC return values specific to GAP - * @{ */ -#define BLE_ERROR_GAP_UUID_LIST_MISMATCH \ - (NRF_GAP_ERR_BASE + 0x000) /**< UUID list does not contain an integral number of UUIDs. */ -#define BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST \ - (NRF_GAP_ERR_BASE + 0x001) /**< Use of Whitelist not permitted with discoverable advertising. */ -#define BLE_ERROR_GAP_INVALID_BLE_ADDR \ - (NRF_GAP_ERR_BASE + 0x002) /**< The upper two bits of the address do not correspond to the specified address type. */ -#define BLE_ERROR_GAP_WHITELIST_IN_USE \ - (NRF_GAP_ERR_BASE + 0x003) /**< Attempt to modify the whitelist while already in use by another operation. */ -#define BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE \ - (NRF_GAP_ERR_BASE + 0x004) /**< Attempt to modify the device identity list while already in use by another operation. */ -#define BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE \ - (NRF_GAP_ERR_BASE + 0x005) /**< The device identity list contains entries with duplicate identity addresses. */ -/**@} */ - -/**@defgroup BLE_GAP_ROLES GAP Roles - * @{ */ -#define BLE_GAP_ROLE_INVALID 0x0 /**< Invalid Role. */ -#define BLE_GAP_ROLE_PERIPH 0x1 /**< Peripheral Role. */ -#define BLE_GAP_ROLE_CENTRAL 0x2 /**< Central Role. */ -/**@} */ - -/**@defgroup BLE_GAP_TIMEOUT_SOURCES GAP Timeout sources - * @{ */ -#define BLE_GAP_TIMEOUT_SRC_SCAN 0x01 /**< Scanning timeout. */ -#define BLE_GAP_TIMEOUT_SRC_CONN 0x02 /**< Connection timeout. */ -#define BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD 0x03 /**< Authenticated payload timeout. */ -/**@} */ - -/**@defgroup BLE_GAP_ADDR_TYPES GAP Address types - * @{ */ -#define BLE_GAP_ADDR_TYPE_PUBLIC 0x00 /**< Public (identity) address.*/ -#define BLE_GAP_ADDR_TYPE_RANDOM_STATIC 0x01 /**< Random static (identity) address. */ -#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE 0x02 /**< Random private resolvable address. */ -#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE 0x03 /**< Random private non-resolvable address. */ -#define BLE_GAP_ADDR_TYPE_ANONYMOUS \ - 0x7F /**< An advertiser may advertise without its address. \ - This type of advertising is called anonymous. */ -/**@} */ - -/**@brief The default interval in seconds at which a private address is refreshed. */ -#define BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S (900) /* 15 minutes. */ -/**@brief The maximum interval in seconds at which a private address can be refreshed. */ -#define BLE_GAP_MAX_PRIVATE_ADDR_CYCLE_INTERVAL_S (41400) /* 11 hours 30 minutes. */ - -/** @brief BLE address length. */ -#define BLE_GAP_ADDR_LEN (6) - -/**@defgroup BLE_GAP_PRIVACY_MODES Privacy modes - * @{ */ -#define BLE_GAP_PRIVACY_MODE_OFF 0x00 /**< Device will send and accept its identity address for its own address. */ -#define BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY 0x01 /**< Device will send and accept only private addresses for its own address. */ -#define BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY \ - 0x02 /**< Device will send and accept only private addresses for its own address, \ - and will not accept a peer using identity address as sender address when \ - the peer IRK is exchanged, non-zero and added to the identity list. */ -/**@} */ - -/** @brief Invalid power level. */ -#define BLE_GAP_POWER_LEVEL_INVALID 127 - -/** @brief Advertising set handle not set. */ -#define BLE_GAP_ADV_SET_HANDLE_NOT_SET (0xFF) - -/** @brief The default number of advertising sets. */ -#define BLE_GAP_ADV_SET_COUNT_DEFAULT (1) - -/** @brief The maximum number of advertising sets supported by this SoftDevice. */ -#define BLE_GAP_ADV_SET_COUNT_MAX (1) - -/**@defgroup BLE_GAP_ADV_SET_DATA_SIZES Advertising data sizes. - * @{ */ -#define BLE_GAP_ADV_SET_DATA_SIZE_MAX \ - (31) /**< Maximum data length for an advertising set. \ - If more advertising data is required, use extended advertising instead. */ -#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED \ - (255) /**< Maximum supported data length for an extended advertising set. */ - -#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED \ - (238) /**< Maximum supported data length for an extended connectable advertising set. */ -/**@}. */ - -/** @brief Set ID not available in advertising report. */ -#define BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE 0xFF - -/**@defgroup BLE_GAP_EVT_ADV_SET_TERMINATED_REASON GAP Advertising Set Terminated reasons - * @{ */ -#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT 0x01 /**< Timeout value reached. */ -#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED 0x02 /**< @ref ble_gap_adv_params_t::max_adv_evts was reached. */ -/**@} */ - -/**@defgroup BLE_GAP_AD_TYPE_DEFINITIONS GAP Advertising and Scan Response Data format - * @note Found at https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm - * @{ */ -#define BLE_GAP_AD_TYPE_FLAGS 0x01 /**< Flags for discoverability. */ -#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 /**< Partial list of 16 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 /**< Complete list of 16 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 /**< Partial list of 32 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 /**< Complete list of 32 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 /**< Partial list of 128 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 /**< Complete list of 128 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 /**< Short local device name. */ -#define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 /**< Complete local device name. */ -#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A /**< Transmit power level. */ -#define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D /**< Class of device. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E /**< Simple Pairing Hash C. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F /**< Simple Pairing Randomizer R. */ -#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 /**< Security Manager TK Value. */ -#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 /**< Security Manager Out Of Band Flags. */ -#define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 /**< Slave Connection Interval Range. */ -#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 /**< List of 16-bit Service Solicitation UUIDs. */ -#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 /**< List of 128-bit Service Solicitation UUIDs. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 /**< Service Data - 16-bit UUID. */ -#define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 /**< Public Target Address. */ -#define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 /**< Random Target Address. */ -#define BLE_GAP_AD_TYPE_APPEARANCE 0x19 /**< Appearance. */ -#define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A /**< Advertising Interval. */ -#define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B /**< LE Bluetooth Device Address. */ -#define BLE_GAP_AD_TYPE_LE_ROLE 0x1C /**< LE Role. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D /**< Simple Pairing Hash C-256. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E /**< Simple Pairing Randomizer R-256. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 /**< Service Data - 32-bit UUID. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 /**< Service Data - 128-bit UUID. */ -#define BLE_GAP_AD_TYPE_LESC_CONFIRMATION_VALUE 0x22 /**< LE Secure Connections Confirmation Value */ -#define BLE_GAP_AD_TYPE_LESC_RANDOM_VALUE 0x23 /**< LE Secure Connections Random Value */ -#define BLE_GAP_AD_TYPE_URI 0x24 /**< URI */ -#define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D /**< 3D Information Data. */ -#define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF /**< Manufacturer Specific Data. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_FLAGS GAP Advertisement Flags - * @{ */ -#define BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE (0x01) /**< LE Limited Discoverable Mode. */ -#define BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) /**< LE General Discoverable Mode. */ -#define BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) /**< BR/EDR not supported. */ -#define BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER (0x08) /**< Simultaneous LE and BR/EDR, Controller. */ -#define BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST (0x10) /**< Simultaneous LE and BR/EDR, Host. */ -#define BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE \ - (BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE | \ - BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE Limited Discoverable Mode, BR/EDR not supported. */ -#define BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE \ - (BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | \ - BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE General Discoverable Mode, BR/EDR not supported. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_INTERVALS GAP Advertising interval max and min - * @{ */ -#define BLE_GAP_ADV_INTERVAL_MIN 0x000020 /**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */ -#define BLE_GAP_ADV_INTERVAL_MAX 0x004000 /**< Maximum Advertising interval in 625 us units, i.e. 10.24 s. */ - /**@} */ - -/**@defgroup BLE_GAP_SCAN_INTERVALS GAP Scan interval max and min - * @{ */ -#define BLE_GAP_SCAN_INTERVAL_MIN 0x0004 /**< Minimum Scan interval in 625 us units, i.e. 2.5 ms. */ -#define BLE_GAP_SCAN_INTERVAL_MAX 0xFFFF /**< Maximum Scan interval in 625 us units, i.e. 40,959.375 s. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_WINDOW GAP Scan window max and min - * @{ */ -#define BLE_GAP_SCAN_WINDOW_MIN 0x0004 /**< Minimum Scan window in 625 us units, i.e. 2.5 ms. */ -#define BLE_GAP_SCAN_WINDOW_MAX 0xFFFF /**< Maximum Scan window in 625 us units, i.e. 40,959.375 s. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_TIMEOUT GAP Scan timeout max and min - * @{ */ -#define BLE_GAP_SCAN_TIMEOUT_MIN 0x0001 /**< Minimum Scan timeout in 10 ms units, i.e 10 ms. */ -#define BLE_GAP_SCAN_TIMEOUT_UNLIMITED 0x0000 /**< Continue to scan forever. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_BUFFER_SIZE GAP Minimum scanner buffer size - * - * Scan buffers are used for storing advertising data received from an advertiser. - * If ble_gap_scan_params_t::extended is set to 0, @ref BLE_GAP_SCAN_BUFFER_MIN is the minimum scan buffer length. - * else the minimum scan buffer size is @ref BLE_GAP_SCAN_BUFFER_EXTENDED_MIN. - * @{ */ -#define BLE_GAP_SCAN_BUFFER_MIN \ - (31) /**< Minimum data length for an \ - advertising set. */ -#define BLE_GAP_SCAN_BUFFER_MAX \ - (31) /**< Maximum data length for an \ - advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MIN \ - (255) /**< Minimum data length for an \ - extended advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX \ - (1650) /**< Maximum data length for an \ - extended advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED \ - (255) /**< Maximum supported data length for \ - an extended advertising set. */ -/** @} */ - -/**@defgroup BLE_GAP_ADV_TYPES GAP Advertising types - * - * Advertising types defined in Bluetooth Core Specification v5.0, Vol 6, Part B, Section 4.4.2. - * - * The maximum advertising data length is defined by @ref BLE_GAP_ADV_SET_DATA_SIZE_MAX. - * The maximum supported data length for an extended advertiser is defined by - * @ref BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED - * Note that some of the advertising types do not support advertising data. Non-scannable types do not support - * scan response data. - * - * @{ */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x01 /**< Connectable and scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE \ - 0x02 /**< Connectable non-scannable directed advertising \ - events. Advertising interval is less that 3.75 ms. \ - Use this type for fast reconnections. \ - @note Advertising data is not supported. */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x03 /**< Connectable non-scannable directed advertising \ - events. \ - @note Advertising data is not supported. */ -#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x04 /**< Non-connectable scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x05 /**< Non-connectable non-scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x06 /**< Connectable non-scannable undirected advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x07 /**< Connectable non-scannable directed advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x08 /**< Non-connectable scannable undirected advertising \ - events using extended advertising PDUs. \ - @note Only scan response data is supported. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED \ - 0x09 /**< Non-connectable scannable directed advertising \ - events using extended advertising PDUs. \ - @note Only scan response data is supported. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x0A /**< Non-connectable non-scannable undirected advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x0B /**< Non-connectable non-scannable directed advertising \ - events using extended advertising PDUs. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_FILTER_POLICIES GAP Advertising filter policies - * @{ */ -#define BLE_GAP_ADV_FP_ANY 0x00 /**< Allow scan requests and connect requests from any device. */ -#define BLE_GAP_ADV_FP_FILTER_SCANREQ 0x01 /**< Filter scan requests with whitelist. */ -#define BLE_GAP_ADV_FP_FILTER_CONNREQ 0x02 /**< Filter connect requests with whitelist. */ -#define BLE_GAP_ADV_FP_FILTER_BOTH 0x03 /**< Filter both scan and connect requests with whitelist. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_DATA_STATUS GAP Advertising data status - * @{ */ -#define BLE_GAP_ADV_DATA_STATUS_COMPLETE 0x00 /**< All data in the advertising event have been received. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA \ - 0x01 /**< More data to be received. \ - @note This value will only be used if \ - @ref ble_gap_scan_params_t::report_incomplete_evts and \ - @ref ble_gap_adv_report_type_t::extended_pdu are set to true. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED \ - 0x02 /**< Incomplete data. Buffer size insufficient to receive more. \ - @note This value will only be used if \ - @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MISSED \ - 0x03 /**< Failed to receive the remaining data. \ - @note This value will only be used if \ - @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ -/**@} */ - -/**@defgroup BLE_GAP_SCAN_FILTER_POLICIES GAP Scanner filter policies - * @{ */ -#define BLE_GAP_SCAN_FP_ACCEPT_ALL \ - 0x00 /**< Accept all advertising packets except directed advertising packets \ - not addressed to this device. */ -#define BLE_GAP_SCAN_FP_WHITELIST \ - 0x01 /**< Accept advertising packets from devices in the whitelist except directed \ - packets not addressed to this device. */ -#define BLE_GAP_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED \ - 0x02 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL. \ - In addition, accept directed advertising packets, where the advertiser's \ - address is a resolvable private address that cannot be resolved. */ -#define BLE_GAP_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED \ - 0x03 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST. \ - In addition, accept directed advertising packets, where the advertiser's \ - address is a resolvable private address that cannot be resolved. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_TIMEOUT_VALUES GAP Advertising timeout values in 10 ms units - * @{ */ -#define BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX \ - (128) /**< Maximum high duty advertising time in 10 ms units. Corresponds to 1.28 s. \ - */ -#define BLE_GAP_ADV_TIMEOUT_LIMITED_MAX \ - (18000) /**< Maximum advertising time in 10 ms units corresponding to TGAP(lim_adv_timeout) = 180 s in limited discoverable \ - mode. */ -#define BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED \ - (0) /**< Unlimited advertising in general discoverable mode. \ - For high duty cycle advertising, this corresponds to @ref BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX. */ -/**@} */ - -/**@defgroup BLE_GAP_DISC_MODES GAP Discovery modes - * @{ */ -#define BLE_GAP_DISC_MODE_NOT_DISCOVERABLE 0x00 /**< Not discoverable discovery Mode. */ -#define BLE_GAP_DISC_MODE_LIMITED 0x01 /**< Limited Discovery Mode. */ -#define BLE_GAP_DISC_MODE_GENERAL 0x02 /**< General Discovery Mode. */ -/**@} */ - -/**@defgroup BLE_GAP_IO_CAPS GAP IO Capabilities - * @{ */ -#define BLE_GAP_IO_CAPS_DISPLAY_ONLY 0x00 /**< Display Only. */ -#define BLE_GAP_IO_CAPS_DISPLAY_YESNO 0x01 /**< Display and Yes/No entry. */ -#define BLE_GAP_IO_CAPS_KEYBOARD_ONLY 0x02 /**< Keyboard Only. */ -#define BLE_GAP_IO_CAPS_NONE 0x03 /**< No I/O capabilities. */ -#define BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY 0x04 /**< Keyboard and Display. */ -/**@} */ - -/**@defgroup BLE_GAP_AUTH_KEY_TYPES GAP Authentication Key Types - * @{ */ -#define BLE_GAP_AUTH_KEY_TYPE_NONE 0x00 /**< No key (may be used to reject). */ -#define BLE_GAP_AUTH_KEY_TYPE_PASSKEY 0x01 /**< 6-digit Passkey. */ -#define BLE_GAP_AUTH_KEY_TYPE_OOB 0x02 /**< Out Of Band data. */ -/**@} */ - -/**@defgroup BLE_GAP_KP_NOT_TYPES GAP Keypress Notification Types - * @{ */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_START 0x00 /**< Passkey entry started. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_IN 0x01 /**< Passkey digit entered. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_OUT 0x02 /**< Passkey digit erased. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_CLEAR 0x03 /**< Passkey cleared. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_END 0x04 /**< Passkey entry completed. */ -/**@} */ - -/**@defgroup BLE_GAP_SEC_STATUS GAP Security status - * @{ */ -#define BLE_GAP_SEC_STATUS_SUCCESS 0x00 /**< Procedure completed with success. */ -#define BLE_GAP_SEC_STATUS_TIMEOUT 0x01 /**< Procedure timed out. */ -#define BLE_GAP_SEC_STATUS_PDU_INVALID 0x02 /**< Invalid PDU received. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE1_BEGIN 0x03 /**< Reserved for Future Use range #1 begin. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE1_END 0x80 /**< Reserved for Future Use range #1 end. */ -#define BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED 0x81 /**< Passkey entry failed (user canceled or other). */ -#define BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE 0x82 /**< Out of Band Key not available. */ -#define BLE_GAP_SEC_STATUS_AUTH_REQ 0x83 /**< Authentication requirements not met. */ -#define BLE_GAP_SEC_STATUS_CONFIRM_VALUE 0x84 /**< Confirm value failed. */ -#define BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP 0x85 /**< Pairing not supported. */ -#define BLE_GAP_SEC_STATUS_ENC_KEY_SIZE 0x86 /**< Encryption key size. */ -#define BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED 0x87 /**< Unsupported SMP command. */ -#define BLE_GAP_SEC_STATUS_UNSPECIFIED 0x88 /**< Unspecified reason. */ -#define BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS 0x89 /**< Too little time elapsed since last attempt. */ -#define BLE_GAP_SEC_STATUS_INVALID_PARAMS 0x8A /**< Invalid parameters. */ -#define BLE_GAP_SEC_STATUS_DHKEY_FAILURE 0x8B /**< DHKey check failure. */ -#define BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE 0x8C /**< Numeric Comparison failure. */ -#define BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG 0x8D /**< BR/EDR pairing in progress. */ -#define BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED 0x8E /**< BR/EDR Link Key cannot be used for LE keys. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE2_BEGIN 0x8F /**< Reserved for Future Use range #2 begin. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE2_END 0xFF /**< Reserved for Future Use range #2 end. */ -/**@} */ - -/**@defgroup BLE_GAP_SEC_STATUS_SOURCES GAP Security status sources - * @{ */ -#define BLE_GAP_SEC_STATUS_SOURCE_LOCAL 0x00 /**< Local failure. */ -#define BLE_GAP_SEC_STATUS_SOURCE_REMOTE 0x01 /**< Remote failure. */ -/**@} */ - -/**@defgroup BLE_GAP_CP_LIMITS GAP Connection Parameters Limits - * @{ */ -#define BLE_GAP_CP_MIN_CONN_INTVL_NONE 0xFFFF /**< No new minimum connection interval specified in connect parameters. */ -#define BLE_GAP_CP_MIN_CONN_INTVL_MIN \ - 0x0006 /**< Lowest minimum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ -#define BLE_GAP_CP_MIN_CONN_INTVL_MAX \ - 0x0C80 /**< Highest minimum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ - */ -#define BLE_GAP_CP_MAX_CONN_INTVL_NONE 0xFFFF /**< No new maximum connection interval specified in connect parameters. */ -#define BLE_GAP_CP_MAX_CONN_INTVL_MIN \ - 0x0006 /**< Lowest maximum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ -#define BLE_GAP_CP_MAX_CONN_INTVL_MAX \ - 0x0C80 /**< Highest maximum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ - */ -#define BLE_GAP_CP_SLAVE_LATENCY_MAX 0x01F3 /**< Highest slave latency permitted, in connection events. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_NONE 0xFFFF /**< No new supervision timeout specified in connect parameters. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN 0x000A /**< Lowest supervision timeout permitted, in units of 10 ms, i.e. 100 ms. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX 0x0C80 /**< Highest supervision timeout permitted, in units of 10 ms, i.e. 32 s. */ -/**@} */ - -/**@defgroup BLE_GAP_DEVNAME GAP device name defines. - * @{ */ -#define BLE_GAP_DEVNAME_DEFAULT "nRF5x" /**< Default device name value. */ -#define BLE_GAP_DEVNAME_DEFAULT_LEN 31 /**< Default number of octets in device name. */ -#define BLE_GAP_DEVNAME_MAX_LEN 248 /**< Maximum number of octets in device name. */ -/**@} */ - -/**@brief Disable RSSI events for connections */ -#define BLE_GAP_RSSI_THRESHOLD_INVALID 0xFF - -/**@defgroup BLE_GAP_PHYS GAP PHYs - * @{ */ -#define BLE_GAP_PHY_AUTO 0x00 /**< Automatic PHY selection. Refer @ref sd_ble_gap_phy_update for more information.*/ -#define BLE_GAP_PHY_1MBPS 0x01 /**< 1 Mbps PHY. */ -#define BLE_GAP_PHY_2MBPS 0x02 /**< 2 Mbps PHY. */ -#define BLE_GAP_PHY_CODED 0x04 /**< Coded PHY. */ -#define BLE_GAP_PHY_NOT_SET 0xFF /**< PHY is not configured. */ - -/**@brief Supported PHYs in connections, for scanning, and for advertising. */ -#define BLE_GAP_PHYS_SUPPORTED (BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_CODED) /**< All PHYs are supported. */ - -/**@} */ - -/**@defgroup BLE_GAP_CONN_SEC_MODE_SET_MACROS GAP attribute security requirement setters - * - * See @ref ble_gap_conn_sec_mode_t. - * @{ */ -/**@brief Set sec_mode pointed to by ptr to have no access rights.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(ptr) \ - do { \ - (ptr)->sm = 0; \ - (ptr)->lv = 0; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require no protection, open link.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_OPEN(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 1; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require encryption, but no MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 2; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require encryption and MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 3; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require LESC encryption and MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 4; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require signing or encryption, no MITM protection needed.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(ptr) \ - do { \ - (ptr)->sm = 2; \ - (ptr)->lv = 1; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require signing or encryption with MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 2; \ - (ptr)->lv = 2; \ - } while (0) -/**@} */ - -/**@brief GAP Security Random Number Length. */ -#define BLE_GAP_SEC_RAND_LEN 8 - -/**@brief GAP Security Key Length. */ -#define BLE_GAP_SEC_KEY_LEN 16 - -/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key Length. */ -#define BLE_GAP_LESC_P256_PK_LEN 64 - -/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman DHKey Length. */ -#define BLE_GAP_LESC_DHKEY_LEN 32 - -/**@brief GAP Passkey Length. */ -#define BLE_GAP_PASSKEY_LEN 6 - -/**@brief Maximum amount of addresses in the whitelist. */ -#define BLE_GAP_WHITELIST_ADDR_MAX_COUNT (8) - -/**@brief Maximum amount of identities in the device identities list. */ -#define BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT (8) - -/**@brief Default connection count for a configuration. */ -#define BLE_GAP_CONN_COUNT_DEFAULT (1) - -/**@defgroup BLE_GAP_EVENT_LENGTH GAP event length defines. - * @{ */ -#define BLE_GAP_EVENT_LENGTH_MIN (2) /**< Minimum event length, in 1.25 ms units. */ -#define BLE_GAP_EVENT_LENGTH_CODED_PHY_MIN (6) /**< The shortest event length in 1.25 ms units supporting LE Coded PHY. */ -#define BLE_GAP_EVENT_LENGTH_DEFAULT (3) /**< Default event length, in 1.25 ms units. */ -/**@} */ - -/**@defgroup BLE_GAP_ROLE_COUNT GAP concurrent connection count defines. - * @{ */ -#define BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT (1) /**< Default maximum number of connections concurrently acting as peripherals. */ -#define BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT (3) /**< Default maximum number of connections concurrently acting as centrals. */ -#define BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT \ - (1) /**< Default number of SMP instances shared between all connections acting as centrals. */ -#define BLE_GAP_ROLE_COUNT_COMBINED_MAX \ - (20) /**< Maximum supported number of concurrent connections in the peripheral and central roles combined. */ - -/**@} */ - -/**@brief Automatic data length parameter. */ -#define BLE_GAP_DATA_LENGTH_AUTO 0 - -/**@defgroup BLE_GAP_AUTH_PAYLOAD_TIMEOUT Authenticated payload timeout defines. - * @{ */ -#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX (48000) /**< Maximum authenticated payload timeout in 10 ms units, i.e. 8 minutes. */ -#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MIN (1) /**< Minimum authenticated payload timeout in 10 ms units, i.e. 10 ms. */ -/**@} */ - -/**@defgroup GAP_SEC_MODES GAP Security Modes - * @{ */ -#define BLE_GAP_SEC_MODE 0x00 /**< No key (may be used to reject). */ -/**@} */ - -/**@brief The total number of channels in Bluetooth Low Energy. */ -#define BLE_GAP_CHANNEL_COUNT (40) - -/**@defgroup BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS Quality of Service (QoS) Channel survey interval defines - * @{ */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS (0) /**< Continuous channel survey. */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MIN_US (7500) /**< Minimum channel survey interval in microseconds (7.5 ms). */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MAX_US (4000000) /**< Maximum channel survey interval in microseconds (4 s). */ - /**@} */ - -/** @} */ - -/** @defgroup BLE_GAP_CHAR_INCL_CONFIG GAP Characteristic inclusion configurations - * @{ - */ -#define BLE_GAP_CHAR_INCL_CONFIG_INCLUDE (0) /**< Include the characteristic in the Attribute Table */ -#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITH_SPACE \ - (1) /**< Do not include the characteristic in the Attribute table. \ - The SoftDevice will reserve the attribute handles \ - which are otherwise used for this characteristic. \ - By reserving the attribute handles it will be possible \ - to upgrade the SoftDevice without changing handle of the \ - Service Changed characteristic. */ -#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITHOUT_SPACE \ - (2) /**< Do not include the characteristic in the Attribute table. \ - The SoftDevice will not reserve the attribute handles \ - which are otherwise used for this characteristic. */ -/**@} */ - -/** @defgroup BLE_GAP_CHAR_INCL_CONFIG_DEFAULTS Characteristic inclusion default values - * @{ */ -#define BLE_GAP_PPCP_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ -#define BLE_GAP_CAR_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ -/**@} */ - -/** @defgroup BLE_GAP_SLAVE_LATENCY Slave latency configuration options - * @{ */ -#define BLE_GAP_SLAVE_LATENCY_ENABLE \ - (0) /**< Slave latency is enabled. When slave latency is enabled, \ - the slave will wake up every time it has data to send, \ - and/or every slave latency number of connection events. */ -#define BLE_GAP_SLAVE_LATENCY_DISABLE \ - (1) /**< Disable slave latency. The slave will wake up every connection event \ - regardless of the requested slave latency. \ - This option consumes the most power. */ -#define BLE_GAP_SLAVE_LATENCY_WAIT_FOR_ACK \ - (2) /**< The slave will wake up every connection event if it has not received \ - an ACK from the master for at least slave latency events. This \ - configuration may increase the power consumption in environments \ - with a lot of radio activity. */ -/**@} */ - -/**@addtogroup BLE_GAP_STRUCTURES Structures - * @{ */ - -/**@brief Advertising event properties. */ -typedef struct { - uint8_t type; /**< Advertising type. See @ref BLE_GAP_ADV_TYPES. */ - uint8_t anonymous : 1; /**< Omit advertiser's address from all PDUs. - @note Anonymous advertising is only available for - @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED and - @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED. */ - uint8_t include_tx_power : 1; /**< This feature is not supported on this SoftDevice. */ -} ble_gap_adv_properties_t; - -/**@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 Advertising Auxiliary Pointer. */ -typedef struct { - uint16_t aux_offset; /**< Time offset from the beginning of advertising packet to the auxiliary packet in 100 us units. */ - uint8_t aux_phy; /**< Indicates the PHY on which the auxiliary advertising packet is sent. See @ref BLE_GAP_PHYS. */ -} ble_gap_aux_pointer_t; - -/**@brief Bluetooth Low Energy address. */ -typedef struct { - uint8_t - addr_id_peer : 1; /**< Only valid for peer addresses. - This bit is set by the SoftDevice to indicate whether the address has been resolved from - a Resolvable Private Address (when the peer is using privacy). - If set to 1, @ref addr and @ref addr_type refer to the identity address of the resolved address. - - This bit is ignored when a variable of type @ref ble_gap_addr_t is used as input to API functions. - */ - uint8_t addr_type : 7; /**< See @ref BLE_GAP_ADDR_TYPES. */ - uint8_t addr[BLE_GAP_ADDR_LEN]; /**< 48-bit address, LSB format. - @ref addr is not used if @ref addr_type is @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. */ -} ble_gap_addr_t; - -/**@brief GAP connection parameters. - * - * @note When ble_conn_params_t is received in an event, both min_conn_interval and - * max_conn_interval will be equal to the connection interval set by the central. - * - * @note If both conn_sup_timeout and max_conn_interval are specified, then the following constraint applies: - * conn_sup_timeout * 4 > (1 + slave_latency) * max_conn_interval - * that corresponds to the following Bluetooth Spec requirement: - * The Supervision_Timeout in milliseconds shall be larger than - * (1 + Conn_Latency) * Conn_Interval_Max * 2, where Conn_Interval_Max is given in milliseconds. - */ -typedef struct { - uint16_t min_conn_interval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t max_conn_interval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t slave_latency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t conn_sup_timeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ -} ble_gap_conn_params_t; - -/**@brief GAP connection security modes. - * - * Security Mode 0 Level 0: No access permissions at all (this level is not defined by the Bluetooth Core specification).\n - * Security Mode 1 Level 1: No security is needed (aka open link).\n - * Security Mode 1 Level 2: Encrypted link required, MITM protection not necessary.\n - * Security Mode 1 Level 3: MITM protected encrypted link required.\n - * Security Mode 1 Level 4: LESC MITM protected encrypted link using a 128-bit strength encryption key required.\n - * Security Mode 2 Level 1: Signing or encryption required, MITM protection not necessary.\n - * Security Mode 2 Level 2: MITM protected signing required, unless link is MITM protected encrypted.\n - */ -typedef struct { - uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ - uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */ - -} ble_gap_conn_sec_mode_t; - -/**@brief GAP connection security status.*/ -typedef struct { - ble_gap_conn_sec_mode_t sec_mode; /**< Currently active security mode for this connection.*/ - uint8_t - encr_key_size; /**< Length of currently active encryption key, 7 to 16 octets (only applicable for bonding procedures). */ -} ble_gap_conn_sec_t; - -/**@brief Identity Resolving Key. */ -typedef struct { - uint8_t irk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing IRK. */ -} ble_gap_irk_t; - -/**@brief Channel mask (40 bits). - * Every channel is represented with a bit positioned as per channel index defined in Bluetooth Core Specification v5.0, - * Vol 6, Part B, Section 1.4.1. The LSB contained in array element 0 represents channel index 0, and bit 39 represents - * channel index 39. If a bit is set to 1, the channel is not used. - */ -typedef uint8_t ble_gap_ch_mask_t[5]; - -/**@brief GAP advertising parameters. */ -typedef struct { - ble_gap_adv_properties_t properties; /**< The properties of the advertising events. */ - ble_gap_addr_t const *p_peer_addr; /**< Address of a known peer. - @note ble_gap_addr_t::addr_type cannot be - @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. - - When privacy is enabled and the local device uses - @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE addresses, - the device identity list is searched for a matching entry. If - the local IRK for that device identity is set, the local IRK - for that device will be used to generate the advertiser address - field in the advertising packet. - - If @ref ble_gap_adv_properties_t::type is directed, this must be - set to the targeted scanner or initiator. If the peer address is - in the device identity list, the peer IRK for that device will be - used to generate @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE - target addresses used in the advertising event PDUs. */ - uint32_t interval; /**< Advertising interval in 625 us units. @sa BLE_GAP_ADV_INTERVALS. - @note If @ref ble_gap_adv_properties_t::type is set to - @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE - advertising, this parameter is ignored. */ - uint16_t duration; /**< Advertising duration in 10 ms units. When timeout is reached, - an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. - @sa BLE_GAP_ADV_TIMEOUT_VALUES. - @note The SoftDevice will always complete at least one advertising - event even if the duration is set too low. */ - uint8_t max_adv_evts; /**< Maximum advertising events that shall be sent prior to disabling - advertising. Setting the value to 0 disables the limitation. When - the count of advertising events specified by this parameter - (if not 0) is reached, advertising will be automatically stopped - and an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised - @note If @ref ble_gap_adv_properties_t::type is set to - @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE, - this parameter is ignored. */ - ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. - At least one of the primary channels, that is channel index 37-39, must be used. - Masking away secondary advertising channels is not supported. */ - uint8_t filter_policy; /**< Filter Policy. @sa BLE_GAP_ADV_FILTER_POLICIES. */ - uint8_t primary_phy; /**< Indicates the PHY on which the primary advertising channel packets - are transmitted. If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS - will be used. - Valid values are @ref BLE_GAP_PHY_1MBPS and @ref BLE_GAP_PHY_CODED. - @note The primary_phy shall indicate @ref BLE_GAP_PHY_1MBPS if - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t secondary_phy; /**< Indicates the PHY on which the secondary advertising channel packets - are transmitted. - If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS will be used. - Valid values are - @ref BLE_GAP_PHY_1MBPS, @ref BLE_GAP_PHY_2MBPS, and @ref BLE_GAP_PHY_CODED. - If @ref ble_gap_adv_properties_t::type is an extended advertising type - and connectable, this is the PHY that will be used to establish a - connection and send AUX_ADV_IND packets on. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t set_id : 4; /**< The advertising set identifier distinguishes this advertising set from other - advertising sets transmitted by this and other devices. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t scan_req_notification : 1; /**< Enable scan request notifications for this advertising set. When a - scan request is received and the scanner address is allowed - by the filter policy, @ref BLE_GAP_EVT_SCAN_REQ_REPORT is raised. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is a non-scannable - advertising type. */ -} ble_gap_adv_params_t; - -/**@brief GAP advertising data buffers. - * - * The application must provide the buffers for advertisement. The memory shall reside in application RAM, and - * shall never be modified while advertising. The data shall be kept alive until either: - * - @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. - * - @ref BLE_GAP_EVT_CONNECTED is raised with @ref ble_gap_evt_connected_t::adv_handle set to the corresponding - * advertising handle. - * - Advertising is stopped. - * - Advertising data is changed. - * To update advertising data while advertising, provide new buffers to @ref sd_ble_gap_adv_set_configure. */ -typedef struct { - ble_data_t adv_data; /**< Advertising data. - @note - Advertising data can only be specified for a @ref ble_gap_adv_properties_t::type - that is allowed to contain advertising data. */ - ble_data_t scan_rsp_data; /**< Scan response data. - @note - Scan response data can only be specified for a @ref ble_gap_adv_properties_t::type - that is scannable. */ -} ble_gap_adv_data_t; - -/**@brief GAP scanning parameters. */ -typedef struct { - uint8_t extended : 1; /**< If 1, the scanner will accept extended advertising packets. - If set to 0, the scanner will not receive advertising packets - on secondary advertising channels, and will not be able - to receive long advertising PDUs. */ - uint8_t report_incomplete_evts : 1; /**< If 1, events of type @ref ble_gap_evt_adv_report_t may have - @ref ble_gap_adv_report_type_t::status set to - @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. - This parameter is ignored when used with @ref sd_ble_gap_connect - @note This may be used to abort receiving more packets from an extended - advertising event, and is only available for extended - scanning, see @ref sd_ble_gap_scan_start. - @note This feature is not supported by this SoftDevice. */ - uint8_t active : 1; /**< If 1, perform active scanning by sending scan requests. - This parameter is ignored when used with @ref sd_ble_gap_connect. */ - uint8_t filter_policy : 2; /**< Scanning filter policy. @sa BLE_GAP_SCAN_FILTER_POLICIES. - @note Only @ref BLE_GAP_SCAN_FP_ACCEPT_ALL and - @ref BLE_GAP_SCAN_FP_WHITELIST are valid when used with - @ref sd_ble_gap_connect */ - uint8_t scan_phys; /**< Bitfield of PHYs to scan on. If set to @ref BLE_GAP_PHY_AUTO, - scan_phys will default to @ref BLE_GAP_PHY_1MBPS. - - If @ref ble_gap_scan_params_t::extended is set to 0, the only - supported PHY is @ref BLE_GAP_PHY_1MBPS. - - When used with @ref sd_ble_gap_scan_start, - the bitfield indicates the PHYs the scanner will use for scanning - on primary advertising channels. The scanner will accept - @ref BLE_GAP_PHYS_SUPPORTED as secondary advertising channel PHYs. - - When used with @ref sd_ble_gap_connect, the bitfield indicates - the PHYs the initiator will use for scanning on primary advertising - channels. The initiator will accept connections initiated on either - of the @ref BLE_GAP_PHYS_SUPPORTED PHYs. - If scan_phys contains @ref BLE_GAP_PHY_1MBPS and/or @ref BLE_GAP_PHY_2MBPS, - the primary scan PHY is @ref BLE_GAP_PHY_1MBPS. - If scan_phys also contains @ref BLE_GAP_PHY_CODED, the primary scan - PHY will also contain @ref BLE_GAP_PHY_CODED. If the only scan PHY is - @ref BLE_GAP_PHY_CODED, the primary scan PHY is - @ref BLE_GAP_PHY_CODED only. */ - uint16_t interval; /**< Scan interval in 625 us units. @sa BLE_GAP_SCAN_INTERVALS. */ - uint16_t window; /**< Scan window in 625 us units. @sa BLE_GAP_SCAN_WINDOW. - If scan_phys contains both @ref BLE_GAP_PHY_1MBPS and - @ref BLE_GAP_PHY_CODED interval shall be larger than or - equal to twice the scan window. */ - uint16_t timeout; /**< Scan timeout in 10 ms units. @sa BLE_GAP_SCAN_TIMEOUT. */ - ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. - At least one of the primary channels, that is channel index 37-39, must be - set to 0. - Masking away secondary channels is not supported. */ -} ble_gap_scan_params_t; - -/**@brief Privacy. - * - * The privacy feature provides a way for the device to avoid being tracked over a period of time. - * The privacy feature, when enabled, hides the local device identity and replaces it with a private address - * that is automatically refreshed at a specified interval. - * - * If a device still wants to be recognized by other peers, it needs to share it's Identity Resolving Key (IRK). - * With this key, a device can generate a random private address that can only be recognized by peers in possession of that - * key, and devices can establish connections without revealing their real identities. - * - * Both network privacy (@ref BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY) and device privacy (@ref - * BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY) are supported. - * - * @note If the device IRK is updated, the new IRK becomes the one to be distributed in all - * bonding procedures performed after @ref sd_ble_gap_privacy_set returns. - * The IRK distributed during bonding procedure is the device IRK that is active when @ref sd_ble_gap_sec_params_reply is - * called. - */ -typedef struct { - uint8_t privacy_mode; /**< Privacy mode, see @ref BLE_GAP_PRIVACY_MODES. Default is @ref BLE_GAP_PRIVACY_MODE_OFF. */ - uint8_t private_addr_type; /**< The private address type must be either @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE or - @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE. */ - uint16_t private_addr_cycle_s; /**< Private address cycle interval in seconds. Providing an address cycle value of 0 will use - the default value defined by @ref BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S. */ - ble_gap_irk_t - *p_device_irk; /**< When used as input, pointer to IRK structure that will be used as the default IRK. If NULL, the device - default IRK will be used. When used as output, pointer to IRK structure where the current default IRK - will be written to. If NULL, this argument is ignored. By default, the default IRK is used to generate - random private resolvable addresses for the local device unless instructed otherwise. */ -} ble_gap_privacy_params_t; - -/**@brief PHY preferences for TX and RX - * @note tx_phys and rx_phys are bit fields. Multiple bits can be set in them to indicate multiple preferred PHYs for each - * direction. - * @code - * p_gap_phys->tx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; - * p_gap_phys->rx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; - * @endcode - * - */ -typedef struct { - uint8_t tx_phys; /**< Preferred transmit PHYs, see @ref BLE_GAP_PHYS. */ - uint8_t rx_phys; /**< Preferred receive PHYs, see @ref BLE_GAP_PHYS. */ -} ble_gap_phys_t; - -/** @brief Keys that can be exchanged during a bonding procedure. */ -typedef struct { - uint8_t enc : 1; /**< Long Term Key and Master Identification. */ - uint8_t id : 1; /**< Identity Resolving Key and Identity Address Information. */ - uint8_t sign : 1; /**< Connection Signature Resolving Key. */ - uint8_t link : 1; /**< Derive the Link Key from the LTK. */ -} ble_gap_sec_kdist_t; - -/**@brief GAP security parameters. */ -typedef struct { - uint8_t bond : 1; /**< Perform bonding. */ - uint8_t mitm : 1; /**< Enable Man In The Middle protection. */ - uint8_t lesc : 1; /**< Enable LE Secure Connection pairing. */ - uint8_t keypress : 1; /**< Enable generation of keypress notifications. */ - uint8_t io_caps : 3; /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */ - uint8_t oob : 1; /**< The OOB data flag. - - In LE legacy pairing, this flag is set if a device has out of band authentication data. - The OOB method is used if both of the devices have out of band authentication data. - - In LE Secure Connections pairing, this flag is set if a device has the peer device's out of band - authentication data. The OOB method is used if at least one device has the peer device's OOB data - available. */ - uint8_t - min_key_size; /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */ - uint8_t max_key_size; /**< Maximum encryption key size in octets between min_key_size and 16. */ - ble_gap_sec_kdist_t kdist_own; /**< Key distribution bitmap: keys that the local device will distribute. */ - ble_gap_sec_kdist_t kdist_peer; /**< Key distribution bitmap: keys that the remote device will distribute. */ -} ble_gap_sec_params_t; - -/**@brief GAP Encryption Information. */ -typedef struct { - uint8_t ltk[BLE_GAP_SEC_KEY_LEN]; /**< Long Term Key. */ - uint8_t lesc : 1; /**< Key generated using LE Secure Connections. */ - uint8_t auth : 1; /**< Authenticated Key. */ - uint8_t ltk_len : 6; /**< LTK length in octets. */ -} ble_gap_enc_info_t; - -/**@brief GAP Master Identification. */ -typedef struct { - uint16_t ediv; /**< Encrypted Diversifier. */ - uint8_t rand[BLE_GAP_SEC_RAND_LEN]; /**< Random Number. */ -} ble_gap_master_id_t; - -/**@brief GAP Signing Information. */ -typedef struct { - uint8_t csrk[BLE_GAP_SEC_KEY_LEN]; /**< Connection Signature Resolving Key. */ -} ble_gap_sign_info_t; - -/**@brief GAP LE Secure Connections P-256 Public Key. */ -typedef struct { - uint8_t pk[BLE_GAP_LESC_P256_PK_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key. Stored in the - standard SMP protocol format: {X,Y} both in little-endian. */ -} ble_gap_lesc_p256_pk_t; - -/**@brief GAP LE Secure Connections DHKey. */ -typedef struct { - uint8_t key[BLE_GAP_LESC_DHKEY_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman Key. Stored in little-endian. */ -} ble_gap_lesc_dhkey_t; - -/**@brief GAP LE Secure Connections OOB data. */ -typedef struct { - ble_gap_addr_t addr; /**< Bluetooth address of the device. */ - uint8_t r[BLE_GAP_SEC_KEY_LEN]; /**< Random Number. */ - uint8_t c[BLE_GAP_SEC_KEY_LEN]; /**< Confirm Value. */ -} ble_gap_lesc_oob_data_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONNECTED. */ -typedef struct { - ble_gap_addr_t - peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref - ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ - uint8_t role; /**< BLE role for this connection, see @ref BLE_GAP_ROLES */ - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ - uint8_t adv_handle; /**< Advertising handle in which advertising has ended. - This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ - ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated - advertising set. The advertising buffers provided in - @ref sd_ble_gap_adv_set_configure are now released. - This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ -} ble_gap_evt_connected_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DISCONNECTED. */ -typedef struct { - uint8_t reason; /**< HCI error code, see @ref BLE_HCI_STATUS_CODES. */ -} ble_gap_evt_disconnected_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE. */ -typedef struct { - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ -} ble_gap_evt_conn_param_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST. */ -typedef struct { - ble_gap_phys_t peer_preferred_phys; /**< The PHYs the peer prefers to use. */ -} ble_gap_evt_phy_update_request_t; - -/**@brief Event Structure for @ref BLE_GAP_EVT_PHY_UPDATE. */ -typedef struct { - uint8_t status; /**< Status of the procedure, see @ref BLE_HCI_STATUS_CODES.*/ - uint8_t tx_phy; /**< TX PHY for this connection, see @ref BLE_GAP_PHYS. */ - uint8_t rx_phy; /**< RX PHY for this connection, see @ref BLE_GAP_PHYS. */ -} ble_gap_evt_phy_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. */ -typedef struct { - ble_gap_sec_params_t peer_params; /**< Initiator Security Parameters. */ -} ble_gap_evt_sec_params_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_INFO_REQUEST. */ -typedef struct { - ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. */ - ble_gap_master_id_t master_id; /**< Master Identification for LTK lookup. */ - uint8_t enc_info : 1; /**< If 1, Encryption Information required. */ - uint8_t id_info : 1; /**< If 1, Identity Information required. */ - uint8_t sign_info : 1; /**< If 1, Signing Information required. */ -} ble_gap_evt_sec_info_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_PASSKEY_DISPLAY. */ -typedef struct { - uint8_t passkey[BLE_GAP_PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */ - uint8_t match_request : 1; /**< If 1 requires the application to report the match using @ref sd_ble_gap_auth_key_reply - with either @ref BLE_GAP_AUTH_KEY_TYPE_NONE if there is no match or - @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY if there is a match. */ -} ble_gap_evt_passkey_display_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_KEY_PRESSED. */ -typedef struct { - uint8_t kp_not; /**< Keypress notification type, see @ref BLE_GAP_KP_NOT_TYPES. */ -} ble_gap_evt_key_pressed_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_KEY_REQUEST. */ -typedef struct { - uint8_t key_type; /**< See @ref BLE_GAP_AUTH_KEY_TYPES. */ -} ble_gap_evt_auth_key_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST. */ -typedef struct { - ble_gap_lesc_p256_pk_t - *p_pk_peer; /**< LE Secure Connections remote P-256 Public Key. This will point to the application-supplied memory - inside the keyset during the call to @ref sd_ble_gap_sec_params_reply. */ - uint8_t oobd_req : 1; /**< LESC OOB data required. A call to @ref sd_ble_gap_lesc_oob_data_set is required to complete the - procedure. */ -} ble_gap_evt_lesc_dhkey_request_t; - -/**@brief Security levels supported. - * @note See Bluetooth Specification Version 4.2 Volume 3, Part C, Chapter 10, Section 10.2.1. - */ -typedef struct { - uint8_t lv1 : 1; /**< If 1: Level 1 is supported. */ - uint8_t lv2 : 1; /**< If 1: Level 2 is supported. */ - uint8_t lv3 : 1; /**< If 1: Level 3 is supported. */ - uint8_t lv4 : 1; /**< If 1: Level 4 is supported. */ -} ble_gap_sec_levels_t; - -/**@brief Encryption Key. */ -typedef struct { - ble_gap_enc_info_t enc_info; /**< Encryption Information. */ - ble_gap_master_id_t master_id; /**< Master Identification. */ -} ble_gap_enc_key_t; - -/**@brief Identity Key. */ -typedef struct { - ble_gap_irk_t id_info; /**< Identity Resolving Key. */ - ble_gap_addr_t id_addr_info; /**< Identity Address. */ -} ble_gap_id_key_t; - -/**@brief Security Keys. */ -typedef struct { - ble_gap_enc_key_t *p_enc_key; /**< Encryption Key, or NULL. */ - ble_gap_id_key_t *p_id_key; /**< Identity Key, or NULL. */ - ble_gap_sign_info_t *p_sign_key; /**< Signing Key, or NULL. */ - ble_gap_lesc_p256_pk_t *p_pk; /**< LE Secure Connections P-256 Public Key. When in debug mode the application must use the - value defined in the Core Bluetooth Specification v4.2 Vol.3, Part H, Section 2.3.5.6.1 */ -} ble_gap_sec_keys_t; - -/**@brief Security key set for both local and peer keys. */ -typedef struct { - ble_gap_sec_keys_t keys_own; /**< Keys distributed by the local device. For LE Secure Connections the encryption key will be - generated locally and will always be stored if bonding. */ - ble_gap_sec_keys_t - keys_peer; /**< Keys distributed by the remote device. For LE Secure Connections, p_enc_key must always be NULL. */ -} ble_gap_sec_keyset_t; - -/**@brief Data Length Update Procedure parameters. */ -typedef struct { - uint16_t max_tx_octets; /**< Maximum number of payload octets that a Controller supports for transmission of a single Link - Layer Data Channel PDU. */ - uint16_t max_rx_octets; /**< Maximum number of payload octets that a Controller supports for reception of a single Link Layer - Data Channel PDU. */ - uint16_t max_tx_time_us; /**< Maximum time, in microseconds, that a Controller supports for transmission of a single Link - Layer Data Channel PDU. */ - uint16_t max_rx_time_us; /**< Maximum time, in microseconds, that a Controller supports for reception of a single Link Layer - Data Channel PDU. */ -} ble_gap_data_length_params_t; - -/**@brief Data Length Update Procedure local limitation. */ -typedef struct { - uint16_t tx_payload_limited_octets; /**< If > 0, the requested TX packet length is too long by this many octets. */ - uint16_t rx_payload_limited_octets; /**< If > 0, the requested RX packet length is too long by this many octets. */ - uint16_t tx_rx_time_limited_us; /**< If > 0, the requested combination of TX and RX packet lengths is too long by this many - microseconds. */ -} ble_gap_data_length_limitation_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_STATUS. */ -typedef struct { - uint8_t auth_status; /**< Authentication status, see @ref BLE_GAP_SEC_STATUS. */ - uint8_t error_src : 2; /**< On error, source that caused the failure, see @ref BLE_GAP_SEC_STATUS_SOURCES. */ - uint8_t bonded : 1; /**< Procedure resulted in a bond. */ - uint8_t lesc : 1; /**< Procedure resulted in a LE Secure Connection. */ - ble_gap_sec_levels_t sm1_levels; /**< Levels supported in Security Mode 1. */ - ble_gap_sec_levels_t sm2_levels; /**< Levels supported in Security Mode 2. */ - ble_gap_sec_kdist_t kdist_own; /**< Bitmap stating which keys were exchanged (distributed) by the local device. If bonding - with LE Secure Connections, the enc bit will be always set. */ - ble_gap_sec_kdist_t kdist_peer; /**< Bitmap stating which keys were exchanged (distributed) by the remote device. If bonding - with LE Secure Connections, the enc bit will never be set. */ -} ble_gap_evt_auth_status_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_SEC_UPDATE. */ -typedef struct { - ble_gap_conn_sec_t conn_sec; /**< Connection security level. */ -} ble_gap_evt_conn_sec_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Source of timeout event, see @ref BLE_GAP_TIMEOUT_SOURCES. */ - union { - ble_data_t adv_report_buffer; /**< If source is set to @ref BLE_GAP_TIMEOUT_SRC_SCAN, the released - scan buffer is contained in this field. */ - } params; /**< Event Parameters. */ -} ble_gap_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_RSSI_CHANGED. */ -typedef struct { - int8_t rssi; /**< Received Signal Strength Indication in dBm. - @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature - measurement. */ - uint8_t ch_index; /**< Data Channel Index on which the Signal Strength is measured (0-36). */ -} ble_gap_evt_rssi_changed_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_ADV_SET_TERMINATED */ -typedef struct { - uint8_t reason; /**< Reason for why the advertising set terminated. See - @ref BLE_GAP_EVT_ADV_SET_TERMINATED_REASON. */ - uint8_t adv_handle; /**< Advertising handle in which advertising has ended. */ - uint8_t num_completed_adv_events; /**< If @ref ble_gap_adv_params_t::max_adv_evts was not set to 0, - this field indicates the number of completed advertising events. */ - ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated - advertising set. The advertising buffers provided in - @ref sd_ble_gap_adv_set_configure are now released. */ -} ble_gap_evt_adv_set_terminated_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; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_REQUEST. */ -typedef struct { - uint8_t bond : 1; /**< Perform bonding. */ - uint8_t mitm : 1; /**< Man In The Middle protection requested. */ - uint8_t lesc : 1; /**< LE Secure Connections requested. */ - uint8_t keypress : 1; /**< Generation of keypress notifications requested. */ -} ble_gap_evt_sec_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST. */ -typedef struct { - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ -} ble_gap_evt_conn_param_update_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SCAN_REQ_REPORT. */ -typedef struct { - uint8_t adv_handle; /**< Advertising handle for the advertising set which received the Scan Request */ - int8_t rssi; /**< Received Signal Strength Indication in dBm. - @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature - measurement. */ - ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref - ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ -} ble_gap_evt_scan_req_report_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST. */ -typedef struct { - ble_gap_data_length_params_t peer_params; /**< Peer data length parameters. */ -} ble_gap_evt_data_length_update_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE. - * - * @note This event may also be raised after a PHY Update procedure. - */ -typedef struct { - ble_gap_data_length_params_t effective_params; /**< The effective data length parameters. */ -} ble_gap_evt_data_length_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT. */ -typedef struct { - int8_t - channel_energy[BLE_GAP_CHANNEL_COUNT]; /**< The measured energy on the Bluetooth Low Energy - channels, in dBm, indexed by Channel Index. - If no measurement is available for the given channel, channel_energy is set to - @ref BLE_GAP_POWER_LEVEL_INVALID. */ -} ble_gap_evt_qos_channel_survey_report_t; - -/**@brief GAP event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which event occurred. */ - union /**< union alternative identified by evt_id in enclosing struct. */ - { - ble_gap_evt_connected_t connected; /**< Connected Event Parameters. */ - ble_gap_evt_disconnected_t disconnected; /**< Disconnected Event Parameters. */ - ble_gap_evt_conn_param_update_t conn_param_update; /**< Connection Parameter Update Parameters. */ - ble_gap_evt_sec_params_request_t sec_params_request; /**< Security Parameters Request Event Parameters. */ - ble_gap_evt_sec_info_request_t sec_info_request; /**< Security Information Request Event Parameters. */ - ble_gap_evt_passkey_display_t passkey_display; /**< Passkey Display Event Parameters. */ - ble_gap_evt_key_pressed_t key_pressed; /**< Key Pressed Event Parameters. */ - ble_gap_evt_auth_key_request_t auth_key_request; /**< Authentication Key Request Event Parameters. */ - ble_gap_evt_lesc_dhkey_request_t lesc_dhkey_request; /**< LE Secure Connections DHKey calculation request. */ - ble_gap_evt_auth_status_t auth_status; /**< Authentication Status Event Parameters. */ - ble_gap_evt_conn_sec_update_t conn_sec_update; /**< Connection Security Update Event Parameters. */ - ble_gap_evt_timeout_t timeout; /**< Timeout Event Parameters. */ - ble_gap_evt_rssi_changed_t rssi_changed; /**< RSSI Event Parameters. */ - ble_gap_evt_adv_report_t adv_report; /**< Advertising Report Event Parameters. */ - ble_gap_evt_adv_set_terminated_t adv_set_terminated; /**< Advertising Set Terminated Event Parameters. */ - ble_gap_evt_sec_request_t sec_request; /**< Security Request Event Parameters. */ - ble_gap_evt_conn_param_update_request_t conn_param_update_request; /**< Connection Parameter Update Parameters. */ - ble_gap_evt_scan_req_report_t scan_req_report; /**< Scan Request Report Parameters. */ - ble_gap_evt_phy_update_request_t phy_update_request; /**< PHY Update Request Event Parameters. */ - ble_gap_evt_phy_update_t phy_update; /**< PHY Update Parameters. */ - ble_gap_evt_data_length_update_request_t data_length_update_request; /**< Data Length Update Request Event Parameters. */ - ble_gap_evt_data_length_update_t data_length_update; /**< Data Length Update Event Parameters. */ - ble_gap_evt_qos_channel_survey_report_t - qos_channel_survey_report; /**< Quality of Service (QoS) Channel Survey Report Parameters. */ - } params; /**< Event Parameters. */ -} ble_gap_evt_t; - -/** - * @brief BLE GAP connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_CONN_COUNT The connection count for the connection configurations is zero. - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - The sum of conn_count for all connection configurations combined exceeds UINT8_MAX. - * - The event length is smaller than @ref BLE_GAP_EVENT_LENGTH_MIN. - */ -typedef struct { - uint8_t conn_count; /**< The number of concurrent connections the application can create with this configuration. - The default and minimum value is @ref BLE_GAP_CONN_COUNT_DEFAULT. */ - uint16_t event_length; /**< The time set aside for this connection on every connection interval in 1.25 ms units. - The default value is @ref BLE_GAP_EVENT_LENGTH_DEFAULT, the minimum value is @ref - BLE_GAP_EVENT_LENGTH_MIN. The event length and the connection interval are the primary parameters - for setting the throughput of a connection. - See the SoftDevice Specification for details on throughput. */ -} ble_gap_conn_cfg_t; - -/** - * @brief Configuration of maximum concurrent connections in the different connected roles, set with - * @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_CONN_COUNT The sum of periph_role_count and central_role_count is too - * large. The maximum supported sum of concurrent connections is - * @ref BLE_GAP_ROLE_COUNT_COMBINED_MAX. - * @retval ::NRF_ERROR_INVALID_PARAM central_sec_count is larger than central_role_count. - * @retval ::NRF_ERROR_RESOURCES The adv_set_count is too large. The maximum - * supported advertising handles is - * @ref BLE_GAP_ADV_SET_COUNT_MAX. - */ -typedef struct { - uint8_t adv_set_count; /**< Maximum number of advertising sets. Default value is @ref BLE_GAP_ADV_SET_COUNT_DEFAULT. */ - uint8_t periph_role_count; /**< Maximum number of connections concurrently acting as a peripheral. Default value is @ref - BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT. */ - uint8_t central_role_count; /**< Maximum number of connections concurrently acting as a central. Default value is @ref - BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT. */ - uint8_t central_sec_count; /**< Number of SMP instances shared between all connections acting as a central. Default value is - @ref BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT. */ - uint8_t qos_channel_survey_role_available : 1; /**< If set, the Quality of Service (QoS) channel survey module is available to - the application using @ref sd_ble_gap_qos_channel_survey_start. */ -} ble_gap_cfg_role_count_t; - -/** - * @brief Device name and its properties, set with @ref sd_ble_cfg_set. - * - * @note If the device name is not configured, the default device name will be - * @ref BLE_GAP_DEVNAME_DEFAULT, the maximum device name length will be - * @ref BLE_GAP_DEVNAME_DEFAULT_LEN, vloc will be set to @ref BLE_GATTS_VLOC_STACK and the device name - * will have no write access. - * - * @note If @ref max_len is more than @ref BLE_GAP_DEVNAME_DEFAULT_LEN and vloc is set to @ref BLE_GATTS_VLOC_STACK, - * the attribute table size must be increased to have room for the longer device name (see - * @ref sd_ble_cfg_set and @ref ble_gatts_cfg_attr_tab_size_t). - * - * @note If vloc is @ref BLE_GATTS_VLOC_STACK : - * - p_value must point to non-volatile memory (flash) or be NULL. - * - If p_value is NULL, the device name will initially be empty. - * - * @note If vloc is @ref BLE_GATTS_VLOC_USER : - * - p_value cannot be NULL. - * - If the device name is writable, p_value must point to volatile memory (RAM). - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - Invalid device name location (vloc). - * - Invalid device name security mode. - * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: - * - The device name length is invalid (must be between 0 and @ref BLE_GAP_DEVNAME_MAX_LEN). - * - The device name length is too long for the given Attribute Table. - * @retval ::NRF_ERROR_NOT_SUPPORTED Device name security mode is not supported. - */ -typedef struct { - ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ - uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ - uint8_t *p_value; /**< Pointer to where the value (device name) is stored or will be stored. */ - uint16_t current_len; /**< Current length in bytes of the memory pointed to by p_value.*/ - uint16_t max_len; /**< Maximum length in bytes of the memory pointed to by p_value.*/ -} ble_gap_cfg_device_name_t; - -/**@brief Peripheral Preferred Connection Parameters include configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t include_cfg; /**< Inclusion configuration of the Peripheral Preferred Connection Parameters characteristic. - See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_PPCP_INCL_CONFIG_DEFAULT. */ -} ble_gap_cfg_ppcp_incl_cfg_t; - -/**@brief Central Address Resolution include configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t include_cfg; /**< Inclusion configuration of the Central Address Resolution characteristic. - See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_CAR_INCL_CONFIG_DEFAULT. */ -} ble_gap_cfg_car_incl_cfg_t; - -/**@brief Configuration structure for GAP configurations. */ -typedef union { - ble_gap_cfg_role_count_t role_count_cfg; /**< Role count configuration, cfg_id is @ref BLE_GAP_CFG_ROLE_COUNT. */ - ble_gap_cfg_device_name_t device_name_cfg; /**< Device name configuration, cfg_id is @ref BLE_GAP_CFG_DEVICE_NAME. */ - ble_gap_cfg_ppcp_incl_cfg_t ppcp_include_cfg; /**< Peripheral Preferred Connection Parameters characteristic include - configuration, cfg_id is @ref BLE_GAP_CFG_PPCP_INCL_CONFIG. */ - ble_gap_cfg_car_incl_cfg_t car_include_cfg; /**< Central Address Resolution characteristic include configuration, - cfg_id is @ref BLE_GAP_CFG_CAR_INCL_CONFIG. */ -} ble_gap_cfg_t; - -/**@brief Channel Map option. - * - * @details Used with @ref sd_ble_opt_get to get the current channel map - * or @ref sd_ble_opt_set to set a new channel map. When setting the - * channel map, it applies to all current and future connections. When getting the - * current channel map, it applies to a single connection and the connection handle - * must be supplied. - * - * @note Setting the channel map may take some time, depending on connection parameters. - * The time taken may be different for each connection and the get operation will - * return the previous channel map until the new one has taken effect. - * - * @note After setting the channel map, by spec it can not be set again until at least 1 s has passed. - * See Bluetooth Specification Version 4.1 Volume 2, Part E, Section 7.3.46. - * - * @retval ::NRF_SUCCESS Get or set successful. - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - Less then two bits in @ref ch_map are set. - * - Bits for primary advertising channels (37-39) are set. - * @retval ::NRF_ERROR_BUSY Channel map was set again before enough time had passed. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied for get. - * - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle (only applicable for get) */ - uint8_t ch_map[5]; /**< Channel Map (37-bit). */ -} ble_gap_opt_ch_map_t; - -/**@brief Local connection latency option. - * - * @details Local connection latency is a feature which enables the slave to improve - * current consumption by ignoring the slave latency set by the peer. The - * local connection latency can only be set to a multiple of the slave latency, - * and cannot be longer than half of the supervision timeout. - * - * @details Used with @ref sd_ble_opt_set to set the local connection latency. The - * @ref sd_ble_opt_get is not supported for this option, but the actual - * local connection latency (unless set to NULL) is set as a return parameter - * when setting the option. - * - * @note The latency set will be truncated down to the closest slave latency event - * multiple, or the nearest multiple before half of the supervision timeout. - * - * @note The local connection latency is disabled by default, and needs to be enabled for new - * connections and whenever the connection is updated. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint16_t requested_latency; /**< Requested local connection latency. */ - uint16_t *p_actual_latency; /**< Pointer to storage for the actual local connection latency (can be set to NULL to skip return - value). */ -} ble_gap_opt_local_conn_latency_t; - -/**@brief Disable slave latency - * - * @details Used with @ref sd_ble_opt_set to temporarily disable slave latency of a peripheral connection - * (see @ref ble_gap_conn_params_t::slave_latency). And to re-enable it again. When disabled, the - * peripheral will ignore the slave_latency set by the central. - * - * @note Shall only be called on peripheral links. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint8_t disable; /**< For allowed values see @ref BLE_GAP_SLAVE_LATENCY */ -} ble_gap_opt_slave_latency_disable_t; - -/**@brief Passkey Option. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} - * @endmscs - * - * @details Structure containing the passkey to be used during pairing. This can be used with @ref - * sd_ble_opt_set to make the SoftDevice use a preprogrammed passkey for authentication - * instead of generating a random one. - * - * @note Repeated pairing attempts using the same preprogrammed passkey makes pairing vulnerable to MITM attacks. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * - */ -typedef struct { - uint8_t const *p_passkey; /**< Pointer to 6-digit ASCII string (digit 0..9 only, no NULL termination) passkey to be used - during pairing. If this is NULL, the SoftDevice will generate a random passkey if required.*/ -} ble_gap_opt_passkey_t; - -/**@brief Compatibility mode 1 option. - * - * @details This can be used with @ref sd_ble_opt_set to enable and disable - * compatibility mode 1. Compatibility mode 1 is disabled by default. - * - * @note Compatibility mode 1 enables interoperability with devices that do not support a value of - * 0 for the WinOffset parameter in the Link Layer CONNECT_IND packet. This applies to a - * limited set of legacy peripheral devices from another vendor. Enabling this compatibility - * mode will only have an effect if the local device will act as a central device and - * initiate a connection to a peripheral device. In that case it may lead to the connection - * creation taking up to one connection interval longer to complete for all connections. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_INVALID_STATE When connection creation is ongoing while mode 1 is set. - */ -typedef struct { - uint8_t enable : 1; /**< Enable compatibility mode 1.*/ -} ble_gap_opt_compat_mode_1_t; - -/**@brief Authenticated payload timeout option. - * - * @details This can be used with @ref sd_ble_opt_set to change the Authenticated payload timeout to a value other - * than the default of @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX. - * - * @note The authenticated payload timeout event ::BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD will be generated - * if auth_payload_timeout time has elapsed without receiving a packet with a valid MIC on an encrypted - * link. - * - * @note The LE ping procedure will be initiated before the timer expires to give the peer a chance - * to reset the timer. In addition the stack will try to prioritize running of LE ping over other - * activities to increase chances of finishing LE ping before timer expires. To avoid side-effects - * on other activities, it is recommended to use high timeout values. - * Recommended timeout > 2*(connInterval * (6 + connSlaveLatency)). - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. auth_payload_timeout was outside of allowed range. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint16_t auth_payload_timeout; /**< Requested timeout in 10 ms unit, see @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT. */ -} ble_gap_opt_auth_payload_timeout_t; - -/**@brief Option structure for GAP options. */ -typedef union { - ble_gap_opt_ch_map_t ch_map; /**< Parameters for the Channel Map option. */ - ble_gap_opt_local_conn_latency_t local_conn_latency; /**< Parameters for the Local connection latency option */ - ble_gap_opt_passkey_t passkey; /**< Parameters for the Passkey option.*/ - ble_gap_opt_compat_mode_1_t compat_mode_1; /**< Parameters for the compatibility mode 1 option.*/ - ble_gap_opt_auth_payload_timeout_t auth_payload_timeout; /**< Parameters for the authenticated payload timeout option.*/ - ble_gap_opt_slave_latency_disable_t slave_latency_disable; /**< Parameters for the Disable slave latency option */ -} ble_gap_opt_t; - -/**@brief Connection event triggering parameters. */ -typedef struct { - uint8_t ppi_ch_id; /**< PPI channel to use. This channel should be regarded as reserved until - connection event PPI task triggering is stopped. - The PPI channel ID can not be one of the PPI channels reserved by - the SoftDevice. See @ref NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK. */ - uint32_t task_endpoint; /**< Task Endpoint to trigger. */ - uint16_t conn_evt_counter_start; /**< The connection event on which the task triggering should start. */ - uint16_t period_in_events; /**< Trigger period. Valid range is [1, 32767]. - If the device is in slave role and slave latency is enabled, - this parameter should be set to a multiple of (slave latency + 1) - to ensure low power operation. */ -} ble_gap_conn_event_trigger_t; -/**@} */ - -/**@addtogroup BLE_GAP_FUNCTIONS Functions - * @{ */ - -/**@brief Set the local Bluetooth identity address. - * - * The local Bluetooth identity address is the address that identifies this device to other peers. - * The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. - * - * @note The identity address cannot be changed while advertising, scanning or creating a connection. - * - * @note This address will be distributed to the peer during bonding. - * If the address changes, the address stored in the peer device will not be valid and the ability to - * reconnect using the old address will be lost. - * - * @note By default the SoftDevice will set an address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC upon being - * enabled. The address is a random number populated during the IC manufacturing process and remains unchanged - * for the lifetime of each IC. - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @endmscs - * - * @param[in] p_addr Pointer to address structure. - * - * @retval ::NRF_SUCCESS Address successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_STATE The identity address cannot be changed while advertising, - * scanning or creating a connection. - */ -SVCALL(SD_BLE_GAP_ADDR_SET, uint32_t, sd_ble_gap_addr_set(ble_gap_addr_t const *p_addr)); - -/**@brief Get local Bluetooth identity address. - * - * @note This will always return the identity address irrespective of the privacy settings, - * i.e. the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. - * - * @param[out] p_addr Pointer to address structure to be filled in. - * - * @retval ::NRF_SUCCESS Address successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - */ -SVCALL(SD_BLE_GAP_ADDR_GET, uint32_t, sd_ble_gap_addr_get(ble_gap_addr_t *p_addr)); - -/**@brief Get the Bluetooth device address used by the advertiser. - * - * @note This function will return the local Bluetooth address used in advertising PDUs. When - * using privacy, the SoftDevice will generate a new private address every - * @ref ble_gap_privacy_params_t::private_addr_cycle_s configured using - * @ref sd_ble_gap_privacy_set. Hence depending on when the application calls this API, the - * address returned may not be the latest address that is used in the advertising PDUs. - * - * @param[in] adv_handle The advertising handle to get the address from. - * @param[out] p_addr Pointer to address structure to be filled in. - * - * @retval ::NRF_SUCCESS Address successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. - * @retval ::NRF_ERROR_INVALID_STATE The advertising set is currently not advertising. - */ -SVCALL(SD_BLE_GAP_ADV_ADDR_GET, uint32_t, sd_ble_gap_adv_addr_get(uint8_t adv_handle, ble_gap_addr_t *p_addr)); - -/**@brief Set the active whitelist in the SoftDevice. - * - * @note Only one whitelist can be used at a time and the whitelist is shared between the BLE roles. - * The whitelist cannot be set if a BLE role is using the whitelist. - * - * @note If an address is resolved using the information in the device identity list, then the whitelist - * filter policy applies to the peer identity address and not the resolvable address sent on air. - * - * @mscs - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} - * @endmscs - * - * @param[in] pp_wl_addrs Pointer to a whitelist of peer addresses, if NULL the whitelist will be cleared. - * @param[in] len Length of the whitelist, maximum @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT. - * - * @retval ::NRF_SUCCESS The whitelist is successfully set/cleared. - * @retval ::NRF_ERROR_INVALID_ADDR The whitelist (or one of its entries) provided is invalid. - * @retval ::BLE_ERROR_GAP_WHITELIST_IN_USE The whitelist is in use by a BLE role and cannot be set or cleared. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_DATA_SIZE The given whitelist size is invalid (zero or too large); this can only return when - * pp_wl_addrs is not NULL. - */ -SVCALL(SD_BLE_GAP_WHITELIST_SET, uint32_t, sd_ble_gap_whitelist_set(ble_gap_addr_t const *const *pp_wl_addrs, uint8_t len)); - -/**@brief Set device identity list. - * - * @note Only one device identity list can be used at a time and the list is shared between the BLE roles. - * The device identity list cannot be set if a BLE role is using the list. - * - * @param[in] pp_id_keys Pointer to an array of peer identity addresses and peer IRKs, if NULL the device identity list will - * be cleared. - * @param[in] pp_local_irks Pointer to an array of local IRKs. Each entry in the array maps to the entry in pp_id_keys at the - * same index. To fill in the list with the currently set device IRK for all peers, set to NULL. - * @param[in] len Length of the device identity list, maximum @ref BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT. - * - * @mscs - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS The device identity list successfully set/cleared. - * @retval ::NRF_ERROR_INVALID_ADDR The device identity list (or one of its entries) provided is invalid. - * This code may be returned if the local IRK list also has an invalid entry. - * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE The device identity list is in use and cannot be set or cleared. - * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE The device identity list contains multiple entries with the same identity - * address. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_DATA_SIZE The given device identity list size invalid (zero or too large); this can - * only return when pp_id_keys is not NULL. - */ -SVCALL(SD_BLE_GAP_DEVICE_IDENTITIES_SET, uint32_t, - sd_ble_gap_device_identities_set(ble_gap_id_key_t const *const *pp_id_keys, ble_gap_irk_t const *const *pp_local_irks, - uint8_t len)); - -/**@brief Set privacy settings. - * - * @note Privacy settings cannot be changed while advertising, scanning or creating a connection. - * - * @param[in] p_privacy_params Privacy settings. - * - * @mscs - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_INVALID_ADDR The pointer to privacy settings is NULL or invalid. - * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. - * @retval ::NRF_ERROR_INVALID_PARAM Out of range parameters are provided. - * @retval ::NRF_ERROR_NOT_SUPPORTED The SoftDevice does not support privacy if the Central Address Resolution - characteristic is not configured to be included and the SoftDevice is configured - to support central roles. - See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - * @retval ::NRF_ERROR_INVALID_STATE Privacy settings cannot be changed while advertising, scanning - * or creating a connection. - */ -SVCALL(SD_BLE_GAP_PRIVACY_SET, uint32_t, sd_ble_gap_privacy_set(ble_gap_privacy_params_t const *p_privacy_params)); - -/**@brief Get privacy settings. - * - * @note ::ble_gap_privacy_params_t::p_device_irk must be initialized to NULL or a valid address before this function is called. - * If it is initialized to a valid address, the address pointed to will contain the current device IRK on return. - * - * @param[in,out] p_privacy_params Privacy settings. - * - * @retval ::NRF_SUCCESS Privacy settings read. - * @retval ::NRF_ERROR_INVALID_ADDR The pointer given for returning the privacy settings may be NULL or invalid. - * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. - */ -SVCALL(SD_BLE_GAP_PRIVACY_GET, uint32_t, sd_ble_gap_privacy_get(ble_gap_privacy_params_t *p_privacy_params)); - -/**@brief Configure an advertising set. Set, clear or update advertising and scan response data. - * - * @note The format of the advertising data will be checked by this call to ensure interoperability. - * Limitations imposed by this API call to the data provided include having a flags data type in the scan response data and - * duplicating the local name in the advertising data and scan response data. - * - * @note In order to update advertising data while advertising, new advertising buffers must be provided. - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in,out] p_adv_handle Provide a pointer to a handle containing @ref - * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising set. On success, a new handle is then returned through the - * pointer. Provide a pointer to an existing advertising handle to configure an existing advertising set. - * @param[in] p_adv_data Advertising data. If set to NULL, no advertising data will be used. See - * @ref ble_gap_adv_data_t. - * @param[in] p_adv_params Advertising parameters. When this function is used to update advertising - * data while advertising, this parameter must be NULL. See @ref ble_gap_adv_params_t. - * - * @retval ::NRF_SUCCESS Advertising set successfully configured. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: - * - Invalid advertising data configuration specified. See @ref - * ble_gap_adv_data_t. - * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. - * - Use of whitelist requested but whitelist has not been set, - * see @ref sd_ble_gap_whitelist_set. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR ble_gap_adv_params_t::p_peer_addr is invalid. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - It is invalid to provide non-NULL advertising set parameters while - * advertising. - * - It is invalid to provide the same data buffers while advertising. To - * update advertising data, provide new advertising buffers. - * @retval ::BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST Discoverable mode and whitelist incompatible. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. Use @ref - * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_FLAGS Invalid combination of advertising flags supplied. - * @retval ::NRF_ERROR_INVALID_DATA Invalid data type(s) supplied. Check the advertising data format - * specification given in Bluetooth Specification Version 5.0, Volume 3, Part C, Chapter 11. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid data length(s) supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported data length or advertising parameter configuration. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to configure a new advertising handle. Update an - * existing advertising handle instead. - * @retval ::BLE_ERROR_GAP_UUID_LIST_MISMATCH Invalid UUID list supplied. - */ -SVCALL(SD_BLE_GAP_ADV_SET_CONFIGURE, uint32_t, - sd_ble_gap_adv_set_configure(uint8_t *p_adv_handle, ble_gap_adv_data_t const *p_adv_data, - ble_gap_adv_params_t const *p_adv_params)); - -/**@brief Start advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). - * - * @note Only one advertiser may be active at any time. - * - * @note If privacy is enabled, the advertiser's private address will be refreshed when this function is called. - * See @ref sd_ble_gap_privacy_set(). - * - * @events - * @event{@ref BLE_GAP_EVT_CONNECTED, Generated after connection has been established through connectable advertising.} - * @event{@ref BLE_GAP_EVT_ADV_SET_TERMINATED, Advertising set has terminated.} - * @event{@ref BLE_GAP_EVT_SCAN_REQ_REPORT, A scan request was received.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] adv_handle Advertising handle to advertise on, received from @ref sd_ble_gap_adv_set_configure. - * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or - * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. For non-connectable - * advertising, this is ignored. - * - * @retval ::NRF_SUCCESS The BLE stack has started advertising. - * @retval ::NRF_ERROR_INVALID_STATE adv_handle is not configured or already advertising. - * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration - * tag has been reached; connectable advertiser cannot be started. - * To increase the number of available connections, - * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. Configure a new adveriting handle with @ref - sd_ble_gap_adv_set_configure. - * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: - * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. - * - Use of whitelist requested but whitelist has not been set, see @ref - sd_ble_gap_whitelist_set. - * @retval ::NRF_ERROR_RESOURCES Either: - * - adv_handle is configured with connectable advertising, but the event_length parameter - * associated with conn_cfg_tag is too small to be able to establish a connection on - * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. - * - Not enough BLE role slots available. - Stop one or more currently active roles (Central, Peripheral, Broadcaster or Observer) - and try again. - * - p_adv_params is configured with connectable advertising, but the event_length - parameter - * associated with conn_cfg_tag is too small to be able to establish a connection on - * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. - */ -SVCALL(SD_BLE_GAP_ADV_START, uint32_t, sd_ble_gap_adv_start(uint8_t adv_handle, uint8_t conn_cfg_tag)); - -/**@brief Stop advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] adv_handle The advertising handle that should stop advertising. - * - * @retval ::NRF_SUCCESS The BLE stack has stopped advertising. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Invalid advertising handle. - * @retval ::NRF_ERROR_INVALID_STATE The advertising handle is not advertising. - */ -SVCALL(SD_BLE_GAP_ADV_STOP, uint32_t, sd_ble_gap_adv_stop(uint8_t adv_handle)); - -/**@brief Update connection parameters. - * - * @details In the central role this will initiate a Link Layer connection parameter update procedure, - * otherwise in the peripheral role, this will send the corresponding L2CAP request and wait for - * the central to perform the procedure. In both cases, and regardless of success or failure, the application - * will be informed of the result with a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE event. - * - * @details This function can be used as a central both to reply to a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST or to start the - * procedure unrequested. - * - * @events - * @event{@ref BLE_GAP_EVT_CONN_PARAM_UPDATE, Result of the connection parameter update procedure.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CPU_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CPU_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CPU_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_conn_params Pointer to desired connection parameters. If NULL is provided on a peripheral role, - * the parameters in the PPCP characteristic of the GAP service will be used instead. - * If NULL is provided on a central role and in response to a @ref - * BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST, the peripheral request will be rejected - * - * @retval ::NRF_SUCCESS The Connection Update procedure has been started successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. - * @retval ::NRF_ERROR_BUSY Procedure already in progress, wait for pending procedures to complete and retry. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GAP_CONN_PARAM_UPDATE, uint32_t, - sd_ble_gap_conn_param_update(uint16_t conn_handle, ble_gap_conn_params_t const *p_conn_params)); - -/**@brief Disconnect (GAP Link Termination). - * - * @details This call initiates the disconnection procedure, and its completion will be communicated to the application - * with a @ref BLE_GAP_EVT_DISCONNECTED event. - * - * @events - * @event{@ref BLE_GAP_EVT_DISCONNECTED, Generated when disconnection procedure is complete.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CONN_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] hci_status_code HCI status code, see @ref BLE_HCI_STATUS_CODES (accepted values are @ref - * BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION and @ref BLE_HCI_CONN_INTERVAL_UNACCEPTABLE). - * - * @retval ::NRF_SUCCESS The disconnection procedure has been started successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. - */ -SVCALL(SD_BLE_GAP_DISCONNECT, uint32_t, sd_ble_gap_disconnect(uint16_t conn_handle, uint8_t hci_status_code)); - -/**@brief Set the radio's transmit power. - * - * @param[in] role The role to set the transmit power for, see @ref BLE_GAP_TX_POWER_ROLES for - * possible roles. - * @param[in] handle The handle parameter is interpreted depending on role: - * - If role is @ref BLE_GAP_TX_POWER_ROLE_CONN, this value is the specific connection handle. - * - If role is @ref BLE_GAP_TX_POWER_ROLE_ADV, the advertising set identified with the advertising handle, - * will use the specified transmit power, and include it in the advertising packet headers if - * @ref ble_gap_adv_properties_t::include_tx_power set. - * - For all other roles handle is ignored. - * @param[in] tx_power Radio transmit power in dBm (see note for accepted values). - * - * @note Supported tx_power values: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm and +4dBm. - * In addition, on some chips following values are supported: +2dBm, +5dBm, +6dBm, +7dBm and +8dBm. - * Setting these values on a chip that does not support them will result in undefined behaviour. - * @note The initiator will have the same transmit power as the scanner. - * @note When a connection is created it will inherit the transmit power from the initiator or - * advertiser leading to the connection. - * - * @retval ::NRF_SUCCESS Successfully changed the transmit power. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_TX_POWER_SET, uint32_t, sd_ble_gap_tx_power_set(uint8_t role, uint16_t handle, int8_t tx_power)); - -/**@brief Set GAP Appearance value. - * - * @param[in] appearance Appearance (16-bit), see @ref BLE_APPEARANCES. - * - * @retval ::NRF_SUCCESS Appearance value set successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - */ -SVCALL(SD_BLE_GAP_APPEARANCE_SET, uint32_t, sd_ble_gap_appearance_set(uint16_t appearance)); - -/**@brief Get GAP Appearance value. - * - * @param[out] p_appearance Pointer to appearance (16-bit) to be filled in, see @ref BLE_APPEARANCES. - * - * @retval ::NRF_SUCCESS Appearance value retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GAP_APPEARANCE_GET, uint32_t, sd_ble_gap_appearance_get(uint16_t *p_appearance)); - -/**@brief Set GAP Peripheral Preferred Connection Parameters. - * - * @param[in] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure with the desired parameters. - * - * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, - see @ref ble_gap_cfg_ppcp_incl_cfg_t. - */ -SVCALL(SD_BLE_GAP_PPCP_SET, uint32_t, sd_ble_gap_ppcp_set(ble_gap_conn_params_t const *p_conn_params)); - -/**@brief Get GAP Peripheral Preferred Connection Parameters. - * - * @param[out] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure where the parameters will be stored. - * - * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, - see @ref ble_gap_cfg_ppcp_incl_cfg_t. - */ -SVCALL(SD_BLE_GAP_PPCP_GET, uint32_t, sd_ble_gap_ppcp_get(ble_gap_conn_params_t *p_conn_params)); - -/**@brief Set GAP device name. - * - * @note If the device name is located in application flash memory (see @ref ble_gap_cfg_device_name_t), - * it cannot be changed. Then @ref NRF_ERROR_FORBIDDEN will be returned. - * - * @param[in] p_write_perm Write permissions for the Device Name characteristic, see @ref ble_gap_conn_sec_mode_t. - * @param[in] p_dev_name Pointer to a UTF-8 encoded, non NULL-terminated string. - * @param[in] len Length of the UTF-8, non NULL-terminated string pointed to by p_dev_name in octets (must be smaller or - * equal than @ref BLE_GAP_DEVNAME_MAX_LEN). - * - * @retval ::NRF_SUCCESS GAP device name and permissions set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_FORBIDDEN Device name is not writable. - */ -SVCALL(SD_BLE_GAP_DEVICE_NAME_SET, uint32_t, - sd_ble_gap_device_name_set(ble_gap_conn_sec_mode_t const *p_write_perm, uint8_t const *p_dev_name, uint16_t len)); - -/**@brief Get GAP device name. - * - * @note If the device name is longer than the size of the supplied buffer, - * p_len will return the complete device name length, - * and not the number of bytes actually returned in p_dev_name. - * The application may use this information to allocate a suitable buffer size. - * - * @param[out] p_dev_name Pointer to an empty buffer where the UTF-8 non NULL-terminated string will be placed. Set to - * NULL to obtain the complete device name length. - * @param[in,out] p_len Length of the buffer pointed by p_dev_name, complete device name length on output. - * - * @retval ::NRF_SUCCESS GAP device name retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - */ -SVCALL(SD_BLE_GAP_DEVICE_NAME_GET, uint32_t, sd_ble_gap_device_name_get(uint8_t *p_dev_name, uint16_t *p_len)); - -/**@brief Initiate the GAP Authentication procedure. - * - * @details In the central role, this function will send an SMP Pairing Request (or an SMP Pairing Failed if rejected), - * otherwise in the peripheral role, an SMP Security Request will be sent. - * - * @events - * @event{Depending on the security parameters set and the packet exchanges with the peer\, the following events may be - * generated:} - * @event{@ref BLE_GAP_EVT_SEC_PARAMS_REQUEST} - * @event{@ref BLE_GAP_EVT_SEC_INFO_REQUEST} - * @event{@ref BLE_GAP_EVT_PASSKEY_DISPLAY} - * @event{@ref BLE_GAP_EVT_KEY_PRESSED} - * @event{@ref BLE_GAP_EVT_AUTH_KEY_REQUEST} - * @event{@ref BLE_GAP_EVT_LESC_DHKEY_REQUEST} - * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE} - * @event{@ref BLE_GAP_EVT_AUTH_STATUS} - * @event{@ref BLE_GAP_EVT_TIMEOUT} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_SEC_REQ_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_sec_params Pointer to the @ref ble_gap_sec_params_t structure with the security parameters to be used during the - * pairing or bonding procedure. In the peripheral role, only the bond, mitm, lesc and keypress fields of this structure are used. - * In the central role, this pointer may be NULL to reject a Security Request. - * - * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - No link has been established. - * - An encryption is already executing or queued. - * @retval ::NRF_ERROR_NO_MEM The maximum number of authentication procedures that can run in parallel for the given role is - * reached. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. - * Distribution of own Identity Information is only supported if the Central - * Address Resolution characteristic is configured to be included or - * the Softdevice is configured to support peripheral roles only. - * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - * @retval ::NRF_ERROR_TIMEOUT A SMP timeout has occurred, and further SMP operations on this link is prohibited. - */ -SVCALL(SD_BLE_GAP_AUTHENTICATE, uint32_t, - sd_ble_gap_authenticate(uint16_t conn_handle, ble_gap_sec_params_t const *p_sec_params)); - -/**@brief Reply with GAP security parameters. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST, calling it at other times will result in - * an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_CONFIRM_FAIL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_KS_TOO_SMALL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_APP_ERROR_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_REMOTE_PAIRING_FAIL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_TIMEOUT_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] sec_status Security status, see @ref BLE_GAP_SEC_STATUS. - * @param[in] p_sec_params Pointer to a @ref ble_gap_sec_params_t security parameters structure. In the central role this must be - * set to NULL, as the parameters have already been provided during a previous call to @ref sd_ble_gap_authenticate. - * @param[in,out] p_sec_keyset Pointer to a @ref ble_gap_sec_keyset_t security keyset structure. Any keys generated and/or - * distributed as a result of the ongoing security procedure will be stored into the memory referenced by the pointers inside this - * structure. The keys will be stored and available to the application upon reception of a @ref BLE_GAP_EVT_AUTH_STATUS event. - * Note that the SoftDevice expects the application to provide memory for storing the - * peer's keys. So it must be ensured that the relevant pointers inside this structure are not NULL. The - * pointers to the local key can, however, be NULL, in which case, the local key data will not be available to the application - * upon reception of the - * @ref BLE_GAP_EVT_AUTH_STATUS event. - * - * @retval ::NRF_SUCCESS Successfully accepted security parameter from the application. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Security parameters has not been requested. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. - * Distribution of own Identity Information is only supported if the Central - * Address Resolution characteristic is configured to be included or - * the Softdevice is configured to support peripheral roles only. - * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - */ -SVCALL(SD_BLE_GAP_SEC_PARAMS_REPLY, uint32_t, - sd_ble_gap_sec_params_reply(uint16_t conn_handle, uint8_t sec_status, ble_gap_sec_params_t const *p_sec_params, - ble_gap_sec_keyset_t const *p_sec_keyset)); - -/**@brief Reply with an authentication key. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_AUTH_KEY_REQUEST or a @ref BLE_GAP_EVT_PASSKEY_DISPLAY, - * calling it at other times will result in an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] key_type See @ref BLE_GAP_AUTH_KEY_TYPES. - * @param[in] p_key If key type is @ref BLE_GAP_AUTH_KEY_TYPE_NONE, then NULL. - * If key type is @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY, then a 6-byte ASCII string (digit 0..9 only, no NULL - * termination) or NULL when confirming LE Secure Connections Numeric Comparison. If key type is @ref BLE_GAP_AUTH_KEY_TYPE_OOB, - * then a 16-byte OOB key value in little-endian format. - * - * @retval ::NRF_SUCCESS Authentication key successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Authentication key has not been requested. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_AUTH_KEY_REPLY, uint32_t, - sd_ble_gap_auth_key_reply(uint16_t conn_handle, uint8_t key_type, uint8_t const *p_key)); - -/**@brief Reply with an LE Secure connections DHKey. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST, calling it at other times will result in - * an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_dhkey LE Secure Connections DHKey. - * - * @retval ::NRF_SUCCESS DHKey successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - The peer is not authenticated. - * - The application has not pulled a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_DHKEY_REPLY, uint32_t, - sd_ble_gap_lesc_dhkey_reply(uint16_t conn_handle, ble_gap_lesc_dhkey_t const *p_dhkey)); - -/**@brief Notify the peer of a local keypress. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] kp_not See @ref BLE_GAP_KP_NOT_TYPES. - * - * @retval ::NRF_SUCCESS Keypress notification successfully queued for transmission. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Authentication key not requested. - * - Passkey has not been entered. - * - Keypresses have not been enabled by both peers. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy. Retry at later time. - */ -SVCALL(SD_BLE_GAP_KEYPRESS_NOTIFY, uint32_t, sd_ble_gap_keypress_notify(uint16_t conn_handle, uint8_t kp_not)); - -/**@brief Generate a set of OOB data to send to a peer out of band. - * - * @note The @ref ble_gap_addr_t included in the OOB data returned will be the currently active one (or, if a connection has - * already been established, the one used during connection setup). The application may manually overwrite it with an updated - * value. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. Can be @ref BLE_CONN_HANDLE_INVALID if a BLE connection has not been established yet. - * @param[in] p_pk_own LE Secure Connections local P-256 Public Key. - * @param[out] p_oobd_own The OOB data to be sent out of band to a peer. - * - * @retval ::NRF_SUCCESS OOB data successfully generated. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_OOB_DATA_GET, uint32_t, - sd_ble_gap_lesc_oob_data_get(uint16_t conn_handle, ble_gap_lesc_p256_pk_t const *p_pk_own, - ble_gap_lesc_oob_data_t *p_oobd_own)); - -/**@brief Provide the OOB data sent/received out of band. - * - * @note An authentication procedure with OOB selected as an algorithm must be in progress when calling this function. - * @note A @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event with the oobd_req set to 1 must have been received prior to calling this - * function. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_oobd_own The OOB data sent out of band to a peer or NULL if the peer has not received OOB data. - * Must correspond to @ref ble_gap_sec_params_t::oob flag in @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. - * @param[in] p_oobd_peer The OOB data received out of band from a peer or NULL if none received. - * Must correspond to @ref ble_gap_sec_params_t::oob flag - * in @ref sd_ble_gap_authenticate in the central role or - * in @ref sd_ble_gap_sec_params_reply in the peripheral role. - * - * @retval ::NRF_SUCCESS OOB data accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Authentication key not requested - * - Not expecting LESC OOB data - * - Have not actually exchanged passkeys. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_OOB_DATA_SET, uint32_t, - sd_ble_gap_lesc_oob_data_set(uint16_t conn_handle, ble_gap_lesc_oob_data_t const *p_oobd_own, - ble_gap_lesc_oob_data_t const *p_oobd_peer)); - -/**@brief Initiate GAP Encryption procedure. - * - * @details In the central role, this function will initiate the encryption procedure using the encryption information provided. - * - * @events - * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE, The connection security has been updated.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_master_id Pointer to a @ref ble_gap_master_id_t master identification structure. - * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. - * - * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::BLE_ERROR_INVALID_ROLE Operation is not supported in the Peripheral role. - * @retval ::NRF_ERROR_BUSY Procedure already in progress or not allowed at this time, wait for pending procedures to complete and - * retry. - */ -SVCALL(SD_BLE_GAP_ENCRYPT, uint32_t, - sd_ble_gap_encrypt(uint16_t conn_handle, ble_gap_master_id_t const *p_master_id, ble_gap_enc_info_t const *p_enc_info)); - -/**@brief Reply with GAP security information. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_INFO_REQUEST, calling it at other times will result in - * @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * @note Data signing is not yet supported, and p_sign_info must therefore be NULL. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_ENC_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. May be NULL to signal none is - * available. - * @param[in] p_id_info Pointer to a @ref ble_gap_irk_t identity information structure. May be NULL to signal none is available. - * @param[in] p_sign_info Pointer to a @ref ble_gap_sign_info_t signing information structure. May be NULL to signal none is - * available. - * - * @retval ::NRF_SUCCESS Successfully accepted security information. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - No link has been established. - * - No @ref BLE_GAP_EVT_SEC_INFO_REQUEST pending. - * - Encryption information provided by the app without being requested. See @ref - * ble_gap_evt_sec_info_request_t::enc_info. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_SEC_INFO_REPLY, uint32_t, - sd_ble_gap_sec_info_reply(uint16_t conn_handle, ble_gap_enc_info_t const *p_enc_info, ble_gap_irk_t const *p_id_info, - ble_gap_sign_info_t const *p_sign_info)); - -/**@brief Get the current connection security. - * - * @param[in] conn_handle Connection handle. - * @param[out] p_conn_sec Pointer to a @ref ble_gap_conn_sec_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Current connection security successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_CONN_SEC_GET, uint32_t, sd_ble_gap_conn_sec_get(uint16_t conn_handle, ble_gap_conn_sec_t *p_conn_sec)); - -/**@brief Start reporting the received signal strength to the application. - * - * A new event is reported whenever the RSSI value changes, until @ref sd_ble_gap_rssi_stop is called. - * - * @events - * @event{@ref BLE_GAP_EVT_RSSI_CHANGED, New RSSI data available. How often the event is generated is - * dependent on the settings of the threshold_dbm - * and skip_count input parameters.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] threshold_dbm Minimum change in dBm before triggering the @ref BLE_GAP_EVT_RSSI_CHANGED event. Events are - * disabled if threshold_dbm equals @ref BLE_GAP_RSSI_THRESHOLD_INVALID. - * @param[in] skip_count Number of RSSI samples with a change of threshold_dbm or more before sending a new @ref - * BLE_GAP_EVT_RSSI_CHANGED event. - * - * @retval ::NRF_SUCCESS Successfully activated RSSI reporting. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is already ongoing. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_RSSI_START, uint32_t, sd_ble_gap_rssi_start(uint16_t conn_handle, uint8_t threshold_dbm, uint8_t skip_count)); - -/**@brief Stop reporting the received signal strength. - * - * @note An RSSI change detected before the call but not yet received by the application - * may be reported after @ref sd_ble_gap_rssi_stop has been called. - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * - * @retval ::NRF_SUCCESS Successfully deactivated RSSI reporting. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_RSSI_STOP, uint32_t, sd_ble_gap_rssi_stop(uint16_t conn_handle)); - -/**@brief Get the received signal strength for the last connection event. - * - * @ref sd_ble_gap_rssi_start must be called to start reporting RSSI before using this function. @ref NRF_ERROR_NOT_FOUND - * will be returned until RSSI was sampled for the first time after calling @ref sd_ble_gap_rssi_start. - * @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature measurement. - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[out] p_rssi Pointer to the location where the RSSI measurement shall be stored. - * @param[out] p_ch_index Pointer to the location where Channel Index for the RSSI measurement shall be stored. - * - * @retval ::NRF_SUCCESS Successfully read the RSSI. - * @retval ::NRF_ERROR_NOT_FOUND No sample is available. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. - */ -SVCALL(SD_BLE_GAP_RSSI_GET, uint32_t, sd_ble_gap_rssi_get(uint16_t conn_handle, int8_t *p_rssi, uint8_t *p_ch_index)); - -/**@brief Start or continue scanning (GAP Discovery procedure, Observer Procedure). - * - * @note A call to this function will require the application to keep the memory pointed by - * p_adv_report_buffer alive until the buffer is released. The buffer is released when the scanner is stopped - * or when this function is called with another buffer. - * - * @note The scanner will automatically stop in the following cases: - * - @ref sd_ble_gap_scan_stop is called. - * - @ref sd_ble_gap_connect is called. - * - A @ref BLE_GAP_EVT_TIMEOUT with source set to @ref BLE_GAP_TIMEOUT_SRC_SCAN is received. - * - When a @ref BLE_GAP_EVT_ADV_REPORT event is received and @ref ble_gap_adv_report_type_t::status is not set to - * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. In this case scanning is only paused to let the application - * access received data. The application must call this function to continue scanning, or call @ref - * sd_ble_gap_scan_stop to stop scanning. - * - * @note If a @ref BLE_GAP_EVT_ADV_REPORT event is received with @ref ble_gap_adv_report_type_t::status set to - * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the scanner will continue scanning, and the application will - * receive more reports from this advertising event. The following reports will include the old and new received data. - * - * @events - * @event{@ref BLE_GAP_EVT_ADV_REPORT, An advertising or scan response packet has been received.} - * @event{@ref BLE_GAP_EVT_TIMEOUT, Scanner has timed out.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_SCAN_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] p_scan_params Pointer to scan parameters structure. When this function is used to continue - * scanning, this parameter must be NULL. - * @param[in] p_adv_report_buffer Pointer to buffer used to store incoming advertising data. - * The memory pointed to should be kept alive until the scanning is stopped. - * See @ref BLE_GAP_SCAN_BUFFER_SIZE for minimum and maximum buffer size. - * If the scanner receives advertising data larger than can be stored in the buffer, - * a @ref BLE_GAP_EVT_ADV_REPORT will be raised with @ref ble_gap_adv_report_type_t::status - * set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED. - * - * @retval ::NRF_SUCCESS Successfully initiated scanning procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Scanning is already ongoing and p_scan_params was not NULL - * - Scanning is not running and p_scan_params was NULL. - * - The scanner has timed out when this function is called to continue scanning. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. See @ref ble_gap_scan_params_t. - * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported parameters supplied. See @ref ble_gap_scan_params_t. - * @retval ::NRF_ERROR_INVALID_LENGTH The provided buffer length is invalid. See @ref BLE_GAP_SCAN_BUFFER_MIN. - * @retval ::NRF_ERROR_RESOURCES Not enough BLE role slots available. - * Stop one or more currently active roles (Central, Peripheral or Broadcaster) and try again - */ -SVCALL(SD_BLE_GAP_SCAN_START, uint32_t, - sd_ble_gap_scan_start(ble_gap_scan_params_t const *p_scan_params, ble_data_t const *p_adv_report_buffer)); - -/**@brief Stop scanning (GAP Discovery procedure, Observer Procedure). - * - * @note The buffer provided in @ref sd_ble_gap_scan_start is released. - * - * @mscs - * @mmsc{@ref BLE_GAP_SCAN_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully stopped scanning procedure. - * @retval ::NRF_ERROR_INVALID_STATE Not in the scanning state. - */ -SVCALL(SD_BLE_GAP_SCAN_STOP, uint32_t, sd_ble_gap_scan_stop(void)); - -/**@brief Create a connection (GAP Link Establishment). - * - * @note If a scanning procedure is currently in progress it will be automatically stopped when calling this function. - * The scanning procedure will be stopped even if the function returns an error. - * - * @events - * @event{@ref BLE_GAP_EVT_CONNECTED, A connection was established.} - * @event{@ref BLE_GAP_EVT_TIMEOUT, Failed to establish a connection.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} - * @endmscs - * - * @param[in] p_peer_addr Pointer to peer identity address. If @ref ble_gap_scan_params_t::filter_policy is set to use - * whitelist, then p_peer_addr is ignored. - * @param[in] p_scan_params Pointer to scan parameters structure. - * @param[in] p_conn_params Pointer to desired connection parameters. - * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or - * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. - * - * @retval ::NRF_SUCCESS Successfully initiated connection procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid parameter(s) pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * - Invalid parameter(s) in p_scan_params or p_conn_params. - * - Use of whitelist requested but whitelist has not been set, see @ref - * sd_ble_gap_whitelist_set. - * - Peer address was not present in the device identity list, see @ref - * sd_ble_gap_device_identities_set. - * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. - * @retval ::NRF_ERROR_INVALID_STATE The SoftDevice is in an invalid state to perform this operation. This may be due to an - * existing locally initiated connect procedure, which must complete before initiating again. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid Peer address. - * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration tag has been reached. - * To increase the number of available connections, - * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. - * @retval ::NRF_ERROR_RESOURCES Either: - * - Not enough BLE role slots available. - * Stop one or more currently active roles (Central, Peripheral or Observer) and try again. - * - The event_length parameter associated with conn_cfg_tag is too small to be able to - * establish a connection on the selected @ref ble_gap_scan_params_t::scan_phys. - * Use @ref sd_ble_cfg_set to increase the event length. - */ -SVCALL(SD_BLE_GAP_CONNECT, uint32_t, - sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params, - ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag)); - -/**@brief Cancel a connection establishment. - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully canceled an ongoing connection procedure. - * @retval ::NRF_ERROR_INVALID_STATE No locally initiated connect procedure started or connection - * completed occurred. - */ -SVCALL(SD_BLE_GAP_CONNECT_CANCEL, uint32_t, sd_ble_gap_connect_cancel(void)); - -/**@brief Initiate or respond to a PHY Update Procedure - * - * @details This function is used to initiate or respond to a PHY Update Procedure. It will always - * generate a @ref BLE_GAP_EVT_PHY_UPDATE event if successfully executed. - * If this function is used to initiate a PHY Update procedure and the only option - * provided in @ref ble_gap_phys_t::tx_phys and @ref ble_gap_phys_t::rx_phys is the - * currently active PHYs in the respective directions, the SoftDevice will generate a - * @ref BLE_GAP_EVT_PHY_UPDATE with the current PHYs set and will not initiate the - * procedure in the Link Layer. - * - * If @ref ble_gap_phys_t::tx_phys or @ref ble_gap_phys_t::rx_phys is @ref BLE_GAP_PHY_AUTO, - * then the stack will select PHYs based on the peer's PHY preferences and the local link - * configuration. The PHY Update procedure will for this case result in a PHY combination - * that respects the time constraints configured with @ref sd_ble_cfg_set and the current - * link layer data length. - * - * When acting as a central, the SoftDevice will select the fastest common PHY in each direction. - * - * If the peer does not support the PHY Update Procedure, then the resulting - * @ref BLE_GAP_EVT_PHY_UPDATE event will have a status set to - * @ref BLE_HCI_UNSUPPORTED_REMOTE_FEATURE. - * - * If the PHY Update procedure was rejected by the peer due to a procedure collision, the status - * will be @ref BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION or - * @ref BLE_HCI_DIFFERENT_TRANSACTION_COLLISION. - * If the peer responds to the PHY Update procedure with invalid parameters, the status - * will be @ref BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS. - * If the PHY Update procedure was rejected by the peer for a different reason, the status will - * contain the reason as specified by the peer. - * - * @events - * @event{@ref BLE_GAP_EVT_PHY_UPDATE, Result of the PHY Update Procedure.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_PHY_UPDATE} - * @mmsc{@ref BLE_GAP_PERIPHERAL_PHY_UPDATE} - * @endmscs - * - * @param[in] conn_handle Connection handle to indicate the connection for which the PHY Update is requested. - * @param[in] p_gap_phys Pointer to PHY structure. - * - * @retval ::NRF_SUCCESS Successfully requested a PHY Update. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the combination of - * @ref ble_gap_phys_t::tx_phys, @ref ble_gap_phys_t::rx_phys, and @ref - * ble_gap_data_length_params_t. The connection event length is configured with @ref BLE_CONN_CFG_GAP using @ref sd_ble_cfg_set. - * @retval ::NRF_ERROR_BUSY Procedure is already in progress or not allowed at this time. Process pending events and wait for the - * pending procedure to complete and retry. - * - */ -SVCALL(SD_BLE_GAP_PHY_UPDATE, uint32_t, sd_ble_gap_phy_update(uint16_t conn_handle, ble_gap_phys_t const *p_gap_phys)); - -/**@brief Initiate or respond to a Data Length Update Procedure. - * - * @note If the application uses @ref BLE_GAP_DATA_LENGTH_AUTO for one or more members of - * p_dl_params, the SoftDevice will choose the highest value supported in current - * configuration and connection parameters. - * @note If the link PHY is Coded, the SoftDevice will ensure that the MaxTxTime and/or MaxRxTime - * used in the Data Length Update procedure is at least 2704 us. Otherwise, MaxTxTime and - * MaxRxTime will be limited to maximum 2120 us. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_dl_params Pointer to local parameters to be used in Data Length Update - * Procedure. Set any member to @ref BLE_GAP_DATA_LENGTH_AUTO to let - * the SoftDevice automatically decide the value for that member. - * Set to NULL to use automatic values for all members. - * @param[out] p_dl_limitation Pointer to limitation to be written when local device does not - * have enough resources or does not support the requested Data Length - * Update parameters. Ignored if NULL. - * - * @mscs - * @mmsc{@ref BLE_GAP_DATA_LENGTH_UPDATE_PROCEDURE_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully set Data Length Extension initiation/response parameters. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The requested parameters are not supported by the SoftDevice. Inspect - * p_dl_limitation to see which parameter is not supported. - * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the requested - * parameters. Use @ref sd_ble_cfg_set with @ref BLE_CONN_CFG_GAP to increase the connection event length. Inspect p_dl_limitation - * to see where the limitation is. - * @retval ::NRF_ERROR_BUSY Peer has already initiated a Data Length Update Procedure. Process the - * pending @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event to respond. - */ -SVCALL(SD_BLE_GAP_DATA_LENGTH_UPDATE, uint32_t, - sd_ble_gap_data_length_update(uint16_t conn_handle, ble_gap_data_length_params_t const *p_dl_params, - ble_gap_data_length_limitation_t *p_dl_limitation)); - -/**@brief Start the Quality of Service (QoS) channel survey module. - * - * @details The channel survey module provides measurements of the energy levels on - * the Bluetooth Low Energy channels. When the module is enabled, @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT - * events will periodically report the measured energy levels for each channel. - * - * @note The measurements are scheduled with lower priority than other Bluetooth Low Energy roles, - * Radio Timeslot API events and Flash API events. - * - * @note The channel survey module will attempt to do measurements so that the average interval - * between measurements will be interval_us. However due to the channel survey module - * having the lowest priority of all roles and modules, this may not be possible. In that - * case fewer than expected channel survey reports may be given. - * - * @note In order to use the channel survey module, @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available - * must be set. This is done using @ref sd_ble_cfg_set. - * - * @param[in] interval_us Requested average interval for the measurements and reports. See - * @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS for valid ranges. If set - * to @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS, the channel - * survey role will be scheduled at every available opportunity. - * - * @retval ::NRF_SUCCESS The module is successfully started. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. interval_us is out of the - * allowed range. - * @retval ::NRF_ERROR_INVALID_STATE Trying to start the module when already running. - * @retval ::NRF_ERROR_RESOURCES The channel survey module is not available to the application. - * Set @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available using - * @ref sd_ble_cfg_set. - */ -SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_START, uint32_t, sd_ble_gap_qos_channel_survey_start(uint32_t interval_us)); - -/**@brief Stop the Quality of Service (QoS) channel survey module. - * - * @note The SoftDevice may generate one @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT event after this - * function is called. - * - * @retval ::NRF_SUCCESS The module is successfully stopped. - * @retval ::NRF_ERROR_INVALID_STATE Trying to stop the module when it is not running. - */ -SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP, uint32_t, sd_ble_gap_qos_channel_survey_stop(void)); - -/**@brief Obtain the next connection event counter value. - * - * @details The connection event counter is initialized to zero on the first connection event. The value is incremented - * by one for each connection event. For more information see Bluetooth Core Specification v5.0, Vol 6, Part B, - * Section 4.5.1. - * - * @note The connection event counter obtained through this API will be outdated if this API is called - * at the same time as the connection event counter is incremented. - * - * @note This API will always return the last connection event counter + 1. - * The actual connection event may be multiple connection events later if: - * - Slave latency is enabled and there is no data to transmit or receive. - * - Another role is scheduled with a higher priority at the same time as the next connection event. - * - * @param[in] conn_handle Connection handle. - * @param[out] p_counter Pointer to the variable where the next connection event counter will be written. - * - * @retval ::NRF_SUCCESS The connection event counter was successfully retrieved. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET, uint32_t, - sd_ble_gap_next_conn_evt_counter_get(uint16_t conn_handle, uint16_t *p_counter)); - -/**@brief Start triggering a given task on connection event start. - * - * @details When enabled, this feature will trigger a PPI task at the start of connection events. - * The application can configure the SoftDevice to trigger every N connection events starting from - * a given connection event counter. See also @ref ble_gap_conn_event_trigger_t. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_params Connection event trigger parameters. - * - * @retval ::NRF_SUCCESS Success. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. See @ref ble_gap_conn_event_trigger_t. - * @retval ::NRF_ERROR_INVALID_STATE Either: - * - Trying to start connection event triggering when it is already ongoing. - * - @ref ble_gap_conn_event_trigger_t::conn_evt_counter_start is in the past. - * Use @ref sd_ble_gap_next_conn_evt_counter_get to find a new value - to be used as ble_gap_conn_event_trigger_t::conn_evt_counter_start. - */ -SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_START, uint32_t, - sd_ble_gap_conn_evt_trigger_start(uint16_t conn_handle, ble_gap_conn_event_trigger_t const *p_params)); - -/**@brief Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. - * - * @param[in] conn_handle Connection handle. - * - * @retval ::NRF_SUCCESS Success. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE Trying to stop connection event triggering when it is not enabled. - */ -SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_STOP, uint32_t, sd_ble_gap_conn_evt_trigger_stop(uint16_t conn_handle)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GAP_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gatt.h b/variants/wio-sdk-wm1110/softdevice/ble_gatt.h deleted file mode 100644 index df0d728fc8..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_gatt.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATT Generic Attribute Profile (GATT) Common - @{ - @brief Common definitions and prototypes for the GATT interfaces. - */ - -#ifndef BLE_GATT_H__ -#define BLE_GATT_H__ - -#include "ble_err.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATT_DEFINES Defines - * @{ */ - -/** @brief Default ATT MTU, in bytes. */ -#define BLE_GATT_ATT_MTU_DEFAULT 23 - -/**@brief Invalid Attribute Handle. */ -#define BLE_GATT_HANDLE_INVALID 0x0000 - -/**@brief First Attribute Handle. */ -#define BLE_GATT_HANDLE_START 0x0001 - -/**@brief Last Attribute Handle. */ -#define BLE_GATT_HANDLE_END 0xFFFF - -/** @defgroup BLE_GATT_TIMEOUT_SOURCES GATT Timeout sources - * @{ */ -#define BLE_GATT_TIMEOUT_SRC_PROTOCOL 0x00 /**< ATT Protocol timeout. */ -/** @} */ - -/** @defgroup BLE_GATT_WRITE_OPS GATT Write operations - * @{ */ -#define BLE_GATT_OP_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATT_OP_WRITE_REQ 0x01 /**< Write Request. */ -#define BLE_GATT_OP_WRITE_CMD 0x02 /**< Write Command. */ -#define BLE_GATT_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ -#define BLE_GATT_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ -#define BLE_GATT_OP_EXEC_WRITE_REQ 0x05 /**< Execute Write Request. */ -/** @} */ - -/** @defgroup BLE_GATT_EXEC_WRITE_FLAGS GATT Execute Write flags - * @{ */ -#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL 0x00 /**< Cancel prepared write. */ -#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE 0x01 /**< Execute prepared write. */ -/** @} */ - -/** @defgroup BLE_GATT_HVX_TYPES GATT Handle Value operations - * @{ */ -#define BLE_GATT_HVX_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATT_HVX_NOTIFICATION 0x01 /**< Handle Value Notification. */ -#define BLE_GATT_HVX_INDICATION 0x02 /**< Handle Value Indication. */ -/** @} */ - -/** @defgroup BLE_GATT_STATUS_CODES GATT Status Codes - * @{ */ -#define BLE_GATT_STATUS_SUCCESS 0x0000 /**< Success. */ -#define BLE_GATT_STATUS_UNKNOWN 0x0001 /**< Unknown or not applicable status. */ -#define BLE_GATT_STATUS_ATTERR_INVALID 0x0100 /**< ATT Error: Invalid Error Code. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_HANDLE 0x0101 /**< ATT Error: Invalid Attribute Handle. */ -#define BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED 0x0102 /**< ATT Error: Read not permitted. */ -#define BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED 0x0103 /**< ATT Error: Write not permitted. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_PDU 0x0104 /**< ATT Error: Used in ATT as Invalid PDU. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION 0x0105 /**< ATT Error: Authenticated link required. */ -#define BLE_GATT_STATUS_ATTERR_REQUEST_NOT_SUPPORTED 0x0106 /**< ATT Error: Used in ATT as Request Not Supported. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_OFFSET 0x0107 /**< ATT Error: Offset specified was past the end of the attribute. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION 0x0108 /**< ATT Error: Used in ATT as Insufficient Authorization. */ -#define BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL 0x0109 /**< ATT Error: Used in ATT as Prepare Queue Full. */ -#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND 0x010A /**< ATT Error: Used in ATT as Attribute not found. */ -#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_LONG \ - 0x010B /**< ATT Error: Attribute cannot be read or written using read/write blob requests. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_ENC_KEY_SIZE 0x010C /**< ATT Error: Encryption key size used is insufficient. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH 0x010D /**< ATT Error: Invalid value size. */ -#define BLE_GATT_STATUS_ATTERR_UNLIKELY_ERROR 0x010E /**< ATT Error: Very unlikely error. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION 0x010F /**< ATT Error: Encrypted link required. */ -#define BLE_GATT_STATUS_ATTERR_UNSUPPORTED_GROUP_TYPE \ - 0x0110 /**< ATT Error: Attribute type is not a supported grouping attribute. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_RESOURCES 0x0111 /**< ATT Error: Insufficient resources. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_BEGIN 0x0112 /**< ATT Error: Reserved for Future Use range #1 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_END 0x017F /**< ATT Error: Reserved for Future Use range #1 end. */ -#define BLE_GATT_STATUS_ATTERR_APP_BEGIN 0x0180 /**< ATT Error: Application range begin. */ -#define BLE_GATT_STATUS_ATTERR_APP_END 0x019F /**< ATT Error: Application range end. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_BEGIN 0x01A0 /**< ATT Error: Reserved for Future Use range #2 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_END 0x01DF /**< ATT Error: Reserved for Future Use range #2 end. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_BEGIN 0x01E0 /**< ATT Error: Reserved for Future Use range #3 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_END 0x01FC /**< ATT Error: Reserved for Future Use range #3 end. */ -#define BLE_GATT_STATUS_ATTERR_CPS_WRITE_REQ_REJECTED \ - 0x01FC /**< ATT Common Profile and Service Error: Write request rejected. \ - */ -#define BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR \ - 0x01FD /**< ATT Common Profile and Service Error: Client Characteristic Configuration Descriptor improperly configured. */ -#define BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG \ - 0x01FE /**< ATT Common Profile and Service Error: Procedure Already in Progress. */ -#define BLE_GATT_STATUS_ATTERR_CPS_OUT_OF_RANGE 0x01FF /**< ATT Common Profile and Service Error: Out Of Range. */ -/** @} */ - -/** @defgroup BLE_GATT_CPF_FORMATS Characteristic Presentation Formats - * @note Found at - * http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml - * @{ */ -#define BLE_GATT_CPF_FORMAT_RFU 0x00 /**< Reserved For Future Use. */ -#define BLE_GATT_CPF_FORMAT_BOOLEAN 0x01 /**< Boolean. */ -#define BLE_GATT_CPF_FORMAT_2BIT 0x02 /**< Unsigned 2-bit integer. */ -#define BLE_GATT_CPF_FORMAT_NIBBLE 0x03 /**< Unsigned 4-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT8 0x04 /**< Unsigned 8-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT12 0x05 /**< Unsigned 12-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT16 0x06 /**< Unsigned 16-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT24 0x07 /**< Unsigned 24-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT32 0x08 /**< Unsigned 32-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT48 0x09 /**< Unsigned 48-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT64 0x0A /**< Unsigned 64-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT128 0x0B /**< Unsigned 128-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT8 0x0C /**< Signed 2-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT12 0x0D /**< Signed 12-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT16 0x0E /**< Signed 16-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT24 0x0F /**< Signed 24-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT32 0x10 /**< Signed 32-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT48 0x11 /**< Signed 48-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT64 0x12 /**< Signed 64-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT128 0x13 /**< Signed 128-bit integer. */ -#define BLE_GATT_CPF_FORMAT_FLOAT32 0x14 /**< IEEE-754 32-bit floating point. */ -#define BLE_GATT_CPF_FORMAT_FLOAT64 0x15 /**< IEEE-754 64-bit floating point. */ -#define BLE_GATT_CPF_FORMAT_SFLOAT 0x16 /**< IEEE-11073 16-bit SFLOAT. */ -#define BLE_GATT_CPF_FORMAT_FLOAT 0x17 /**< IEEE-11073 32-bit FLOAT. */ -#define BLE_GATT_CPF_FORMAT_DUINT16 0x18 /**< IEEE-20601 format. */ -#define BLE_GATT_CPF_FORMAT_UTF8S 0x19 /**< UTF-8 string. */ -#define BLE_GATT_CPF_FORMAT_UTF16S 0x1A /**< UTF-16 string. */ -#define BLE_GATT_CPF_FORMAT_STRUCT 0x1B /**< Opaque Structure. */ -/** @} */ - -/** @defgroup BLE_GATT_CPF_NAMESPACES GATT Bluetooth Namespaces - * @{ - */ -#define BLE_GATT_CPF_NAMESPACE_BTSIG 0x01 /**< Bluetooth SIG defined Namespace. */ -#define BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN 0x0000 /**< Namespace Description Unknown. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATT_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATT connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_PARAM att_mtu is smaller than @ref BLE_GATT_ATT_MTU_DEFAULT. - */ -typedef struct { - uint16_t att_mtu; /**< Maximum size of ATT packet the SoftDevice can send or receive. - The default and minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - @mscs - @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} - @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} - @endmscs - */ -} ble_gatt_conn_cfg_t; - -/**@brief GATT Characteristic Properties. */ -typedef struct { - /* Standard properties */ - uint8_t broadcast : 1; /**< Broadcasting of the value permitted. */ - uint8_t read : 1; /**< Reading the value permitted. */ - uint8_t write_wo_resp : 1; /**< Writing the value with Write Command permitted. */ - uint8_t write : 1; /**< Writing the value with Write Request permitted. */ - uint8_t notify : 1; /**< Notification of the value permitted. */ - uint8_t indicate : 1; /**< Indications of the value permitted. */ - uint8_t auth_signed_wr : 1; /**< Writing the value with Signed Write Command permitted. */ -} ble_gatt_char_props_t; - -/**@brief GATT Characteristic Extended Properties. */ -typedef struct { - /* Extended properties */ - uint8_t reliable_wr : 1; /**< Writing the value with Queued Write operations permitted. */ - uint8_t wr_aux : 1; /**< Writing the Characteristic User Description descriptor permitted. */ -} ble_gatt_char_ext_props_t; - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GATT_H__ - -/** @} */ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gattc.h b/variants/wio-sdk-wm1110/softdevice/ble_gattc.h deleted file mode 100644 index f1df1782ca..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_gattc.h +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATTC Generic Attribute Profile (GATT) Client - @{ - @brief Definitions and prototypes for the GATT Client interface. - */ - -#ifndef BLE_GATTC_H__ -#define BLE_GATTC_H__ - -#include "ble_err.h" -#include "ble_gatt.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATTC_ENUMERATIONS Enumerations - * @{ */ - -/**@brief GATTC API SVC numbers. */ -enum BLE_GATTC_SVCS { - SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER = BLE_GATTC_SVC_BASE, /**< Primary Service Discovery. */ - SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, /**< Relationship Discovery. */ - SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, /**< Characteristic Discovery. */ - SD_BLE_GATTC_DESCRIPTORS_DISCOVER, /**< Characteristic Descriptor Discovery. */ - SD_BLE_GATTC_ATTR_INFO_DISCOVER, /**< Attribute Information Discovery. */ - SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, /**< Read Characteristic Value by UUID. */ - SD_BLE_GATTC_READ, /**< Generic read. */ - SD_BLE_GATTC_CHAR_VALUES_READ, /**< Read multiple Characteristic Values. */ - SD_BLE_GATTC_WRITE, /**< Generic write. */ - SD_BLE_GATTC_HV_CONFIRM, /**< Handle Value Confirmation. */ - SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. */ -}; - -/** - * @brief GATT Client Event IDs. - */ -enum BLE_GATTC_EVTS { - BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP = BLE_GATTC_EVT_BASE, /**< Primary Service Discovery Response event. \n See @ref - ble_gattc_evt_prim_srvc_disc_rsp_t. */ - BLE_GATTC_EVT_REL_DISC_RSP, /**< Relationship Discovery Response event. \n See @ref ble_gattc_evt_rel_disc_rsp_t. - */ - BLE_GATTC_EVT_CHAR_DISC_RSP, /**< Characteristic Discovery Response event. \n See @ref - ble_gattc_evt_char_disc_rsp_t. */ - BLE_GATTC_EVT_DESC_DISC_RSP, /**< Descriptor Discovery Response event. \n See @ref - ble_gattc_evt_desc_disc_rsp_t. */ - BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, /**< Attribute Information Response event. \n See @ref - ble_gattc_evt_attr_info_disc_rsp_t. */ - BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP, /**< Read By UUID Response event. \n See @ref - ble_gattc_evt_char_val_by_uuid_read_rsp_t. */ - BLE_GATTC_EVT_READ_RSP, /**< Read Response event. \n See @ref ble_gattc_evt_read_rsp_t. */ - BLE_GATTC_EVT_CHAR_VALS_READ_RSP, /**< Read multiple Response event. \n See @ref - ble_gattc_evt_char_vals_read_rsp_t. */ - BLE_GATTC_EVT_WRITE_RSP, /**< Write Response event. \n See @ref ble_gattc_evt_write_rsp_t. */ - BLE_GATTC_EVT_HVX, /**< Handle Value Notification or Indication event. \n Confirm indication with @ref - sd_ble_gattc_hv_confirm. \n See @ref ble_gattc_evt_hvx_t. */ - BLE_GATTC_EVT_EXCHANGE_MTU_RSP, /**< Exchange MTU Response event. \n See @ref - ble_gattc_evt_exchange_mtu_rsp_t. */ - BLE_GATTC_EVT_TIMEOUT, /**< Timeout event. \n See @ref ble_gattc_evt_timeout_t. */ - BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE /**< Write without Response transmission complete. \n See @ref - ble_gattc_evt_write_cmd_tx_complete_t. */ -}; - -/**@brief GATTC Option IDs. - * IDs that uniquely identify a GATTC option. - */ -enum BLE_GATTC_OPTS { - BLE_GATTC_OPT_UUID_DISC = BLE_GATTC_OPT_BASE, /**< UUID discovery. @ref ble_gattc_opt_uuid_disc_t */ -}; - -/** @} */ - -/** @addtogroup BLE_GATTC_DEFINES Defines - * @{ */ - -/** @defgroup BLE_ERRORS_GATTC SVC return values specific to GATTC - * @{ */ -#define BLE_ERROR_GATTC_PROC_NOT_PERMITTED (NRF_GATTC_ERR_BASE + 0x000) /**< Procedure not Permitted. */ -/** @} */ - -/** @defgroup BLE_GATTC_ATTR_INFO_FORMAT Attribute Information Formats - * @{ */ -#define BLE_GATTC_ATTR_INFO_FORMAT_16BIT 1 /**< 16-bit Attribute Information Format. */ -#define BLE_GATTC_ATTR_INFO_FORMAT_128BIT 2 /**< 128-bit Attribute Information Format. */ -/** @} */ - -/** @defgroup BLE_GATTC_DEFAULTS GATT Client defaults - * @{ */ -#define BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT \ - 1 /**< Default number of Write without Response that can be queued for transmission. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATTC_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATTC connection configuration parameters, set with @ref sd_ble_cfg_set. - */ -typedef struct { - uint8_t write_cmd_tx_queue_size; /**< The guaranteed minimum number of Write without Response that can be queued for - transmission. The default value is @ref BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT */ -} ble_gattc_conn_cfg_t; - -/**@brief Operation Handle Range. */ -typedef struct { - uint16_t start_handle; /**< Start Handle. */ - uint16_t end_handle; /**< End Handle. */ -} ble_gattc_handle_range_t; - -/**@brief GATT service. */ -typedef struct { - ble_uuid_t uuid; /**< Service UUID. */ - ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */ -} ble_gattc_service_t; - -/**@brief GATT include. */ -typedef struct { - uint16_t handle; /**< Include Handle. */ - ble_gattc_service_t included_srvc; /**< Handle of the included service. */ -} ble_gattc_include_t; - -/**@brief GATT characteristic. */ -typedef struct { - ble_uuid_t uuid; /**< Characteristic UUID. */ - ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ - uint8_t char_ext_props : 1; /**< Extended properties present. */ - uint16_t handle_decl; /**< Handle of the Characteristic Declaration. */ - uint16_t handle_value; /**< Handle of the Characteristic Value. */ -} ble_gattc_char_t; - -/**@brief GATT descriptor. */ -typedef struct { - uint16_t handle; /**< Descriptor Handle. */ - ble_uuid_t uuid; /**< Descriptor UUID. */ -} ble_gattc_desc_t; - -/**@brief Write Parameters. */ -typedef struct { - uint8_t write_op; /**< Write Operation to be performed, see @ref BLE_GATT_WRITE_OPS. */ - uint8_t flags; /**< Flags, see @ref BLE_GATT_EXEC_WRITE_FLAGS. */ - uint16_t handle; /**< Handle to the attribute to be written. */ - uint16_t offset; /**< Offset in bytes. @note For WRITE_CMD and WRITE_REQ, offset must be 0. */ - uint16_t len; /**< Length of data in bytes. */ - uint8_t const *p_value; /**< Pointer to the value data. */ -} ble_gattc_write_params_t; - -/**@brief Attribute Information for 16-bit Attribute UUID. */ -typedef struct { - uint16_t handle; /**< Attribute handle. */ - ble_uuid_t uuid; /**< 16-bit Attribute UUID. */ -} ble_gattc_attr_info16_t; - -/**@brief Attribute Information for 128-bit Attribute UUID. */ -typedef struct { - uint16_t handle; /**< Attribute handle. */ - ble_uuid128_t uuid; /**< 128-bit Attribute UUID. */ -} ble_gattc_attr_info128_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Service count. */ - ble_gattc_service_t services[1]; /**< Service data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use - event structures with variable length array members. */ -} ble_gattc_evt_prim_srvc_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_REL_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Include count. */ - ble_gattc_include_t includes[1]; /**< Include data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use - event structures with variable length array members. */ -} ble_gattc_evt_rel_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Characteristic count. */ - ble_gattc_char_t chars[1]; /**< Characteristic data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event - structures with variable length array members. */ -} ble_gattc_evt_char_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_DESC_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Descriptor count. */ - ble_gattc_desc_t descs[1]; /**< Descriptor data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event - structures with variable length array members. */ -} ble_gattc_evt_desc_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Attribute count. */ - uint8_t format; /**< Attribute information format, see @ref BLE_GATTC_ATTR_INFO_FORMAT. */ - union { - ble_gattc_attr_info16_t attr_info16[1]; /**< Attribute information for 16-bit Attribute UUID. - @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on - how to use event structures with variable length array members. */ - ble_gattc_attr_info128_t attr_info128[1]; /**< Attribute information for 128-bit Attribute UUID. - @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on - how to use event structures with variable length array members. */ - } info; /**< Attribute information union. */ -} ble_gattc_evt_attr_info_disc_rsp_t; - -/**@brief GATT read by UUID handle value pair. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint8_t *p_value; /**< Pointer to the Attribute Value, length is available in @ref - ble_gattc_evt_char_val_by_uuid_read_rsp_t::value_len. */ -} ble_gattc_handle_value_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP. */ -typedef struct { - uint16_t count; /**< Handle-Value Pair Count. */ - uint16_t value_len; /**< Length of the value in Handle-Value(s) list. */ - uint8_t handle_value[1]; /**< Handle-Value(s) list. To iterate through the list use @ref - sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter. - @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with - variable length array members. */ -} ble_gattc_evt_char_val_by_uuid_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_READ_RSP. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint16_t offset; /**< Offset of the attribute data. */ - uint16_t len; /**< Attribute data length. */ - uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP. */ -typedef struct { - uint16_t len; /**< Concatenated Attribute values length. */ - uint8_t values[1]; /**< Attribute values. @note This is a variable length array. The size of 1 indicated is only a placeholder - for compilation. See @ref sd_ble_evt_get for more information on how to use event structures with - variable length array members. */ -} ble_gattc_evt_char_vals_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_RSP. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint8_t write_op; /**< Type of write operation, see @ref BLE_GATT_WRITE_OPS. */ - uint16_t offset; /**< Data offset. */ - uint16_t len; /**< Data length. */ - uint8_t data[1]; /**< Data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_write_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_HVX. */ -typedef struct { - uint16_t handle; /**< Handle to which the HVx operation applies. */ - uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ - uint16_t len; /**< Attribute data length. */ - uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_hvx_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. */ -typedef struct { - uint16_t server_rx_mtu; /**< Server RX MTU size. */ -} ble_gattc_evt_exchange_mtu_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ -} ble_gattc_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE. */ -typedef struct { - uint8_t count; /**< Number of write without response transmissions completed. */ -} ble_gattc_evt_write_cmd_tx_complete_t; - -/**@brief GATTC event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which event occurred. */ - uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ - uint16_t - error_handle; /**< In case of error: The handle causing the error. In all other cases @ref BLE_GATT_HANDLE_INVALID. */ - union { - ble_gattc_evt_prim_srvc_disc_rsp_t prim_srvc_disc_rsp; /**< Primary Service Discovery Response Event Parameters. */ - ble_gattc_evt_rel_disc_rsp_t rel_disc_rsp; /**< Relationship Discovery Response Event Parameters. */ - ble_gattc_evt_char_disc_rsp_t char_disc_rsp; /**< Characteristic Discovery Response Event Parameters. */ - ble_gattc_evt_desc_disc_rsp_t desc_disc_rsp; /**< Descriptor Discovery Response Event Parameters. */ - ble_gattc_evt_char_val_by_uuid_read_rsp_t - char_val_by_uuid_read_rsp; /**< Characteristic Value Read by UUID Response Event Parameters. */ - ble_gattc_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. */ - ble_gattc_evt_char_vals_read_rsp_t char_vals_read_rsp; /**< Characteristic Values Read Response Event Parameters. */ - ble_gattc_evt_write_rsp_t write_rsp; /**< Write Response Event Parameters. */ - ble_gattc_evt_hvx_t hvx; /**< Handle Value Notification/Indication Event Parameters. */ - ble_gattc_evt_exchange_mtu_rsp_t exchange_mtu_rsp; /**< Exchange MTU Response Event Parameters. */ - ble_gattc_evt_timeout_t timeout; /**< Timeout Event Parameters. */ - ble_gattc_evt_attr_info_disc_rsp_t attr_info_disc_rsp; /**< Attribute Information Discovery Event Parameters. */ - ble_gattc_evt_write_cmd_tx_complete_t - write_cmd_tx_complete; /**< Write without Response transmission complete Event Parameters. */ - } params; /**< Event Parameters. @note Only valid if @ref gatt_status == @ref BLE_GATT_STATUS_SUCCESS. */ -} ble_gattc_evt_t; - -/**@brief UUID discovery option. - * - * @details Used with @ref sd_ble_opt_set to enable and disable automatic insertion of discovered 128-bit UUIDs to the - * Vendor Specific UUID table. Disabled by default. - * - When disabled, if a procedure initiated by - * @ref sd_ble_gattc_primary_services_discover, - * @ref sd_ble_gattc_relationships_discover, - * @ref sd_ble_gattc_characteristics_discover, - * @ref sd_ble_gattc_descriptors_discover - * finds a 128-bit UUID which was not added by @ref sd_ble_uuid_vs_add, @ref ble_uuid_t::type will be set - * to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. - * - When enabled, all found 128-bit UUIDs will be automatically added. The application can use - * @ref sd_ble_uuid_encode to retrieve the 128-bit UUID from @ref ble_uuid_t received in the corresponding - * event. If the total number of Vendor Specific UUIDs exceeds the table capacity, @ref ble_uuid_t::type will - * be set to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. - * See also @ref ble_common_cfg_vs_uuid_t, @ref sd_ble_uuid_vs_remove. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * - * @retval ::NRF_SUCCESS Set successfully. - * - */ -typedef struct { - uint8_t auto_add_vs_enable : 1; /**< Set to 1 to enable (or 0 to disable) automatic insertion of discovered 128-bit UUIDs. */ -} ble_gattc_opt_uuid_disc_t; - -/**@brief Option structure for GATTC options. */ -typedef union { - ble_gattc_opt_uuid_disc_t uuid_disc; /**< Parameters for the UUID discovery option. */ -} ble_gattc_opt_t; - -/** @} */ - -/** @addtogroup BLE_GATTC_FUNCTIONS Functions - * @{ */ - -/**@brief Initiate or continue a GATT Primary Service Discovery procedure. - * - * @details This function initiates or resumes a Primary Service discovery procedure, starting from the supplied handle. - * If the last service has not been reached, this function must be called again with an updated start handle value to - * continue the search. See also @ref ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_PRIM_SRVC_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] start_handle Handle to start searching from. - * @param[in] p_srvc_uuid Pointer to the service UUID to be found. If it is NULL, all primary services will be returned. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Primary Service Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER, uint32_t, - sd_ble_gattc_primary_services_discover(uint16_t conn_handle, uint16_t start_handle, ble_uuid_t const *p_srvc_uuid)); - -/**@brief Initiate or continue a GATT Relationship Discovery procedure. - * - * @details This function initiates or resumes the Find Included Services sub-procedure. If the last included service has not been - * reached, this must be called again with an updated handle range to continue the search. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_REL_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_REL_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Relationship Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, uint32_t, - sd_ble_gattc_relationships_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Characteristic Discovery procedure. - * - * @details This function initiates or resumes a Characteristic discovery procedure. If the last Characteristic has not been - * reached, this must be called again with an updated handle range to continue the discovery. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_CHAR_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Characteristic Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, uint32_t, - sd_ble_gattc_characteristics_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Characteristic Descriptor Discovery procedure. - * - * @details This function initiates or resumes a Characteristic Descriptor discovery procedure. If the last Descriptor has not - * been reached, this must be called again with an updated handle range to continue the discovery. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_DESC_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_DESC_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Characteristic to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Descriptor Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t, - sd_ble_gattc_descriptors_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Read using Characteristic UUID procedure. - * - * @details This function initiates or resumes a Read using Characteristic UUID procedure. If the last Characteristic has not been - * reached, this must be called again with an updated handle range to continue the discovery. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_READ_UUID_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_uuid Pointer to a Characteristic value UUID to read. - * @param[in] p_handle_range A pointer to the range of handles to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Read using Characteristic UUID procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, uint32_t, - sd_ble_gattc_char_value_by_uuid_read(uint16_t conn_handle, ble_uuid_t const *p_uuid, - ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Read (Long) Characteristic or Descriptor procedure. - * - * @details This function initiates or resumes a GATT Read (Long) Characteristic or Descriptor procedure. If the Characteristic or - * Descriptor to be read is longer than ATT_MTU - 1, this function must be called multiple times with appropriate offset to read - * the complete value. - * - * @events - * @event{@ref BLE_GATTC_EVT_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_VALUE_READ_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] handle The handle of the attribute to be read. - * @param[in] offset Offset into the attribute value to be read. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Read (Long) procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_READ, uint32_t, sd_ble_gattc_read(uint16_t conn_handle, uint16_t handle, uint16_t offset)); - -/**@brief Initiate a GATT Read Multiple Characteristic Values procedure. - * - * @details This function initiates a GATT Read Multiple Characteristic Values procedure. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_READ_MULT_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handles A pointer to the handle(s) of the attribute(s) to be read. - * @param[in] handle_count The number of handles in p_handles. - * - * @retval ::NRF_SUCCESS Successfully started the Read Multiple Characteristic Values procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t, - sd_ble_gattc_char_values_read(uint16_t conn_handle, uint16_t const *p_handles, uint16_t handle_count)); - -/**@brief Perform a Write (Characteristic Value or Descriptor, with or without response, signed or not, long or reliable) - * procedure. - * - * @details This function can perform all write procedures described in GATT. - * - * @note Only one write with response procedure can be ongoing per connection at a time. - * If the application tries to write with response while another write with response procedure is ongoing, - * the function call will return @ref NRF_ERROR_BUSY. - * A @ref BLE_GATTC_EVT_WRITE_RSP event will be issued as soon as the write response arrives from the peer. - * - * @note The number of Write without Response that can be queued is configured by @ref - * ble_gattc_conn_cfg_t::write_cmd_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. - * A @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event will be issued as soon as the transmission of the write without - * response is complete. - * - * @note The application can keep track of the available queue element count for writes without responses by following the - * procedure below: - * - Store initial queue element count in a variable. - * - Decrement the variable, which stores the currently available queue element count, by one when a call to this - * function returns @ref NRF_SUCCESS. - * - Increment the variable, which stores the current available queue element count, by the count variable in @ref - * BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event. - * - * @events - * @event{@ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE, Write without response transmission complete.} - * @event{@ref BLE_GATTC_EVT_WRITE_RSP, Write response received from the peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_VALUE_WRITE_WITHOUT_RESP_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_WRITE_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_LONG_WRITE_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_RELIABLE_WRITE_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_write_params A pointer to a write parameters structure. - * - * @retval ::NRF_SUCCESS Successfully started the Write procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_BUSY For write with response, procedure already in progress. Wait for a @ref BLE_GATTC_EVT_WRITE_RSP event - * and retry. - * @retval ::NRF_ERROR_RESOURCES Too many writes without responses queued. - * Wait for a @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event and retry. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_WRITE, uint32_t, sd_ble_gattc_write(uint16_t conn_handle, ble_gattc_write_params_t const *p_write_params)); - -/**@brief Send a Handle Value Confirmation to the GATT Server. - * - * @mscs - * @mmsc{@ref BLE_GATTC_HVI_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] handle The handle of the attribute in the indication. - * - * @retval ::NRF_SUCCESS Successfully queued the Handle Value Confirmation for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no Indication pending to be confirmed. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_HV_CONFIRM, uint32_t, sd_ble_gattc_hv_confirm(uint16_t conn_handle, uint16_t handle)); - -/**@brief Discovers information about a range of attributes on a GATT server. - * - * @events - * @event{@ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, Generated when information about a range of attributes has been received.} - * @endevents - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range The range of handles to request information about. - * - * @retval ::NRF_SUCCESS Successfully started an attribute information discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t, - sd_ble_gattc_attr_info_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Start an ATT_MTU exchange by sending an Exchange MTU Request to the server. - * - * @details The SoftDevice sets ATT_MTU to the minimum of: - * - The Client RX MTU value, and - * - The Server RX MTU value from @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. - * - * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. - * - * @events - * @event{@ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] client_rx_mtu Client RX MTU size. - * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration - used for this connection. - * - The value must be equal to Server RX MTU size given in @ref sd_ble_gatts_exchange_mtu_reply - * if an ATT_MTU exchange has already been performed in the other direction. - * - * @retval ::NRF_SUCCESS Successfully sent request to the server. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state or an ATT_MTU exchange was already requested once. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid Client RX MTU size supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, uint32_t, - sd_ble_gattc_exchange_mtu_request(uint16_t conn_handle, uint16_t client_rx_mtu)); - -/**@brief Iterate through Handle-Value(s) list in @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. - * - * @param[in] p_gattc_evt Pointer to event buffer containing @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. - * @note If the buffer contains different event, behavior is undefined. - * @param[in,out] p_iter Iterator, points to @ref ble_gattc_handle_value_t structure that will be filled in with - * the next Handle-Value pair in each iteration. If the function returns other than - * @ref NRF_SUCCESS, it will not be changed. - * - To start iteration, initialize the structure to zero. - * - To continue, pass the value from previous iteration. - * - * \code - * ble_gattc_handle_value_t iter; - * memset(&iter, 0, sizeof(ble_gattc_handle_value_t)); - * while (sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(&ble_evt.evt.gattc_evt, &iter) == NRF_SUCCESS) - * { - * app_handle = iter.handle; - * memcpy(app_value, iter.p_value, ble_evt.evt.gattc_evt.params.char_val_by_uuid_read_rsp.value_len); - * } - * \endcode - * - * @retval ::NRF_SUCCESS Successfully retrieved the next Handle-Value pair. - * @retval ::NRF_ERROR_NOT_FOUND No more Handle-Value pairs available in the list. - */ -__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, - ble_gattc_handle_value_t *p_iter); - -/** @} */ - -#ifndef SUPPRESS_INLINE_IMPLEMENTATION - -__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, - ble_gattc_handle_value_t *p_iter) -{ - uint32_t value_len = p_gattc_evt->params.char_val_by_uuid_read_rsp.value_len; - uint8_t *p_first = p_gattc_evt->params.char_val_by_uuid_read_rsp.handle_value; - uint8_t *p_next = p_iter->p_value ? p_iter->p_value + value_len : p_first; - - if ((p_next - p_first) / (sizeof(uint16_t) + value_len) < p_gattc_evt->params.char_val_by_uuid_read_rsp.count) { - p_iter->handle = (uint16_t)p_next[1] << 8 | p_next[0]; - p_iter->p_value = p_next + sizeof(uint16_t); - return NRF_SUCCESS; - } else { - return NRF_ERROR_NOT_FOUND; - } -} - -#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ - -#ifdef __cplusplus -} -#endif -#endif /* BLE_GATTC_H__ */ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gatts.h b/variants/wio-sdk-wm1110/softdevice/ble_gatts.h deleted file mode 100644 index dc94957cd1..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_gatts.h +++ /dev/null @@ -1,904 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATTS Generic Attribute Profile (GATT) Server - @{ - @brief Definitions and prototypes for the GATTS interface. - */ - -#ifndef BLE_GATTS_H__ -#define BLE_GATTS_H__ - -#include "ble_err.h" -#include "ble_gap.h" -#include "ble_gatt.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATTS_ENUMERATIONS Enumerations - * @{ */ - -/** - * @brief GATTS API SVC numbers. - */ -enum BLE_GATTS_SVCS { - SD_BLE_GATTS_SERVICE_ADD = BLE_GATTS_SVC_BASE, /**< Add a service. */ - SD_BLE_GATTS_INCLUDE_ADD, /**< Add an included service. */ - SD_BLE_GATTS_CHARACTERISTIC_ADD, /**< Add a characteristic. */ - SD_BLE_GATTS_DESCRIPTOR_ADD, /**< Add a generic attribute. */ - SD_BLE_GATTS_VALUE_SET, /**< Set an attribute value. */ - SD_BLE_GATTS_VALUE_GET, /**< Get an attribute value. */ - SD_BLE_GATTS_HVX, /**< Handle Value Notification or Indication. */ - SD_BLE_GATTS_SERVICE_CHANGED, /**< Perform a Service Changed Indication to one or more peers. */ - SD_BLE_GATTS_RW_AUTHORIZE_REPLY, /**< Reply to an authorization request for a read or write operation on one or more - attributes. */ - SD_BLE_GATTS_SYS_ATTR_SET, /**< Set the persistent system attributes for a connection. */ - SD_BLE_GATTS_SYS_ATTR_GET, /**< Retrieve the persistent system attributes. */ - SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, /**< Retrieve the first valid user handle. */ - SD_BLE_GATTS_ATTR_GET, /**< Retrieve the UUID and/or metadata of an attribute. */ - SD_BLE_GATTS_EXCHANGE_MTU_REPLY /**< Reply to Exchange MTU Request. */ -}; - -/** - * @brief GATT Server Event IDs. - */ -enum BLE_GATTS_EVTS { - BLE_GATTS_EVT_WRITE = BLE_GATTS_EVT_BASE, /**< Write operation performed. \n See - @ref ble_gatts_evt_write_t. */ - BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST, /**< Read/Write Authorization request. \n Reply with - @ref sd_ble_gatts_rw_authorize_reply. \n See @ref ble_gatts_evt_rw_authorize_request_t. - */ - BLE_GATTS_EVT_SYS_ATTR_MISSING, /**< A persistent system attribute access is pending. \n Respond with @ref - sd_ble_gatts_sys_attr_set. \n See @ref ble_gatts_evt_sys_attr_missing_t. */ - BLE_GATTS_EVT_HVC, /**< Handle Value Confirmation. \n See @ref ble_gatts_evt_hvc_t. - */ - BLE_GATTS_EVT_SC_CONFIRM, /**< Service Changed Confirmation. \n No additional event - structure applies. */ - BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. \n Reply with - @ref sd_ble_gatts_exchange_mtu_reply. \n See @ref ble_gatts_evt_exchange_mtu_request_t. - */ - BLE_GATTS_EVT_TIMEOUT, /**< Peer failed to respond to an ATT request in time. \n See @ref - ble_gatts_evt_timeout_t. */ - BLE_GATTS_EVT_HVN_TX_COMPLETE /**< Handle Value Notification transmission complete. \n See @ref - ble_gatts_evt_hvn_tx_complete_t. */ -}; - -/**@brief GATTS Configuration IDs. - * - * IDs that uniquely identify a GATTS configuration. - */ -enum BLE_GATTS_CFGS { - BLE_GATTS_CFG_SERVICE_CHANGED = BLE_GATTS_CFG_BASE, /**< Service changed configuration. */ - BLE_GATTS_CFG_ATTR_TAB_SIZE, /**< Attribute table size configuration. */ - BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM, /**< Service changed CCCD permission configuration. */ -}; - -/** @} */ - -/** @addtogroup BLE_GATTS_DEFINES Defines - * @{ */ - -/** @defgroup BLE_ERRORS_GATTS SVC return values specific to GATTS - * @{ */ -#define BLE_ERROR_GATTS_INVALID_ATTR_TYPE (NRF_GATTS_ERR_BASE + 0x000) /**< Invalid attribute type. */ -#define BLE_ERROR_GATTS_SYS_ATTR_MISSING (NRF_GATTS_ERR_BASE + 0x001) /**< System Attributes missing. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_LENS_MAX Maximum attribute lengths - * @{ */ -#define BLE_GATTS_FIX_ATTR_LEN_MAX (510) /**< Maximum length for fixed length Attribute Values. */ -#define BLE_GATTS_VAR_ATTR_LEN_MAX (512) /**< Maximum length for variable length Attribute Values. */ -/** @} */ - -/** @defgroup BLE_GATTS_SRVC_TYPES GATT Server Service Types - * @{ */ -#define BLE_GATTS_SRVC_TYPE_INVALID 0x00 /**< Invalid Service Type. */ -#define BLE_GATTS_SRVC_TYPE_PRIMARY 0x01 /**< Primary Service. */ -#define BLE_GATTS_SRVC_TYPE_SECONDARY 0x02 /**< Secondary Type. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_TYPES GATT Server Attribute Types - * @{ */ -#define BLE_GATTS_ATTR_TYPE_INVALID 0x00 /**< Invalid Attribute Type. */ -#define BLE_GATTS_ATTR_TYPE_PRIM_SRVC_DECL 0x01 /**< Primary Service Declaration. */ -#define BLE_GATTS_ATTR_TYPE_SEC_SRVC_DECL 0x02 /**< Secondary Service Declaration. */ -#define BLE_GATTS_ATTR_TYPE_INC_DECL 0x03 /**< Include Declaration. */ -#define BLE_GATTS_ATTR_TYPE_CHAR_DECL 0x04 /**< Characteristic Declaration. */ -#define BLE_GATTS_ATTR_TYPE_CHAR_VAL 0x05 /**< Characteristic Value. */ -#define BLE_GATTS_ATTR_TYPE_DESC 0x06 /**< Descriptor. */ -#define BLE_GATTS_ATTR_TYPE_OTHER 0x07 /**< Other, non-GATT specific type. */ -/** @} */ - -/** @defgroup BLE_GATTS_OPS GATT Server Operations - * @{ */ -#define BLE_GATTS_OP_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATTS_OP_WRITE_REQ 0x01 /**< Write Request. */ -#define BLE_GATTS_OP_WRITE_CMD 0x02 /**< Write Command. */ -#define BLE_GATTS_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ -#define BLE_GATTS_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ -#define BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL 0x05 /**< Execute Write Request: Cancel all prepared writes. */ -#define BLE_GATTS_OP_EXEC_WRITE_REQ_NOW 0x06 /**< Execute Write Request: Immediately execute all prepared writes. */ -/** @} */ - -/** @defgroup BLE_GATTS_VLOCS GATT Value Locations - * @{ */ -#define BLE_GATTS_VLOC_INVALID 0x00 /**< Invalid Location. */ -#define BLE_GATTS_VLOC_STACK 0x01 /**< Attribute Value is located in stack memory, no user memory is required. */ -#define BLE_GATTS_VLOC_USER \ - 0x02 /**< Attribute Value is located in user memory. This requires the user to maintain a valid buffer through the lifetime \ - of the attribute, since the stack will read and write directly to the memory using the pointer provided in the APIs. \ - There are no alignment requirements for the buffer. */ -/** @} */ - -/** @defgroup BLE_GATTS_AUTHORIZE_TYPES GATT Server Authorization Types - * @{ */ -#define BLE_GATTS_AUTHORIZE_TYPE_INVALID 0x00 /**< Invalid Type. */ -#define BLE_GATTS_AUTHORIZE_TYPE_READ 0x01 /**< Authorize a Read Operation. */ -#define BLE_GATTS_AUTHORIZE_TYPE_WRITE 0x02 /**< Authorize a Write Request Operation. */ -/** @} */ - -/** @defgroup BLE_GATTS_SYS_ATTR_FLAGS System Attribute Flags - * @{ */ -#define BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS (1 << 0) /**< Restrict system attributes to system services only. */ -#define BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS (1 << 1) /**< Restrict system attributes to user services only. */ -/** @} */ - -/** @defgroup BLE_GATTS_SERVICE_CHANGED Service Changed Inclusion Values - * @{ - */ -#define BLE_GATTS_SERVICE_CHANGED_DEFAULT \ - (1) /**< Default is to include the Service Changed characteristic in the Attribute Table. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_TAB_SIZE Attribute Table size - * @{ - */ -#define BLE_GATTS_ATTR_TAB_SIZE_MIN (248) /**< Minimum Attribute Table size */ -#define BLE_GATTS_ATTR_TAB_SIZE_DEFAULT (1408) /**< Default Attribute Table size. */ -/** @} */ - -/** @defgroup BLE_GATTS_DEFAULTS GATT Server defaults - * @{ - */ -#define BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT \ - 1 /**< Default number of Handle Value Notifications that can be queued for transmission. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATTS_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATTS connection configuration parameters, set with @ref sd_ble_cfg_set. - */ -typedef struct { - uint8_t hvn_tx_queue_size; /**< Minimum guaranteed number of Handle Value Notifications that can be queued for transmission. - The default value is @ref BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT */ -} ble_gatts_conn_cfg_t; - -/**@brief Attribute metadata. */ -typedef struct { - ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */ - ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ - uint8_t vlen : 1; /**< Variable length attribute. */ - uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ - uint8_t rd_auth : 1; /**< Read authorization and value will be requested from the application on every read operation. */ - uint8_t wr_auth : 1; /**< Write authorization will be requested from the application on every Write Request operation (but not - Write Command). */ -} ble_gatts_attr_md_t; - -/**@brief GATT Attribute. */ -typedef struct { - ble_uuid_t const *p_uuid; /**< Pointer to the attribute UUID. */ - ble_gatts_attr_md_t const *p_attr_md; /**< Pointer to the attribute metadata structure. */ - uint16_t init_len; /**< Initial attribute value length in bytes. */ - uint16_t init_offs; /**< Initial attribute value offset in bytes. If different from zero, the first init_offs bytes of the - attribute value will be left uninitialized. */ - uint16_t max_len; /**< Maximum attribute value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */ - uint8_t *p_value; /**< Pointer to the attribute data. Please note that if the @ref BLE_GATTS_VLOC_USER value location is - selected in the attribute metadata, this will have to point to a buffer that remains valid through the - lifetime of the attribute. This excludes usage of automatic variables that may go out of scope or any - other temporary location. The stack may access that memory directly without the application's - knowledge. For writable characteristics, this value must not be a location in flash memory.*/ -} ble_gatts_attr_t; - -/**@brief GATT Attribute Value. */ -typedef struct { - uint16_t len; /**< Length in bytes to be written or read. Length in bytes written or read after successful return.*/ - uint16_t offset; /**< Attribute value offset. */ - uint8_t *p_value; /**< Pointer to where value is stored or will be stored. - If value is stored in user memory, only the attribute length is updated when p_value == NULL. - Set to NULL when reading to obtain the complete length of the attribute value */ -} ble_gatts_value_t; - -/**@brief GATT Characteristic Presentation Format. */ -typedef struct { - uint8_t format; /**< Format of the value, see @ref BLE_GATT_CPF_FORMATS. */ - int8_t exponent; /**< Exponent for integer data types. */ - uint16_t unit; /**< Unit from Bluetooth Assigned Numbers. */ - uint8_t name_space; /**< Namespace from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ - uint16_t desc; /**< Namespace description from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ -} ble_gatts_char_pf_t; - -/**@brief GATT Characteristic metadata. */ -typedef struct { - ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ - ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic Extended Properties. */ - uint8_t const * - p_char_user_desc; /**< Pointer to a UTF-8 encoded string (non-NULL terminated), NULL if the descriptor is not required. */ - uint16_t char_user_desc_max_size; /**< The maximum size in bytes of the user description descriptor. */ - uint16_t char_user_desc_size; /**< The size of the user description, must be smaller or equal to char_user_desc_max_size. */ - ble_gatts_char_pf_t const - *p_char_pf; /**< Pointer to a presentation format structure or NULL if the CPF descriptor is not required. */ - ble_gatts_attr_md_t const - *p_user_desc_md; /**< Attribute metadata for the User Description descriptor, or NULL for default values. */ - ble_gatts_attr_md_t const - *p_cccd_md; /**< Attribute metadata for the Client Characteristic Configuration Descriptor, or NULL for default values. */ - ble_gatts_attr_md_t const - *p_sccd_md; /**< Attribute metadata for the Server Characteristic Configuration Descriptor, or NULL for default values. */ -} ble_gatts_char_md_t; - -/**@brief GATT Characteristic Definition Handles. */ -typedef struct { - uint16_t value_handle; /**< Handle to the characteristic value. */ - uint16_t user_desc_handle; /**< Handle to the User Description descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */ - uint16_t cccd_handle; /**< Handle to the Client Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if - not present. */ - uint16_t sccd_handle; /**< Handle to the Server Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if - not present. */ -} ble_gatts_char_handles_t; - -/**@brief GATT HVx parameters. */ -typedef struct { - uint16_t handle; /**< Characteristic Value Handle. */ - uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ - uint16_t offset; /**< Offset within the attribute value. */ - uint16_t *p_len; /**< Length in bytes to be written, length in bytes written after return. */ - uint8_t const *p_data; /**< Actual data content, use NULL to use the current attribute value. */ -} ble_gatts_hvx_params_t; - -/**@brief GATT Authorization parameters. */ -typedef struct { - uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ - uint8_t update : 1; /**< If set, data supplied in p_data will be used to update the attribute value. - Please note that for @ref BLE_GATTS_AUTHORIZE_TYPE_WRITE operations this bit must always be set, - as the data to be written needs to be stored and later provided by the application. */ - uint16_t offset; /**< Offset of the attribute value being updated. */ - uint16_t len; /**< Length in bytes of the value in p_data pointer, see @ref BLE_GATTS_ATTR_LENS_MAX. */ - uint8_t const *p_data; /**< Pointer to new value used to update the attribute value. */ -} ble_gatts_authorize_params_t; - -/**@brief GATT Read or Write Authorize Reply parameters. */ -typedef struct { - uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ - union { - ble_gatts_authorize_params_t read; /**< Read authorization parameters. */ - ble_gatts_authorize_params_t write; /**< Write authorization parameters. */ - } params; /**< Reply Parameters. */ -} ble_gatts_rw_authorize_reply_params_t; - -/**@brief Service Changed Inclusion configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t service_changed : 1; /**< If 1, include the Service Changed characteristic in the Attribute Table. Default is @ref - BLE_GATTS_SERVICE_CHANGED_DEFAULT. */ -} ble_gatts_cfg_service_changed_t; - -/**@brief Service Changed CCCD permission configuration parameters, set with @ref sd_ble_cfg_set. - * - * @note @ref ble_gatts_attr_md_t::vlen is ignored and should be set to 0. - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - @ref ble_gatts_attr_md_t::write_perm is out of range. - * - @ref ble_gatts_attr_md_t::write_perm is @ref BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS, that is - * not allowed by the Bluetooth Specification. - * - wrong @ref ble_gatts_attr_md_t::read_perm, only @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN is - * allowed by the Bluetooth Specification. - * - wrong @ref ble_gatts_attr_md_t::vloc, only @ref BLE_GATTS_VLOC_STACK is allowed. - * @retval ::NRF_ERROR_NOT_SUPPORTED Security Mode 2 not supported - */ -typedef struct { - ble_gatts_attr_md_t - perm; /**< Permission for Service Changed CCCD. Default is @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN, no authorization. */ -} ble_gatts_cfg_service_changed_cccd_perm_t; - -/**@brief Attribute table size configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: - * - The specified Attribute Table size is too small. - * The minimum acceptable size is defined by @ref BLE_GATTS_ATTR_TAB_SIZE_MIN. - * - The specified Attribute Table size is not a multiple of 4. - */ -typedef struct { - uint32_t attr_tab_size; /**< Attribute table size. Default is @ref BLE_GATTS_ATTR_TAB_SIZE_DEFAULT, minimum is @ref - BLE_GATTS_ATTR_TAB_SIZE_MIN. */ -} ble_gatts_cfg_attr_tab_size_t; - -/**@brief Config structure for GATTS configurations. */ -typedef union { - ble_gatts_cfg_service_changed_t - service_changed; /**< Include service changed characteristic, cfg_id is @ref BLE_GATTS_CFG_SERVICE_CHANGED. */ - ble_gatts_cfg_service_changed_cccd_perm_t service_changed_cccd_perm; /**< Service changed CCCD permission, cfg_id is @ref - BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM. */ - ble_gatts_cfg_attr_tab_size_t attr_tab_size; /**< Attribute table size, cfg_id is @ref BLE_GATTS_CFG_ATTR_TAB_SIZE. */ -} ble_gatts_cfg_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_WRITE. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - ble_uuid_t uuid; /**< Attribute UUID. */ - uint8_t op; /**< Type of write operation, see @ref BLE_GATTS_OPS. */ - uint8_t auth_required; /**< Writing operation deferred due to authorization requirement. Application may use @ref - sd_ble_gatts_value_set to finalize the writing operation. */ - uint16_t offset; /**< Offset for the write operation. */ - uint16_t len; /**< Length of the received data. */ - uint8_t data[1]; /**< Received data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gatts_evt_write_t; - -/**@brief Event substructure for authorized read requests, see @ref ble_gatts_evt_rw_authorize_request_t. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - ble_uuid_t uuid; /**< Attribute UUID. */ - uint16_t offset; /**< Offset for the read operation. */ -} ble_gatts_evt_read_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST. */ -typedef struct { - uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ - union { - ble_gatts_evt_read_t read; /**< Attribute Read Parameters. */ - ble_gatts_evt_write_t write; /**< Attribute Write Parameters. */ - } request; /**< Request Parameters. */ -} ble_gatts_evt_rw_authorize_request_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. */ -typedef struct { - uint8_t hint; /**< Hint (currently unused). */ -} ble_gatts_evt_sys_attr_missing_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_HVC. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ -} ble_gatts_evt_hvc_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST. */ -typedef struct { - uint16_t client_rx_mtu; /**< Client RX MTU size. */ -} ble_gatts_evt_exchange_mtu_request_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ -} ble_gatts_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_HVN_TX_COMPLETE. */ -typedef struct { - uint8_t count; /**< Number of notification transmissions completed. */ -} ble_gatts_evt_hvn_tx_complete_t; - -/**@brief GATTS event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which the event occurred. */ - union { - ble_gatts_evt_write_t write; /**< Write Event Parameters. */ - ble_gatts_evt_rw_authorize_request_t authorize_request; /**< Read or Write Authorize Request Parameters. */ - ble_gatts_evt_sys_attr_missing_t sys_attr_missing; /**< System attributes missing. */ - ble_gatts_evt_hvc_t hvc; /**< Handle Value Confirmation Event Parameters. */ - ble_gatts_evt_exchange_mtu_request_t exchange_mtu_request; /**< Exchange MTU Request Event Parameters. */ - ble_gatts_evt_timeout_t timeout; /**< Timeout Event. */ - ble_gatts_evt_hvn_tx_complete_t hvn_tx_complete; /**< Handle Value Notification transmission complete Event Parameters. */ - } params; /**< Event Parameters. */ -} ble_gatts_evt_t; - -/** @} */ - -/** @addtogroup BLE_GATTS_FUNCTIONS Functions - * @{ */ - -/**@brief Add a service declaration to the Attribute Table. - * - * @note Secondary Services are only relevant in the context of the entity that references them, it is therefore forbidden to - * add a secondary service declaration that is not referenced by another service later in the Attribute Table. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] type Toggles between primary and secondary services, see @ref BLE_GATTS_SRVC_TYPES. - * @param[in] p_uuid Pointer to service UUID. - * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a service declaration. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, Vendor Specific UUIDs need to be present in the table. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type, ble_uuid_t const *p_uuid, uint16_t *p_handle)); - -/**@brief Add an include declaration to the Attribute Table. - * - * @note It is currently only possible to add an include declaration to the last added service (i.e. only sequential population is - * supported at this time). - * - * @note The included service must already be present in the Attribute Table prior to this call. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] service_handle Handle of the service where the included service is to be placed, if @ref BLE_GATT_HANDLE_INVALID - * is used, it will be placed sequentially. - * @param[in] inc_srvc_handle Handle of the included service. - * @param[out] p_include_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added an include declaration. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, handle values need to match previously added services. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. - * @retval ::NRF_ERROR_NOT_SUPPORTED Feature is not supported, service_handle must be that of the last added service. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, self inclusions are not allowed. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - */ -SVCALL(SD_BLE_GATTS_INCLUDE_ADD, uint32_t, - sd_ble_gatts_include_add(uint16_t service_handle, uint16_t inc_srvc_handle, uint16_t *p_include_handle)); - -/**@brief Add a characteristic declaration, a characteristic value declaration and optional characteristic descriptor declarations - * to the Attribute Table. - * - * @note It is currently only possible to add a characteristic to the last added service (i.e. only sequential population is - * supported at this time). - * - * @note Several restrictions apply to the parameters, such as matching permissions between the user description descriptor and - * the writable auxiliaries bits, readable (no security) and writable (selectable) CCCDs and SCCDs and valid presentation format - * values. - * - * @note If no metadata is provided for the optional descriptors, their permissions will be derived from the characteristic - * permissions. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] service_handle Handle of the service where the characteristic is to be placed, if @ref BLE_GATT_HANDLE_INVALID is - * used, it will be placed sequentially. - * @param[in] p_char_md Characteristic metadata. - * @param[in] p_attr_char_value Pointer to the attribute structure corresponding to the characteristic value. - * @param[out] p_handles Pointer to the structure where the assigned handles will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a characteristic. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, service handle, Vendor Specific UUIDs, lengths, and - * permissions need to adhere to the constraints. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - */ -SVCALL(SD_BLE_GATTS_CHARACTERISTIC_ADD, uint32_t, - sd_ble_gatts_characteristic_add(uint16_t service_handle, ble_gatts_char_md_t const *p_char_md, - ble_gatts_attr_t const *p_attr_char_value, ble_gatts_char_handles_t *p_handles)); - -/**@brief Add a descriptor to the Attribute Table. - * - * @note It is currently only possible to add a descriptor to the last added characteristic (i.e. only sequential population is - * supported at this time). - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] char_handle Handle of the characteristic where the descriptor is to be placed, if @ref BLE_GATT_HANDLE_INVALID is - * used, it will be placed sequentially. - * @param[in] p_attr Pointer to the attribute structure. - * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a descriptor. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, characteristic handle, Vendor Specific UUIDs, lengths, and - * permissions need to adhere to the constraints. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a characteristic context is required. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - */ -SVCALL(SD_BLE_GATTS_DESCRIPTOR_ADD, uint32_t, - sd_ble_gatts_descriptor_add(uint16_t char_handle, ble_gatts_attr_t const *p_attr, uint16_t *p_handle)); - -/**@brief Set the value of a given attribute. - * - * @note Values other than system attributes can be set at any time, regardless of whether any active connections exist. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. - * @param[in] handle Attribute handle. - * @param[in,out] p_value Attribute value information. - * - * @retval ::NRF_SUCCESS Successfully set the value of the attribute. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden handle supplied, certain attributes are not modifiable by the application. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. - */ -SVCALL(SD_BLE_GATTS_VALUE_SET, uint32_t, - sd_ble_gatts_value_set(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); - -/**@brief Get the value of a given attribute. - * - * @note If the attribute value is longer than the size of the supplied buffer, - * @ref ble_gatts_value_t::len will return the total attribute value length (excluding offset), - * and not the number of bytes actually returned in @ref ble_gatts_value_t::p_value. - * The application may use this information to allocate a suitable buffer size. - * - * @note When retrieving system attribute values with this function, the connection handle - * may refer to an already disconnected connection. Refer to the documentation of - * @ref sd_ble_gatts_sys_attr_get for further information. - * - * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. - * @param[in] handle Attribute handle. - * @param[in,out] p_value Attribute value information. - * - * @retval ::NRF_SUCCESS Successfully retrieved the value of the attribute. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid attribute offset supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - */ -SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, - sd_ble_gatts_value_get(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); - -/**@brief Notify or Indicate an attribute value. - * - * @details This function checks for the relevant Client Characteristic Configuration descriptor value to verify that the relevant - * operation (notification or indication) has been enabled by the client. It is also able to update the attribute value before - * issuing the PDU, so that the application can atomically perform a value update and a server initiated transaction with a single - * API call. - * - * @note The local attribute value may be updated even if an outgoing packet is not sent to the peer due to an error during - * execution. The Attribute Table has been updated if one of the following error codes is returned: @ref NRF_ERROR_INVALID_STATE, - * @ref NRF_ERROR_BUSY, - * @ref NRF_ERROR_FORBIDDEN, @ref BLE_ERROR_GATTS_SYS_ATTR_MISSING and @ref NRF_ERROR_RESOURCES. - * The caller can check whether the value has been updated by looking at the contents of *(@ref - * ble_gatts_hvx_params_t::p_len). - * - * @note Only one indication procedure can be ongoing per connection at a time. - * If the application tries to indicate an attribute value while another indication procedure is ongoing, - * the function call will return @ref NRF_ERROR_BUSY. - * A @ref BLE_GATTS_EVT_HVC event will be issued as soon as the confirmation arrives from the peer. - * - * @note The number of Handle Value Notifications that can be queued is configured by @ref - * ble_gatts_conn_cfg_t::hvn_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. A @ref - * BLE_GATTS_EVT_HVN_TX_COMPLETE event will be issued as soon as the transmission of the notification is complete. - * - * @note The application can keep track of the available queue element count for notifications by following the procedure - * below: - * - Store initial queue element count in a variable. - * - Decrement the variable, which stores the currently available queue element count, by one when a call to this - * function returns @ref NRF_SUCCESS. - * - Increment the variable, which stores the current available queue element count, by the count variable in @ref - * BLE_GATTS_EVT_HVN_TX_COMPLETE event. - * - * @events - * @event{@ref BLE_GATTS_EVT_HVN_TX_COMPLETE, Notification transmission complete.} - * @event{@ref BLE_GATTS_EVT_HVC, Confirmation received from the peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} - * @mmsc{@ref BLE_GATTS_HVN_MSC} - * @mmsc{@ref BLE_GATTS_HVI_MSC} - * @mmsc{@ref BLE_GATTS_HVX_DISABLED_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in,out] p_hvx_params Pointer to an HVx parameters structure. If @ref ble_gatts_hvx_params_t::p_data - * contains a non-NULL pointer the attribute value will be updated with the contents - * pointed by it before sending the notification or indication. If the attribute value - * is updated, @ref ble_gatts_hvx_params_t::p_len is updated by the SoftDevice to - * contain the number of actual bytes written, else it will be set to 0. - * - * @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute - * value. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: - * - Invalid Connection State - * - Notifications and/or indications not enabled in the CCCD - * - An ATT_MTU exchange is ongoing - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application - * are available to notify and indicate. - * @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and - * indicated. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_FORBIDDEN The connection's current security level is lower than the one required by the write permissions - * of the CCCD associated with this characteristic. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC - * event and retry. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - * @retval ::NRF_ERROR_RESOURCES Too many notifications queued. - * Wait for a @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event and retry. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_gatts_hvx_params_t const *p_hvx_params)); - -/**@brief Indicate the Service Changed attribute value. - * - * @details This call will send a Handle Value Indication to one or more peers connected to inform them that the Attribute - * Table layout has changed. As soon as the peer has confirmed the indication, a @ref BLE_GATTS_EVT_SC_CONFIRM event will - * be issued. - * - * @note Some of the restrictions and limitations that apply to @ref sd_ble_gatts_hvx also apply here. - * - * @events - * @event{@ref BLE_GATTS_EVT_SC_CONFIRM, Confirmation of attribute table change received from peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTS_SC_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] start_handle Start of affected attribute handle range. - * @param[in] end_handle End of affected attribute handle range. - * - * @retval ::NRF_SUCCESS Successfully queued the Service Changed indication for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_NOT_SUPPORTED Service Changed not enabled at initialization. See @ref - * sd_ble_cfg_set and @ref ble_gatts_cfg_service_changed_t. - * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: - * - Invalid Connection State - * - Notifications and/or indications not enabled in the CCCD - * - An ATT_MTU exchange is ongoing - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied, handles must be in the range populated by the - * application. - * @retval ::NRF_ERROR_BUSY Procedure already in progress. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t, - sd_ble_gatts_service_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle)); - -/**@brief Respond to a Read/Write authorization request. - * - * @note This call should only be used as a response to a @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event issued to the application. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_READ_REQ_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_WRITE_REQ_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_rw_authorize_reply_params Pointer to a structure with the attribute provided by the application. - * - * @note @ref ble_gatts_authorize_params_t::p_data is ignored when this function is used to respond - * to a @ref BLE_GATTS_AUTHORIZE_TYPE_READ event if @ref ble_gatts_authorize_params_t::update - * is set to 0. - * - * @retval ::NRF_SUCCESS Successfully queued a response to the peer, and in the case of a write operation, Attribute - * Table updated. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no authorization request pending. - * @retval ::NRF_ERROR_INVALID_PARAM Authorization op invalid, - * handle supplied does not match requested handle, - * or invalid data to be written provided by the application. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_RW_AUTHORIZE_REPLY, uint32_t, - sd_ble_gatts_rw_authorize_reply(uint16_t conn_handle, - ble_gatts_rw_authorize_reply_params_t const *p_rw_authorize_reply_params)); - -/**@brief Update persistent system attribute information. - * - * @details Supply information about persistent system attributes to the stack, - * previously obtained using @ref sd_ble_gatts_sys_attr_get. - * This call is only allowed for active connections, and is usually - * made immediately after a connection is established with an known bonded device, - * often as a response to a @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. - * - * p_sysattrs may point directly to the application's stored copy of the system attributes - * obtained using @ref sd_ble_gatts_sys_attr_get. - * If the pointer is NULL, the system attribute info is initialized, assuming that - * the application does not have any previously saved system attribute data for this device. - * - * @note The state of persistent system attributes is reset upon connection establishment and then remembered for its duration. - * - * @note If this call returns with an error code different from @ref NRF_SUCCESS, the storage of persistent system attributes may - * have been completed only partially. This means that the state of the attribute table is undefined, and the application should - * either provide a new set of attributes using this same call or reset the SoftDevice to return to a known state. - * - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system - * services will be modified. - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user - * services will be modified. - * - * @mscs - * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_UNK_PEER_MSC} - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_sys_attr_data Pointer to a saved copy of system attributes supplied to the stack, or NULL. - * @param[in] len Size of data pointed by p_sys_attr_data, in octets. - * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS - * - * @retval ::NRF_SUCCESS Successfully set the system attribute information. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. - * @retval ::NRF_ERROR_INVALID_DATA Invalid data supplied, the data should be exactly the same as retrieved with @ref - * sd_ble_gatts_sys_attr_get. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GATTS_SYS_ATTR_SET, uint32_t, - sd_ble_gatts_sys_attr_set(uint16_t conn_handle, uint8_t const *p_sys_attr_data, uint16_t len, uint32_t flags)); - -/**@brief Retrieve persistent system attribute information from the stack. - * - * @details This call is used to retrieve information about values to be stored persistently by the application - * during the lifetime of a connection or after it has been terminated. When a new connection is established with the - * same bonded device, the system attribute information retrieved with this function should be restored using using @ref - * sd_ble_gatts_sys_attr_set. If retrieved after disconnection, the data should be read before a new connection established. The - * connection handle for the previous, now disconnected, connection will remain valid until a new one is created to allow this API - * call to refer to it. Connection handles belonging to active connections can be used as well, but care should be taken since the - * system attributes may be written to at any time by the peer during a connection's lifetime. - * - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system - * services will be returned. - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user - * services will be returned. - * - * @mscs - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle of the recently terminated connection. - * @param[out] p_sys_attr_data Pointer to a buffer where updated information about system attributes will be filled in. The - * format of the data is described in @ref BLE_GATTS_SYS_ATTRS_FORMAT. NULL can be provided to obtain the length of the data. - * @param[in,out] p_len Size of application buffer if p_sys_attr_data is not NULL. Unconditionally updated to actual - * length of system attribute data. - * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS - * - * @retval ::NRF_SUCCESS Successfully retrieved the system attribute information. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. - * @retval ::NRF_ERROR_DATA_SIZE The system attribute information did not fit into the provided buffer. - * @retval ::NRF_ERROR_NOT_FOUND No system attributes found. - */ -SVCALL(SD_BLE_GATTS_SYS_ATTR_GET, uint32_t, - sd_ble_gatts_sys_attr_get(uint16_t conn_handle, uint8_t *p_sys_attr_data, uint16_t *p_len, uint32_t flags)); - -/**@brief Retrieve the first valid user attribute handle. - * - * @param[out] p_handle Pointer to an integer where the handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully retrieved the handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, uint32_t, sd_ble_gatts_initial_user_handle_get(uint16_t *p_handle)); - -/**@brief Retrieve the attribute UUID and/or metadata. - * - * @param[in] handle Attribute handle - * @param[out] p_uuid UUID of the attribute. Use NULL to omit this field. - * @param[out] p_md Metadata of the attribute. Use NULL to omit this field. - * - * @retval ::NRF_SUCCESS Successfully retrieved the attribute metadata, - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. Returned when both @c p_uuid and @c p_md are NULL. - * @retval ::NRF_ERROR_NOT_FOUND Attribute was not found. - */ -SVCALL(SD_BLE_GATTS_ATTR_GET, uint32_t, sd_ble_gatts_attr_get(uint16_t handle, ble_uuid_t *p_uuid, ble_gatts_attr_md_t *p_md)); - -/**@brief Reply to an ATT_MTU exchange request by sending an Exchange MTU Response to the client. - * - * @details This function is only used to reply to a @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event. - * - * @details The SoftDevice sets ATT_MTU to the minimum of: - * - The Client RX MTU value from @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, and - * - The Server RX MTU value. - * - * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. - * - * @mscs - * @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] server_rx_mtu Server RX MTU size. - * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration - * used for this connection. - * - The value must be equal to Client RX MTU size given in @ref sd_ble_gattc_exchange_mtu_request - * if an ATT_MTU exchange has already been performed in the other direction. - * - * @retval ::NRF_SUCCESS Successfully sent response to the client. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no ATT_MTU exchange request pending. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid Server RX MTU size supplied. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_EXCHANGE_MTU_REPLY, uint32_t, sd_ble_gatts_exchange_mtu_reply(uint16_t conn_handle, uint16_t server_rx_mtu)); -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GATTS_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_hci.h b/variants/wio-sdk-wm1110/softdevice/ble_hci.h deleted file mode 100644 index 27f85d52ea..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_hci.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ -*/ - -#ifndef BLE_HCI_H__ -#define BLE_HCI_H__ -#ifdef __cplusplus -extern "C" { -#endif - -/** @defgroup BLE_HCI_STATUS_CODES Bluetooth status codes - * @{ */ - -#define BLE_HCI_STATUS_CODE_SUCCESS 0x00 /**< Success. */ -#define BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND 0x01 /**< Unknown BLE Command. */ -#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02 /**< Unknown Connection Identifier. */ -/*0x03 Hardware Failure -0x04 Page Timeout -*/ -#define BLE_HCI_AUTHENTICATION_FAILURE 0x05 /**< Authentication Failure. */ -#define BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING 0x06 /**< Pin or Key missing. */ -#define BLE_HCI_MEMORY_CAPACITY_EXCEEDED 0x07 /**< Memory Capacity Exceeded. */ -#define BLE_HCI_CONNECTION_TIMEOUT 0x08 /**< Connection Timeout. */ -/*0x09 Connection Limit Exceeded -0x0A Synchronous Connection Limit To A Device Exceeded -0x0B ACL Connection Already Exists*/ -#define BLE_HCI_STATUS_CODE_COMMAND_DISALLOWED 0x0C /**< Command Disallowed. */ -/*0x0D Connection Rejected due to Limited Resources -0x0E Connection Rejected Due To Security Reasons -0x0F Connection Rejected due to Unacceptable BD_ADDR -0x10 Connection Accept Timeout Exceeded -0x11 Unsupported Feature or Parameter Value*/ -#define BLE_HCI_STATUS_CODE_INVALID_BTLE_COMMAND_PARAMETERS 0x12 /**< Invalid BLE Command Parameters. */ -#define BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION 0x13 /**< Remote User Terminated Connection. */ -#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES \ - 0x14 /**< Remote Device Terminated Connection due to low \ - resources.*/ -#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF 0x15 /**< Remote Device Terminated Connection due to power off. */ -#define BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION 0x16 /**< Local Host Terminated Connection. */ -/* -0x17 Repeated Attempts -0x18 Pairing Not Allowed -0x19 Unknown LMP PDU -*/ -#define BLE_HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A /**< Unsupported Remote Feature. */ -/* -0x1B SCO Offset Rejected -0x1C SCO Interval Rejected -0x1D SCO Air Mode Rejected*/ -#define BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS 0x1E /**< Invalid LMP Parameters. */ -#define BLE_HCI_STATUS_CODE_UNSPECIFIED_ERROR 0x1F /**< Unspecified Error. */ -/*0x20 Unsupported LMP Parameter Value -0x21 Role Change Not Allowed -*/ -#define BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT 0x22 /**< LMP Response Timeout. */ -#define BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION 0x23 /**< LMP Error Transaction Collision/LL Procedure Collision. */ -#define BLE_HCI_STATUS_CODE_LMP_PDU_NOT_ALLOWED 0x24 /**< LMP PDU Not Allowed. */ -/*0x25 Encryption Mode Not Acceptable -0x26 Link Key Can Not be Changed -0x27 Requested QoS Not Supported -*/ -#define BLE_HCI_INSTANT_PASSED 0x28 /**< Instant Passed. */ -#define BLE_HCI_PAIRING_WITH_UNIT_KEY_UNSUPPORTED 0x29 /**< Pairing with Unit Key Unsupported. */ -#define BLE_HCI_DIFFERENT_TRANSACTION_COLLISION 0x2A /**< Different Transaction Collision. */ -/* -0x2B Reserved -0x2C QoS Unacceptable Parameter -0x2D QoS Rejected -0x2E Channel Classification Not Supported -0x2F Insufficient Security -*/ -#define BLE_HCI_PARAMETER_OUT_OF_MANDATORY_RANGE 0x30 /**< Parameter Out Of Mandatory Range. */ -/* -0x31 Reserved -0x32 Role Switch Pending -0x33 Reserved -0x34 Reserved Slot Violation -0x35 Role Switch Failed -0x36 Extended Inquiry Response Too Large -0x37 Secure Simple Pairing Not Supported By Host. -0x38 Host Busy - Pairing -0x39 Connection Rejected due to No Suitable Channel Found*/ -#define BLE_HCI_CONTROLLER_BUSY 0x3A /**< Controller Busy. */ -#define BLE_HCI_CONN_INTERVAL_UNACCEPTABLE 0x3B /**< Connection Interval Unacceptable. */ -#define BLE_HCI_DIRECTED_ADVERTISER_TIMEOUT 0x3C /**< Directed Advertisement Timeout. */ -#define BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE 0x3D /**< Connection Terminated due to MIC Failure. */ -#define BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED 0x3E /**< Connection Failed to be Established. */ - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_HCI_H__ - -/** @} */ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h b/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h deleted file mode 100644 index 5f4bd277d3..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_L2CAP Logical Link Control and Adaptation Protocol (L2CAP) - @{ - @brief Definitions and prototypes for the L2CAP interface. - */ - -#ifndef BLE_L2CAP_H__ -#define BLE_L2CAP_H__ - -#include "ble_err.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup BLE_L2CAP_TERMINOLOGY Terminology - * @{ - * @details - * - * L2CAP SDU - * - A data unit that the application can send/receive to/from a peer. - * - * L2CAP PDU - * - A data unit that is exchanged between local and remote L2CAP entities. - * It consists of L2CAP protocol control information and payload fields. - * The payload field can contain an L2CAP SDU or a part of an L2CAP SDU. - * - * L2CAP MTU - * - The maximum length of an L2CAP SDU. - * - * L2CAP MPS - * - The maximum length of an L2CAP PDU payload field. - * - * Credits - * - A value indicating the number of L2CAP PDUs that the receiver of the credit can send to the peer. - * @} */ - -/**@addtogroup BLE_L2CAP_ENUMERATIONS Enumerations - * @{ */ - -/**@brief L2CAP API SVC numbers. */ -enum BLE_L2CAP_SVCS { - SD_BLE_L2CAP_CH_SETUP = BLE_L2CAP_SVC_BASE + 0, /**< Set up an L2CAP channel. */ - SD_BLE_L2CAP_CH_RELEASE = BLE_L2CAP_SVC_BASE + 1, /**< Release an L2CAP channel. */ - SD_BLE_L2CAP_CH_RX = BLE_L2CAP_SVC_BASE + 2, /**< Receive an SDU on an L2CAP channel. */ - SD_BLE_L2CAP_CH_TX = BLE_L2CAP_SVC_BASE + 3, /**< Transmit an SDU on an L2CAP channel. */ - SD_BLE_L2CAP_CH_FLOW_CONTROL = BLE_L2CAP_SVC_BASE + 4, /**< Advanced SDU reception flow control. */ -}; - -/**@brief L2CAP Event IDs. */ -enum BLE_L2CAP_EVTS { - BLE_L2CAP_EVT_CH_SETUP_REQUEST = BLE_L2CAP_EVT_BASE + 0, /**< L2CAP Channel Setup Request event. - \n Reply with @ref sd_ble_l2cap_ch_setup. - \n See @ref ble_l2cap_evt_ch_setup_request_t. */ - BLE_L2CAP_EVT_CH_SETUP_REFUSED = BLE_L2CAP_EVT_BASE + 1, /**< L2CAP Channel Setup Refused event. - \n See @ref ble_l2cap_evt_ch_setup_refused_t. */ - BLE_L2CAP_EVT_CH_SETUP = BLE_L2CAP_EVT_BASE + 2, /**< L2CAP Channel Setup Completed event. - \n See @ref ble_l2cap_evt_ch_setup_t. */ - BLE_L2CAP_EVT_CH_RELEASED = BLE_L2CAP_EVT_BASE + 3, /**< L2CAP Channel Released event. - \n No additional event structure applies. */ - BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED = BLE_L2CAP_EVT_BASE + 4, /**< L2CAP Channel SDU data buffer released event. - \n See @ref ble_l2cap_evt_ch_sdu_buf_released_t. */ - BLE_L2CAP_EVT_CH_CREDIT = BLE_L2CAP_EVT_BASE + 5, /**< L2CAP Channel Credit received. - \n See @ref ble_l2cap_evt_ch_credit_t. */ - BLE_L2CAP_EVT_CH_RX = BLE_L2CAP_EVT_BASE + 6, /**< L2CAP Channel SDU received. - \n See @ref ble_l2cap_evt_ch_rx_t. */ - BLE_L2CAP_EVT_CH_TX = BLE_L2CAP_EVT_BASE + 7, /**< L2CAP Channel SDU transmitted. - \n See @ref ble_l2cap_evt_ch_tx_t. */ -}; - -/** @} */ - -/**@addtogroup BLE_L2CAP_DEFINES Defines - * @{ */ - -/**@brief Maximum number of L2CAP channels per connection. */ -#define BLE_L2CAP_CH_COUNT_MAX (64) - -/**@brief Minimum L2CAP MTU, in bytes. */ -#define BLE_L2CAP_MTU_MIN (23) - -/**@brief Minimum L2CAP MPS, in bytes. */ -#define BLE_L2CAP_MPS_MIN (23) - -/**@brief Invalid CID. */ -#define BLE_L2CAP_CID_INVALID (0x0000) - -/**@brief Default number of credits for @ref sd_ble_l2cap_ch_flow_control. */ -#define BLE_L2CAP_CREDITS_DEFAULT (1) - -/**@defgroup BLE_L2CAP_CH_SETUP_REFUSED_SRCS L2CAP channel setup refused sources - * @{ */ -#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_LOCAL (0x01) /**< Local. */ -#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_REMOTE (0x02) /**< Remote. */ - /** @} */ - -/** @defgroup BLE_L2CAP_CH_STATUS_CODES L2CAP channel status codes - * @{ */ -#define BLE_L2CAP_CH_STATUS_CODE_SUCCESS (0x0000) /**< Success. */ -#define BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED (0x0002) /**< LE_PSM not supported. */ -#define BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES (0x0004) /**< No resources available. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHENTICATION (0x0005) /**< Insufficient authentication. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHORIZATION (0x0006) /**< Insufficient authorization. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC_KEY_SIZE (0x0007) /**< Insufficient encryption key size. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC (0x0008) /**< Insufficient encryption. */ -#define BLE_L2CAP_CH_STATUS_CODE_INVALID_SCID (0x0009) /**< Invalid Source CID. */ -#define BLE_L2CAP_CH_STATUS_CODE_SCID_ALLOCATED (0x000A) /**< Source CID already allocated. */ -#define BLE_L2CAP_CH_STATUS_CODE_UNACCEPTABLE_PARAMS (0x000B) /**< Unacceptable parameters. */ -#define BLE_L2CAP_CH_STATUS_CODE_NOT_UNDERSTOOD \ - (0x8000) /**< Command Reject received instead of LE Credit Based Connection Response. */ -#define BLE_L2CAP_CH_STATUS_CODE_TIMEOUT (0xC000) /**< Operation timed out. */ -/** @} */ - -/** @} */ - -/**@addtogroup BLE_L2CAP_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE L2CAP connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @note These parameters are set per connection, so all L2CAP channels created on this connection - * will have the same parameters. - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - rx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. - * - tx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. - * - ch_count is greater than @ref BLE_L2CAP_CH_COUNT_MAX. - * @retval ::NRF_ERROR_NO_MEM rx_mps or tx_mps is set too high. - */ -typedef struct { - uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall - be able to receive on L2CAP channels on connections with this - configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ - uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall - be able to transmit on L2CAP channels on connections with this - configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ - uint8_t rx_queue_size; /**< Number of SDU data buffers that can be queued for reception per - L2CAP channel. The minimum value is one. */ - uint8_t tx_queue_size; /**< Number of SDU data buffers that can be queued for transmission - per L2CAP channel. The minimum value is one. */ - uint8_t ch_count; /**< Number of L2CAP channels the application can create per connection - with this configuration. The default value is zero, the maximum - value is @ref BLE_L2CAP_CH_COUNT_MAX. - @note if this parameter is set to zero, all other parameters in - @ref ble_l2cap_conn_cfg_t are ignored. */ -} ble_l2cap_conn_cfg_t; - -/**@brief L2CAP channel RX parameters. */ -typedef struct { - uint16_t rx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP shall be able to - receive on this L2CAP channel. - - Must be equal to or greater than @ref BLE_L2CAP_MTU_MIN. */ - uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall be - able to receive on this L2CAP channel. - - Must be equal to or greater than @ref BLE_L2CAP_MPS_MIN. - - Must be equal to or less than @ref ble_l2cap_conn_cfg_t::rx_mps. */ - ble_data_t sdu_buf; /**< SDU data buffer for reception. - - If @ref ble_data_t::p_data is non-NULL, initial credits are - issued to the peer. - - If @ref ble_data_t::p_data is NULL, no initial credits are - issued to the peer. */ -} ble_l2cap_ch_rx_params_t; - -/**@brief L2CAP channel setup parameters. */ -typedef struct { - ble_l2cap_ch_rx_params_t rx_params; /**< L2CAP channel RX parameters. */ - uint16_t le_psm; /**< LE Protocol/Service Multiplexer. Used when requesting - setup of an L2CAP channel, ignored otherwise. */ - uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES. - Used when replying to a setup request of an L2CAP - channel, ignored otherwise. */ -} ble_l2cap_ch_setup_params_t; - -/**@brief L2CAP channel TX parameters. */ -typedef struct { - uint16_t tx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP is able to - transmit on this L2CAP channel. */ - uint16_t peer_mps; /**< The maximum L2CAP PDU payload size, in bytes, that the peer is - able to receive on this L2CAP channel. */ - uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP is able - to transmit on this L2CAP channel. This is effective tx_mps, - selected by the SoftDevice as - MIN( @ref ble_l2cap_ch_tx_params_t::peer_mps, @ref ble_l2cap_conn_cfg_t::tx_mps ) */ - uint16_t credits; /**< Initial credits given by the peer. */ -} ble_l2cap_ch_tx_params_t; - -/**@brief L2CAP Channel Setup Request event. */ -typedef struct { - ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ - uint16_t le_psm; /**< LE Protocol/Service Multiplexer. */ -} ble_l2cap_evt_ch_setup_request_t; - -/**@brief L2CAP Channel Setup Refused event. */ -typedef struct { - uint8_t source; /**< Source, see @ref BLE_L2CAP_CH_SETUP_REFUSED_SRCS */ - uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES */ -} ble_l2cap_evt_ch_setup_refused_t; - -/**@brief L2CAP Channel Setup Completed event. */ -typedef struct { - ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ -} ble_l2cap_evt_ch_setup_t; - -/**@brief L2CAP Channel SDU Data Buffer Released event. */ -typedef struct { - ble_data_t sdu_buf; /**< Returned reception or transmission SDU data buffer. The SoftDevice - returns SDU data buffers supplied by the application, which have - not yet been returned previously via a @ref BLE_L2CAP_EVT_CH_RX or - @ref BLE_L2CAP_EVT_CH_TX event. */ -} ble_l2cap_evt_ch_sdu_buf_released_t; - -/**@brief L2CAP Channel Credit received event. */ -typedef struct { - uint16_t credits; /**< Additional credits given by the peer. */ -} ble_l2cap_evt_ch_credit_t; - -/**@brief L2CAP Channel received SDU event. */ -typedef struct { - uint16_t sdu_len; /**< Total SDU length, in bytes. */ - ble_data_t sdu_buf; /**< SDU data buffer. - @note If there is not enough space in the buffer - (sdu_buf.len < sdu_len) then the rest of the SDU will be - silently discarded by the SoftDevice. */ -} ble_l2cap_evt_ch_rx_t; - -/**@brief L2CAP Channel transmitted SDU event. */ -typedef struct { - ble_data_t sdu_buf; /**< SDU data buffer. */ -} ble_l2cap_evt_ch_tx_t; - -/**@brief L2CAP event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which the event occured. */ - uint16_t local_cid; /**< Local Channel ID of the L2CAP channel, or - @ref BLE_L2CAP_CID_INVALID if not present. */ - union { - ble_l2cap_evt_ch_setup_request_t ch_setup_request; /**< L2CAP Channel Setup Request Event Parameters. */ - ble_l2cap_evt_ch_setup_refused_t ch_setup_refused; /**< L2CAP Channel Setup Refused Event Parameters. */ - ble_l2cap_evt_ch_setup_t ch_setup; /**< L2CAP Channel Setup Completed Event Parameters. */ - ble_l2cap_evt_ch_sdu_buf_released_t ch_sdu_buf_released; /**< L2CAP Channel SDU Data Buffer Released Event Parameters. */ - ble_l2cap_evt_ch_credit_t credit; /**< L2CAP Channel Credit Received Event Parameters. */ - ble_l2cap_evt_ch_rx_t rx; /**< L2CAP Channel SDU Received Event Parameters. */ - ble_l2cap_evt_ch_tx_t tx; /**< L2CAP Channel SDU Transmitted Event Parameters. */ - } params; /**< Event Parameters. */ -} ble_l2cap_evt_t; - -/** @} */ - -/**@addtogroup BLE_L2CAP_FUNCTIONS Functions - * @{ */ - -/**@brief Set up an L2CAP channel. - * - * @details This function is used to: - * - Request setup of an L2CAP channel: sends an LE Credit Based Connection Request packet to a peer. - * - Reply to a setup request of an L2CAP channel (if called in response to a - * @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST event): sends an LE Credit Based Connection - * Response packet to a peer. - * - * @note A call to this function will require the application to keep the SDU data buffer alive - * until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX or - * @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_SETUP, Setup successful.} - * @event{@ref BLE_L2CAP_EVT_CH_SETUP_REFUSED, Setup failed.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_SETUP_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in,out] p_local_cid Pointer to a uint16_t containing Local Channel ID of the L2CAP channel: - * - As input: @ref BLE_L2CAP_CID_INVALID when requesting setup of an L2CAP - * channel or local_cid provided in the @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST - * event when replying to a setup request of an L2CAP channel. - * - As output: local_cid for this channel. - * @param[in] p_params L2CAP channel parameters. - * - * @retval ::NRF_SUCCESS Successfully queued request or response for transmission. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_LENGTH Supplied higher rx_mps than has been configured on this link. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (L2CAP channel already set up). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_RESOURCES The limit has been reached for available L2CAP channels, - * see @ref ble_l2cap_conn_cfg_t::ch_count. - */ -SVCALL(SD_BLE_L2CAP_CH_SETUP, uint32_t, - sd_ble_l2cap_ch_setup(uint16_t conn_handle, uint16_t *p_local_cid, ble_l2cap_ch_setup_params_t const *p_params)); - -/**@brief Release an L2CAP channel. - * - * @details This sends a Disconnection Request packet to a peer. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_RELEASED, Release complete.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_RELEASE_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * - * @retval ::NRF_SUCCESS Successfully queued request for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for the L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - */ -SVCALL(SD_BLE_L2CAP_CH_RELEASE, uint32_t, sd_ble_l2cap_ch_release(uint16_t conn_handle, uint16_t local_cid)); - -/**@brief Receive an SDU on an L2CAP channel. - * - * @details This may issue additional credits to the peer using an LE Flow Control Credit packet. - * - * @note A call to this function will require the application to keep the memory pointed by - * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX - * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::rx_queue_size SDU data buffers - * for reception per L2CAP channel. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_RX, The SDU is received.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_RX_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * @param[in] p_sdu_buf Pointer to the SDU data buffer. - * - * @retval ::NRF_SUCCESS Buffer accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for an L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_RESOURCES Too many SDU data buffers supplied. Wait for a - * @ref BLE_L2CAP_EVT_CH_RX event and retry. - */ -SVCALL(SD_BLE_L2CAP_CH_RX, uint32_t, sd_ble_l2cap_ch_rx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); - -/**@brief Transmit an SDU on an L2CAP channel. - * - * @note A call to this function will require the application to keep the memory pointed by - * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_TX - * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::tx_queue_size SDUs for - * transmission per L2CAP channel. - * - * @note The application can keep track of the available credits for transmission by following - * the procedure below: - * - Store initial credits given by the peer in a variable. - * (Initial credits are provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) - * - Decrement the variable, which stores the currently available credits, by - * ceiling((@ref ble_data_t::len + 2) / tx_mps) when a call to this function returns - * @ref NRF_SUCCESS. (tx_mps is provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) - * - Increment the variable, which stores the currently available credits, by additional - * credits given by the peer in a @ref BLE_L2CAP_EVT_CH_CREDIT event. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_TX, The SDU is transmitted.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_TX_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * @param[in] p_sdu_buf Pointer to the SDU data buffer. - * - * @retval ::NRF_SUCCESS Successfully queued L2CAP SDU for transmission. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for the L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_DATA_SIZE Invalid SDU length supplied, must not be more than - * @ref ble_l2cap_ch_tx_params_t::tx_mtu provided in - * @ref BLE_L2CAP_EVT_CH_SETUP event. - * @retval ::NRF_ERROR_RESOURCES Too many SDUs queued for transmission. Wait for a - * @ref BLE_L2CAP_EVT_CH_TX event and retry. - */ -SVCALL(SD_BLE_L2CAP_CH_TX, uint32_t, sd_ble_l2cap_ch_tx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); - -/**@brief Advanced SDU reception flow control. - * - * @details Adjust the way the SoftDevice issues credits to the peer. - * This may issue additional credits to the peer using an LE Flow Control Credit packet. - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_FLOW_CONTROL_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel or @ref BLE_L2CAP_CID_INVALID to set - * the value that will be used for newly created channels. - * @param[in] credits Number of credits that the SoftDevice will make sure the peer has every - * time it starts using a new reception buffer. - * - @ref BLE_L2CAP_CREDITS_DEFAULT is the default value the SoftDevice will - * use if this function is not called. - * - If set to zero, the SoftDevice will stop issuing credits for new reception - * buffers the application provides or has provided. SDU reception that is - * currently ongoing will be allowed to complete. - * @param[out] p_credits NULL or pointer to a uint16_t. If a valid pointer is provided, it will be - * written by the SoftDevice with the number of credits that is or will be - * available to the peer. If the value written by the SoftDevice is 0 when - * credits parameter was set to 0, the peer will not be able to send more - * data until more credits are provided by calling this function again with - * credits > 0. This parameter is ignored when local_cid is set to - * @ref BLE_L2CAP_CID_INVALID. - * - * @note Application should take care when setting number of credits higher than default value. In - * this case the application must make sure that the SoftDevice always has reception buffers - * available (see @ref sd_ble_l2cap_ch_rx) for that channel. If the SoftDevice does not have - * such buffers available, packets may be NACKed on the Link Layer and all Bluetooth traffic - * on the connection handle may be stalled until the SoftDevice again has an available - * reception buffer. This applies even if the application has used this call to set the - * credits back to default, or zero. - * - * @retval ::NRF_SUCCESS Flow control parameters accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for an L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - */ -SVCALL(SD_BLE_L2CAP_CH_FLOW_CONTROL, uint32_t, - sd_ble_l2cap_ch_flow_control(uint16_t conn_handle, uint16_t local_cid, uint16_t credits, uint16_t *p_credits)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_L2CAP_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_ranges.h b/variants/wio-sdk-wm1110/softdevice/ble_ranges.h deleted file mode 100644 index 2768e49967..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_ranges.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @defgroup ble_ranges Module specific SVC, event and option number subranges - @{ - - @brief Definition of SVC, event and option number subranges for each API module. - - @note - SVCs, event and option numbers are split into subranges for each API module. - Each module receives its entire allocated range of SVC calls, whether implemented or not, - but return BLE_ERROR_NOT_SUPPORTED for unimplemented or undefined calls in its range. - - Note that the symbols BLE__SVC_LAST is the end of the allocated SVC range, - rather than the last SVC function call actually defined and implemented. - - Specific SVC, event and option values are defined in each module's ble_.h file, - which defines names of each individual SVC code based on the range start value. -*/ - -#ifndef BLE_RANGES_H__ -#define BLE_RANGES_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#define BLE_SVC_BASE 0x60 /**< Common BLE SVC base. */ -#define BLE_SVC_LAST 0x6B /**< Common BLE SVC last. */ - -#define BLE_GAP_SVC_BASE 0x6C /**< GAP BLE SVC base. */ -#define BLE_GAP_SVC_LAST 0x9A /**< GAP BLE SVC last. */ - -#define BLE_GATTC_SVC_BASE 0x9B /**< GATTC BLE SVC base. */ -#define BLE_GATTC_SVC_LAST 0xA7 /**< GATTC BLE SVC last. */ - -#define BLE_GATTS_SVC_BASE 0xA8 /**< GATTS BLE SVC base. */ -#define BLE_GATTS_SVC_LAST 0xB7 /**< GATTS BLE SVC last. */ - -#define BLE_L2CAP_SVC_BASE 0xB8 /**< L2CAP BLE SVC base. */ -#define BLE_L2CAP_SVC_LAST 0xBF /**< L2CAP BLE SVC last. */ - -#define BLE_EVT_INVALID 0x00 /**< Invalid BLE Event. */ - -#define BLE_EVT_BASE 0x01 /**< Common BLE Event base. */ -#define BLE_EVT_LAST 0x0F /**< Common BLE Event last. */ - -#define BLE_GAP_EVT_BASE 0x10 /**< GAP BLE Event base. */ -#define BLE_GAP_EVT_LAST 0x2F /**< GAP BLE Event last. */ - -#define BLE_GATTC_EVT_BASE 0x30 /**< GATTC BLE Event base. */ -#define BLE_GATTC_EVT_LAST 0x4F /**< GATTC BLE Event last. */ - -#define BLE_GATTS_EVT_BASE 0x50 /**< GATTS BLE Event base. */ -#define BLE_GATTS_EVT_LAST 0x6F /**< GATTS BLE Event last. */ - -#define BLE_L2CAP_EVT_BASE 0x70 /**< L2CAP BLE Event base. */ -#define BLE_L2CAP_EVT_LAST 0x8F /**< L2CAP BLE Event last. */ - -#define BLE_OPT_INVALID 0x00 /**< Invalid BLE Option. */ - -#define BLE_OPT_BASE 0x01 /**< Common BLE Option base. */ -#define BLE_OPT_LAST 0x1F /**< Common BLE Option last. */ - -#define BLE_GAP_OPT_BASE 0x20 /**< GAP BLE Option base. */ -#define BLE_GAP_OPT_LAST 0x3F /**< GAP BLE Option last. */ - -#define BLE_GATT_OPT_BASE 0x40 /**< GATT BLE Option base. */ -#define BLE_GATT_OPT_LAST 0x5F /**< GATT BLE Option last. */ - -#define BLE_GATTC_OPT_BASE 0x60 /**< GATTC BLE Option base. */ -#define BLE_GATTC_OPT_LAST 0x7F /**< GATTC BLE Option last. */ - -#define BLE_GATTS_OPT_BASE 0x80 /**< GATTS BLE Option base. */ -#define BLE_GATTS_OPT_LAST 0x9F /**< GATTS BLE Option last. */ - -#define BLE_L2CAP_OPT_BASE 0xA0 /**< L2CAP BLE Option base. */ -#define BLE_L2CAP_OPT_LAST 0xBF /**< L2CAP BLE Option last. */ - -#define BLE_CFG_INVALID 0x00 /**< Invalid BLE configuration. */ - -#define BLE_CFG_BASE 0x01 /**< Common BLE configuration base. */ -#define BLE_CFG_LAST 0x1F /**< Common BLE configuration last. */ - -#define BLE_CONN_CFG_BASE 0x20 /**< BLE connection configuration base. */ -#define BLE_CONN_CFG_LAST 0x3F /**< BLE connection configuration last. */ - -#define BLE_GAP_CFG_BASE 0x40 /**< GAP BLE configuration base. */ -#define BLE_GAP_CFG_LAST 0x5F /**< GAP BLE configuration last. */ - -#define BLE_GATT_CFG_BASE 0x60 /**< GATT BLE configuration base. */ -#define BLE_GATT_CFG_LAST 0x7F /**< GATT BLE configuration last. */ - -#define BLE_GATTC_CFG_BASE 0x80 /**< GATTC BLE configuration base. */ -#define BLE_GATTC_CFG_LAST 0x9F /**< GATTC BLE configuration last. */ - -#define BLE_GATTS_CFG_BASE 0xA0 /**< GATTS BLE configuration base. */ -#define BLE_GATTS_CFG_LAST 0xBF /**< GATTS BLE configuration last. */ - -#define BLE_L2CAP_CFG_BASE 0xC0 /**< L2CAP BLE configuration base. */ -#define BLE_L2CAP_CFG_LAST 0xDF /**< L2CAP BLE configuration last. */ - -#ifdef __cplusplus -} -#endif -#endif /* BLE_RANGES_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_types.h b/variants/wio-sdk-wm1110/softdevice/ble_types.h deleted file mode 100644 index db3656cfdd..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_types.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @defgroup ble_types Common types and macro definitions - @{ - - @brief Common types and macro definitions for the BLE SoftDevice. - */ - -#ifndef BLE_TYPES_H__ -#define BLE_TYPES_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_TYPES_DEFINES Defines - * @{ */ - -/** @defgroup BLE_CONN_HANDLES BLE Connection Handles - * @{ */ -#define BLE_CONN_HANDLE_INVALID 0xFFFF /**< Invalid Connection Handle. */ -#define BLE_CONN_HANDLE_ALL 0xFFFE /**< Applies to all Connection Handles. */ -/** @} */ - -/** @defgroup BLE_UUID_VALUES Assigned Values for BLE UUIDs - * @{ */ -/* Generic UUIDs, applicable to all services */ -#define BLE_UUID_UNKNOWN 0x0000 /**< Reserved UUID. */ -#define BLE_UUID_SERVICE_PRIMARY 0x2800 /**< Primary Service. */ -#define BLE_UUID_SERVICE_SECONDARY 0x2801 /**< Secondary Service. */ -#define BLE_UUID_SERVICE_INCLUDE 0x2802 /**< Include. */ -#define BLE_UUID_CHARACTERISTIC 0x2803 /**< Characteristic. */ -#define BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP 0x2900 /**< Characteristic Extended Properties Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_USER_DESC 0x2901 /**< Characteristic User Description Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG 0x2902 /**< Client Characteristic Configuration Descriptor. */ -#define BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG 0x2903 /**< Server Characteristic Configuration Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT 0x2904 /**< Characteristic Presentation Format Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_AGGREGATE_FORMAT 0x2905 /**< Characteristic Aggregate Format Descriptor. */ -/* GATT specific UUIDs */ -#define BLE_UUID_GATT 0x1801 /**< Generic Attribute Profile. */ -#define BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED 0x2A05 /**< Service Changed Characteristic. */ -/* GAP specific UUIDs */ -#define BLE_UUID_GAP 0x1800 /**< Generic Access Profile. */ -#define BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME 0x2A00 /**< Device Name Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_APPEARANCE 0x2A01 /**< Appearance Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_RECONN_ADDR 0x2A03 /**< Reconnection Address Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_PPCP 0x2A04 /**< Peripheral Preferred Connection Parameters Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_CAR 0x2AA6 /**< Central Address Resolution Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_RPA_ONLY 0x2AC9 /**< Resolvable Private Address Only Characteristic. */ -/** @} */ - -/** @defgroup BLE_UUID_TYPES Types of UUID - * @{ */ -#define BLE_UUID_TYPE_UNKNOWN 0x00 /**< Invalid UUID type. */ -#define BLE_UUID_TYPE_BLE 0x01 /**< Bluetooth SIG UUID (16-bit). */ -#define BLE_UUID_TYPE_VENDOR_BEGIN 0x02 /**< Vendor UUID types start at this index (128-bit). */ -/** @} */ - -/** @defgroup BLE_APPEARANCES Bluetooth Appearance values - * @note Retrieved from - * http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml - * @{ */ -#define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */ -#define BLE_APPEARANCE_GENERIC_PHONE 64 /**< Generic Phone. */ -#define BLE_APPEARANCE_GENERIC_COMPUTER 128 /**< Generic Computer. */ -#define BLE_APPEARANCE_GENERIC_WATCH 192 /**< Generic Watch. */ -#define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /**< Watch: Sports Watch. */ -#define BLE_APPEARANCE_GENERIC_CLOCK 256 /**< Generic Clock. */ -#define BLE_APPEARANCE_GENERIC_DISPLAY 320 /**< Generic Display. */ -#define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /**< Generic Remote Control. */ -#define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /**< Generic Eye-glasses. */ -#define BLE_APPEARANCE_GENERIC_TAG 512 /**< Generic Tag. */ -#define BLE_APPEARANCE_GENERIC_KEYRING 576 /**< Generic Keyring. */ -#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /**< Generic Media Player. */ -#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /**< Generic Barcode Scanner. */ -#define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /**< Generic Thermometer. */ -#define BLE_APPEARANCE_THERMOMETER_EAR 769 /**< Thermometer: Ear. */ -#define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /**< Generic Heart rate Sensor. */ -#define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /**< Heart Rate Sensor: Heart Rate Belt. */ -#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /**< Generic Blood Pressure. */ -#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /**< Blood Pressure: Arm. */ -#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /**< Blood Pressure: Wrist. */ -#define BLE_APPEARANCE_GENERIC_HID 960 /**< Human Interface Device (HID). */ -#define BLE_APPEARANCE_HID_KEYBOARD 961 /**< Keyboard (HID Subtype). */ -#define BLE_APPEARANCE_HID_MOUSE 962 /**< Mouse (HID Subtype). */ -#define BLE_APPEARANCE_HID_JOYSTICK 963 /**< Joystick (HID Subtype). */ -#define BLE_APPEARANCE_HID_GAMEPAD 964 /**< Gamepad (HID Subtype). */ -#define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /**< Digitizer Tablet (HID Subtype). */ -#define BLE_APPEARANCE_HID_CARD_READER 966 /**< Card Reader (HID Subtype). */ -#define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /**< Digital Pen (HID Subtype). */ -#define BLE_APPEARANCE_HID_BARCODE 968 /**< Barcode Scanner (HID Subtype). */ -#define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /**< Generic Glucose Meter. */ -#define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /**< Generic Running Walking Sensor. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /**< Running Walking Sensor: In-Shoe. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /**< Running Walking Sensor: On-Shoe. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /**< Running Walking Sensor: On-Hip. */ -#define BLE_APPEARANCE_GENERIC_CYCLING 1152 /**< Generic Cycling. */ -#define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /**< Cycling: Cycling Computer. */ -#define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /**< Cycling: Speed Sensor. */ -#define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /**< Cycling: Cadence Sensor. */ -#define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /**< Cycling: Power Sensor. */ -#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /**< Cycling: Speed and Cadence Sensor. */ -#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /**< Generic Pulse Oximeter. */ -#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /**< Fingertip (Pulse Oximeter subtype). */ -#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /**< Wrist Worn(Pulse Oximeter subtype). */ -#define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /**< Generic Weight Scale. */ -#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /**< Generic Outdoor Sports Activity. */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /**< Location Display Device (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP \ - 5186 /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /**< Location Pod (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD \ - 5188 /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */ -/** @} */ - -/** @brief Set .type and .uuid fields of ble_uuid_struct to specified UUID value. */ -#define BLE_UUID_BLE_ASSIGN(instance, value) \ - do { \ - instance.type = BLE_UUID_TYPE_BLE; \ - instance.uuid = value; \ - } while (0) - -/** @brief Copy type and uuid members from src to dst ble_uuid_t pointer. Both pointers must be valid/non-null. */ -#define BLE_UUID_COPY_PTR(dst, src) \ - do { \ - (dst)->type = (src)->type; \ - (dst)->uuid = (src)->uuid; \ - } while (0) - -/** @brief Copy type and uuid members from src to dst ble_uuid_t struct. */ -#define BLE_UUID_COPY_INST(dst, src) \ - do { \ - (dst).type = (src).type; \ - (dst).uuid = (src).uuid; \ - } while (0) - -/** @brief Compare for equality both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ -#define BLE_UUID_EQ(p_uuid1, p_uuid2) (((p_uuid1)->type == (p_uuid2)->type) && ((p_uuid1)->uuid == (p_uuid2)->uuid)) - -/** @brief Compare for difference both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ -#define BLE_UUID_NEQ(p_uuid1, p_uuid2) (((p_uuid1)->type != (p_uuid2)->type) || ((p_uuid1)->uuid != (p_uuid2)->uuid)) - -/** @} */ - -/** @addtogroup BLE_TYPES_STRUCTURES Structures - * @{ */ - -/** @brief 128 bit UUID values. */ -typedef struct { - uint8_t uuid128[16]; /**< Little-Endian UUID bytes. */ -} ble_uuid128_t; - -/** @brief Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */ -typedef struct { - uint16_t uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */ - uint8_t - type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is @ref BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */ -} ble_uuid_t; - -/**@brief Data structure. */ -typedef struct { - uint8_t *p_data; /**< Pointer to the data buffer provided to/from the application. */ - uint16_t len; /**< Length of the data buffer, in bytes. */ -} ble_data_t; - -/** @} */ -#ifdef __cplusplus -} -#endif - -#endif /* BLE_TYPES_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h b/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h deleted file mode 100644 index 4e0bd752ab..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2014 - 2017, Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_mbr_api Master Boot Record API - @{ - - @brief APIs for updating SoftDevice and BootLoader - -*/ - -#ifndef NRF_MBR_H__ -#define NRF_MBR_H__ - -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup NRF_MBR_DEFINES Defines - * @{ */ - -/**@brief MBR SVC Base number. */ -#define MBR_SVC_BASE (0x18) - -/**@brief Page size in words. */ -#define MBR_PAGE_SIZE_IN_WORDS (1024) - -/** @brief The size that must be reserved for the MBR when a SoftDevice is written to flash. -This is the offset where the first byte of the SoftDevice hex file is written. */ -#define MBR_SIZE (0x1000) - -/** @brief Location (in the flash memory) of the bootloader address. */ -#define MBR_BOOTLOADER_ADDR (0xFF8) - -/** @brief Location (in UICR) of the bootloader address. */ -#define MBR_UICR_BOOTLOADER_ADDR (&(NRF_UICR->NRFFW[0])) - -/** @brief Location (in the flash memory) of the address of the MBR parameter page. */ -#define MBR_PARAM_PAGE_ADDR (0xFFC) - -/** @brief Location (in UICR) of the address of the MBR parameter page. */ -#define MBR_UICR_PARAM_PAGE_ADDR (&(NRF_UICR->NRFFW[1])) - -/** @} */ - -/** @addtogroup NRF_MBR_ENUMS Enumerations - * @{ */ - -/**@brief nRF Master Boot Record API SVC numbers. */ -enum NRF_MBR_SVCS { - SD_MBR_COMMAND = MBR_SVC_BASE, /**< ::sd_mbr_command */ -}; - -/**@brief Possible values for ::sd_mbr_command_t.command */ -enum NRF_MBR_COMMANDS { - SD_MBR_COMMAND_COPY_BL, /**< Copy a new BootLoader. @see ::sd_mbr_command_copy_bl_t*/ - SD_MBR_COMMAND_COPY_SD, /**< Copy a new SoftDevice. @see ::sd_mbr_command_copy_sd_t*/ - SD_MBR_COMMAND_INIT_SD, /**< Initialize forwarding interrupts to SD, and run reset function in SD. Does not require any - parameters in ::sd_mbr_command_t params.*/ - SD_MBR_COMMAND_COMPARE, /**< This command works like memcmp. @see ::sd_mbr_command_compare_t*/ - SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET, /**< Change the address the MBR starts after a reset. @see - ::sd_mbr_command_vector_table_base_set_t*/ - SD_MBR_COMMAND_RESERVED, - SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET, /**< Start forwarding all interrupts to this address. @see - ::sd_mbr_command_irq_forward_address_set_t*/ -}; - -/** @} */ - -/** @addtogroup NRF_MBR_TYPES Types - * @{ */ - -/**@brief This command copies part of a new SoftDevice - * - * The destination area is erased before copying. - * If dst is in the middle of a flash page, that whole flash page will be erased. - * If (dst+len) is in the middle of a flash page, that whole flash page will be erased. - * - * The user of this function is responsible for setting the BPROT registers. - * - * @retval ::NRF_SUCCESS indicates that the contents of the memory blocks where copied correctly. - * @retval ::NRF_ERROR_INTERNAL indicates that the contents of the memory blocks where not verified correctly after copying. - */ -typedef struct { - uint32_t *src; /**< Pointer to the source of data to be copied.*/ - uint32_t *dst; /**< Pointer to the destination where the content is to be copied.*/ - uint32_t len; /**< Number of 32 bit words to copy. Must be a multiple of @ref MBR_PAGE_SIZE_IN_WORDS words.*/ -} sd_mbr_command_copy_sd_t; - -/**@brief This command works like memcmp, but takes the length in words. - * - * @retval ::NRF_SUCCESS indicates that the contents of both memory blocks are equal. - * @retval ::NRF_ERROR_NULL indicates that the contents of the memory blocks are not equal. - */ -typedef struct { - uint32_t *ptr1; /**< Pointer to block of memory. */ - uint32_t *ptr2; /**< Pointer to block of memory. */ - uint32_t len; /**< Number of 32 bit words to compare.*/ -} sd_mbr_command_compare_t; - -/**@brief This command copies a new BootLoader. - * - * The MBR assumes that either @ref MBR_BOOTLOADER_ADDR or @ref MBR_UICR_BOOTLOADER_ADDR is set to - * the address where the bootloader will be copied. If both addresses are set, the MBR will prioritize - * @ref MBR_BOOTLOADER_ADDR. - * - * The bootloader destination is erased by this function. - * If (destination+bl_len) is in the middle of a flash page, that whole flash page will be erased. - * - * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, - * see @ref sd_mbr_command. - * - * This command will use the flash protect peripheral (BPROT or ACL) to protect the flash that is - * not intended to be written. - * - * On success, this function will not return. It will start the new bootloader from reset-vector as normal. - * - * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. - * @retval ::NRF_ERROR_FORBIDDEN if the bootloader address is not set. - * @retval ::NRF_ERROR_INVALID_LENGTH if parameters attempts to read or write outside flash area. - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. - */ -typedef struct { - uint32_t *bl_src; /**< Pointer to the source of the bootloader to be be copied.*/ - uint32_t bl_len; /**< Number of 32 bit words to copy for BootLoader. */ -} sd_mbr_command_copy_bl_t; - -/**@brief Change the address the MBR starts after a reset - * - * Once this function has been called, this address is where the MBR will start to forward - * interrupts to after a reset. - * - * To restore default forwarding, this function should be called with @ref address set to 0. If a - * bootloader is present, interrupts will be forwarded to the bootloader. If not, interrupts will - * be forwarded to the SoftDevice. - * - * The location of a bootloader can be specified in @ref MBR_BOOTLOADER_ADDR or - * @ref MBR_UICR_BOOTLOADER_ADDR. If both addresses are set, the MBR will prioritize - * @ref MBR_BOOTLOADER_ADDR. - * - * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, - * see @ref sd_mbr_command. - * - * On success, this function will not return. It will reset the device. - * - * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. - * @retval ::NRF_ERROR_INVALID_ADDR if parameter address is outside of the flash size. - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. - */ -typedef struct { - uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ -} sd_mbr_command_vector_table_base_set_t; - -/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the MBR - * - * Unlike sd_mbr_command_vector_table_base_set_t, this function does not reset, and it does not - * change where the MBR starts after reset. - * - * @retval ::NRF_SUCCESS - */ -typedef struct { - uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ -} sd_mbr_command_irq_forward_address_set_t; - -/**@brief Input structure containing data used when calling ::sd_mbr_command - * - * Depending on what command value that is set, the corresponding params value type must also be - * set. See @ref NRF_MBR_COMMANDS for command types and corresponding params value type. If command - * @ref SD_MBR_COMMAND_INIT_SD is set, it is not necessary to set any values under params. - */ -typedef struct { - uint32_t command; /**< Type of command to be issued. See @ref NRF_MBR_COMMANDS. */ - union { - sd_mbr_command_copy_sd_t copy_sd; /**< Parameters for copy SoftDevice.*/ - sd_mbr_command_compare_t compare; /**< Parameters for verify.*/ - sd_mbr_command_copy_bl_t copy_bl; /**< Parameters for copy BootLoader. Requires parameter page. */ - sd_mbr_command_vector_table_base_set_t base_set; /**< Parameters for vector table base set. Requires parameter page.*/ - sd_mbr_command_irq_forward_address_set_t irq_forward_address_set; /**< Parameters for irq forward address set*/ - } params; /**< Command parameters. */ -} sd_mbr_command_t; - -/** @} */ - -/** @addtogroup NRF_MBR_FUNCTIONS Functions - * @{ */ - -/**@brief Issue Master Boot Record commands - * - * Commands used when updating a SoftDevice and bootloader. - * - * The @ref SD_MBR_COMMAND_COPY_BL and @ref SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET requires - * parameters to be retained by the MBR when resetting the IC. This is done in a separate flash - * page. The location of the flash page should be provided by the application in either - * @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR. If both addresses are set, the MBR - * will prioritize @ref MBR_PARAM_PAGE_ADDR. This page will be cleared by the MBR and is used to - * store the command before reset. When an address is specified, the page it refers to must not be - * used by the application. If no address is provided by the application, i.e. both - * @ref MBR_PARAM_PAGE_ADDR and @ref MBR_UICR_PARAM_PAGE_ADDR is 0xFFFFFFFF, MBR commands which use - * flash will be unavailable and return @ref NRF_ERROR_NO_MEM. - * - * @param[in] param Pointer to a struct describing the command. - * - * @note For a complete set of return values, see ::sd_mbr_command_copy_sd_t, - * ::sd_mbr_command_copy_bl_t, ::sd_mbr_command_compare_t, - * ::sd_mbr_command_vector_table_base_set_t, ::sd_mbr_command_irq_forward_address_set_t - * - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page provided - * @retval ::NRF_ERROR_INVALID_PARAM if an invalid command is given. - */ -SVCALL(SD_MBR_COMMAND, uint32_t, sd_mbr_command(sd_mbr_command_t *param)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_MBR_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error.h b/variants/wio-sdk-wm1110/softdevice/nrf_error.h deleted file mode 100644 index fb2831e191..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_error.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_error SoftDevice Global Error Codes - @{ - - @brief Global Error definitions -*/ - -/* Header guard */ -#ifndef NRF_ERROR_H__ -#define NRF_ERROR_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** @defgroup NRF_ERRORS_BASE Error Codes Base number definitions - * @{ */ -#define NRF_ERROR_BASE_NUM (0x0) ///< Global error base -#define NRF_ERROR_SDM_BASE_NUM (0x1000) ///< SDM error base -#define NRF_ERROR_SOC_BASE_NUM (0x2000) ///< SoC error base -#define NRF_ERROR_STK_BASE_NUM (0x3000) ///< STK error base -/** @} */ - -#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command -#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing -#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled -#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error -#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation -#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found -#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported -#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter -#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state -#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length -#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags -#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data -#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Invalid Data size -#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out -#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer -#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation -#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address -#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy -#define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded. -#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h b/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h deleted file mode 100644 index 2fd6210576..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup nrf_sdm_api - @{ - @defgroup nrf_sdm_error SoftDevice Manager Error Codes - @{ - - @brief Error definitions for the SDM API -*/ - -/* Header guard */ -#ifndef NRF_ERROR_SDM_H__ -#define NRF_ERROR_SDM_H__ - -#include "nrf_error.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN (NRF_ERROR_SDM_BASE_NUM + 0) ///< Unknown LFCLK source. -#define NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION \ - (NRF_ERROR_SDM_BASE_NUM + 1) ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having - ///< enabled SoftDevice interrupts). -#define NRF_ERROR_SDM_INCORRECT_CLENR0 \ - (NRF_ERROR_SDM_BASE_NUM + 2) ///< Incorrect CLENR0 (can be caused by erroneous SoftDevice flashing). - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_SDM_H__ - -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h b/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h deleted file mode 100644 index cbd0ba8ac4..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup nrf_soc_api - @{ - @defgroup nrf_soc_error SoC Library Error Codes - @{ - - @brief Error definitions for the SoC library - -*/ - -/* Header guard */ -#ifndef NRF_ERROR_SOC_H__ -#define NRF_ERROR_SOC_H__ - -#include "nrf_error.h" -#ifdef __cplusplus -extern "C" { -#endif - -/* Mutex Errors */ -#define NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN (NRF_ERROR_SOC_BASE_NUM + 0) ///< Mutex already taken - -/* NVIC errors */ -#define NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE (NRF_ERROR_SOC_BASE_NUM + 1) ///< NVIC interrupt not available -#define NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED (NRF_ERROR_SOC_BASE_NUM + 2) ///< NVIC interrupt priority not allowed -#define NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 3) ///< NVIC should not return - -/* Power errors */ -#define NRF_ERROR_SOC_POWER_MODE_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 4) ///< Power mode unknown -#define NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 5) ///< Power POF threshold unknown -#define NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 6) ///< Power off should not return - -/* Rand errors */ -#define NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES (NRF_ERROR_SOC_BASE_NUM + 7) ///< RAND not enough values - -/* PPI errors */ -#define NRF_ERROR_SOC_PPI_INVALID_CHANNEL (NRF_ERROR_SOC_BASE_NUM + 8) ///< Invalid PPI Channel -#define NRF_ERROR_SOC_PPI_INVALID_GROUP (NRF_ERROR_SOC_BASE_NUM + 9) ///< Invalid PPI Group - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_SOC_H__ -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h b/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h deleted file mode 100644 index d4ab204d96..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @defgroup nrf_nvic_api SoftDevice NVIC API - * @{ - * - * @note In order to use this module, the following code has to be added to a .c file: - * \code - * nrf_nvic_state_t nrf_nvic_state = {0}; - * \endcode - * - * @note Definitions and declarations starting with __ (double underscore) in this header file are - * not intended for direct use by the application. - * - * @brief APIs for the accessing NVIC when using a SoftDevice. - * - */ - -#ifndef NRF_NVIC_H__ -#define NRF_NVIC_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup NRF_NVIC_DEFINES Defines - * @{ */ - -/**@defgroup NRF_NVIC_ISER_DEFINES SoftDevice NVIC internal definitions - * @{ */ - -#define __NRF_NVIC_NVMC_IRQn \ - (30) /**< The peripheral ID of the NVMC. IRQ numbers are used to identify peripherals, but the NVMC doesn't have an IRQ \ - number in the MDK. */ - -#define __NRF_NVIC_ISER_COUNT (2) /**< The number of ISER/ICER registers in the NVIC that are used. */ - -/**@brief Interrupt priority levels used by the SoftDevice. */ -#define __NRF_NVIC_SD_IRQ_PRIOS \ - ((uint8_t)((1U << 0) /**< Priority level high .*/ \ - | (1U << 1) /**< Priority level medium. */ \ - | (1U << 4) /**< Priority level low. */ \ - )) - -/**@brief Interrupt priority levels available to the application. */ -#define __NRF_NVIC_APP_IRQ_PRIOS ((uint8_t)~__NRF_NVIC_SD_IRQ_PRIOS) - -/**@brief Interrupts used by the SoftDevice, with IRQn in the range 0-31. */ -#define __NRF_NVIC_SD_IRQS_0 \ - ((uint32_t)((1U << POWER_CLOCK_IRQn) | (1U << RADIO_IRQn) | (1U << RTC0_IRQn) | (1U << TIMER0_IRQn) | (1U << RNG_IRQn) | \ - (1U << ECB_IRQn) | (1U << CCM_AAR_IRQn) | (1U << TEMP_IRQn) | (1U << __NRF_NVIC_NVMC_IRQn) | \ - (1U << (uint32_t)SWI5_IRQn))) - -/**@brief Interrupts used by the SoftDevice, with IRQn in the range 32-63. */ -#define __NRF_NVIC_SD_IRQS_1 ((uint32_t)0) - -/**@brief Interrupts available for to application, with IRQn in the range 0-31. */ -#define __NRF_NVIC_APP_IRQS_0 (~__NRF_NVIC_SD_IRQS_0) - -/**@brief Interrupts available for to application, with IRQn in the range 32-63. */ -#define __NRF_NVIC_APP_IRQS_1 (~__NRF_NVIC_SD_IRQS_1) - -/**@} */ - -/**@} */ - -/**@addtogroup NRF_NVIC_VARIABLES Variables - * @{ */ - -/**@brief Type representing the state struct for the SoftDevice NVIC module. */ -typedef struct { - uint32_t volatile __irq_masks[__NRF_NVIC_ISER_COUNT]; /**< IRQs enabled by the application in the NVIC. */ - uint32_t volatile __cr_flag; /**< Non-zero if already in a critical region */ -} nrf_nvic_state_t; - -/**@brief Variable keeping the state for the SoftDevice NVIC module. This must be declared in an - * application source file. */ -extern nrf_nvic_state_t nrf_nvic_state; - -/**@} */ - -/**@addtogroup NRF_NVIC_INTERNAL_FUNCTIONS SoftDevice NVIC internal functions - * @{ */ - -/**@brief Disables IRQ interrupts globally, including the SoftDevice's interrupts. - * - * @retval The value of PRIMASK prior to disabling the interrupts. - */ -__STATIC_INLINE int __sd_nvic_irq_disable(void); - -/**@brief Enables IRQ interrupts globally, including the SoftDevice's interrupts. - */ -__STATIC_INLINE void __sd_nvic_irq_enable(void); - -/**@brief Checks if IRQn is available to application - * @param[in] IRQn IRQ to check - * - * @retval 1 (true) if the IRQ to check is available to the application - */ -__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn); - -/**@brief Checks if priority is available to application - * @param[in] priority priority to check - * - * @retval 1 (true) if the priority to check is available to the application - */ -__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority); - -/**@} */ - -/**@addtogroup NRF_NVIC_FUNCTIONS SoftDevice NVIC public functions - * @{ */ - -/**@brief Enable External Interrupt. - * @note Corresponds to NVIC_EnableIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_EnableIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt was enabled. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt has a priority not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn); - -/**@brief Disable External Interrupt. - * @note Corresponds to NVIC_DisableIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_DisableIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt was disabled. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn); - -/**@brief Get Pending Interrupt. - * @note Corresponds to NVIC_GetPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_GetPendingIRQ documentation in CMSIS. - * @param[out] p_pending_irq Return value from NVIC_GetPendingIRQ. - * - * @retval ::NRF_SUCCESS The interrupt is available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq); - -/**@brief Set Pending Interrupt. - * @note Corresponds to NVIC_SetPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_SetPendingIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt is set pending. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn); - -/**@brief Clear Pending Interrupt. - * @note Corresponds to NVIC_ClearPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_ClearPendingIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt pending flag is cleared. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn); - -/**@brief Set Interrupt Priority. - * @note Corresponds to NVIC_SetPriority in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * @pre Priority is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_SetPriority documentation in CMSIS. - * @param[in] priority A valid IRQ priority for use by the application. - * - * @retval ::NRF_SUCCESS The interrupt and priority level is available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt priority is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority); - -/**@brief Get Interrupt Priority. - * @note Corresponds to NVIC_GetPriority in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_GetPriority documentation in CMSIS. - * @param[out] p_priority Return value from NVIC_GetPriority. - * - * @retval ::NRF_SUCCESS The interrupt priority is returned in p_priority. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE - IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority); - -/**@brief System Reset. - * @note Corresponds to NVIC_SystemReset in CMSIS. - * - * @retval ::NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN - */ -__STATIC_INLINE uint32_t sd_nvic_SystemReset(void); - -/**@brief Enter critical region. - * - * @post Application interrupts will be disabled. - * @note sd_nvic_critical_region_enter() and ::sd_nvic_critical_region_exit() must be called in matching pairs inside each - * execution context - * @sa sd_nvic_critical_region_exit - * - * @param[out] p_is_nested_critical_region If 1, the application is now in a nested critical region. - * - * @retval ::NRF_SUCCESS - */ -__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region); - -/**@brief Exit critical region. - * - * @pre Application has entered a critical region using ::sd_nvic_critical_region_enter. - * @post If not in a nested critical region, the application interrupts will restored to the state before - * ::sd_nvic_critical_region_enter was called. - * - * @param[in] is_nested_critical_region If this is set to 1, the critical region won't be exited. @sa - * sd_nvic_critical_region_enter. - * - * @retval ::NRF_SUCCESS - */ -__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region); - -/**@} */ - -#ifndef SUPPRESS_INLINE_IMPLEMENTATION - -__STATIC_INLINE int __sd_nvic_irq_disable(void) -{ - int pm = __get_PRIMASK(); - __disable_irq(); - return pm; -} - -__STATIC_INLINE void __sd_nvic_irq_enable(void) -{ - __enable_irq(); -} - -__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn) -{ - if (IRQn < 32) { - return ((1UL << IRQn) & __NRF_NVIC_APP_IRQS_0) != 0; - } else if (IRQn < 64) { - return ((1UL << (IRQn - 32)) & __NRF_NVIC_APP_IRQS_1) != 0; - } else { - return 1; - } -} - -__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority) -{ - if ((priority >= (1 << __NVIC_PRIO_BITS)) || (((1 << priority) & __NRF_NVIC_APP_IRQ_PRIOS) == 0)) { - return 0; - } - return 1; -} - -__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - if (!__sd_nvic_is_app_accessible_priority(NVIC_GetPriority(IRQn))) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; - } - - if (nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] |= - (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F)); - } else { - NVIC_EnableIRQ(IRQn); - } - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - - if (nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] &= ~(1UL << ((uint32_t)(IRQn)&0x1F)); - } else { - NVIC_DisableIRQ(IRQn); - } - - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - *p_pending_irq = NVIC_GetPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - NVIC_SetPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - NVIC_ClearPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - - if (!__sd_nvic_is_app_accessible_priority(priority)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; - } - - NVIC_SetPriority(IRQn, (uint32_t)priority); - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - *p_priority = (NVIC_GetPriority(IRQn) & 0xFF); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SystemReset(void) -{ - NVIC_SystemReset(); - return NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN; -} - -__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region) -{ - int was_masked = __sd_nvic_irq_disable(); - if (!nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__cr_flag = 1; - nrf_nvic_state.__irq_masks[0] = (NVIC->ICER[0] & __NRF_NVIC_APP_IRQS_0); - NVIC->ICER[0] = __NRF_NVIC_APP_IRQS_0; - nrf_nvic_state.__irq_masks[1] = (NVIC->ICER[1] & __NRF_NVIC_APP_IRQS_1); - NVIC->ICER[1] = __NRF_NVIC_APP_IRQS_1; - *p_is_nested_critical_region = 0; - } else { - *p_is_nested_critical_region = 1; - } - if (!was_masked) { - __sd_nvic_irq_enable(); - } - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region) -{ - if (nrf_nvic_state.__cr_flag && (is_nested_critical_region == 0)) { - int was_masked = __sd_nvic_irq_disable(); - NVIC->ISER[0] = nrf_nvic_state.__irq_masks[0]; - NVIC->ISER[1] = nrf_nvic_state.__irq_masks[1]; - nrf_nvic_state.__cr_flag = 0; - if (!was_masked) { - __sd_nvic_irq_enable(); - } - } - - return NRF_SUCCESS; -} - -#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ - -#ifdef __cplusplus -} -#endif - -#endif // NRF_NVIC_H__ - -/**@} */ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h b/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h deleted file mode 100644 index 2786a86a45..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_sdm.h +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_sdm_api SoftDevice Manager API - @{ - - @brief APIs for SoftDevice management. - -*/ - -#ifndef NRF_SDM_H__ -#define NRF_SDM_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_sdm.h" -#include "nrf_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup NRF_SDM_DEFINES Defines - * @{ */ -#ifdef NRFSOC_DOXYGEN -/// Declared in nrf_mbr.h -#define MBR_SIZE 0 -#warning test -#endif - -/** @brief The major version for the SoftDevice binary distributed with this header file. */ -#define SD_MAJOR_VERSION (7) - -/** @brief The minor version for the SoftDevice binary distributed with this header file. */ -#define SD_MINOR_VERSION (3) - -/** @brief The bugfix version for the SoftDevice binary distributed with this header file. */ -#define SD_BUGFIX_VERSION (0) - -/** @brief The SoftDevice variant of this firmware. */ -#define SD_VARIANT_ID 140 - -/** @brief The full version number for the SoftDevice binary this header file was distributed - * with, as a decimal number in the form Mmmmbbb, where: - * - M is major version (one or more digits) - * - mmm is minor version (three digits) - * - bbb is bugfix version (three digits). */ -#define SD_VERSION (SD_MAJOR_VERSION * 1000000 + SD_MINOR_VERSION * 1000 + SD_BUGFIX_VERSION) - -/** @brief SoftDevice Manager SVC Base number. */ -#define SDM_SVC_BASE 0x10 - -/** @brief SoftDevice unique string size in bytes. */ -#define SD_UNIQUE_STR_SIZE 20 - -/** @brief Invalid info field. Returned when an info field does not exist. */ -#define SDM_INFO_FIELD_INVALID (0) - -/** @brief Defines the SoftDevice Information Structure location (address) as an offset from -the start of the SoftDevice (without MBR)*/ -#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000) - -/** @brief Defines the absolute SoftDevice Information Structure location (address) when the - * SoftDevice is installed just above the MBR (the usual case). */ -#define SOFTDEVICE_INFO_STRUCT_ADDRESS (SOFTDEVICE_INFO_STRUCT_OFFSET + MBR_SIZE) - -/** @brief Defines the offset for the SoftDevice Information Structure size value relative to the - * SoftDevice base address. The size value is of type uint8_t. */ -#define SD_INFO_STRUCT_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET) - -/** @brief Defines the offset for the SoftDevice size value relative to the SoftDevice base address. - * The size value is of type uint32_t. */ -#define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08) - -/** @brief Defines the offset for FWID value relative to the SoftDevice base address. The FWID value - * is of type uint16_t. */ -#define SD_FWID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x0C) - -/** @brief Defines the offset for the SoftDevice ID relative to the SoftDevice base address. The ID - * is of type uint32_t. */ -#define SD_ID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x10) - -/** @brief Defines the offset for the SoftDevice version relative to the SoftDevice base address in - * the same format as @ref SD_VERSION, stored as an uint32_t. */ -#define SD_VERSION_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x14) - -/** @brief Defines the offset for the SoftDevice unique string relative to the SoftDevice base address. - * The SD_UNIQUE_STR is stored as an array of uint8_t. The size of array is @ref SD_UNIQUE_STR_SIZE. - */ -#define SD_UNIQUE_STR_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x18) - -/** @brief Defines a macro for retrieving the actual SoftDevice Information Structure size value - * from a given base address. Use @ref MBR_SIZE as the argument when the SoftDevice is - * installed just above the MBR (the usual case). */ -#define SD_INFO_STRUCT_SIZE_GET(baseaddr) (*((uint8_t *)((baseaddr) + SD_INFO_STRUCT_SIZE_OFFSET))) - -/** @brief Defines a macro for retrieving the actual SoftDevice size value from a given base - * address. Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above - * the MBR (the usual case). */ -#define SD_SIZE_GET(baseaddr) (*((uint32_t *)((baseaddr) + SD_SIZE_OFFSET))) - -/** @brief Defines the amount of flash that is used by the SoftDevice. - * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed - * just above the MBR (the usual case). - */ -#define SD_FLASH_SIZE 0x26000 - -/** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use - * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual - * case). */ -#define SD_FWID_GET(baseaddr) (*((uint16_t *)((baseaddr) + SD_FWID_OFFSET))) - -/** @brief Defines a macro for retrieving the actual SoftDevice ID from a given base address. Use - * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the - * usual case). */ -#define SD_ID_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_ID_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (*((uint32_t *)((baseaddr) + SD_ID_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/** @brief Defines a macro for retrieving the actual SoftDevice version from a given base address. - * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR - * (the usual case). */ -#define SD_VERSION_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_VERSION_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (*((uint32_t *)((baseaddr) + SD_VERSION_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/** @brief Defines a macro for retrieving the address of SoftDevice unique str based on a given base address. - * Use @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR - * (the usual case). */ -#define SD_UNIQUE_STR_ADDR_GET(baseaddr) \ - ((SD_INFO_STRUCT_SIZE_GET(baseaddr) > (SD_UNIQUE_STR_OFFSET - SOFTDEVICE_INFO_STRUCT_OFFSET)) \ - ? (((uint8_t *)((baseaddr) + SD_UNIQUE_STR_OFFSET))) \ - : SDM_INFO_FIELD_INVALID) - -/**@defgroup NRF_FAULT_ID_RANGES Fault ID ranges - * @{ */ -#define NRF_FAULT_ID_SD_RANGE_START 0x00000000 /**< SoftDevice ID range start. */ -#define NRF_FAULT_ID_APP_RANGE_START 0x00001000 /**< Application ID range start. */ -/**@} */ - -/**@defgroup NRF_FAULT_IDS Fault ID types - * @{ */ -#define NRF_FAULT_ID_SD_ASSERT \ - (NRF_FAULT_ID_SD_RANGE_START + 1) /**< SoftDevice assertion. The info parameter is reserved for future used. */ -#define NRF_FAULT_ID_APP_MEMACC \ - (NRF_FAULT_ID_APP_RANGE_START + 1) /**< Application invalid memory access. The info parameter will contain 0x00000000, \ - in case of SoftDevice RAM access violation. In case of SoftDevice peripheral \ - register violation the info parameter will contain the sub-region number of \ - PREGION[0], on whose address range the disallowed write access caused the \ - memory access fault. */ -/**@} */ - -/** @} */ - -/** @addtogroup NRF_SDM_ENUMS Enumerations - * @{ */ - -/**@brief nRF SoftDevice Manager API SVC numbers. */ -enum NRF_SD_SVCS { - SD_SOFTDEVICE_ENABLE = SDM_SVC_BASE, /**< ::sd_softdevice_enable */ - SD_SOFTDEVICE_DISABLE, /**< ::sd_softdevice_disable */ - SD_SOFTDEVICE_IS_ENABLED, /**< ::sd_softdevice_is_enabled */ - SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, /**< ::sd_softdevice_vector_table_base_set */ - SVC_SDM_LAST /**< Placeholder for last SDM SVC */ -}; - -/** @} */ - -/** @addtogroup NRF_SDM_DEFINES Defines - * @{ */ - -/**@defgroup NRF_CLOCK_LF_ACCURACY Clock accuracy - * @{ */ - -#define NRF_CLOCK_LF_ACCURACY_250_PPM (0) /**< Default: 250 ppm */ -#define NRF_CLOCK_LF_ACCURACY_500_PPM (1) /**< 500 ppm */ -#define NRF_CLOCK_LF_ACCURACY_150_PPM (2) /**< 150 ppm */ -#define NRF_CLOCK_LF_ACCURACY_100_PPM (3) /**< 100 ppm */ -#define NRF_CLOCK_LF_ACCURACY_75_PPM (4) /**< 75 ppm */ -#define NRF_CLOCK_LF_ACCURACY_50_PPM (5) /**< 50 ppm */ -#define NRF_CLOCK_LF_ACCURACY_30_PPM (6) /**< 30 ppm */ -#define NRF_CLOCK_LF_ACCURACY_20_PPM (7) /**< 20 ppm */ -#define NRF_CLOCK_LF_ACCURACY_10_PPM (8) /**< 10 ppm */ -#define NRF_CLOCK_LF_ACCURACY_5_PPM (9) /**< 5 ppm */ -#define NRF_CLOCK_LF_ACCURACY_2_PPM (10) /**< 2 ppm */ -#define NRF_CLOCK_LF_ACCURACY_1_PPM (11) /**< 1 ppm */ - -/** @} */ - -/**@defgroup NRF_CLOCK_LF_SRC Possible LFCLK oscillator sources - * @{ */ - -#define NRF_CLOCK_LF_SRC_RC (0) /**< LFCLK RC oscillator. */ -#define NRF_CLOCK_LF_SRC_XTAL (1) /**< LFCLK crystal oscillator. */ -#define NRF_CLOCK_LF_SRC_SYNTH (2) /**< LFCLK Synthesized from HFCLK. */ - -/** @} */ - -/** @} */ - -/** @addtogroup NRF_SDM_TYPES Types - * @{ */ - -/**@brief Type representing LFCLK oscillator source. */ -typedef struct { - uint8_t source; /**< LF oscillator clock source, see @ref NRF_CLOCK_LF_SRC. */ - uint8_t rc_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: Calibration timer interval in 1/4 second - units (nRF52: 1-32). - @note To avoid excessive clock drift, 0.5 degrees Celsius is the - maximum temperature change allowed in one calibration timer - interval. The interval should be selected to ensure this. - - @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. */ - uint8_t rc_temp_ctiv; /**< Only for ::NRF_CLOCK_LF_SRC_RC: How often (in number of calibration - intervals) the RC oscillator shall be calibrated if the temperature - hasn't changed. - 0: Always calibrate even if the temperature hasn't changed. - 1: Only calibrate if the temperature has changed (legacy - nRF51 only). - 2-33: Check the temperature and only calibrate if it has changed, - however calibration will take place every rc_temp_ctiv - intervals in any case. - - @note Must be 0 if source is not ::NRF_CLOCK_LF_SRC_RC. - - @note For nRF52, the application must ensure calibration at least once - every 8 seconds to ensure +/-500 ppm clock stability. The - recommended configuration for ::NRF_CLOCK_LF_SRC_RC on nRF52 is - rc_ctiv=16 and rc_temp_ctiv=2. This will ensure calibration at - least once every 8 seconds and for temperature changes of 0.5 - degrees Celsius every 4 seconds. See the Product Specification - for the nRF52 device being used for more information.*/ - uint8_t accuracy; /**< External clock accuracy used in the LL to compute timing - windows, see @ref NRF_CLOCK_LF_ACCURACY.*/ -} nrf_clock_lf_cfg_t; - -/**@brief Fault Handler type. - * - * When certain unrecoverable errors occur within the application or SoftDevice the fault handler will be called back. - * The protocol stack will be in an undefined state when this happens and the only way to recover will be to - * perform a reset, using e.g. CMSIS NVIC_SystemReset(). - * If the application returns from the fault handler the SoftDevice will call NVIC_SystemReset(). - * - * @note It is recommended to either perform a reset in the fault handler or to let the SoftDevice reset the device. - * Otherwise SoC peripherals may behave in an undefined way. For example, the RADIO peripherial may - * continously transmit packets. - * - * @note This callback is executed in HardFault context, thus SVC functions cannot be called from the fault callback. - * - * @param[in] id Fault identifier. See @ref NRF_FAULT_IDS. - * @param[in] pc The program counter of the instruction that triggered the fault. - * @param[in] info Optional additional information regarding the fault. Refer to each Fault identifier for details. - * - * @note When id is set to @ref NRF_FAULT_ID_APP_MEMACC, pc will contain the address of the instruction being executed at the time - * when the fault is detected by the CPU. The CPU program counter may have advanced up to 2 instructions (no branching) after the - * one that triggered the fault. - */ -typedef void (*nrf_fault_handler_t)(uint32_t id, uint32_t pc, uint32_t info); - -/** @} */ - -/** @addtogroup NRF_SDM_FUNCTIONS Functions - * @{ */ - -/**@brief Enables the SoftDevice and by extension the protocol stack. - * - * @note Some care must be taken if a low frequency clock source is already running when calling this function: - * If the LF clock has a different source then the one currently running, it will be stopped. Then, the new - * clock source will be started. - * - * @note This function has no effect when returning with an error. - * - * @post If return code is ::NRF_SUCCESS - * - SoC library and protocol stack APIs are made available. - * - A portion of RAM will be unavailable (see relevant SDS documentation). - * - Some peripherals will be unavailable or available only through the SoC API (see relevant SDS documentation). - * - Interrupts will not arrive from protected peripherals or interrupts. - * - nrf_nvic_ functions must be used instead of CMSIS NVIC_ functions for reliable usage of the SoftDevice. - * - Interrupt latency may be affected by the SoftDevice (see relevant SDS documentation). - * - Chosen low frequency clock source will be running. - * - * @param p_clock_lf_cfg Low frequency clock source and accuracy. - If NULL the clock will be configured as an RC source with rc_ctiv = 16 and .rc_temp_ctiv = 2 - In the case of XTAL source, the PPM accuracy of the chosen clock source must be greater than or equal to - the actual characteristics of your XTAL clock. - * @param fault_handler Callback to be invoked in case of fault, cannot be NULL. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE SoftDevice is already enabled, and the clock source and fault handler cannot be updated. - * @retval ::NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION SoftDevice interrupt is already enabled, or an enabled interrupt has - an illegal priority level. - * @retval ::NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN Unknown low frequency clock source selected. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid clock source configuration supplied in p_clock_lf_cfg. - */ -SVCALL(SD_SOFTDEVICE_ENABLE, uint32_t, - sd_softdevice_enable(nrf_clock_lf_cfg_t const *p_clock_lf_cfg, nrf_fault_handler_t fault_handler)); - -/**@brief Disables the SoftDevice and by extension the protocol stack. - * - * Idempotent function to disable the SoftDevice. - * - * @post SoC library and protocol stack APIs are made unavailable. - * @post All interrupts that was protected by the SoftDevice will be disabled and initialized to priority 0 (highest). - * @post All peripherals used by the SoftDevice will be reset to default values. - * @post All of RAM become available. - * @post All interrupts are forwarded to the application. - * @post LFCLK source chosen in ::sd_softdevice_enable will be left running. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_DISABLE, uint32_t, sd_softdevice_disable(void)); - -/**@brief Check if the SoftDevice is enabled. - * - * @param[out] p_softdevice_enabled If the SoftDevice is enabled: 1 else 0. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_IS_ENABLED, uint32_t, sd_softdevice_is_enabled(uint8_t *p_softdevice_enabled)); - -/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the SoftDevice - * - * This function is only intended to be called when a bootloader is enabled. - * - * @param[in] address The base address of the interrupt vector table for forwarded interrupts. - - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table_base_set(uint32_t address)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_SDM_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_soc.h b/variants/wio-sdk-wm1110/softdevice/nrf_soc.h deleted file mode 100644 index c649ca836d..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_soc.h +++ /dev/null @@ -1,1046 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @defgroup nrf_soc_api SoC Library API - * @{ - * - * @brief APIs for the SoC library. - * - */ - -#ifndef NRF_SOC_H__ -#define NRF_SOC_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup NRF_SOC_DEFINES Defines - * @{ */ - -/**@brief The number of the lowest SVC number reserved for the SoC library. */ -#define SOC_SVC_BASE (0x20) /**< Base value for SVCs that are available when the SoftDevice is disabled. */ -#define SOC_SVC_BASE_NOT_AVAILABLE (0x2C) /**< Base value for SVCs that are not available when the SoftDevice is disabled. */ - -/**@brief Guaranteed time for application to process radio inactive notification. */ -#define NRF_RADIO_NOTIFICATION_INACTIVE_GUARANTEED_TIME_US (62) - -/**@brief The minimum allowed timeslot extension time. */ -#define NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US (200) - -/**@brief The maximum processing time to handle a timeslot extension. */ -#define NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US (20) - -/**@brief The latest time before the end of a timeslot the timeslot can be extended. */ -#define NRF_RADIO_MIN_EXTENSION_MARGIN_US (82) - -#define SOC_ECB_KEY_LENGTH (16) /**< ECB key length. */ -#define SOC_ECB_CLEARTEXT_LENGTH (16) /**< ECB cleartext length. */ -#define SOC_ECB_CIPHERTEXT_LENGTH (SOC_ECB_CLEARTEXT_LENGTH) /**< ECB ciphertext length. */ - -#define SD_EVT_IRQn (SWI2_IRQn) /**< SoftDevice Event IRQ number. Used for both protocol events and SoC events. */ -#define SD_EVT_IRQHandler \ - (SWI2_IRQHandler) /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. \ - The default interrupt priority for this handler is set to 6 */ -#define RADIO_NOTIFICATION_IRQn (SWI1_IRQn) /**< The radio notification IRQ number. */ -#define RADIO_NOTIFICATION_IRQHandler \ - (SWI1_IRQHandler) /**< The radio notification IRQ handler. \ - The default interrupt priority for this handler is set to 6 */ -#define NRF_RADIO_LENGTH_MIN_US (100) /**< The shortest allowed radio timeslot, in microseconds. */ -#define NRF_RADIO_LENGTH_MAX_US (100000) /**< The longest allowed radio timeslot, in microseconds. */ - -#define NRF_RADIO_DISTANCE_MAX_US \ - (128000000UL - 1UL) /**< The longest timeslot distance, in microseconds, allowed for the distance parameter (see @ref \ - nrf_radio_request_normal_t) in the request. */ - -#define NRF_RADIO_EARLIEST_TIMEOUT_MAX_US \ - (128000000UL - 1UL) /**< The longest timeout, in microseconds, allowed when requesting the earliest possible timeslot. */ - -#define NRF_RADIO_START_JITTER_US \ - (2) /**< The maximum jitter in @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START relative to the requested start time. */ - -/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is disabled. */ -#define NRF_SOC_SD_PPI_CHANNELS_SD_DISABLED_MSK ((uint32_t)(0)) - -/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is enabled. */ -#define NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK \ - ((uint32_t)((1U << 17) | (1U << 18) | (1U << 19) | (1U << 20) | (1U << 21) | (1U << 22) | (1U << 23) | (1U << 24) | \ - (1U << 25) | (1U << 26) | (1U << 27) | (1U << 28) | (1U << 29) | (1U << 30) | (1U << 31))) - -/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is disabled. */ -#define NRF_SOC_SD_PPI_GROUPS_SD_DISABLED_MSK ((uint32_t)(0)) - -/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is enabled. */ -#define NRF_SOC_SD_PPI_GROUPS_SD_ENABLED_MSK ((uint32_t)((1U << 4) | (1U << 5))) - -/**@} */ - -/**@addtogroup NRF_SOC_ENUMS Enumerations - * @{ */ - -/**@brief The SVC numbers used by the SVC functions in the SoC library. */ -enum NRF_SOC_SVCS { - SD_PPI_CHANNEL_ENABLE_GET = SOC_SVC_BASE, - SD_PPI_CHANNEL_ENABLE_SET = SOC_SVC_BASE + 1, - SD_PPI_CHANNEL_ENABLE_CLR = SOC_SVC_BASE + 2, - SD_PPI_CHANNEL_ASSIGN = SOC_SVC_BASE + 3, - SD_PPI_GROUP_TASK_ENABLE = SOC_SVC_BASE + 4, - SD_PPI_GROUP_TASK_DISABLE = SOC_SVC_BASE + 5, - SD_PPI_GROUP_ASSIGN = SOC_SVC_BASE + 6, - SD_PPI_GROUP_GET = SOC_SVC_BASE + 7, - SD_FLASH_PAGE_ERASE = SOC_SVC_BASE + 8, - SD_FLASH_WRITE = SOC_SVC_BASE + 9, - SD_PROTECTED_REGISTER_WRITE = SOC_SVC_BASE + 11, - SD_MUTEX_NEW = SOC_SVC_BASE_NOT_AVAILABLE, - SD_MUTEX_ACQUIRE = SOC_SVC_BASE_NOT_AVAILABLE + 1, - SD_MUTEX_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 2, - SD_RAND_APPLICATION_POOL_CAPACITY_GET = SOC_SVC_BASE_NOT_AVAILABLE + 3, - SD_RAND_APPLICATION_BYTES_AVAILABLE_GET = SOC_SVC_BASE_NOT_AVAILABLE + 4, - SD_RAND_APPLICATION_VECTOR_GET = SOC_SVC_BASE_NOT_AVAILABLE + 5, - SD_POWER_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 6, - SD_POWER_SYSTEM_OFF = SOC_SVC_BASE_NOT_AVAILABLE + 7, - SD_POWER_RESET_REASON_GET = SOC_SVC_BASE_NOT_AVAILABLE + 8, - SD_POWER_RESET_REASON_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 9, - SD_POWER_POF_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 10, - SD_POWER_POF_THRESHOLD_SET = SOC_SVC_BASE_NOT_AVAILABLE + 11, - SD_POWER_POF_THRESHOLDVDDH_SET = SOC_SVC_BASE_NOT_AVAILABLE + 12, - SD_POWER_RAM_POWER_SET = SOC_SVC_BASE_NOT_AVAILABLE + 13, - SD_POWER_RAM_POWER_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 14, - SD_POWER_RAM_POWER_GET = SOC_SVC_BASE_NOT_AVAILABLE + 15, - SD_POWER_GPREGRET_SET = SOC_SVC_BASE_NOT_AVAILABLE + 16, - SD_POWER_GPREGRET_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 17, - SD_POWER_GPREGRET_GET = SOC_SVC_BASE_NOT_AVAILABLE + 18, - SD_POWER_DCDC_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 19, - SD_POWER_DCDC0_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 20, - SD_APP_EVT_WAIT = SOC_SVC_BASE_NOT_AVAILABLE + 21, - SD_CLOCK_HFCLK_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 22, - SD_CLOCK_HFCLK_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 23, - SD_CLOCK_HFCLK_IS_RUNNING = SOC_SVC_BASE_NOT_AVAILABLE + 24, - SD_RADIO_NOTIFICATION_CFG_SET = SOC_SVC_BASE_NOT_AVAILABLE + 25, - SD_ECB_BLOCK_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 26, - SD_ECB_BLOCKS_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 27, - SD_RADIO_SESSION_OPEN = SOC_SVC_BASE_NOT_AVAILABLE + 28, - SD_RADIO_SESSION_CLOSE = SOC_SVC_BASE_NOT_AVAILABLE + 29, - SD_RADIO_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 30, - SD_EVT_GET = SOC_SVC_BASE_NOT_AVAILABLE + 31, - SD_TEMP_GET = SOC_SVC_BASE_NOT_AVAILABLE + 32, - SD_POWER_USBPWRRDY_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 33, - SD_POWER_USBDETECTED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 34, - SD_POWER_USBREMOVED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 35, - SD_POWER_USBREGSTATUS_GET = SOC_SVC_BASE_NOT_AVAILABLE + 36, - SVC_SOC_LAST = SOC_SVC_BASE_NOT_AVAILABLE + 37 -}; - -/**@brief Possible values of a ::nrf_mutex_t. */ -enum NRF_MUTEX_VALUES { NRF_MUTEX_FREE, NRF_MUTEX_TAKEN }; - -/**@brief Power modes. */ -enum NRF_POWER_MODES { - NRF_POWER_MODE_CONSTLAT, /**< Constant latency mode. See power management in the reference manual. */ - NRF_POWER_MODE_LOWPWR /**< Low power mode. See power management in the reference manual. */ -}; - -/**@brief Power failure thresholds */ -enum NRF_POWER_THRESHOLDS { - NRF_POWER_THRESHOLD_V17 = 4UL, /**< 1.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V18, /**< 1.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V19, /**< 1.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V20, /**< 2.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V21, /**< 2.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V22, /**< 2.2 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V23, /**< 2.3 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V24, /**< 2.4 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V25, /**< 2.5 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V26, /**< 2.6 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V27, /**< 2.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V28 /**< 2.8 Volts power failure threshold. */ -}; - -/**@brief Power failure thresholds for high voltage */ -enum NRF_POWER_THRESHOLDVDDHS { - NRF_POWER_THRESHOLDVDDH_V27, /**< 2.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V28, /**< 2.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V29, /**< 2.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V30, /**< 3.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V31, /**< 3.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V32, /**< 3.2 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V33, /**< 3.3 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V34, /**< 3.4 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V35, /**< 3.5 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V36, /**< 3.6 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V37, /**< 3.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V38, /**< 3.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V39, /**< 3.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V40, /**< 4.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V41, /**< 4.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V42 /**< 4.2 Volts power failure threshold. */ -}; - -/**@brief DC/DC converter modes. */ -enum NRF_POWER_DCDC_MODES { - NRF_POWER_DCDC_DISABLE, /**< The DCDC is disabled. */ - NRF_POWER_DCDC_ENABLE /**< The DCDC is enabled. */ -}; - -/**@brief Radio notification distances. */ -enum NRF_RADIO_NOTIFICATION_DISTANCES { - NRF_RADIO_NOTIFICATION_DISTANCE_NONE = 0, /**< The event does not have a notification. */ - NRF_RADIO_NOTIFICATION_DISTANCE_800US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_1740US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_2680US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_3620US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_4560US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_5500US /**< The distance from the active notification to start of radio activity. */ -}; - -/**@brief Radio notification types. */ -enum NRF_RADIO_NOTIFICATION_TYPES { - NRF_RADIO_NOTIFICATION_TYPE_NONE = 0, /**< The event does not have a radio notification signal. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, /**< Using interrupt for notification when the radio will be enabled. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, /**< Using interrupt for notification when the radio has been disabled. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, /**< Using interrupt for notification both when the radio will be enabled and - disabled. */ -}; - -/**@brief The Radio signal callback types. */ -enum NRF_RADIO_CALLBACK_SIGNAL_TYPE { - NRF_RADIO_CALLBACK_SIGNAL_TYPE_START, /**< This signal indicates the start of the radio timeslot. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0, /**< This signal indicates the NRF_TIMER0 interrupt. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO, /**< This signal indicates the NRF_RADIO interrupt. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED, /**< This signal indicates extend action failed. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED /**< This signal indicates extend action succeeded. */ -}; - -/**@brief The actions requested by the signal callback. - * - * This code gives the SOC instructions about what action to take when the signal callback has - * returned. - */ -enum NRF_RADIO_SIGNAL_CALLBACK_ACTION { - NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE, /**< Return without action. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND, /**< Request an extension of the current - timeslot. Maximum execution time for this action: - @ref NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US. - This action must be started at least - @ref NRF_RADIO_MIN_EXTENSION_MARGIN_US before - the end of the timeslot. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_END, /**< End the current radio timeslot. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END /**< Request a new radio timeslot and end the current timeslot. */ -}; - -/**@brief Radio timeslot high frequency clock source configuration. */ -enum NRF_RADIO_HFCLK_CFG { - NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED, /**< The SoftDevice will guarantee that the high frequency clock source is the - external crystal for the whole duration of the timeslot. This should be the - preferred option for events that use the radio or require high timing accuracy. - @note The SoftDevice will automatically turn on and off the external crystal, - at the beginning and end of the timeslot, respectively. The crystal may also - intentionally be left running after the timeslot, in cases where it is needed - by the SoftDevice shortly after the end of the timeslot. */ - NRF_RADIO_HFCLK_CFG_NO_GUARANTEE /**< This configuration allows for earlier and tighter scheduling of timeslots. - The RC oscillator may be the clock source in part or for the whole duration of the - timeslot. The RC oscillator's accuracy must therefore be taken into consideration. - @note If the application will use the radio peripheral in timeslots with this - configuration, it must make sure that the crystal is running and stable before - starting the radio. */ -}; - -/**@brief Radio timeslot priorities. */ -enum NRF_RADIO_PRIORITY { - NRF_RADIO_PRIORITY_HIGH, /**< High (equal priority as the normal connection priority of the SoftDevice stack(s)). */ - NRF_RADIO_PRIORITY_NORMAL, /**< Normal (equal priority as the priority of secondary activities of the SoftDevice stack(s)). */ -}; - -/**@brief Radio timeslot request type. */ -enum NRF_RADIO_REQUEST_TYPE { - NRF_RADIO_REQ_TYPE_EARLIEST, /**< Request radio timeslot as early as possible. This should always be used for the first - request in a session. */ - NRF_RADIO_REQ_TYPE_NORMAL /**< Normal radio timeslot request. */ -}; - -/**@brief SoC Events. */ -enum NRF_SOC_EVTS { - NRF_EVT_HFCLKSTARTED, /**< Event indicating that the HFCLK has started. */ - NRF_EVT_POWER_FAILURE_WARNING, /**< Event indicating that a power failure warning has occurred. */ - NRF_EVT_FLASH_OPERATION_SUCCESS, /**< Event indicating that the ongoing flash operation has completed successfully. */ - NRF_EVT_FLASH_OPERATION_ERROR, /**< Event indicating that the ongoing flash operation has timed out with an error. */ - NRF_EVT_RADIO_BLOCKED, /**< Event indicating that a radio timeslot was blocked. */ - NRF_EVT_RADIO_CANCELED, /**< Event indicating that a radio timeslot was canceled by SoftDevice. */ - NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN, /**< Event indicating that a radio timeslot signal callback handler return was - invalid. */ - NRF_EVT_RADIO_SESSION_IDLE, /**< Event indicating that a radio timeslot session is idle. */ - NRF_EVT_RADIO_SESSION_CLOSED, /**< Event indicating that a radio timeslot session is closed. */ - NRF_EVT_POWER_USB_POWER_READY, /**< Event indicating that a USB 3.3 V supply is ready. */ - NRF_EVT_POWER_USB_DETECTED, /**< Event indicating that voltage supply is detected on VBUS. */ - NRF_EVT_POWER_USB_REMOVED, /**< Event indicating that voltage supply is removed from VBUS. */ - NRF_EVT_NUMBER_OF_EVTS -}; - -/**@} */ - -/**@addtogroup NRF_SOC_STRUCTURES Structures - * @{ */ - -/**@brief Represents a mutex for use with the nrf_mutex functions. - * @note Accessing the value directly is not safe, use the mutex functions! - */ -typedef volatile uint8_t nrf_mutex_t; - -/**@brief Parameters for a request for a timeslot as early as possible. */ -typedef struct { - uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ - uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ - uint32_t length_us; /**< The radio timeslot length (in the range 100 to 100,000] microseconds). */ - uint32_t timeout_us; /**< Longest acceptable delay until the start of the requested timeslot (up to @ref - NRF_RADIO_EARLIEST_TIMEOUT_MAX_US microseconds). */ -} nrf_radio_request_earliest_t; - -/**@brief Parameters for a normal radio timeslot request. */ -typedef struct { - uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ - uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ - uint32_t distance_us; /**< Distance from the start of the previous radio timeslot (up to @ref NRF_RADIO_DISTANCE_MAX_US - microseconds). */ - uint32_t length_us; /**< The radio timeslot length (in the range [100..100,000] microseconds). */ -} nrf_radio_request_normal_t; - -/**@brief Radio timeslot request parameters. */ -typedef struct { - uint8_t request_type; /**< Type of request, see @ref NRF_RADIO_REQUEST_TYPE. */ - union { - nrf_radio_request_earliest_t earliest; /**< Parameters for requesting a radio timeslot as early as possible. */ - nrf_radio_request_normal_t normal; /**< Parameters for requesting a normal radio timeslot. */ - } params; /**< Parameter union. */ -} nrf_radio_request_t; - -/**@brief Return parameters of the radio timeslot signal callback. */ -typedef struct { - uint8_t callback_action; /**< The action requested by the application when returning from the signal callback, see @ref - NRF_RADIO_SIGNAL_CALLBACK_ACTION. */ - union { - struct { - nrf_radio_request_t *p_next; /**< The request parameters for the next radio timeslot. */ - } request; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END. */ - struct { - uint32_t length_us; /**< Requested extension of the radio timeslot duration (microseconds) (for minimum time see @ref - NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US). */ - } extend; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND. */ - } params; /**< Parameter union. */ -} nrf_radio_signal_callback_return_param_t; - -/**@brief The radio timeslot signal callback type. - * - * @note In case of invalid return parameters, the radio timeslot will automatically end - * immediately after returning from the signal callback and the - * @ref NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN event will be sent. - * @note The returned struct pointer must remain valid after the signal callback - * function returns. For instance, this means that it must not point to a stack variable. - * - * @param[in] signal_type Type of signal, see @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE. - * - * @return Pointer to structure containing action requested by the application. - */ -typedef nrf_radio_signal_callback_return_param_t *(*nrf_radio_signal_callback_t)(uint8_t signal_type); - -/**@brief AES ECB parameter typedefs */ -typedef uint8_t soc_ecb_key_t[SOC_ECB_KEY_LENGTH]; /**< Encryption key type. */ -typedef uint8_t soc_ecb_cleartext_t[SOC_ECB_CLEARTEXT_LENGTH]; /**< Cleartext data type. */ -typedef uint8_t soc_ecb_ciphertext_t[SOC_ECB_CIPHERTEXT_LENGTH]; /**< Ciphertext data type. */ - -/**@brief AES ECB data structure */ -typedef struct { - soc_ecb_key_t key; /**< Encryption key. */ - soc_ecb_cleartext_t cleartext; /**< Cleartext data. */ - soc_ecb_ciphertext_t ciphertext; /**< Ciphertext data. */ -} nrf_ecb_hal_data_t; - -/**@brief AES ECB block. Used to provide multiple blocks in a single call - to @ref sd_ecb_blocks_encrypt.*/ -typedef struct { - soc_ecb_key_t const *p_key; /**< Pointer to the Encryption key. */ - soc_ecb_cleartext_t const *p_cleartext; /**< Pointer to the Cleartext data. */ - soc_ecb_ciphertext_t *p_ciphertext; /**< Pointer to the Ciphertext data. */ -} nrf_ecb_hal_data_block_t; - -/**@} */ - -/**@addtogroup NRF_SOC_FUNCTIONS Functions - * @{ */ - -/**@brief Initialize a mutex. - * - * @param[in] p_mutex Pointer to the mutex to initialize. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_MUTEX_NEW, uint32_t, sd_mutex_new(nrf_mutex_t *p_mutex)); - -/**@brief Attempt to acquire a mutex. - * - * @param[in] p_mutex Pointer to the mutex to acquire. - * - * @retval ::NRF_SUCCESS The mutex was successfully acquired. - * @retval ::NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN The mutex could not be acquired. - */ -SVCALL(SD_MUTEX_ACQUIRE, uint32_t, sd_mutex_acquire(nrf_mutex_t *p_mutex)); - -/**@brief Release a mutex. - * - * @param[in] p_mutex Pointer to the mutex to release. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_MUTEX_RELEASE, uint32_t, sd_mutex_release(nrf_mutex_t *p_mutex)); - -/**@brief Query the capacity of the application random pool. - * - * @param[out] p_pool_capacity The capacity of the pool. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RAND_APPLICATION_POOL_CAPACITY_GET, uint32_t, sd_rand_application_pool_capacity_get(uint8_t *p_pool_capacity)); - -/**@brief Get number of random bytes available to the application. - * - * @param[out] p_bytes_available The number of bytes currently available in the pool. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RAND_APPLICATION_BYTES_AVAILABLE_GET, uint32_t, sd_rand_application_bytes_available_get(uint8_t *p_bytes_available)); - -/**@brief Get random bytes from the application pool. - * - * @param[out] p_buff Pointer to unit8_t buffer for storing the bytes. - * @param[in] length Number of bytes to take from pool and place in p_buff. - * - * @retval ::NRF_SUCCESS The requested bytes were written to p_buff. - * @retval ::NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES No bytes were written to the buffer, because there were not enough bytes - * available. - */ -SVCALL(SD_RAND_APPLICATION_VECTOR_GET, uint32_t, sd_rand_application_vector_get(uint8_t *p_buff, uint8_t length)); - -/**@brief Gets the reset reason register. - * - * @param[out] p_reset_reason Contents of the NRF_POWER->RESETREAS register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RESET_REASON_GET, uint32_t, sd_power_reset_reason_get(uint32_t *p_reset_reason)); - -/**@brief Clears the bits of the reset reason register. - * - * @param[in] reset_reason_clr_msk Contains the bits to clear from the reset reason register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RESET_REASON_CLR, uint32_t, sd_power_reset_reason_clr(uint32_t reset_reason_clr_msk)); - -/**@brief Sets the power mode when in CPU sleep. - * - * @param[in] power_mode The power mode to use when in CPU sleep, see @ref NRF_POWER_MODES. @sa sd_app_evt_wait - * - * @retval ::NRF_SUCCESS The power mode was set. - * @retval ::NRF_ERROR_SOC_POWER_MODE_UNKNOWN The power mode was unknown. - */ -SVCALL(SD_POWER_MODE_SET, uint32_t, sd_power_mode_set(uint8_t power_mode)); - -/**@brief Puts the chip in System OFF mode. - * - * @retval ::NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN - */ -SVCALL(SD_POWER_SYSTEM_OFF, uint32_t, sd_power_system_off(void)); - -/**@brief Enables or disables the power-fail comparator. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_FAILURE_WARNING) when the power failure warning occurs. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] pof_enable True if the power-fail comparator should be enabled, false if it should be disabled. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_POF_ENABLE, uint32_t, sd_power_pof_enable(uint8_t pof_enable)); - -/**@brief Enables or disables the USB power ready event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_POWER_READY) when a USB 3.3 V supply is ready. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbpwrrdy_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBPWRRDY_ENABLE, uint32_t, sd_power_usbpwrrdy_enable(uint8_t usbpwrrdy_enable)); - -/**@brief Enables or disables the power USB-detected event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_DETECTED) when a voltage supply is detected on VBUS. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbdetected_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBDETECTED_ENABLE, uint32_t, sd_power_usbdetected_enable(uint8_t usbdetected_enable)); - -/**@brief Enables or disables the power USB-removed event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_REMOVED) when a voltage supply is removed from VBUS. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbremoved_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBREMOVED_ENABLE, uint32_t, sd_power_usbremoved_enable(uint8_t usbremoved_enable)); - -/**@brief Get USB supply status register content. - * - * @param[out] usbregstatus The content of USBREGSTATUS register. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBREGSTATUS_GET, uint32_t, sd_power_usbregstatus_get(uint32_t *usbregstatus)); - -/**@brief Sets the power failure comparator threshold value. - * - * @note: Power failure comparator threshold setting. This setting applies both for normal voltage - * mode (supply connected to both VDD and VDDH) and high voltage mode (supply connected to - * VDDH only). - * - * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDS. - * - * @retval ::NRF_SUCCESS The power failure threshold was set. - * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. - */ -SVCALL(SD_POWER_POF_THRESHOLD_SET, uint32_t, sd_power_pof_threshold_set(uint8_t threshold)); - -/**@brief Sets the power failure comparator threshold value for high voltage. - * - * @note: Power failure comparator threshold setting for high voltage mode (supply connected to - * VDDH only). This setting does not apply for normal voltage mode (supply connected to both - * VDD and VDDH). - * - * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDVDDHS. - * - * @retval ::NRF_SUCCESS The power failure threshold was set. - * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. - */ -SVCALL(SD_POWER_POF_THRESHOLDVDDH_SET, uint32_t, sd_power_pof_thresholdvddh_set(uint8_t threshold)); - -/**@brief Writes the NRF_POWER->RAM[index].POWERSET register. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERSET register to write to. - * @param[in] ram_powerset Contains the word to write to the NRF_POWER->RAM[index].POWERSET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_SET, uint32_t, sd_power_ram_power_set(uint8_t index, uint32_t ram_powerset)); - -/**@brief Writes the NRF_POWER->RAM[index].POWERCLR register. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERCLR register to write to. - * @param[in] ram_powerclr Contains the word to write to the NRF_POWER->RAM[index].POWERCLR register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_CLR, uint32_t, sd_power_ram_power_clr(uint8_t index, uint32_t ram_powerclr)); - -/**@brief Get contents of NRF_POWER->RAM[index].POWER register, indicates power status of RAM[index] blocks. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWER register to read from. - * @param[out] p_ram_power Content of NRF_POWER->RAM[index].POWER register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_GET, uint32_t, sd_power_ram_power_get(uint8_t index, uint32_t *p_ram_power)); - -/**@brief Set bits in the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[in] gpregret_msk Bits to be set in the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_SET, uint32_t, sd_power_gpregret_set(uint32_t gpregret_id, uint32_t gpregret_msk)); - -/**@brief Clear bits in the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[in] gpregret_msk Bits to be clear in the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_CLR, uint32_t, sd_power_gpregret_clr(uint32_t gpregret_id, uint32_t gpregret_msk)); - -/**@brief Get contents of the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[out] p_gpregret Contents of the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_GET, uint32_t, sd_power_gpregret_get(uint32_t gpregret_id, uint32_t *p_gpregret)); - -/**@brief Enable or disable the DC/DC regulator for the regulator stage 1 (REG1). - * - * @param[in] dcdc_mode The mode of the DCDC, see @ref NRF_POWER_DCDC_MODES. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_PARAM The DCDC mode is invalid. - */ -SVCALL(SD_POWER_DCDC_MODE_SET, uint32_t, sd_power_dcdc_mode_set(uint8_t dcdc_mode)); - -/**@brief Enable or disable the DC/DC regulator for the regulator stage 0 (REG0). - * - * For more details on the REG0 stage, please see product specification. - * - * @param[in] dcdc_mode The mode of the DCDC0, see @ref NRF_POWER_DCDC_MODES. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_PARAM The dcdc_mode is invalid. - */ -SVCALL(SD_POWER_DCDC0_MODE_SET, uint32_t, sd_power_dcdc0_mode_set(uint8_t dcdc_mode)); - -/**@brief Request the high frequency crystal oscillator. - * - * Will start the high frequency crystal oscillator, the startup time of the crystal varies - * and the ::sd_clock_hfclk_is_running function can be polled to check if it has started. - * - * @see sd_clock_hfclk_is_running - * @see sd_clock_hfclk_release - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_REQUEST, uint32_t, sd_clock_hfclk_request(void)); - -/**@brief Releases the high frequency crystal oscillator. - * - * Will stop the high frequency crystal oscillator, this happens immediately. - * - * @see sd_clock_hfclk_is_running - * @see sd_clock_hfclk_request - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_RELEASE, uint32_t, sd_clock_hfclk_release(void)); - -/**@brief Checks if the high frequency crystal oscillator is running. - * - * @see sd_clock_hfclk_request - * @see sd_clock_hfclk_release - * - * @param[out] p_is_running 1 if the external crystal oscillator is running, 0 if not. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_IS_RUNNING, uint32_t, sd_clock_hfclk_is_running(uint32_t *p_is_running)); - -/**@brief Waits for an application event. - * - * An application event is either an application interrupt or a pended interrupt when the interrupt - * is disabled. - * - * When the application waits for an application event by calling this function, an interrupt that - * is enabled will be taken immediately on pending since this function will wait in thread mode, - * then the execution will return in the application's main thread. - * - * In order to wake up from disabled interrupts, the SEVONPEND flag has to be set in the Cortex-M - * MCU's System Control Register (SCR), CMSIS_SCB. In that case, when a disabled interrupt gets - * pended, this function will return to the application's main thread. - * - * @note The application must ensure that the pended flag is cleared using ::sd_nvic_ClearPendingIRQ - * in order to sleep using this function. This is only necessary for disabled interrupts, as - * the interrupt handler will clear the pending flag automatically for enabled interrupts. - * - * @note If an application interrupt has happened since the last time sd_app_evt_wait was - * called this function will return immediately and not go to sleep. This is to avoid race - * conditions that can occur when a flag is updated in the interrupt handler and processed - * in the main loop. - * - * @post An application interrupt has happened or a interrupt pending flag is set. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_APP_EVT_WAIT, uint32_t, sd_app_evt_wait(void)); - -/**@brief Get PPI channel enable register contents. - * - * @param[out] p_channel_enable The contents of the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_GET, uint32_t, sd_ppi_channel_enable_get(uint32_t *p_channel_enable)); - -/**@brief Set PPI channel enable register. - * - * @param[in] channel_enable_set_msk Mask containing the bits to set in the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_SET, uint32_t, sd_ppi_channel_enable_set(uint32_t channel_enable_set_msk)); - -/**@brief Clear PPI channel enable register. - * - * @param[in] channel_enable_clr_msk Mask containing the bits to clear in the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_CLR, uint32_t, sd_ppi_channel_enable_clr(uint32_t channel_enable_clr_msk)); - -/**@brief Assign endpoints to a PPI channel. - * - * @param[in] channel_num Number of the PPI channel to assign. - * @param[in] evt_endpoint Event endpoint of the PPI channel. - * @param[in] task_endpoint Task endpoint of the PPI channel. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_CHANNEL The channel number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ASSIGN, uint32_t, - sd_ppi_channel_assign(uint8_t channel_num, const volatile void *evt_endpoint, const volatile void *task_endpoint)); - -/**@brief Task to enable a channel group. - * - * @param[in] group_num Number of the channel group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_TASK_ENABLE, uint32_t, sd_ppi_group_task_enable(uint8_t group_num)); - -/**@brief Task to disable a channel group. - * - * @param[in] group_num Number of the PPI group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_TASK_DISABLE, uint32_t, sd_ppi_group_task_disable(uint8_t group_num)); - -/**@brief Assign PPI channels to a channel group. - * - * @param[in] group_num Number of the channel group. - * @param[in] channel_msk Mask of the channels to assign to the group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_ASSIGN, uint32_t, sd_ppi_group_assign(uint8_t group_num, uint32_t channel_msk)); - -/**@brief Gets the PPI channels of a channel group. - * - * @param[in] group_num Number of the channel group. - * @param[out] p_channel_msk Mask of the channels assigned to the group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_GET, uint32_t, sd_ppi_group_get(uint8_t group_num, uint32_t *p_channel_msk)); - -/**@brief Configures the Radio Notification signal. - * - * @note - * - The notification signal latency depends on the interrupt priority settings of SWI used - * for notification signal. - * - To ensure that the radio notification signal behaves in a consistent way, the radio - * notifications must be configured when there is no protocol stack or other SoftDevice - * activity in progress. It is recommended that the radio notification signal is - * configured directly after the SoftDevice has been enabled. - * - In the period between the ACTIVE signal and the start of the Radio Event, the SoftDevice - * will interrupt the application to do Radio Event preparation. - * - Using the Radio Notification feature may limit the bandwidth, as the SoftDevice may have - * to shorten the connection events to have time for the Radio Notification signals. - * - * @param[in] type Type of notification signal, see @ref NRF_RADIO_NOTIFICATION_TYPES. - * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE shall be used to turn off radio - * notification. Using @ref NRF_RADIO_NOTIFICATION_DISTANCE_NONE is - * recommended (but not required) to be used with - * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE. - * - * @param[in] distance Distance between the notification signal and start of radio activity, see @ref - * NRF_RADIO_NOTIFICATION_DISTANCES. This parameter is ignored when @ref NRF_RADIO_NOTIFICATION_TYPE_NONE or - * @ref NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE is used. - * - * @retval ::NRF_ERROR_INVALID_PARAM The group number is invalid. - * @retval ::NRF_ERROR_INVALID_STATE A protocol stack or other SoftDevice is running. Stop all - * running activities and retry. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RADIO_NOTIFICATION_CFG_SET, uint32_t, sd_radio_notification_cfg_set(uint8_t type, uint8_t distance)); - -/**@brief Encrypts a block according to the specified parameters. - * - * 128-bit AES encryption. - * - * @note: - * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while - * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application - * main or low interrupt level. - * - * @param[in, out] p_ecb_data Pointer to the ECB parameters' struct (two input - * parameters and one output parameter). - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_ECB_BLOCK_ENCRYPT, uint32_t, sd_ecb_block_encrypt(nrf_ecb_hal_data_t *p_ecb_data)); - -/**@brief Encrypts multiple data blocks provided as an array of data block structures. - * - * @details: Performs 128-bit AES encryption on multiple data blocks - * - * @note: - * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while - * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application - * main or low interrupt level. - * - * @param[in] block_count Count of blocks in the p_data_blocks array. - * @param[in,out] p_data_blocks Pointer to the first entry in a contiguous array of - * @ref nrf_ecb_hal_data_block_t structures. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_ECB_BLOCKS_ENCRYPT, uint32_t, sd_ecb_blocks_encrypt(uint8_t block_count, nrf_ecb_hal_data_block_t *p_data_blocks)); - -/**@brief Gets any pending events generated by the SoC API. - * - * The application should keep calling this function to get events, until ::NRF_ERROR_NOT_FOUND is returned. - * - * @param[out] p_evt_id Set to one of the values in @ref NRF_SOC_EVTS, if any events are pending. - * - * @retval ::NRF_SUCCESS An event was pending. The event id is written in the p_evt_id parameter. - * @retval ::NRF_ERROR_NOT_FOUND No pending events. - */ -SVCALL(SD_EVT_GET, uint32_t, sd_evt_get(uint32_t *p_evt_id)); - -/**@brief Get the temperature measured on the chip - * - * This function will block until the temperature measurement is done. - * It takes around 50 us from call to return. - * - * @param[out] p_temp Result of temperature measurement. Die temperature in 0.25 degrees Celsius. - * - * @retval ::NRF_SUCCESS A temperature measurement was done, and the temperature was written to temp - */ -SVCALL(SD_TEMP_GET, uint32_t, sd_temp_get(int32_t *p_temp)); - -/**@brief Flash Write - * - * Commands to write a buffer to flash - * - * If the SoftDevice is enabled: - * This call initiates the flash access command, and its completion will be communicated to the - * application with exactly one of the following events: - * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. - * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. - * - * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the - * write has been completed - * - * @note - * - This call takes control over the radio and the CPU during flash erase and write to make sure that - * they will not interfere with the flash access. This means that all interrupts will be blocked - * for a predictable time (depending on the NVMC specification in the device's Product Specification - * and the command parameters). - * - The data in the p_src buffer should not be modified before the @ref NRF_EVT_FLASH_OPERATION_SUCCESS - * or the @ref NRF_EVT_FLASH_OPERATION_ERROR have been received if the SoftDevice is enabled. - * - This call will make the SoftDevice trigger a hardfault when the page is written, if it is - * protected. - * - * - * @param[in] p_dst Pointer to start of flash location to be written. - * @param[in] p_src Pointer to buffer with data to be written. - * @param[in] size Number of 32-bit words to write. Maximum size is the number of words in one - * flash page. See the device's Product Specification for details. - * - * @retval ::NRF_ERROR_INVALID_ADDR Tried to write to a non existing flash address, or p_dst or p_src was unaligned. - * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. - * @retval ::NRF_ERROR_INVALID_LENGTH Size was 0, or higher than the maximum allowed size. - * @retval ::NRF_ERROR_FORBIDDEN Tried to write to an address outside the application flash area. - * @retval ::NRF_SUCCESS The command was accepted. - */ -SVCALL(SD_FLASH_WRITE, uint32_t, sd_flash_write(uint32_t *p_dst, uint32_t const *p_src, uint32_t size)); - -/**@brief Flash Erase page - * - * Commands to erase a flash page - * If the SoftDevice is enabled: - * This call initiates the flash access command, and its completion will be communicated to the - * application with exactly one of the following events: - * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. - * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. - * - * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the - * erase has been completed - * - * @note - * - This call takes control over the radio and the CPU during flash erase and write to make sure that - * they will not interfere with the flash access. This means that all interrupts will be blocked - * for a predictable time (depending on the NVMC specification in the device's Product Specification - * and the command parameters). - * - This call will make the SoftDevice trigger a hardfault when the page is erased, if it is - * protected. - * - * - * @param[in] page_number Page number of the page to erase - * - * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. - * @retval ::NRF_ERROR_INVALID_ADDR Tried to erase to a non existing flash page. - * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. - * @retval ::NRF_ERROR_FORBIDDEN Tried to erase a page outside the application flash area. - * @retval ::NRF_SUCCESS The command was accepted. - */ -SVCALL(SD_FLASH_PAGE_ERASE, uint32_t, sd_flash_page_erase(uint32_t page_number)); - -/**@brief Opens a session for radio timeslot requests. - * - * @note Only one session can be open at a time. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) will be called when the radio timeslot - * starts. From this point the NRF_RADIO and NRF_TIMER0 peripherals can be freely accessed - * by the application. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0) is called whenever the NRF_TIMER0 - * interrupt occurs. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO) is called whenever the NRF_RADIO - * interrupt occurs. - * @note p_radio_signal_callback() will be called at ARM interrupt priority level 0. This - * implies that none of the sd_* API calls can be used from p_radio_signal_callback(). - * - * @param[in] p_radio_signal_callback The signal callback. - * - * @retval ::NRF_ERROR_INVALID_ADDR p_radio_signal_callback is an invalid function pointer. - * @retval ::NRF_ERROR_BUSY If session cannot be opened. - * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_SESSION_OPEN, uint32_t, sd_radio_session_open(nrf_radio_signal_callback_t p_radio_signal_callback)); - -/**@brief Closes a session for radio timeslot requests. - * - * @note Any current radio timeslot will be finished before the session is closed. - * @note If a radio timeslot is scheduled when the session is closed, it will be canceled. - * @note The application cannot consider the session closed until the @ref NRF_EVT_RADIO_SESSION_CLOSED - * event is received. - * - * @retval ::NRF_ERROR_FORBIDDEN If session not opened. - * @retval ::NRF_ERROR_BUSY If session is currently being closed. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_SESSION_CLOSE, uint32_t, sd_radio_session_close(void)); - -/**@brief Requests a radio timeslot. - * - * @note The request type is determined by p_request->request_type, and can be one of @ref NRF_RADIO_REQ_TYPE_EARLIEST - * and @ref NRF_RADIO_REQ_TYPE_NORMAL. The first request in a session must always be of type @ref - * NRF_RADIO_REQ_TYPE_EARLIEST. - * @note For a normal request (@ref NRF_RADIO_REQ_TYPE_NORMAL), the start time of a radio timeslot is specified by - * p_request->distance_us and is given relative to the start of the previous timeslot. - * @note A too small p_request->distance_us will lead to a @ref NRF_EVT_RADIO_BLOCKED event. - * @note Timeslots scheduled too close will lead to a @ref NRF_EVT_RADIO_BLOCKED event. - * @note See the SoftDevice Specification for more on radio timeslot scheduling, distances and lengths. - * @note If an opportunity for the first radio timeslot is not found before 100 ms after the call to this - * function, it is not scheduled, and instead a @ref NRF_EVT_RADIO_BLOCKED event is sent. - * The application may then try to schedule the first radio timeslot again. - * @note Successful requests will result in nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START). - * Unsuccessful requests will result in a @ref NRF_EVT_RADIO_BLOCKED event, see @ref NRF_SOC_EVTS. - * @note The jitter in the start time of the radio timeslots is +/- @ref NRF_RADIO_START_JITTER_US us. - * @note The nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) call has a latency relative to the - * specified radio timeslot start, but this does not affect the actual start time of the timeslot. - * @note NRF_TIMER0 is reset at the start of the radio timeslot, and is clocked at 1MHz from the high frequency - * (16 MHz) clock source. If p_request->hfclk_force_xtal is true, the high frequency clock is - * guaranteed to be clocked from the external crystal. - * @note The SoftDevice will neither access the NRF_RADIO peripheral nor the NRF_TIMER0 peripheral - * during the radio timeslot. - * - * @param[in] p_request Pointer to the request parameters. - * - * @retval ::NRF_ERROR_FORBIDDEN Either: - * - The session is not open. - * - The session is not IDLE. - * - This is the first request and its type is not @ref NRF_RADIO_REQ_TYPE_EARLIEST. - * - The request type was set to @ref NRF_RADIO_REQ_TYPE_NORMAL after a - * @ref NRF_RADIO_REQ_TYPE_EARLIEST request was blocked. - * @retval ::NRF_ERROR_INVALID_ADDR If the p_request pointer is invalid. - * @retval ::NRF_ERROR_INVALID_PARAM If the parameters of p_request are not valid. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_REQUEST, uint32_t, sd_radio_request(nrf_radio_request_t const *p_request)); - -/**@brief Write register protected by the SoftDevice - * - * This function writes to a register that is write-protected by the SoftDevice. Please refer to your - * SoftDevice Specification for more details about which registers that are protected by SoftDevice. - * This function can write to the following protected peripheral: - * - ACL - * - * @note Protected registers may be read directly. - * @note Register that are write-once will return @ref NRF_SUCCESS on second set, even the value in - * the register has not changed. See the Product Specification for more details about register - * properties. - * - * @param[in] p_register Pointer to register to be written. - * @param[in] value Value to be written to the register. - * - * @retval ::NRF_ERROR_INVALID_ADDR This function can not write to the reguested register. - * @retval ::NRF_SUCCESS Value successfully written to register. - * - */ -SVCALL(SD_PROTECTED_REGISTER_WRITE, uint32_t, sd_protected_register_write(volatile uint32_t *p_register, uint32_t value)); - -/**@} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_SOC_H__ - -/**@} */ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_svc.h b/variants/wio-sdk-wm1110/softdevice/nrf_svc.h deleted file mode 100644 index 1de44656f3..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_svc.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef NRF_SVC__ -#define NRF_SVC__ - -#include "stdint.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @brief Supervisor call declaration. - * - * A call to a function marked with @ref SVCALL, will trigger a Supervisor Call (SVC) Exception. - * The SVCs with SVC numbers 0x00-0x0F are forwared to the application. All other SVCs are handled by the SoftDevice. - * - * @param[in] number The SVC number to be used. - * @param[in] return_type The return type of the SVC function. - * @param[in] signature Function signature. The function can have at most four arguments. - */ - -#ifdef SVCALL_AS_NORMAL_FUNCTION -#define SVCALL(number, return_type, signature) return_type signature -#else - -#ifndef SVCALL -#if defined(__CC_ARM) -#define SVCALL(number, return_type, signature) return_type __svc(number) signature -#elif defined(__GNUC__) -#ifdef __cplusplus -#define GCC_CAST_CPP (uint16_t) -#else -#define GCC_CAST_CPP -#endif -#define SVCALL(number, return_type, signature) \ - _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") __attribute__((naked)) \ - __attribute__((unused)) static return_type signature \ - { \ - __asm("svc %0\n" \ - "bx r14" \ - : \ - : "I"(GCC_CAST_CPP number) \ - : "r0"); \ - } \ - _Pragma("GCC diagnostic pop") - -#elif defined(__ICCARM__) -#define PRAGMA(x) _Pragma(#x) -#define SVCALL(number, return_type, signature) \ - PRAGMA(swi_number = (number)) \ - __swi return_type signature; -#else -#define SVCALL(number, return_type, signature) return_type signature -#endif -#endif // SVCALL - -#endif // SVCALL_AS_NORMAL_FUNCTION - -#ifdef __cplusplus -} -#endif -#endif // NRF_SVC__ From 46d7b82ac1a4292ba52ca690e1a433d3a501a9e5 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 16 Jul 2024 09:37:50 -0500 Subject: [PATCH 166/211] Migrate to new defaults (#4294) * Upgrade module config state version but don't blow everything away * ModuleConfig version intervals roll forward * Be specific about version migration criteria * initModuleConfigIntervals fix * Don't forget power! --- src/mesh/NodeDB.cpp | 32 ++++++++++++++++++++++++++++---- src/mesh/NodeDB.h | 4 ++-- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index fa5c437c42..5678009c08 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -425,10 +425,14 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role) void NodeDB::initModuleConfigIntervals() { - moduleConfig.telemetry.device_update_interval = default_broadcast_interval_secs; - moduleConfig.telemetry.environment_update_interval = default_broadcast_interval_secs; - moduleConfig.telemetry.air_quality_interval = default_broadcast_interval_secs; - moduleConfig.neighbor_info.update_interval = default_broadcast_interval_secs; + // Zero out telemetry intervals so that they coalesce to defaults in Default.h + moduleConfig.telemetry.device_update_interval = 0; + moduleConfig.telemetry.environment_update_interval = 0; + moduleConfig.telemetry.air_quality_interval = 0; + moduleConfig.telemetry.power_update_interval = 0; + moduleConfig.neighbor_info.update_interval = 0; + moduleConfig.paxcounter.paxcounter_update_interval = 0; + moduleConfig.neighbor_info.update_interval = 0; } void NodeDB::installDefaultChannels() @@ -648,6 +652,26 @@ void NodeDB::loadFromDisk() if (state == LoadFileResult::SUCCESS) { LOG_INFO("Loaded OEMStore\n"); } + + // 2.4.X - configuration migration to update new default intervals + if (moduleConfig.version < 23) { + LOG_DEBUG("ModuleConfig version %d is stale, upgrading to new default intervals\n", moduleConfig.version); + moduleConfig.version = DEVICESTATE_CUR_VER; + if (moduleConfig.telemetry.device_update_interval == 900) + moduleConfig.telemetry.device_update_interval = 0; + if (moduleConfig.telemetry.environment_update_interval == 900) + moduleConfig.telemetry.environment_update_interval = 0; + if (moduleConfig.telemetry.air_quality_interval == 900) + moduleConfig.telemetry.air_quality_interval = 0; + if (moduleConfig.telemetry.power_update_interval == 900) + moduleConfig.telemetry.power_update_interval = 0; + if (moduleConfig.neighbor_info.update_interval == 900) + moduleConfig.neighbor_info.update_interval = 0; + if (moduleConfig.paxcounter.paxcounter_update_interval == 900) + moduleConfig.paxcounter.paxcounter_update_interval = 0; + + saveToDisk(SEGMENT_MODULECONFIG); + } } /** Save a protobuf from a file, return true for success */ diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 61bf90d4d3..5207d8629b 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -20,8 +20,8 @@ DeviceState versions used to be defined in the .proto file but really only this #define SEGMENT_DEVICESTATE 4 #define SEGMENT_CHANNELS 8 -#define DEVICESTATE_CUR_VER 22 -#define DEVICESTATE_MIN_VER DEVICESTATE_CUR_VER +#define DEVICESTATE_CUR_VER 23 +#define DEVICESTATE_MIN_VER 22 extern meshtastic_DeviceState devicestate; extern meshtastic_ChannelFile channelFile; From f25644e8cfb30f64a4aa9cb2eeff67eeca94c6eb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 06:13:03 -0500 Subject: [PATCH 167/211] [create-pull-request] automated change (#4287) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 7d2c262489..4c87608d0a 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 4 -build = 0 +build = 1 From 54df153e9e23190e0b1201ab3c3689560a3b3acb Mon Sep 17 00:00:00 2001 From: todd-herbert Date: Sat, 20 Jul 2024 23:46:26 +1200 Subject: [PATCH 168/211] Wait for I2C power to stabilize on Heltec VME213; tidy variant folder (#4308) * Tidy variant.h and pins_arduino.h (VME213) * Wait for peripherals to stabilize after enabling I2C power The 3.3V power for the I2C "quick link" connector is from Ve_3V3 --- src/main.cpp | 7 ++++ .../heltec_vision_master_e213/pins_arduino.h | 6 ++-- variants/heltec_vision_master_e213/variant.h | 36 ++++++++----------- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 95eeb998d9..1879423449 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -308,6 +308,13 @@ void setup() digitalWrite(RESET_OLED, 1); #endif +#ifdef PERIPHERAL_WARMUP_MS + // Some peripherals may require additional time to stabilize after power is connected + // e.g. I2C on Heltec Vision Master + LOG_INFO("Waiting for peripherals to stabilize\n"); + delay(PERIPHERAL_WARMUP_MS); +#endif + #ifdef BUTTON_PIN #ifdef ARCH_ESP32 diff --git a/variants/heltec_vision_master_e213/pins_arduino.h b/variants/heltec_vision_master_e213/pins_arduino.h index 359922499e..ce35348fd4 100644 --- a/variants/heltec_vision_master_e213/pins_arduino.h +++ b/variants/heltec_vision_master_e213/pins_arduino.h @@ -3,8 +3,8 @@ #include -static const uint8_t LED_BUILTIN = 35; -#define BUILTIN_LED LED_BUILTIN // backward compatibility +static const uint8_t LED_BUILTIN = -1; // Board has no built-in LED, despite what schematic shows +#define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN static const uint8_t TX = 43; @@ -56,6 +56,6 @@ static const uint8_t T14 = 14; static const uint8_t RST_LoRa = 12; static const uint8_t BUSY_LoRa = 13; -static const uint8_t DIO0 = 14; +static const uint8_t DIO1 = 14; #endif /* Pins_Arduino_h */ diff --git a/variants/heltec_vision_master_e213/variant.h b/variants/heltec_vision_master_e213/variant.h index d4e42ad1cc..99bc1d138d 100644 --- a/variants/heltec_vision_master_e213/variant.h +++ b/variants/heltec_vision_master_e213/variant.h @@ -1,14 +1,11 @@ -// #define LED_PIN 18 +#define BUTTON_PIN 0 -// Enable bus for external periherals +// I2C #define I2C_SDA SDA #define I2C_SCL SCL +// Display (E-Ink) #define USE_EINK - -/* - * eink display pins - */ #define PIN_EINK_CS 5 #define PIN_EINK_BUSY 1 #define PIN_EINK_DC 2 @@ -16,33 +13,30 @@ #define PIN_EINK_SCLK 4 #define PIN_EINK_MOSI 6 -/* - * SPI interfaces - */ +// SPI #define SPI_INTERFACES_COUNT 2 - -#define PIN_SPI_MISO 10 // MISO P0.17 -#define PIN_SPI_MOSI 11 // MOSI P0.15 -#define PIN_SPI_SCK 9 // SCK P0.13 - -#define VEXT_ENABLE 18 // powers the oled display and the lora antenna boost -#define VEXT_ON_VALUE 1 -#define BUTTON_PIN 0 - +#define PIN_SPI_MISO 10 // MISO +#define PIN_SPI_MOSI 11 // MOSI +#define PIN_SPI_SCK 9 // SCK + +// Power +#define VEXT_ENABLE 18 // Powers the E-Ink display, and the 3.3V supply to the I2C QuickLink connector +#define PERIPHERAL_WARMUP_MS 1000 // Make sure I2C QuickLink has stable power before continuing +#define VEXT_ON_VALUE HIGH #define ADC_CTRL 46 #define ADC_CTRL_ENABLED HIGH #define BATTERY_PIN 7 #define ADC_CHANNEL ADC1_GPIO7_CHANNEL -#define ADC_MULTIPLIER 4.9 * 1.03 // Voltage divider is roughly 1:1 -#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high +#define ADC_MULTIPLIER 4.9 * 1.03 +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 +// LoRa #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module #define LORA_RESET 12 #define LORA_DIO1 14 // SX1262 IRQ #define LORA_DIO2 13 // SX1262 BUSY -#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled #define LORA_SCK 9 #define LORA_MISO 11 From f9d79964ef5c1019b70c40914e01838bb35a3429 Mon Sep 17 00:00:00 2001 From: Mictronics Date: Sat, 20 Jul 2024 13:47:04 +0200 Subject: [PATCH 169/211] Remove duplicate code and fix error: #if with no expression (#4307) * Fix LED pinout for T-Echo board marked v1.0, date 2021-6-28 * Merge PR #420 * Fixed double and missing Default class. * Use correct format specifier and fixed typo. * Removed duplicate code. * Fix error: #if with no expression --------- Co-authored-by: Ben Meadors --- src/gps/GPS.cpp | 2 +- src/mesh/NodeDB.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 8eb7fef273..feeac84945 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -865,7 +865,7 @@ void GPS::writePinStandby(bool standby) // Determine the new value for the pin // Normally: active HIGH for awake -#if PIN_GPS_STANDBY_INVERTED +#ifdef PIN_GPS_STANDBY_INVERTED bool val = standby; #else bool val = !standby; diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 5678009c08..c0bed34371 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -432,7 +432,6 @@ void NodeDB::initModuleConfigIntervals() moduleConfig.telemetry.power_update_interval = 0; moduleConfig.neighbor_info.update_interval = 0; moduleConfig.paxcounter.paxcounter_update_interval = 0; - moduleConfig.neighbor_info.update_interval = 0; } void NodeDB::installDefaultChannels() From dadf9234e5ed7d9e21333608de1f5be9b2fbfeac Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 21 Jul 2024 07:09:10 -0500 Subject: [PATCH 170/211] Remove status topic (#4305) --- src/mesh/MeshTypes.h | 2 ++ src/mqtt/MQTT.cpp | 19 ++++++------------- src/mqtt/MQTT.h | 10 +++++----- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/mesh/MeshTypes.h b/src/mesh/MeshTypes.h index 5b2cbd1b12..c0919bf5d3 100644 --- a/src/mesh/MeshTypes.h +++ b/src/mesh/MeshTypes.h @@ -10,6 +10,8 @@ typedef uint32_t NodeNum; typedef uint32_t PacketId; // A packet sequence number #define NODENUM_BROADCAST UINT32_MAX +#define NODENUM_BROADCAST_NO_LORA \ + 1 // Reserved to only deliver packets over high speed (non-lora) transports, such as MQTT or BLE mesh (not yet implemented) #define ERRNO_OK 0 #define ERRNO_NO_INTERFACES 33 #define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index a64720c78c..50086e7a2b 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -188,12 +188,10 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) mqtt = this; if (*moduleConfig.mqtt.root) { - statusTopic = moduleConfig.mqtt.root + statusTopic; cryptTopic = moduleConfig.mqtt.root + cryptTopic; jsonTopic = moduleConfig.mqtt.root + jsonTopic; mapTopic = moduleConfig.mqtt.root + mapTopic; } else { - statusTopic = "msh" + statusTopic; cryptTopic = "msh" + cryptTopic; jsonTopic = "msh" + jsonTopic; mapTopic = "msh" + mapTopic; @@ -216,7 +214,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) enabled = true; runASAP = true; reconnectCount = 0; - publishStatus(); + publishNodeInfo(); } // preflightSleepObserver.observe(&preflightSleep); } else { @@ -281,7 +279,7 @@ void MQTT::reconnect() runASAP = true; reconnectCount = 0; - publishStatus(); + publishNodeInfo(); return; // Don't try to connect directly to the server } #if HAS_NETWORKING @@ -330,15 +328,14 @@ void MQTT::reconnect() LOG_INFO("Attempting to connect directly to MQTT server %s, port: %d, username: %s, password: %s\n", serverAddr, serverPort, mqttUsername, mqttPassword); - auto myStatus = (statusTopic + owner.id); - bool connected = pubSub.connect(owner.id, mqttUsername, mqttPassword, myStatus.c_str(), 1, true, "offline"); + bool connected = pubSub.connect(owner.id, mqttUsername, mqttPassword); if (connected) { LOG_INFO("MQTT connected\n"); enabled = true; // Start running background process again runASAP = true; reconnectCount = 0; - publishStatus(); + publishNodeInfo(); sendSubscriptions(); } else { #if HAS_WIFI && !defined(ARCH_PORTDUINO) @@ -437,14 +434,10 @@ int32_t MQTT::runOnce() return 30000; } -/// FIXME, include more information in the status text -void MQTT::publishStatus() +void MQTT::publishNodeInfo() { - auto myStatus = (statusTopic + owner.id); - bool ok = publish(myStatus.c_str(), "online", true); - LOG_INFO("published online=%d\n", ok); + // TODO: NodeInfo broadcast over MQTT only (NODENUM_BROADCAST_NO_LORA) } - void MQTT::publishQueuedMessages() { if (!mqttQueue.isEmpty()) { diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index 1ebba4afe9..d68f1b88d7 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -81,10 +81,9 @@ class MQTT : private concurrency::OSThread virtual int32_t runOnce() override; private: - std::string statusTopic = "/2/stat/"; // For "online"/"offline" message - std::string cryptTopic = "/2/e/"; // msh/2/e/CHANNELID/NODEID - std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID - std::string mapTopic = "/2/map/"; // For protobuf-encoded MapReport messages + std::string cryptTopic = "/2/e/"; // msh/2/e/CHANNELID/NODEID + std::string jsonTopic = "/2/json/"; // msh/2/json/CHANNELID/NODEID + std::string mapTopic = "/2/map/"; // For protobuf-encoded MapReport messages // For map reporting (only applies when enabled) const uint32_t default_map_position_precision = 14; // defaults to max. offset of ~1459m @@ -110,9 +109,10 @@ class MQTT : private concurrency::OSThread /// Called when a new publish arrives from the MQTT server std::string meshPacketToJson(meshtastic_MeshPacket *mp); - void publishStatus(); void publishQueuedMessages(); + void publishNodeInfo(); + // Check if we should report unencrypted information about our node for consumption by a map void perhapsReportToMap(); From fa6624548b5232efd7a2310ea26bd10635f309a1 Mon Sep 17 00:00:00 2001 From: Tavis Date: Sun, 21 Jul 2024 05:09:37 -0700 Subject: [PATCH 171/211] Serial Mode for Ecowitt WS85 weather station. (#4296) * protobufs * initial mods, not tested * manual telem packet creation, compiles. * add gust and lull computation * telem packet is getting fired off * new pb ? * pb and gust lull * need to set the variant type for it to work. * add gust and lull to mqtt json output. * parse bat voltage and cap voltage and send the larger of the two in telem packet also use the new ws85 serial mode (6). must set it with cli. : meshtastic --set serial.mode 6 * set hard coded average/transmit interval to 5 minutes. * proper direction averging with trig. * Update protobufs * sweep some crud * read in 512 bytes at a time and break and clear serial input if we got wind data * factor out sendTelemetry function * Revert "factor out sendTelemetry function" This reverts commit b61ba1a3c5d68ff881a5479f3f85452d7e9b7c8f. * Reapply "factor out sendTelemetry function" This reverts commit d0af9cfd7d141b28ce24a2c3853b2776f9fc456e. * update protobufs * put WS85 Serial2 is tcho and canaryone exclusion #ifdef * include GeoCoord.h so dr-dev will compile. * remove old TODO comment. * breakout WS85 serial operation to it's own function called processWXSerial() * canaryone and t-echo exclusion for Serial2 --------- Co-authored-by: Ben Meadors --- src/modules/SerialModule.cpp | 188 ++++++++++++++++++++++++++++++++++- src/modules/SerialModule.h | 2 + src/mqtt/MQTT.cpp | 4 +- 3 files changed, 191 insertions(+), 3 deletions(-) diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 96a99b13e3..4b8a4d2284 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -1,4 +1,5 @@ #include "SerialModule.h" +#include "GeoCoord.h" #include "MeshService.h" #include "NMEAWPL.h" #include "NodeDB.h" @@ -66,7 +67,7 @@ SerialModule::SerialModule() : StreamAPI(&Serial2), concurrency::OSThread("Seria static Print *serialPrint = &Serial2; #endif -char serialBytes[meshtastic_Constants_DATA_PAYLOAD_LEN]; +char serialBytes[512]; size_t serialPayloadSize; SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio") @@ -198,8 +199,12 @@ int32_t SerialModule::runOnce() } } } + #if !defined(TTGO_T_ECHO) && !defined(CANARYONE) - else { + else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) { + processWXSerial(); + + } else { while (Serial2.available()) { serialPayloadSize = Serial2.readBytes(serialBytes, meshtastic_Constants_DATA_PAYLOAD_LEN); serialModuleRadio->sendPayload(); @@ -213,6 +218,27 @@ int32_t SerialModule::runOnce() } } +/** + * Sends telemetry packet over the mesh network. + * + * @param m The telemetry data to be sent + * + * @return void + * + * @throws None + */ +void SerialModule::sendTelemetry(meshtastic_Telemetry m) +{ + meshtastic_MeshPacket *p = router->allocForSending(); + p->decoded.portnum = meshtastic_PortNum_TELEMETRY_APP; + p->decoded.payload.size = + pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_Telemetry_msg, &m); + p->to = NODENUM_BROADCAST; + p->decoded.want_response = false; + p->priority = meshtastic_MeshPacket_Priority_RELIABLE; + service.sendToMesh(p, RX_SRC_LOCAL, true); +} + /** * Allocates a new mesh packet for use as a reply to a received packet. * @@ -357,4 +383,162 @@ uint32_t SerialModule::getBaudRate() } return BAUD; } + +/** + * Process the received weather station serial data, extract wind, voltage, and temperature information, + * calculate averages and send telemetry data over the mesh network. + * + * @return void + */ +void SerialModule::processWXSerial() +{ +#if !defined(TTGO_T_ECHO) && !defined(CANARYONE) + static unsigned int lastAveraged = 0; + static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded. + static double dir_sum_sin = 0; + static double dir_sum_cos = 0; + static float velSum = 0; + static float gust = 0; + static float lull = -1; + static int velCount = 0; + static int dirCount = 0; + static char windDir[4] = "xxx"; // Assuming windDir is 3 characters long + null terminator + static char windVel[5] = "xx.x"; // Assuming windVel is 4 characters long + null terminator + static char windGust[5] = "xx.x"; // Assuming windGust is 4 characters long + null terminator + static char batVoltage[5] = "0.0V"; + static char capVoltage[5] = "0.0V"; + static float batVoltageF = 0; + static float capVoltageF = 0; + bool gotwind = false; + + while (Serial2.available()) { + // clear serialBytes buffer + memset(serialBytes, '\0', sizeof(serialBytes)); + // memset(formattedString, '\0', sizeof(formattedString)); + serialPayloadSize = Serial2.readBytes(serialBytes, 512); + // check for a strings we care about + // example output of serial data fields from the WS85 + // WindDir = 79 + // WindSpeed = 0.5 + // WindGust = 0.6 + // GXTS04Temp = 24.4 + if (serialPayloadSize > 0) { + // Define variables for line processing + int lineStart = 0; + int lineEnd = -1; + + // Process each byte in the received data + for (size_t i = 0; i < serialPayloadSize; i++) { + // go until we hit the end of line and then process the line + if (serialBytes[i] == '\n') { + lineEnd = i; + // Extract the current line + char line[meshtastic_Constants_DATA_PAYLOAD_LEN]; + memset(line, '\0', sizeof(line)); + memcpy(line, &serialBytes[lineStart], lineEnd - lineStart); + + if (strstr(line, "Wind") != NULL) // we have a wind line + { + gotwind = true; + // Find the positions of "=" signs in the line + char *windDirPos = strstr(line, "WindDir = "); + char *windSpeedPos = strstr(line, "WindSpeed = "); + char *windGustPos = strstr(line, "WindGust = "); + + if (windDirPos != NULL) { + // Extract data after "=" for WindDir + strcpy(windDir, windDirPos + 15); // Add 15 to skip "WindDir = " + double radians = toRadians(strtof(windDir, nullptr)); + dir_sum_sin += sin(radians); + dir_sum_cos += cos(radians); + dirCount++; + } else if (windSpeedPos != NULL) { + // Extract data after "=" for WindSpeed + strcpy(windVel, windSpeedPos + 15); // Add 15 to skip "WindSpeed = " + float newv = strtof(windVel, nullptr); + velSum += newv; + velCount++; + if (newv < lull || lull == -1) + lull = newv; + + } else if (windGustPos != NULL) { + strcpy(windGust, windGustPos + 15); // Add 15 to skip "WindSpeed = " + float newg = strtof(windGust, nullptr); + if (newg > gust) + gust = newg; + } + + // these are also voltage data we care about possibly + } else if (strstr(line, "BatVoltage") != NULL) { // we have a battVoltage line + char *batVoltagePos = strstr(line, "BatVoltage = "); + if (batVoltagePos != NULL) { + strcpy(batVoltage, batVoltagePos + 17); // 18 for ws 80, 17 for ws85 + batVoltageF = strtof(batVoltage, nullptr); + break; // last possible data we want so break + } + } else if (strstr(line, "CapVoltage") != NULL) { // we have a cappVoltage line + char *capVoltagePos = strstr(line, "CapVoltage = "); + if (capVoltagePos != NULL) { + strcpy(capVoltage, capVoltagePos + 17); // 18 for ws 80, 17 for ws85 + capVoltageF = strtof(capVoltage, nullptr); + } + } + + // Update lineStart for the next line + lineStart = lineEnd + 1; + } + } + break; + // clear the input buffer + while (Serial2.available() > 0) { + Serial2.read(); // Read and discard the bytes in the input buffer + } + } + } + if (gotwind) { + + LOG_INFO("WS85 : %i %.1fg%.1f %.1fv %.1fv\n", atoi(windDir), strtof(windVel, nullptr), strtof(windGust, nullptr), + batVoltageF, capVoltageF); + } + if (gotwind && millis() - lastAveraged > averageIntervalMillis) { + // calulate averages and send to the mesh + float velAvg = 1.0 * velSum / velCount; + + double avgSin = dir_sum_sin / dirCount; + double avgCos = dir_sum_cos / dirCount; + + double avgRadians = atan2(avgSin, avgCos); + float dirAvg = toDegrees(avgRadians); + + if (dirAvg < 0) { + dirAvg += 360.0; + } + lastAveraged = millis(); + + // make a telemetry packet with the data + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + m.which_variant = meshtastic_Telemetry_environment_metrics_tag; + m.variant.environment_metrics.wind_speed = velAvg; + m.variant.environment_metrics.wind_direction = dirAvg; + m.variant.environment_metrics.wind_gust = gust; + m.variant.environment_metrics.wind_lull = lull; + m.variant.environment_metrics.voltage = + capVoltageF > batVoltageF ? capVoltageF : batVoltageF; // send the larger of the two voltage values. + + LOG_INFO("WS85 Transmit speed=%fm/s, direction=%d , lull=%f, gust=%f, voltage=%f\n", + m.variant.environment_metrics.wind_speed, m.variant.environment_metrics.wind_direction, + m.variant.environment_metrics.wind_lull, m.variant.environment_metrics.wind_gust, + m.variant.environment_metrics.voltage); + + sendTelemetry(m); + + // reset counters and gust/lull + velSum = velCount = dirCount = 0; + dir_sum_sin = dir_sum_cos = 0; + gust = 0; + lull = -1; + } +#endif + return; +} #endif \ No newline at end of file diff --git a/src/modules/SerialModule.h b/src/modules/SerialModule.h index 18ad8a1bab..fa86db28f5 100644 --- a/src/modules/SerialModule.h +++ b/src/modules/SerialModule.h @@ -28,6 +28,8 @@ class SerialModule : public StreamAPI, private concurrency::OSThread private: uint32_t getBaudRate(); + void sendTelemetry(meshtastic_Telemetry m); + void processWXSerial(); }; extern SerialModule *serialModule; diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 50086e7a2b..5f7d6d9027 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -673,8 +673,10 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) msgPayload["lux"] = new JSONValue(decoded->variant.environment_metrics.lux); msgPayload["white_lux"] = new JSONValue(decoded->variant.environment_metrics.white_lux); msgPayload["iaq"] = new JSONValue((uint)decoded->variant.environment_metrics.iaq); - msgPayload["wind_speed"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_speed); + msgPayload["wind_speed"] = new JSONValue(decoded->variant.environment_metrics.wind_speed); msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction); + msgPayload["wind_gust"] = new JSONValue(decoded->variant.environment_metrics.wind_gust); + msgPayload["wind_lull"] = new JSONValue(decoded->variant.environment_metrics.wind_lull); } else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) { msgPayload["voltage_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_voltage); msgPayload["current_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_current); From 1123223058e1797860a0810afb52b824d8fda58b Mon Sep 17 00:00:00 2001 From: Lennart Buhl Date: Mon, 22 Jul 2024 13:58:24 +0200 Subject: [PATCH 172/211] Fix a typo in src/mesh/MeshService.h (#4314) --- src/mesh/MeshService.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index 3ac35bb627..ef92ba7d40 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -144,7 +144,7 @@ class MeshService /// returns 0 to allow further processing int onGPSChanged(const meshtastic::GPSStatus *arg); #endif - /// Handle a packet that just arrived from the radio. This method does _ReliableRouternot_ free the provided packet. If it + /// Handle a packet that just arrived from the radio. This method does _not_ free the provided packet. If it /// needs to keep the packet around it makes a copy int handleFromRadio(const meshtastic_MeshPacket *p); friend class RoutingModule; From bdd1c53072f8d4c425a04d832622c5bd21980690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 22 Jul 2024 15:30:36 +0200 Subject: [PATCH 173/211] Revert "Sync Wio lr1110 refresh with master (#4288)" This reverts commit 5cc8ca59a37d87943781caf655bb9df2d95a045b. Revert "Sync Wio lr1110 refresh with master (#4251)" This reverts commit d97e6b86b8bc9be3b24589795c7abac07140fb48. Revert "update SD_FLASH_SIZE to 0x27000 (#4232)" This reverts commit 2df8093fef22034d99df783e5ede1a1ca660a52d. --- .github/actions/setup-base/action.yml | 2 +- .github/workflows/build_native.yml | 2 +- .github/workflows/build_nrf52.yml | 1 - .github/workflows/build_raspbian.yml | 1 - .github/workflows/build_raspbian_armv7l.yml | 1 - .github/workflows/main_matrix.yml | 3 +- .trunk/trunk.yaml | 6 +- .vscode/settings.json | 5 +- arch/esp32/esp32.ini | 2 +- bin/build-nrf52.sh | 29 +- bin/mergehex | Bin 2102544 -> 0 bytes bin/s140_nrf52_7.3.0_softdevice.hex | 9726 ----------------- bin/setup-python-for-esp-debug.sh | 12 - bin/uf2conv.py | 223 +- boards/heltec_mesh_node_t114.json | 53 - boards/wio-sdk-wm1110.json | 2 +- boards/wio-tracker-wm1110.json | 2 +- boards/wiscore_rak4631.json | 2 +- platformio.ini | 10 +- pyocd.yaml | 7 - src/AccelerometerThread.h | 36 +- src/BluetoothCommon.cpp | 6 +- src/BluetoothCommon.h | 4 +- src/ButtonThread.cpp | 5 +- src/DebugConfiguration.cpp | 2 +- src/DebugConfiguration.h | 19 +- src/FSCommon.cpp | 52 - src/FSCommon.h | 2 - src/GPSStatus.h | 2 +- src/Power.cpp | 17 +- src/PowerFSM.cpp | 17 - src/PowerMon.cpp | 45 - src/PowerMon.h | 34 - src/RedirectablePrint.cpp | 280 +- src/RedirectablePrint.h | 23 +- src/SerialConsole.cpp | 36 +- src/SerialConsole.h | 10 +- src/commands.h | 6 +- src/configuration.h | 13 +- src/detect/ScanI2CTwoWire.cpp | 4 +- src/gps/GPS.cpp | 524 +- src/gps/GPS.h | 49 +- src/gps/GPSUpdateScheduling.cpp | 118 - src/gps/GPSUpdateScheduling.h | 29 - src/graphics/EInkDisplay2.cpp | 3 +- src/graphics/EInkDisplay2.h | 8 +- src/graphics/Screen.cpp | 610 +- src/graphics/Screen.h | 150 +- src/graphics/ScreenFonts.h | 8 +- src/main.cpp | 26 +- src/main.h | 2 - src/mesh/Default.h | 1 - src/mesh/FloodingRouter.cpp | 3 +- src/mesh/LR11x0Interface.cpp | 3 +- src/mesh/MeshModule.cpp | 15 +- src/mesh/MeshModule.h | 28 +- src/mesh/MeshService.cpp | 13 +- src/mesh/NodeDB.cpp | 18 +- src/mesh/NodeDB.h | 4 +- src/mesh/PhoneAPI.cpp | 51 +- src/mesh/PhoneAPI.h | 17 +- src/mesh/RF95Interface.cpp | 31 +- src/mesh/RadioInterface.cpp | 3 +- src/mesh/RadioLibInterface.cpp | 21 - src/mesh/RadioLibInterface.h | 13 +- src/mesh/Router.cpp | 6 +- src/mesh/SX126xInterface.cpp | 3 +- src/mesh/SX128xInterface.cpp | 3 +- src/mesh/StreamAPI.cpp | 23 +- src/mesh/StreamAPI.h | 5 +- src/mesh/eth/ethClient.cpp | 4 - src/mesh/generated/meshtastic/apponly.pb.h | 2 +- src/mesh/generated/meshtastic/config.pb.h | 24 +- src/mesh/generated/meshtastic/deviceonly.pb.h | 3 +- src/mesh/generated/meshtastic/localonly.pb.h | 4 +- src/mesh/generated/meshtastic/mesh.pb.cpp | 5 +- src/mesh/generated/meshtastic/mesh.pb.h | 44 +- .../generated/meshtastic/module_config.pb.h | 20 +- src/mesh/generated/meshtastic/portnums.pb.h | 2 - src/mesh/generated/meshtastic/powermon.pb.cpp | 17 - src/mesh/generated/meshtastic/powermon.pb.h | 138 - src/mesh/generated/meshtastic/telemetry.pb.h | 18 +- src/mesh/http/ContentHandler.cpp | 2 +- src/mesh/wifi/WiFiAPClient.cpp | 2 +- src/modules/AdminModule.cpp | 17 +- src/modules/AdminModule.h | 4 +- src/modules/CannedMessageModule.cpp | 49 +- src/modules/CannedMessageModule.h | 6 +- src/modules/Modules.cpp | 6 - src/modules/PositionModule.cpp | 4 +- src/modules/PowerStressModule.cpp | 77 - src/modules/PowerStressModule.h | 38 - src/modules/Telemetry/AirQualityTelemetry.cpp | 110 +- src/modules/Telemetry/AirQualityTelemetry.h | 5 - src/modules/Telemetry/DeviceTelemetry.cpp | 32 +- .../Telemetry/EnvironmentTelemetry.cpp | 122 +- src/modules/Telemetry/EnvironmentTelemetry.h | 5 - src/modules/Telemetry/PowerTelemetry.cpp | 85 +- src/modules/Telemetry/PowerTelemetry.h | 5 - .../Telemetry/Sensor/INA3221Sensor.cpp | 68 +- src/modules/Telemetry/Sensor/INA3221Sensor.h | 25 - src/modules/WaypointModule.cpp | 166 +- src/modules/WaypointModule.h | 14 +- src/modules/esp32/AudioModule.cpp | 6 +- src/modules/esp32/PaxcounterModule.cpp | 8 +- src/modules/esp32/StoreForwardModule.cpp | 4 +- src/mqtt/MQTT.cpp | 25 +- src/mqtt/MQTT.h | 6 +- src/nimble/NimbleBluetooth.cpp | 45 +- src/nimble/NimbleBluetooth.h | 1 - src/platform/esp32/architecture.h | 8 - src/platform/esp32/main-esp32.cpp | 29 +- src/platform/nrf52/NRF52Bluetooth.cpp | 113 +- src/platform/nrf52/NRF52Bluetooth.h | 2 +- src/platform/nrf52/main-nrf52.cpp | 52 +- src/platform/nrf52/softdevice/nrf_sdm.h | 2 +- src/shutdown.h | 2 +- src/sleep.cpp | 20 +- src/sleep.h | 2 + variants/heltec_capsule_sensor_v3/variant.h | 2 +- variants/heltec_mesh_node_t114/platformio.ini | 15 - variants/heltec_mesh_node_t114/variant.cpp | 44 - variants/heltec_mesh_node_t114/variant.h | 210 - .../heltec_vision_master_e213/pins_arduino.h | 63 - .../heltec_vision_master_e213/platformio.ini | 23 - variants/heltec_vision_master_e213/variant.h | 58 - .../heltec_vision_master_e290/pins_arduino.h | 61 - .../heltec_vision_master_e290/platformio.ini | 25 - variants/heltec_vision_master_e290/variant.h | 58 - .../heltec_vision_master_t190/pins_arduino.h | 61 - .../heltec_vision_master_t190/platformio.ini | 13 - variants/heltec_vision_master_t190/variant.h | 76 - variants/heltec_wireless_paper/pins_arduino.h | 13 +- variants/heltec_wireless_paper/variant.h | 28 +- .../heltec_wireless_paper_v1/pins_arduino.h | 8 +- variants/heltec_wireless_paper_v1/variant.h | 28 +- .../heltec_wireless_tracker/platformio.ini | 4 +- variants/rak4631/platformio.ini | 92 +- variants/tlora_t3s3_v1/platformio.ini | 2 +- variants/wio-sdk-wm1110/platformio.ini | 18 +- variants/wio-sdk-wm1110/softdevice/ble.h | 652 -- variants/wio-sdk-wm1110/softdevice/ble_err.h | 92 - variants/wio-sdk-wm1110/softdevice/ble_gap.h | 2895 ----- variants/wio-sdk-wm1110/softdevice/ble_gatt.h | 232 - .../wio-sdk-wm1110/softdevice/ble_gattc.h | 764 -- .../wio-sdk-wm1110/softdevice/ble_gatts.h | 904 -- variants/wio-sdk-wm1110/softdevice/ble_hci.h | 135 - .../wio-sdk-wm1110/softdevice/ble_l2cap.h | 495 - .../wio-sdk-wm1110/softdevice/ble_ranges.h | 149 - .../wio-sdk-wm1110/softdevice/ble_types.h | 217 - .../wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h | 259 - .../wio-sdk-wm1110/softdevice/nrf_error.h | 90 - .../wio-sdk-wm1110/softdevice/nrf_error_sdm.h | 73 - .../wio-sdk-wm1110/softdevice/nrf_error_soc.h | 85 - variants/wio-sdk-wm1110/softdevice/nrf_nvic.h | 449 - variants/wio-sdk-wm1110/softdevice/nrf_soc.h | 1046 -- variants/wio-sdk-wm1110/softdevice/nrf_svc.h | 98 - variants/wio-sdk-wm1110/variant.h | 2 - variants/wio-tracker-wm1110/platformio.ini | 3 +- variants/xiao_ble/platformio.ini | 2 +- version.properties | 2 +- 161 files changed, 1303 insertions(+), 22181 deletions(-) delete mode 100644 bin/mergehex delete mode 100644 bin/s140_nrf52_7.3.0_softdevice.hex delete mode 100644 bin/setup-python-for-esp-debug.sh delete mode 100644 boards/heltec_mesh_node_t114.json delete mode 100644 pyocd.yaml delete mode 100644 src/PowerMon.cpp delete mode 100644 src/PowerMon.h delete mode 100644 src/gps/GPSUpdateScheduling.cpp delete mode 100644 src/gps/GPSUpdateScheduling.h delete mode 100644 src/mesh/generated/meshtastic/powermon.pb.cpp delete mode 100644 src/mesh/generated/meshtastic/powermon.pb.h delete mode 100644 src/modules/PowerStressModule.cpp delete mode 100644 src/modules/PowerStressModule.h delete mode 100644 variants/heltec_mesh_node_t114/platformio.ini delete mode 100644 variants/heltec_mesh_node_t114/variant.cpp delete mode 100644 variants/heltec_mesh_node_t114/variant.h delete mode 100644 variants/heltec_vision_master_e213/pins_arduino.h delete mode 100644 variants/heltec_vision_master_e213/platformio.ini delete mode 100644 variants/heltec_vision_master_e213/variant.h delete mode 100644 variants/heltec_vision_master_e290/pins_arduino.h delete mode 100644 variants/heltec_vision_master_e290/platformio.ini delete mode 100644 variants/heltec_vision_master_e290/variant.h delete mode 100644 variants/heltec_vision_master_t190/pins_arduino.h delete mode 100644 variants/heltec_vision_master_t190/platformio.ini delete mode 100644 variants/heltec_vision_master_t190/variant.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_err.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gap.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gatt.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gattc.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_gatts.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_hci.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_l2cap.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_ranges.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/ble_types.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_nvic.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_soc.h delete mode 100644 variants/wio-sdk-wm1110/softdevice/nrf_svc.h diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml index 7f8659523b..b5b4cb6f30 100644 --- a/.github/actions/setup-base/action.yml +++ b/.github/actions/setup-base/action.yml @@ -14,7 +14,7 @@ runs: - name: Install dependencies shell: bash run: | - sudo apt-get -y update --fix-missing + sudo apt-get -y update sudo apt-get install -y cppcheck libbluetooth-dev libgpiod-dev libyaml-cpp-dev - name: Setup Python diff --git a/.github/workflows/build_native.yml b/.github/workflows/build_native.yml index 3e8b4c001c..8fe8e6c318 100644 --- a/.github/workflows/build_native.yml +++ b/.github/workflows/build_native.yml @@ -13,7 +13,7 @@ jobs: - name: Install libbluetooth shell: bash run: | - sudo apt-get update --fix-missing + sudo apt-get update sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code diff --git a/.github/workflows/build_nrf52.yml b/.github/workflows/build_nrf52.yml index ac509a096a..eb17799635 100644 --- a/.github/workflows/build_nrf52.yml +++ b/.github/workflows/build_nrf52.yml @@ -29,7 +29,6 @@ jobs: name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip overwrite: true path: | - release/*.hex release/*.uf2 release/*.elf release/*.zip diff --git a/.github/workflows/build_raspbian.yml b/.github/workflows/build_raspbian.yml index 1fd8fad307..697d08727f 100644 --- a/.github/workflows/build_raspbian.yml +++ b/.github/workflows/build_raspbian.yml @@ -13,7 +13,6 @@ jobs: - name: Install libbluetooth shell: bash run: | - apt-get update -y --fix-missing apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code diff --git a/.github/workflows/build_raspbian_armv7l.yml b/.github/workflows/build_raspbian_armv7l.yml index 39b297d1b1..ee5eb66ebb 100644 --- a/.github/workflows/build_raspbian_armv7l.yml +++ b/.github/workflows/build_raspbian_armv7l.yml @@ -13,7 +13,6 @@ jobs: - name: Install libbluetooth shell: bash run: | - apt-get update -y --fix-missing apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 14c8a9d10c..25a0fbad22 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -136,7 +136,7 @@ jobs: build-rpi2040, package-raspbian, package-raspbian-armv7l, - package-native, + package-native ] steps: - name: Checkout code @@ -168,7 +168,6 @@ jobs: path: | ./firmware-*.bin ./firmware-*.uf2 - ./firmware-*.hex ./firmware-*-ota.zip ./device-*.sh ./device-*.bat diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 2d9f608997..8a2f18ad5d 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -1,6 +1,6 @@ version: 0.1 cli: - version: 1.22.2 + version: 1.22.1 plugins: sources: - id: trunk @@ -31,10 +31,6 @@ lint: - gitleaks@8.18.2 - clang-format@16.0.3 - prettier@3.2.5 - ignore: - - linters: [ALL] - paths: - - bin/** runtimes: enabled: - python@3.10.8 diff --git a/.vscode/settings.json b/.vscode/settings.json index bf9b82111d..07e198f0a7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,8 +4,5 @@ "trunk.enableWindows": true, "files.insertFinalNewline": false, "files.trimFinalNewlines": false, - "cmake.configureOnOpen": false, - "[cpp]": { - "editor.defaultFormatter": "trunk.io" - } + "cmake.configureOnOpen": false } diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index 58c1302da8..f3eb0cbc03 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -44,7 +44,7 @@ lib_deps = ${networking_base.lib_deps} ${environmental_base.lib_deps} https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2 - h2zero/NimBLE-Arduino@^1.4.2 + h2zero/NimBLE-Arduino@^1.4.1 https://github.com/dbSuS/libpax.git#7bcd3fcab75037505be9b122ab2b24cc5176b587 https://github.com/lewisxhe/XPowersLib.git#84b7373faea3118b6c37954d52f98b8a337148d6 https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index cf4ca60cb2..a9980f486b 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -2,8 +2,8 @@ set -e -VERSION=$(bin/buildinfo.py long) -SHORT_VERSION=$(bin/buildinfo.py short) +VERSION=`bin/buildinfo.py long` +SHORT_VERSION=`bin/buildinfo.py short` OUTDIR=release/ @@ -11,7 +11,7 @@ rm -f $OUTDIR/firmware* rm -r $OUTDIR/* || true # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale -platformio pkg update +platformio pkg update echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS" rm -f .pio/build/$1/firmware.* @@ -23,27 +23,14 @@ basename=firmware-$1-$VERSION pio run --environment $1 # -v SRCELF=.pio/build/$1/firmware.elf -cp $SRCELF $OUTDIR/$basename.elf - -echo "Generating NRF52 dfu file" DFUPKG=.pio/build/$1/firmware.zip +cp $SRCELF $OUTDIR/$basename.elf cp $DFUPKG $OUTDIR/$basename-ota.zip echo "Generating NRF52 uf2 file" SRCHEX=.pio/build/$1/firmware.hex +bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 -# if WM1110 target, merge hex with softdevice 7.3.0 -if (echo $1 | grep -q "wio-sdk-wm1110"); then - echo "Merging with softdevice" - sudo chmod +x ./bin/mergehex - bin/mergehex -m bin/s140_nrf52_7.3.0_softdevice.hex $SRCHEX -o .pio/build/$1/$basename.hex - SRCHEX=.pio/build/$1/$basename.hex - bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 - cp $SRCHEX $OUTDIR - cp bin/*.uf2 $OUTDIR -else - bin/uf2conv.py $SRCHEX -c -o $OUTDIR/$basename.uf2 -f 0xADA52840 - cp bin/device-install.* $OUTDIR - cp bin/device-update.* $OUTDIR - cp bin/*.uf2 $OUTDIR -fi +cp bin/device-install.* $OUTDIR +cp bin/device-update.* $OUTDIR +cp bin/*.uf2 $OUTDIR diff --git a/bin/mergehex b/bin/mergehex deleted file mode 100644 index 2a93c571003f60f7d94e7a588acbc00285af9354..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2102544 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

$&*Qh7qS<%!@nUL*MI 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

jqWDRdU%3zsH=u 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�hF6bG}d+&NiOQLS&25sIl1%U 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

d zk3$G9{bB`mzl=C8;NBdEtdsFXwT%5_^vMv8VMxe-Y4X+z*G#y&*BGvZumfTgJ~X2S z0dp*@+a~&Zt5OY;F-JAdq+R~FE zYmCMH~ zV4nLmj6=jeaIT5 zzBGz%dfaLo?`~%HrRy1O0OwKsCJw@{KA%U6!+35lJl33o3)Bc z9A>hR97^*pcIG7HaUWstldwmaVXZldeN0^DUFRqythgBZUC!oP{W)>gkax{Oh(0yVzl+=l?`{N4?&eUME5JVE&*KR?9y_j2xyO-Vg< zUECmbQFI9%L4Wb-8Fj3|54Uk;y3d!1%|EmB_&!6F%pCJe7pv>u0P!@@4$tAYSx47O z9X%@$Y)REovDahx>&M@_#2=T`$K7x{;jR_}9W%;`epvEi+5B;>pXR;RHlZ}_?J6P> zdvJ=#;u87Qa0PYgd9bVeGfnyAUUGiwD!&U^)yP__rJM5m;o9ML3+KpV$6O~AsPT4X zD^+Rhi^wX$K0Iv6ihI3vbc}2K7whivV=|Qx`(AXU$Fm)OAGZ9trfI|SER%4xgd2a2 z;ZVsFC!FWP8FiAx$0b}ZT&aWG0as_^B+gxM?QpL}SCQ{|9sLU7NV2|!D}d{V)9(Bh zEP?BTW4fs?;VR&^!`a6QHExa4C#2^=6ky*8w6 zt?oO_wFT*A&Gnph_BDbM!c`M)k#KSDoi_Talo{RVug19VxZVmHE6unh zy&lSUPeX}FEYl&NIiCnh0PqM{bpG>aAFX?)y*^2+m#KRTh zua)?t#Q!+=#+_#T_VJaj!`SAwl_=4YxwIw|MVEYkWGS5o_36=8I^R!E>TSk zfqoRZo3$Mgxw%Xp8*q1R_gU5kCC@4eH$b?TxHt9DV{-EB6DegF2;Y(%Jr&}u`SsX~ zxH;A|e)fXbb8#U596BAT51q)1;C8>*h8p{NHtWe)0&5Vq-tVpE2MvS4*=oNx#t(D4 zvDxowAm})9c5agn;gE#HkK|* zSfQkpOijqIE~3hPBlf#%MxA@${E{)8j4w!;V`Z?~zc~x<{h_Nv$S<=d7fCvQrLX8k zuc0rd*ShcWZb;4J7H+9|9XE! z-(SIhrjq9Tp9P|pd(nYla*3>R%4sLur=;B<^}N?sSM~gtd6w^K3M4(z+T@r1s!8fg z&y3n7;r{#+%U+x%X>wa95__>1F)mrOPTPxNbnE%*j2aci%rrGvs%t$bi7$K~b0^Yl zw3+c)dqlcVuL{&l<(K+k&IheMhC=eHy_fNh=y{=AxZWJEvIpGcFGqzM!bR_={z|xt z%y6MVXO8bs$(U4(sWtuhF|610&8Y86TAa46Bh~ho*)}PQorK#>xZ|xhXiuMa(iZND zWFpNnOb~AJ!Pg$&Dhz7lL$5u)C}mau@QfOfvN-)YUG~;~8EeZjH}A~x{=}X&YjmCI zBivH|jKWe<*UWI%dWKt_k@@tW-Rn%1E~7=M&)=9)c_MF?n&`-D(ZhGxvNB?{McMLK zMxKSgIisFp?bP_88Fs&Gyu&%ZqxQ4LD}6{iG6#3CE-CqP`!annkl6j_DZ>qxsmH&R z`QV!wCwqY;37yW;YKFO{M|Ds0=VG5p}QSG^e`SXu6#tn{f@W#Msj_*46d`#&vg3Oxd zEIpnyWv2Io$wwDGJmh1=Pv|ElKkhjQJ=hm|`~dk;i_HEpOOM+RtcR3m2LsctpU|9 z9!vHbj`jBf)D`^?yK;|u3^ZPRmR4ns4I)9>3u)RS1Z~V^9#Q6HuY1`%Vx6B|^JR+; zsjs{kw(drf) zHf9VzWYJ3I8DqyXzWnWs`Z)JyU9ydlS>v%PknVS+Pd0-1uboj}lzpp8bk=n!yh;=`wNH$12H$m)+a7F6T;Q zP9w8*hII!i=RfnXJ^5fi$DrrB+R~muc1k0n-k76gZDU17*>TKw=B>Tz=S>+_J0vgT z#wOWEF~|H2Axo|d1g}lXNR4TmiRS9+gxEefPbJ`JN!e37*( zvEP@O`dDLRJvOLvj*%z5zOh`_GEC`La6ENzA7^t?`Z?Nf+9t5p=vyr&A#*aY&M$4T z9$9fUqxNxcYm1w8zy3_BE$aN0w%AEMiFjt!EmU4(gcmF5x|+4zHwHR=a_q;YN^aC+ zok`-)qivrkX`w9b{o&QA=r{Pi&!&FJuwSpy7g0_%{#lhrSmSC_mkb-O2W`)p1~ye) z%(bKl;e&Zr_%mKxc`*Zgz~7a?5P>#T53AAGnj!i^J7 zr|%y3aL)8epD{w`({$9Vs!O%otnFqq)4p-nW=l^lcBSwH#^nXG>IQ>6KGxLXF4-H) z=*KNP#d(IEVt+FYfwsS*Ulf_!3uo2uS0HodDV>koWN*@b&PUr$eLQ02ip=Fcy)PxQ z29Z_!7E9JMNm*6dWcjkmlC&D++tS-+)k@K;+mv;e7g^cT%7cLC$=RqZX=NDhse32= zSIMkx-JUf>>&&6V*+QICxNoAzH`XQNbSp0_e;IrAxf@!YCt^FL{3qWztF9J%wIV4~ z+iun*wi+4ZnARL!2{Okq8}+=i=p6_xomDT3yq8!>)3#Wzzc}Wd*0`bGSK+SWdVf8l zqR8uf_pHj1{`X;1Ud9+!m%pqwv+qWBnB8xc-`YA$F(E$#xn(P0)mrCK;;1N_RWC>! zHzsv<vlKPl5~PH43) z+Vd~=W4lCV33-&hi zetLc=GMl76MP}7!rMzD`2$_`kf%0)DGRqrg)r{EhUnFJjKOZ03kNp-s3(3c^E3C9X zkd(Qf@;->PN0GVx+F3O(X}|LzWFACaA4X>6M(Vnxy)!BEf1mae(q3>9>#4C>^;_<3 zV|Mm*K9m|HOJkFKs(cUQ)LUoO8zoIAnek`XbUEqiWj|=yx>%;n=(I<6`E0B?h~{Ud~%{OqhMm-e*#i38Qwje%b8ZLYS78Gx?;WwfU| zXVs;LA@7N#y!2ei(Vyy>i${Q9OTT1 zbIGB~FKZgLr%-+`bIw}?TW8brxsAft@0wk9ma`Qu0>?J6zQkXbgtu{QVR-uCn&FNY zUtu|yTdPmJi`!1zI$YdpaGNAek?vWwPR3bBlP1U7PI?`|8pHJF_-=OZU$UJ^{=lp0 z{O-+mhX32=TYKLR{g=*fspl~=DE~{d>Z{xvUxe55Q^v#AIyMKlyqxh{HcuOo6YmoD#wljJ?rRYGc?{OOyf3=eYUY~~ z&mxOg`N??ZAJ^%VypK>Wqr{`vuzm-hHSeu>uy>!z)*&I!rLI3co=*GrY-{i;auhX)xmYaT_uEG zXQGYU&-O7c@UAw8u&HGOYM8G7gxy8hBPA@C*yMgH%oyDJxi?NA9mtH!GdTKOXGHHW z@Yt3oh`U_2`tg-l(s>k=+972oGKa~R4WRMcL7gwc<&!T1$#{MSpCulV5#{gMq>M*R z8TD|r$mmDLBitJgm@@43D{VJ*xvytGxzRO)!<@f!8Jmlqa@o@O_%G6FtaMvrZA8zj z31b{%>RHWw;(heT=s6?8^xQ_dWzLu1;_#47s{?}#|)y3+klm0jqYxyg~ zX$pTO_;b`nP62FT&#}_G$+R)%R0|y>Od*js5at?7wzck+3PabOUL7S2QFy|H=_Sl# z%fqmantDd8o+Gu(7FG%BslOiL-^&-()F7@Ci5KG-_PA+KA(6#adAnVoIw9F zbV%-}yTo6XJhh&(LF@e-_O~y6o8!C^^0p6Ibu!NMo9VH)X-EF@44>EcsLTa2=RbOV z)y0?dX9VJKK!z;yG72VwE5&H zg>?dphlGe+{MX|@4;jtk|5Nza_LSTfyWMnSYCJ82iy(gFvg!J}pQiJq$!@z#(f1+z z8mF52N?aqv6(p|D34h|UxWwkLgi>gp@xW$Dx|{gBBPnNPT229-OiNOZ`i@;^S2=^o z*`1X03jVpI{zX1O|35sNdd7FFJcHrv1KCfK>c*(Yv_I8y=9(sws*t9veqZ(; z)M@_T>o|yx|Dq4nI@YIk^qj%^%Qt4#qbVKfL!3I^k*Q-4{}qJorA$s@?q{AoVv6Vs zllAhHT$R5Jx*k76jLmDfH`@v&Eo~*pIcBMj_zc<3RJP!)i?SXk%su3!@zi5p&jqPx zRo(h#X?GuSn{;i^r<`A^4%FL61X<3AVfCAcJHL|sD)Qqw=|j#+JvZd2XI39l<2zsK zS?C#-51-{h3AV~Rz2Uy1z zoBQxG-Q4q}HHQPrE{P8LeLqN#?I}mnXSR5~_b2u!NV$Iu`~Ft$jf;qjOLXW%hr&l^ z)rjQJrYt(x)6|(G&6N?n<9s4IMBOt^uc3<#mCI&-FBwVO-_C6FiOHyq*#Epr`eN^| zvIrAfW2_~AsV_$`k8|3YblubQW4#`6!b;cN)#D~<=e4V8zrUGPXS^QSFMcb-c4f%i zzQXsT{j3{Ge)gl|&cDtsd**Wp&XYfvT01D@=O|nroO7K(WK820boiHrk5U)^k}pNL zRpK_xy=lKGFRTC3X9eV8I?kk*gl*jw$2?)|9heM5^!PZ6ynNE|l*psZ>}LPvZY)+#5f@KYH5t|79=} zcdW074Je?TI*y!EPe?fVsE;1w(Jz`~JT{E1j>{V3h45eax;b60#?49psWBllmbCw7 zWHzs-Jn?^n*nxE4mbRy9JFqe9+4Ob(3*1cHx@4cXY!+;e;iu8l^N(3oYLKp}Z`jvk zsKNIALEXQdB^BwT?(H($TG&ZHURIaf->32Wv-YTGWxeS>%cts2H)+7AE4lqjL=ntuha$5Gnu z>il-h^Q!{GD}3K`PqVgfE`7uYo=vBDc!hnaLHwed)Wx4M_F^5zV|*vATa0?pt7g>~ zSHPcO)=&GKDy^HfPc>}#u6EzI$aZ$|Yd^B-mTfIKaN!=cN_6{2TDQU~`dwpA{Z({( z|1#b57%XkWbzNb@ex>hd_k7E?PQAje+sZ8Y_E2PxwlT)h=)e`^Z^s7a8?@^umyJ6& zV`pSExlZq0jiY~iA#MK{^p~)Xa?jA8b@nRJpSG7VY9LOr!KE9q->c@-H@Fvh)_gj> zzCl3dbiPnr5@yDt6J2>P|Y zZ%)0-vdQ+k#Pj`ec}J1;eiwNkjjz*vETqdz+D;MqTz}e}Dij?LOX}#>cC7k2XPr^t z*>p!9>is{_v1t?eSTU#Wk;PJ7COXafojHy&k$IQzC8_V3Y1Z~fE89bBl0J{c_JV z^|R|z1Sk60bt!}EamWk7IrXc9bLtm`bL!U$=hUwY&Z%ENoHPH1;6y)r+D73d|Loip zT#JKSf@^kgd7G)9aCx@855h$q+$y+6N7!n(28X{0T)o3z6I{f>wZqjpxNf*wxHsB# z8L;HpxnVfb&(4j(In%ov&Y9i>oTS&DSNUg|^6XqOoTS$tM>(9xvvXlMDGxhW4=3eo z=bGW9zSy}AxIPEh1GnA5ZHF6ja6934Ik<7SF$XsdHwkA?n{4z>IJg41aR*ld=ag3g zC-Us+sDYbya1C%v4tXtbiw-UhH|OAbEqQjGcfjp-#IehgXV+x{&eOhJzd5)(2WOnk z_|?G`!WBEXQn)e)R|!|);A-Kj9b6+^t%Hlf)x!mBb-WWUV&jT&>w~Ls4^B1DAnH;%tGB9Fak^ZkP6 zv$f*hfP3y|vb(qAUcSuzQdY0e(a+{e_&(elv$*Huz7zLu+z;noF5$-Ex@?^EZPRd_ zaBIbr-b4R*Y7ag4T;ybNE5>aJHyHz&;ciTYtHiBzOQu^XUL&}5o@YK6Bjb7d84ejL z_1U(zMdvvF%aHX3iHA$LUbqSew*#&kPSPZo_}c|n>+m-LSMT8F;Gz!BsKs77r3)k=98sT<0gPxR8U3!qqsqR=5b9J>D+3Mu)$CxMn!J zeH(&nb#S9_aR)aA*X`hz;QHX~@#cMq{>I@i2sh;5R>AFZaMf^Q4lV*W3HJtFOU-)P z1UK#A+ToTQTsNH2u{`VmT)u-FhAVP#V{j!7Za3U22bX}Wba46S)5INIFENc}Mjf1|j{e`l6~OIw za3yey4z2>ubNgKC{efbKYT)v0ob+D}aD{M8RjmGIqx4_Ax9Gw^A#)5~<*V1(;`pn? z-_OKfdVa~-?Jb7b%Ldk}Z2M$7%rIf5Uqcv%{+>m`bl)+j{IdQ;JQ;iKM8^Bf?lxCi zQtO8yzr3=5otqTHtWMG#x`6s|=kk20gKL0$GwyPUzbIUj!(S_0%)xcRbvVNI!*w~h zA-G-#Hwri4;HKaP9o!P!PPjK|?M(ghE~I`qxFFnwgIfi++rd@CEjqXeoF~3KjwZM~ z2iFc)2xrf$Zn$CxHvm`W;D+HU9P-BCsvX>JxLQZp1YEs?%fEfw4ETr*rhoU{$Oq;7P;?Sy-aX3RbL9=K6BrfT+fQxgbYlxjCEIPJvW68_Tf z6Vht{>Gf27mP@Zu$h#}P>$-cf&M$|&SkZT^T!iI?5H36`2GW))BecJ*>A3BC+oX%-9&J;>xWZ#$P{n%T07m$8Oaiu)|=DN@4i6LtO zS=+xbr#Rtgtu^hZUex$r@4g(SAIL7xT+-q(n{o{>t&Ej&fwDwSlmUgx&q6 zIrVBPU$U<0QI0-OwtVrv;+lT_9ERk7dpzs)E_!Ce=FZHy%p7H$G=2THC5BFP7zwBC1S+!q< ztafB|Jiz=-%2Mw&=`#|nD|;VF?HyJ7FG$@}j-ta5;p+R+w#UBS>sU+O?|am0kd;eb zwLdtgj%7{VIPDA8dO3Su*89vI^7L~!XS=VZ>hoQqU*r<>8~D%l6Fb|FtoCotsoPkK zwyhgGY`k?YgSG9i$XdDE2>^midY4FVU)7v?4+|^CeO*?1-PYf&wQZj7xbP5HnR@+Q z=DTv)_EnD`NbkM$W;@SzY}Fn$N4XpCLkBL=t*f5;RYShP7#AgVOSjRCvS?l5`;&X) z$#$;c_HU$hYt6Q2^@-{|>L$_ckhE@PltbP*bLwi@6F4DLxAdNsE(`W83}3f-9ug(Ke}7zo7A_F%b0I{YwrK#x%$FODTnQI>g8PGxQaORUPb!+ zm7~84$#ZGP%DD*oK*tC|*N;NojDoM;il^D}DbAxYlufM#rU&uYM$5 zR+HKG@IF92`kU0FGty<%@=<;dt1L!5T>vOJJ(bJR=d?&JUpPp0CaBo}BlhYYD zVKaFz9NU77u*B~ieh2WY=UCd->a|4i%ddA&Vbn|+qN{tfyVm+MiQ)@=&is-I=; zMB40C`_oO^y0c`TY^$`{4HjaxnTZ@(P3 zmzJO7>4qzSJ6=55p7+V;=MLPucg>~Vch8X4vx{==gL{s9mXw z>bvXS@l_~Cub&#kv&$)Y*GJf;=digVj5Zwi^5zQmxg{@#aSQ*1F^;%#2{#5;4QF2u z-VGOm)A?!nOTg7Txcn=akHd-1a#iwI4A&3$iV!+}@-_Lct@Nqlb^dyDgu?R)ypl1j z*V1`Cqt>Yr8KLKw&xK=fH8!pq@tu@y1nze3je<_EXS0+e{qpiNsrudL>z-jf@?-GA*hcT z_JIkg_dAYEpjHsfvy*>?lxs+A3-8Ih%eyf(XV&8sJ!jT++52;IPRY2LJSMNHADkqE zWb$t(H~3d)l8j_(h+-A_)`9+;-$}Z^6Stoua~qFW1$qzlz2nWUEhXF7`G0!T_O$XB3|{|GWY1W%D=l6Lbf1N(zZrBHM>~-`YgX={Xwr+S@V<{?~hz-D6fX%K(CAO=e4mlsblKG|sw|bXeAKS#i*zJ@-x!dqv`lxPXh2DLTvg*AZfyOffO_4z3>Oj4Iz`;!} zk4!h76==FZ`yvi03lDjeD6`7q=GzatEXoPDc#>5X7n|X-l|>8DG+sx&ICI2n87 zeVpYYICtfZJ^H=TOs;&<7el4=hbc8%N6Et0IuwP^Qwz+ys4k#xemR~ZRyvW;~UDB ziI%(s@>)-yS3gh5OWR33k59LcketQ)sk=NqH7Q z=~`1{(LwTZ34Lle&MW=)1Iov4e=wJAD>kw6xt0VwMjbLfTSoEzY)M~rGvyV|p1v~t zMDbI7sPn8Sv2Ww8mi*@89TGEl5BXBzMU5<2# zy@?^CGeSRZ$*`~AI@ZzTT|E~{^K-N7L1gVhR>Oz0+Z2g!8b383nODEE>YqKn^m>-I zA3T%q%W;oylRt#4a`JtueqMb7-Ho<3-B#`U$c$&KZ<#Xu%VBAy%(0Wf-f<0bT9H$9 z*}S?;+I)>EXFqyzKL7Q;8{O>?EylFtV>hB-bY6Xy-_mBR=VbJE&eD3xgQxbbl`8)& z%L#2Kg5+5YSyj2{H~wkMCh57NUYB#&NfP^d@5Qd=v`#;p*VKZ%=6ThV(hd7&|Nbil z%-;K@C}$s=t@rbiRy!f(IfSfHWN|Xv>JQR-rPqjcTc#!Xj&?84kYCnMa_Jmb-8iql zVATz~J=9}U**Sg0)GD<;vChw!OVmm+)&AxbLn~*{$~aMUZA5-^%e?x!EL1S>$SC7< z-$faFy@+wC>+Ahu4|X7H{I+@ZKJGo|NZ(4&$*sgQidzD=Z!NFm?qy}p>)o1^F8iXJ zvDcr%?xgaB{I#zqiP3&0m0oi;B`Y5eN)D?_pA$vi@Tce1sj@J0pgfqQzm>i%Q#(Cp zlC~q|zx^(35aUgwx7Dhf=`n$$O|uri!gq@MnxpQ+MP@$vH*oj7I$LDkn3SpOReElR zPS&&0yxD1m?|%0_Sg-Gk%m!o*-ZQW6Cf&ySk}}i#W$C)AZBInraR`h)r<(!!B-FTvhYR$LN*Z6%GKz!sx!b^Lrq#P!m zn^#wejN47Uw#hfZt$kK)Z&`P3Td5zvkO{7{C(vaovf{|{ylBa~^nkJ+aFLa&$K%K< zetBL^tVFN(C-W;kzD?J;Dzlte2Pl+s%G~Ie=BwLp=_hG#q37reB#w%?OkrT)- zTVTE*Hdpt9q~HFoRqBhpQ>E1_Pt`e#g)ho1dIKG-p?C6bgbuzX-s<(eF3Fs2F_MlD zla$7P&a02ENTwrgFRGpIpGL?g_x_s*UrLJKWQo`7CVjWEwlY7b){`#d&Reaq2J6dP zebqjJo z(u$6I=ha!PRi|{!sW*Gv17K{d4*9yH{Q|!MH3nq;P#7 z&U5i}9*r8dy_y2#m+`j|9hgpfjOT9A`IFE6^rx6lp+gDxa!Gl5TIomOUKacHP5e6A z;l|W+bGkhB=WDVoPUvQeUq?=4w8uVqcWNkHj6rU+|yo$)KTeZf4x+ z{@bccj0wKz-gZ)Z>0R&lc-}$1y&w6;yO1gGU34*OVkm?7@w8DN{ynd*MOT?CdU-7e zeUA5IfIPG(ev0ukn3&h;kv^i$duAZWv`xAv=}g2=HGYhJ+2u%{NAXjm=G8+Im+ot@ z6Y`DOGI<}CH3?)CFKwb5zhj;S#aRGdms8`>&KzGUd0_vZium7!|5{@~ed!?mFX4aZ zAqOYF4EZJP*g5~f`Nz9n!-)`PIIxgfAI^twf*XN5Mm%u|*A6!h_YTdNTsPbz+#77% z0G#KDh14Eih@Zo7MR1RZKmCns#(y%eE|aZqbNVT-)G1u6N8?q`jL6<5FM*5V`V8EN z`CYkO7FFAkGcIzpP0(u-%$eE@z85T#&XZLH?^S_9qR|^YqI)IbO7j<%oujRVD~HqL zbNqdYKDau#x7fHrOP<}|h$YX?OMVJuYsR#_QMg|G{Y$uX9y5Px zGp;wQG>@Bx{PMy8mi4cZdy&~E@{e3d*)0h!aSXw?!siLWCEO@n4DM*nkOpuHt^-cj zIohC{o|I8TNr<4`Z4m>zUQsU%8FARf8F?9gc#(LjGtuL?MP%0@``a$E^;}n8inkh3_K>V7G6lCY5?b#whdQu7$V=AkBp-nv zcHx`h2OYe$~To?*D`KZ=4#$cP4&~ zvyjOpeZ!QLcfo>sQTR>pjNSD&(e?Mum(6U8_1Wp)CRe2B(JC7IdQdr zxYOggoV1)O?zDf&btxy28^o>E#Z7do!0lcaHxVOsDS~??IvpwmSCGFZxC*#ygwVF; z8kAY*XPBy0Du(XDPX~TJCw@}v*O%jCgP+f3;oEF?L-_N&!LsA{6RRd=Fb1Cs|9UHY z7+&<5hR=szAv~9Go;daj&fW$J;0odL#GOn0mB1C)ILVs|IFaYHb>dcM`FFaBtY+Lq zeo_zd-?1P6eJ=h7_v3%e;a}q1ZTU}@g>VTtXMW^wHS;6sPx7-EPV)1u+)H_|*QWEi z0$#$~`7*rJ!b|#M;$OEl{a#Yt&q>e1ctR|)IXI#I2JzNGmGO&)a{LdTwaZX zfs+*wv%CS?!UQpkYK*a3*D3TakN_ymS z$O$Ip_-t~j@fY02d=EJc7j;@Pp6`&pf+s{AQx>MA%e#saf=7`REL>2nB8&4fY$eH; zeffW;p9NnMS{2BJ7hUG~i@h_QrgDA{5Wb%93*1Y-TIbtHojf1Lo|R;7SB5US&y(^m ze&d3AfJ$fFa&5*uC%qn`*WhH{>YZWcz_gk!(S9;ytsavM20WhMyLQL^eqeOY~kN;#*?uxV9nK=@FV3hL_cvKvbIZ@qfJ>-raj1NMV3BGcMQB~oAenS z2`A6@9!(x;9sFjveE6}uu(yPJ2lsLbw;Qe)QVI;%5jMQWs5o>19#f ztn)*-&Ed8|-1K-skCAkJ(D{RV@U07~!3w*DQmWv75xxa}PJZ}@?FFyamyuK3)~`{*4^Ub zaAm=?EtYcVg{y#b+EHC^aI3`aDEuWakv#@q4WBG);daA?;PNbwB0FJ)KUp~Pzs<|| zkz|UST#hv2Zr0ZzZeu6xQ74Kg>k@s!pEvbCG)aO|4;nh@KZslAFUGY|-FI_5PiLrv z>tiwI+sHdo+&_Xlm*~)gynMnPFN9eKv5cnMAa2DjZaV$AmE)G|(?r&8I7z=VAM0^5 z?l$vF*4LySS?iGQdnWbzi_MuI%&GRXa^PYv!sb49BXO)ccES9rsM1(@|u+pHeKv=ZiA)Nb)B0=UMKRB{jTJdeEd2NcZl3` z30DBuVdEtKO5obzocSl^7qa}H#J%Sd-aSkMm2pgjJl{^3capEh-B(&`ZM3!2K5?0@ zAMN;i=J-8|VH$g>_!IkRnD6lyefp5!eVjEn=eKZ!a1C!;K3^SytA|V0aj_Yba1ppq zac`SbXd7Y8b;{%g;LG|iUL)%4zg7{v^b52{WL;&+vcJ#4%g3{=9(^s{n00H;dm9Kh zPPp@3!f~F*@{8R|u2SGn(%3^dPjNau!fl63APW3AlHd)1h7Qjti z#4<$j9=#@`!|_19)P)Jcc}`qVtb+0lRl;Fg+{YrQ{K?E+136G2c_o)^K6vI0>A7d6 zZQDTG>@xg*o-{~ZH7+;PAmPLOMalEI_bljdGa2Wa`eb}(jxk*7z0;JxoMOt{LNebw zT|?V`FL5E3?|7JTNjzf^<0mhux3Ly#oRN%2?|o^TuE%=mc-C{=k`ur#(J;}H{2jYN zY|S2Zi^OwuI-ZJqum`6us0$>Xw~W-@nMvw!4myZ^GQMo;AbHjN zWy-H&L4AOG&vk)($@31lDL6eIWP!QO%flq>F33uggz3k<-~(wJRs%Ogy~v0AlceP= zGc6hIo5s_&(mcsWr$-}T;=~9#?7z-TUy5qr{!%yFcMW~KEUM@|iTz8y3^Yw9U^njr4p$^})& zyTe;?s$IrW@O@@XhSJ)w*d%{MU2_=KPQD(N}j8XK{8BX901 zf?tAfhW{w{V&6DHb)jDG=Vuvzh2+^z-2a<<<55$`W#heDQvWW zB;I1$Qi3v(F`IFW8E>Q9lNT))uwE!@Bf?YWb~~M38?nyC*88StYc3-ko(cH2tAjK} zt%HZYU>qI3CGr0DQe7`ZhYoZo`0#@IgS0#053Iv4-F4u-6f$Vc9Db#AU_IO8CI7V! z51TsZG9mw4FI~{z;4y?phjgFn?MZd2l(^()^h)d;a>SMxThelBkyCh?)i>YZl#|&v z??6sjQqJbIoF3$OkTWLoKj@T`sZRnqOXRKA=gnz3Q^@H~>T|eLPNqH~COE@MIe)lB zmr)Hml=hN8$hlAI$t&;&Dx=mM-wEz#<78;5^RR$&Zy>G*C5_)t$JI?-I~uLHg#SN? ztChIEnvClnGcIZC#@Db%S1+jN(aUpBc~KOT6gb(b(eZO z%wHra>(}+Ve0BZ5pZR4{rx)Ot)&ESLqF0j_NjVRia>Vx6_Mt0sF6Q3s(|H&+*R*?0 z#4&-}X*d}-?LQ8Y)r+j@EV71>Rd%f<>$C&QnnqS7{_Bxz>81DaCGEKnu)dL$_0Ny& zH|@HAqr!G&kyVSV@uaNB_b*HOqIP8M#(zKd-JHM6x7K(8CO^eC_93t3I?F!aXv+Kl zWuJQ~r~0>8w(O};eKe`xwQ2qOkUN;v?;}aMdJN|}*E5*7RVMX& zpD9P|_cU^Pk)!SR38tL=)}w>4-(%FxsW)5p`;c^8bq_IbZnfeP{y_ERAmXZ|{NF;l zNQTGw)5W^{B;R)uSMHVt^^YV^T+8hDeJT50<(GP4+H%=O)%9X@g_-Ztu8pTnxl%8R z9>yLb_e9|zgFisMh<%)~W-{MzPwUr!obIH4H<@x?i+)Xvr5DL#t>3w6{f3ZR`B_W9 zwFlO(=z8)BIlA5+lh)7Zr~V`7406=)C-q~_V?S>qduz0>W$UEuOiF(eT*Ddya!-|f z`tL}pT}6eptaMg6 z^~+3WANq|WN0-Cf(sJU+@!V;p^C+jB%ydp8r#C6*FBj>2mpU@`4f+%GIfr|zpJTpl z_P=w)QA!-T|9y%u%gSVV93m??K%K_Fo2-hjV~>-vZri`CFtVb^>cszq^mD}PZhJP! zd361KhPS&9@b!MUl;;rf2e&5ctr@>-d1k4%<000gk4e_s3w8d9+ye41_pSwVUGcZ@ zI*&M4n0!YCi;`B~Qte-xx=-1Yynx5E8M(Tj*&?>25%7`RA;3=O*Q5PxnsNLF35L>7Kkmmy6sFe2el%&Y|4P736Oit_Y5$Fl!xO z)|ytEXZOxB*CM9y(~X}ur2OdNs9sm|Jjy-`Zbyq7m(=+Jxc)5u%WxZT_z%GiX7OK- z+mOS5Gu*B${yT9Sarp0p8+Y*^MAu>5CUDzt`teiu`7G(*F8g$j^usk~@n42p)Zsq_ z*OJA5J#I0F|7N%j7ynXMIw`9-Zl`l^OrLMJPn^Z&;Fh&pCJR5(XUyG18!oi!%1-=q zNg0k4M>}%fECl_1oA-P%f!b}+ir>vG|1mRuH@8yUI$dOn-qqxBS5oiLf%TT>nRXp* z>0Ol8yK_JB4`hj7(z^>ciQlPrK5kREb>p^~d%1*Lf*W&idEdtEZfkyI`3u5D9Na3n zez=GT;}Ut*aElHu0$16!pp-5Z(_a%@={=m~Wy~d)lwmtuby_{%YY`9R3>N+8zF4aIFr1op5ouCuEGkC3)HhSN_%I+#uZ4 zeQCQT{zl;D9NZ*a!oe-V<@PQQoBLhrqJt}f3p%(mxKalff-84$b#NgE7lo^_anf#E z;UaLljPzcK**A$>4{r5Y+y-%L$l^AJTVoctIozUI-15Fh`DSq|!L2!qTL`z7EN=C< z#j?1?aBFpOld|l_tsOUezdQifnZ^Gu+`1h8C*XRs_+P@U&*4As``DK({!4J%f!hjO zy{r)bUt3VWLtnXc`-h9)zo33#QhL9q0j~Uk1%=7C#wd(^`<2ZW4ggzz8EKZ|K7`*n{EmoU#;Dd9(0;b1#=FHamtpN%!Y&cEz0caC(_zzR z=k&Rl4QO{oX4oKMR}B)Lu;)u&=)RSgeESY(v@Qv$_E$pJ;b+xDoLLY*$hW_H82Q$o zoqT?GFmn%y)!`t)dXUli@Phg&_hvjY3FTG7W;C8k=wbYX`xn$H2aMM=qg+)lVp2vKe3zMQuxUTn^}ZbEV%j*P zTIu}@XMZ{QMVYgj%#K8mFztjH{6>1ew2d%j@&*7&CwU?Dq8~q@fd%uOY1&St>JTqO zwCV-&#P1k>cj5O(+)KV$&lSi!$*to?rd&z8=fAKA-&`=?G0#s)LjhbrT#1#Z_I)p@ zv`^a4FH@f+Of_NpzIE{FE+R~fFr$wysNZuh=c?Ph-uqeiT<^awkSn_N;NH8PyRdm5R()?l{fc{CA9*}p-YpU4=S~Ta z+a@Wm^m%iu&Xve6ZIHKYB-htnCwi`i$2LRCpC>Ap zonP1GPnd?m*A^y5m{Gz!C~4C1=x6RyZG|VWGUC}znDFDTEzA^Qb`gfI&ov%eS~?!y z*Cb_L_$1@A|1#GU&9mkX`zWTX#bF;U`%p{R!Y4R?B=KqccyVg((S%!R7PmNVm08^S zMIRTpVxriITO)3FNqijpp&f13?TGiOQqSe{D!T1V<8KsyH;cctU2yG(3hBU#hYsww zNutDW3x2P$>Yrunc{D9feM#DS?-$7}IP#IQ#`^IvC5tEWoIvUfO32Sso6FwwvW`=c z5-R0|_{0tj5@++1*0TiZv}~kQ8dLU=@({mM_}zuyHtucd7Qf_>Wjigu`A<+0r?Uc*XQw!?XOlpk64SLR-u{Oq;3+r6mX5M9U zp1f*1bBlY8K1bMa95(IHJ*pSk#tP(dNjy^iO+Q{xL5b(@)%JKe+hM&sF&$5scl6!6 z!ZjZAyyEm%7!wiCc8SNEj;EIVE_snP31T+>x-1^IGc>d$-*N8ezRc%86UQ@#C!TzX z=Ud3*lKY`y?CWTHZd3#}3KxM3a*v&)s?pt2qsn-YOx)*&_wSzn^#0w;4&Yw1A9vBY z$#PH5=PKda;p)(t>8WL(Xd|ij5!5#Z8abl4-h3t4Re^er_oRmqbOHK2%PwS$A>#y* zLArTDJ(X^WcQ@`+w!9K90XGSEw1nXjF8_zr6PrKDvtqd2a6#_f@-%b+_l5(ww;#a0 zZ$Iv$^G?g%o~Pq*lHUI$Pm7+Re*M(42w6@Zb`B5vJT z-146#J-9_u;dnBiXR;(*DQ@{ccXzACtroZ1R5+@E6<-5x-C4r5;x>`Rtp~T@FWhAg z;?{tho1SC1^=EOL!)-e0rl0*{5XWg)NnhTN8UMawJujy7j4t0wdkJpsS=>Unjc0MI z$E|eSU1kio)+}z_xQ*ea)92802X2MG%#>L~8b&GGsO4tluJM{>&$N%S5cfI44kg2C zxtJWu0Nlhqe;4`iswLaSy^Q>eSnkHa>SgkSgs;JU0QV^OMrYDp_CRH}V(!^A<7X-9 zrzz8q=+TWHp(In6D=DR$;KO5u3H% zkM+{_NY33h=Iqh$_ApK$9GA%3jl726TJnxQczGSjJ2@$DMotJ&NBArM3F(_mKhr37 zCQP1ghm)rZjGy3_ej#HV%b?YIM_U!+*ogZU?;5|z>p|Y=?-$fFBJci#lJ{kId2981 zA*Ru}<`2vF1U%29w~dp$Dxhqt;U>8^K5WKoUjy05Dgw{zr{|2E50G$S!p$Yal^eLIQ z@9)d&{Sw@wgUfr7`s?6=aMS;fw)26n?40xe&CQ((i8KfX!KGP(sL&t?GSfRVnVGar zE7i0OP204MHYzmQ(3CJSg0u|{4YCBGvn$B1Swd%t?JPldWr=P4%#tN`V+C1rlL^B8 zy+6-+&b{ZHdv4~owdeJ^Gbf+#pXd90pXWT!_xW?4f;|*Q z!_d0iv@Xj|YYM%hd(%1&HW-qYe7S_aA!z^0eXP{cm$go!iTQUsZ38o%&I?jJiy`BH z3tyfd2b4CruY1Yo)%^PLd709gdRf}%?JQoDJp5$Vy1e|*2dyjzZ4_F04%$&@J40y7 z?>uE(0quWfM-6tEx?}e8W!8mqkBHTDc>X6(ub2>4ri%YNX{gX1mPRt>HF5hv5{N{YV$tP4!~yt-5$ z+9;=PXqtD9eeESSEi=ch65yjCcARY2yQIQ1=KRG=J$21HPOkgCEuUM^$t54mlGbt3 zx|RFbbxvCLtQIyz+4E8KO@izrvrL<@d;@L&=Bjf>!z&%V%5!{yb_2bx?}gQZt#~ly zy%B5~>>1q4-+J1`+YY|v;T6^cw&}rY!3HVMB-kC?$9_;}>n-PU+V3FAVXtvwF6a5A zutT2Dzk7+-XMy)H&L)3KKh}?aE~Oix{7Q;Xn*CF;?(lS(P*$v$PPZJfK7PMBW%ccG z^a*eNA?1#~Cvfl9JJpj;@DA|D2{&^O&N{zj2B38YWMtbIwsnIWpZxO0dHF>8bbi`Z zu5DjKj!XJh(Km&@4|5;;e7L@_ymq4R>8`#*jy|PRuZ6ji?7X&s7l8-!DjT{N5P@d$ z^vZA>g5|8VR~(FJL5@p#>O|iF`b;@Zh3gB;(=z(b zaP_^*(I?+cFVg;po9l)crdTB zVG0!KE zHw~5m(|9G)>YN!j2i6YuOkr0z*b-PDn6VRB=_bJj!JZ~QE@4Ig!E*-o6oWWe1=v&o zs{uO(_8bpi0&Ee?#6DJED_Amsb%B*V%FoviRvo}bz#75+%9F+sunsV zHxJeY_5=^M4AvXKHo*qKynZfWfvO+On?@Y04@|MNF8Qh!Y!Ix}AP&|D7Sz`kqOUtd z-$01IQLE2u%VdbY8LRJ1k1Y#e%CA>;1*`{5_UqFBTVUN_-a1+KQ^$X2iHXz3#8(NX z{Ca&=2d4Z!N_<>#eobJ*U^fcj+=!tlXKXMTp+g)sHj%Dwcuv6cT=8(JeIEeZ1k>~8 z9YcsV4s9!hCSAv%(XjdKnz#I3TbHeV7i&ap6D)~dnn06g_&lw9E=%+-=BrplXD^2L zC`8`GksXO8{DU33*Hy)@b%}g|)d(>m(tg{ktwCPTn*5_{EMVU<*l3>i zmHph2uahlYiW4fqW|8j@knx|t-Z9DRb)Rf$LoQP8FUxMQtvqcRv+{18)3Y)KR*lX} zxcBT&BI)P>cYBiR%p!ap@Vz^mk7>iqJ|^+TmdPKyN3(gUycu5kq6Xf!$DTCndmdkS z=ay>t&Zh76$$I2EksCqoLrMc5ddrwi754ijTBMd}x{TFqnrGk$@=4?mNj|gROZjG2 zKVzf(z5s9QJj4sKx zTYc{QNd;Js)%OuG(NC~nPoJAG-`P=lj6k17&$~pwDt!hCd$bP4R3J{1=$z9z18?=? zZGUg(;$M}X%Q^wA2HKOP$Ivo!wwusup?ULJ@?Q?WYpdFhIGFT5Ey^F1oA+BUoCiOo z@6Ke_^P=AhUDsfJERJ{=y2_q#(wvQ}zV(o%z*xKF%b*ADgD!s!!_x%MW4YI*K5zo8 z73?VjE|i=zcT&lpGtkxO54jr-orhY&YP%-QJe zuCtAfYWVu$Gjq=z&g`|L5!wi}mt^VaNb8Wj-SADq_k8jB>hYCndsPQU;X4lBxoJK( zUspLbfQ-5GoyXx_fp?#Hjr~OUP?g>iw2CL5Or4X~WBOM5;f#O8SF}QXfbSLJ!^emD z=8@ya*QD)IeW-!23BKFK$444$A8h({n&U${i;JTKeQn{vVl~~~*3mhqzYkr*=+ZNx z%alLZ7}$#i5W~y139wlgGd^Q(#hjC$$%AC);9G)kw`8xg@jqC_ll(Dq608c$TgQri zN&dl}Az99j9E!G?=ctiCE1@+)>ktk9dcWJl{#JADG!L*Zhl%0?egM%be%w9nKbO4?Hav#tJIvm z=6pMvO&gibid0zH-h+@CoEt{vHuvrana z8}cnVl0ww8BpK9doIl?&NP)u&p{2Nv| zZ5ndb@YW$${tTyoj(y)JM~Q*lOO3o}EzqW+y;?L=H+W+RLD9OQZ9xmm z&k(do)q~5=EV4bw2KBa~a+!M53#}5L#$NOkQ^q!q&Ag9b;#h4Gq9?C8P+CQcmTtZ1 zm`9vb6}__`W)|8o)NedcaJ&R<VEtg; zx>2^Ct*;U+sILwzsILhusIT4X^X9k5>hofQR-gOK$o4TX<=4wM1=bbF+i|eY0N)~* z{HGWx@@gmcT?LbUUSCBvocun@`aaJ88noelR5SsEi0BsYR*RD~^@5Lsqeiv&*b_Q$}S*Ej1ns@Sf7`{av zXxG#8*dGj?$F_6CC8zMub2Ig(3YBrNKCl|A-@B(KIFH?A<@a0Op=kI#b`N|<(D{zE zP7~*4<`Wg?F%tBJVm2n9LUt=)<8iRfJZzM&*Q~r^Ctc0_Vw-fkXWKcwob%Xkz##8z zYhv4Z>{fIp(5W*Brbv@O~+qm+`0_H^VDmY{J`8 z^T6k^YyL<)j@*Zo20rwbaX$0d-N>&ZKag!B@8xG~l;6kTZGOJLU7P}I0`v9>$H5xG zyfMilSOV;kN{37OR>2wqvXL#~g#cC#RtI*Lk#uCMz*@lE`d$I89!&OqMtsgZHeW^7 zi51B6YlFT7Jun9KJ+F+Ee2=TfjysVZMYi$<;q%%@p;bY9B7Dx+MPHe8?3{;I4b8Pv z?Z&d@f1l;|jt>uL?Sc08&>4(>d;`RN#W(q%Q{%%LCN8=H`V(NCV9#fKp*nG==1y%N zl-c`lzGJ_Sz5m|`og-&75l4I&U2V17&ygR6XB3{tDnDHE*DTlsSlAr-GPEPmUMObl z%Qe4U@@Jl(96G9?9fxN6`^-ER<5%Wj`P-dmZ-#FUz85Ji=G?q<ExW4W8;0+I_?Z9C%#mZiGm~ffsTTOA;WN*8jyZC^aqO%2=j!bV zAL7iBkE3e~UCM(lJ;z7Eie6-W{90%3cNVM`?4@EdzUACuGe@4ugJjp>Yl80;;=9_3 z3uBRjNH5sqg>fmZonQlCCU!UT;rb$nlYT9TCcs|Dz0$(Ogm!AA1ng4ooo|oTi`2#Pv2{Bd_jG(XX)BFrNPYO@j`ieB;I5u z|9$=;z(=XIk0}P8e!CN?>a?rzI+qjfq>4Es3Tu5 zc{^Vo2b+Y?V8AN#TChd1w}_AE!8>2x46Xj9`OTO2!Mg;ndG4f_-!NFo%j`O@+g91L z5N>liNM_ac6u-eUXP`PWi(ChC-{#)awrJ*0jREruv`}`=JV_lWs<(6IFDuEKGcPYJ zh*UwJkS^m#6K9&boQ^Yt9T)G5s9c(n9Yfabf8@6guu-r%tIwW~!WhLjXO0_H{OPz* zU7_hmCuGmdPo^+Cw>|W{zRF|AG)u^?BJ0|tdYlAX0o$$~D=!s%h-@t&TLUJ2+sW1; z+X`P2zA5fKbllTl^~b*2--nw}9OBemM@KITXvt?P6`(s(?>6)NlY?$t(SH;R&!tu(wMW z?NxA|I}Y3l&jdV|i6>;fTy=N|o+WsGDIPa3>i0tC!l$LLAyclZXLFS6IM_Yh$8O>a zKIrhqI;WcpFTp2eyH2J?CBMg!_qHJ#mfE@S^t%w%@FtM!MNVtgv8Ot6c788wE?n(n z&lx-q@E_scV`JcXu&c=F$01Qnz;6dm&d2@OR$$trAHVF}t6G&84l zO=+3huOwL2Zo77B_&HL=&V83XtRT_`?LBE-2b?V?p1JQ@cxK^IJ$K3}GxyyLZ57%j zX?eXH>CAn1L9018+|EI0wa~nFj)Apw@wdvq16qydwC{b`Uwlq`XA$=7 z@%K5^U^QT-&*^sNv>U*>z#izFb}w=R$hk3xo~Wj z06PIT17`eZ^{s);dHB?Z#2!w626h4WDo^hmk7wSTxoTP}=yX6PPN_$34Y`+Fx$Wk( zJK>G(%`QvT#{pDQ&>x{^l}L>i#GWg^?+U`=3;2mDSomuOv#NVy^o%#{$ikW9^D9WLE=3Aro2r(0tIOQ|25Q+TkpH@x& zVhQ-U>_?9oKhW+RjuHU!El-V|R3<~DGYox*`&hY?j(2~}b@XRW!@IZmmh}A| zv#vJM8HwCMntEnpzbG_ma%<9EM(-?o70btd0FC~~oy%2ys+?z=nJasrBU>Zc5}qIA zGW`+bT6+e*`htJ-dW-R^WSa4D-+_~7LVy!AWsNa`C{uzst)Rj9n6 zeS-Vgx1*-qZ`XOALxmhGb~u(PkKM)E=#qIu(8*U7!Ns%Pe0>OcF4@~dn$zg*Rz2hr zHV9UJUSQ3a?@ZPa9}r zUeg9@A)M`czP$&DV&<%Th=wfYJA$p~JBq&dTYaaQm+uKX%}#CeIC@IXKk0mb!nDoV zvG^_i$k#mUi^$bJKsoub>`dwda=O>0|0}^-!Ok&=6O-5B+X1jE!D9DCY@0yaVV@7q z2eHfV`-<&GA=9Mjd8_W`eaf%f`hGXETq=VhbdIA_&3NoiN2m3hIiD{xmt?=gXHKB3 zBR*tQ;$4~M$x=GCZ;nL1^R?Afocq`%PCBaBNz!S&;ADz$k?)2&>DYG0w593tzL(PV z#^;Pkq_>Q~?E|jfXF7W2r=~I#Hv8us+rhR-%R3L*1GWiPf{ZT74uT~E*cjMa0Gk3^ z4d^=#wi3V=!IlHEt6)n3Eb^#=$cX?}4z>v9wiB|i3QYRESUs5R^X9D?ENEW`nC$b) z_JS$D50eA9l*W+N_bh`r*f>}TKK05T1=|_GX2B{0*a@&252pTn4Xhqa<3J}q$m|y` zc{J@~4q6qojvTZEwB8)Fc4$L6XnoMebI?Yi9SxzWA3aJr&O(!)Vn_c(fTF(Ci6PW( zEvH%EGk1MJ-(h_ZAySCJCdN_>(_Bvb z*>W=VBkrZoyFOyp!0cJtzL^f@Dop%?Y~|aaOrj-8^7$q$sR%W_=A*PMz-_vlg>H)CWgq& zO`G|={iXfU=vM-r-LB$ls&E`%RkS(d`Pj#QZ`%?#_SaFDnZbhio8fPQ|5e<_ZVmFY z<`CfThriF|zhrxUwMkPrGEd$%c*|aUdcDfSAiO>Bdh;~~HXOjFl)eX(&yQ2SvtXAfFHhY( zZ5buu--O?k(H~C*__NEX5?@wbVfpXho?m%sc>?hw{NB8Dg7tVX`MnQp7%ZPMIs$Jp zPu>Nk-=3e|$P-yV$%9wf1ZfSw6&? zwaWh%bej1O&fh)YoaMH6=nRfhYdpK`hO;Bl^PEH6_MctmtbZW8iR?keDF-~VyYDRA zb4P5SPQ%nmaCeU;4+(^rFi{pjoZICEOc+d)s>_Bwt!Uw$c^EO0#H)S;tKCjS3qW?!Y+ zz*+Rvf?dpgtkSV7Ge>oOR==|ee+T>*ia!$MXAg9spQ@@Th>XB*+RPKlZQD%M^VX-( zU&HTh1G~VMJebWCc-udfAMc{l&x2QOObmZkO`J@nbYJ4+E!Z~U!Au*& zEQjRkky~@+R!(}`v~*j+Yau>4JzqV@O@ErTCpLS=zU9b;$KCe4$hCsP{jtzz*37p^ z=PWuGj-E{Y8<7_j&z=KbrO$x_iUOmN5;-4h3ibWSI5!Wx@7(NFsJ+;sy}x=mHz6t*3QT0 zp%Z^@XQ!TtuBTC7{^ai?`oXpW*a%qBpHKR}U3Ua57Ql{yMFQBo)%OU})1`Em!8S?5 zi*14>Jy;`rB~N$k`$-{xn6aR#KW6S}x7x`}x$NiL5bw}Xkk=-dF7i%3?JjOdycJyo z1%H`$~InDD5xUT{_5bxL{A|DF2TaypgR^9if9wEsU$pJ4PDA z(PZj-XYhyHpLov(E&MCfZmL3ye--|khbL3Vz5Mhc`*fD4a|VCmT~W2P=bAiJoK+B+ zKQozXqHPZ5p~>%$1Ep&P(PZf+miMy*d5|4o!_k`s5^d)iFSnz%pEQm=Dw$f%Ck^`U z4;PfqlE6H_MG{#ek(p?YMD&1kp?8@y8q1TZK5dxGlq-d1zxlzrfc72k1Eo_t3TvaG zHt#7e{6s^`+4(n=L;c?Ruqbu#tr^s~?V+IJL& z&tbRkFYUavv^(K^-sJMqcAZBb^2D55Y;;edyZX6*dEM>UUGhu}K0BFuuK!tVNS9`|MClQp`>BFXffs~YZ}#%^l14Xa%snre`dm5<_J(Ek(Y9Sg-6uS0 z>>`b8+%&S|_r~JrOlaadSfYotSCzjPBvTy^=MU2kWcuAqn{3w>W(o>_6D^%Bpl*=C zMSe>Kt)(*s(RYTXvA4KzPVBp2-)Gq`hF$$nM-~0gOOw8J{a&!x%QBeS=ON0r3`}(> z_OM?EVoV|_PfV(HjAQUO!2fme|9sWPU(9o)&kQx^5i~^Ep5a@ivhQneVZ#jaZojB_ zwCq{5$6#jvDn9b=1-Q(t@R`qPMdI+*!#fXe1NZW$zV#Pp`amz*tItv1+u>RDq#>*a zYz3@Ha$Ld&!Ir_y9svGs<~K%pt${@;w%DWH{F(JH60&EyYDP!zZxeB*SG*5udDw^W z^f>9Pka3RhoS3@&bqjKGXcF0x?4_huxYSbumH)-}}#g6^L&hG`jSF``@I3EvXe6^?es2HIn9f)J|(qCJfOC3G(K@)n~ z_aswqCl|3lFK6aB?OdKS$N3eUV7~Hpu0Gl$eXFmJL_UK)W7oeU$E9)@dp_m0H<|jT z08ywuIp^^OfHhd6cN zSYtBvDehyJf&0tBdmNd`%Mj@nxp{d>Mo%YtD)%Q-Uyz<>xpsMde67#N1NdZd%=);< z(IcNsy@2|Po(JNSWzw!XkaWJkcl_s>axvfE+i%AHnm@kYEg9;R%4OgUk;wI~4Ie~~ zOZ`>tIn3XouSr1Q+iK0wR&&t0pv4a+L%&%z2(2RrZ35a6Xf5gVGT&C4QF=M#PC%<^ z3QunnS`V}^o#nOUFNa(Ww5=SpCTI=kF}_IKnfZQNC$tf0ZK9d|8kz5|4M1DWAvX@K z`uuR6$DsA+pe;gM$U#d&tGXauXW0ws51|F^RKHRUZN`-g`8HY;J}ql@^u}KQpKPep zz7!%#`|UNAf4fV+Fq=Mv{wYg$d}Lxo^KG^`=}#gbxiIN`TkWx~y#L#3^YApeJnKu= zh76DLktCf_czU?E>9Bh-^KG;87ttPWL$8J2dQooq7ULine=_%RvUrd zyAAy)^u=xH3()IY!u9K!Rr!xXA6Fas!=IWq&AU&>%ypXiNjnzqF08k6oq;8@UB%7l zOW@Cyi<7CO^nET5efjd-GyJwl|||6MPKqVt1t4<^r;MH(RaL!K3w)K|K#*#N*O#~^PH4(R-vL# zIxFyZ{0gh{#}8d+JvzJ5*>`0!HO77H`;JcU_|xpY)K^qBXFPWJ*m_?BzavW_~%a z{>=JnLG+(O^*Qgm4pWiGI{fv10&FyZO@oaDusN_{4^~5dm%xU=Cb)OToo}J33w))_ zLCn56$&|m0`2U*xWmGPWFJZj{nPSzy^Zp|f|9aOWh}Z~z_Y?faS=!)scX2cEm*fYL zZ@Dg+>XaX!mP@`(LXE|p$hSMUO;&zZ>31fby@%^3GBJ*`M!qK<Dl)=cu$A! z#52cK4$sar=$l9Ep6f|RztWAoocIDgPu9Jem$<~#1JNp=)#RYnK~wr+axKtgZ;&Rt zyQy3C(2U*Hr?-0^yF2lV{1A&}?4I5x{e>LqD^F|Clzz}Q=`VQ&@f)-f?sW-^gNfgZ z)q*L1UaS#J{_tXLVDg_A>jsm*z1RR)RR9|Ws|;Y1VDSJp16C2h7Ql9bxno-8W5w$8 zVq0KA`^sLKZC@pr?DNXjfhoV<{o74o()TPmk4x#cgEa+Yd%#))*dSO(02>4A_FyW% zDX>1U;QnLL=AaGdpshfg$U%!W5U=H+#i7mRpw&ZL%0X*|mJFd)U}q10FS^^Ys zILN<$dqm|2-OL|XKsRGfGxp8ezdb`b_3(!6-#!7Y0h(KGrv8I9fd&27gk2^0s2y69 z+Q1`=SusSQFH5K|`*rAQ$id>QL-O*x>Pv=qmp$=w{FN z6J2^{&-Xm^ie5|q^Zi!dq1Pe5hE4U*|BHM1HFSSAYZ$)$*~~3Swt6?~5f4(f6WNKk zJn(c?P7}zszBTE*H)rYs{fc?dCi8s=@y)^4p9fzOz9V_?Rh-LwZytOJ_%`$4>w+(S z>*@0`0$*bue8=GHJ`GN8x*`Vw2zg(AMkB+Mn42N8fDs03=vqEc}Xsccu=* zV&iIb*5SkBw6^{hx(o;ZzH@dZ_iI}54_WP@G1}E@K*Hu^K}%g zE`ZG{eGeudo>2V&yM+7LB@4D4&AoTM1mBFqZ_4PLAb)ll)x$sU@}Idqzw*+xmxlEn z{=D>qRd_I!(Fj-_SUzPm1MgU#ysJw8o%!kAxsU!h4_@Uf0q-ol-n!Qcwj98^z#@k- zd>X&^t9-!<)aTs)eN#rky@z4@qNkBdx^iFi$))!mhV6@9LvC)srgx`LZrgp)Rrqe= zT~_V}pIpxL`0>80>cQLr;@^Ktrq7#I8@QzU0%rC__c(TC`l;-F(PjIY zUxDB3i*63`XYY${fWPEE+h$e=`TcFCZ0tTr`~|o7-y3Ys=GHU2gwDPN>ZNo(DG#0O<82JrY0fp2&RTqUPW-u@ zoq8q)&S$>=iR-@oVWVIJ0c;X%7|h)VB-t6Tp#Zi3HWgx@ogRb>+1$nsz88IM+TuwRsDq zQTLSfl)h7%?oaF*G~1k6>MV@A8>7V^YsO!d>#5gz`2+i+7tOxty~XYD*TO&j?DbS@ zh(Ge)7ky=D7EE8OG)76|X!Uw(GoLha?u!mjL@!NrqIZilnxD6xI;jalQ?7ycB{KV> z_m>XuC_JR~g6x7#6i2&DM|Zrobezq*N7%$X#YWv}{-4Klt2b5KlL(Tkw&vX+?5(g#T@`eD#41ERFSqimHPXWy}7*NwTA z%VM3RH@f3eE1-PlYt_F>&}+aOi=#iy#yAwyZ~Zm~$+J2n+b?jN4k`C%>Nd`1v8nHI z{coJ|70`=9GIIm?9`Gi(_jn7FO}{%>mhr2{ zp0g*K)#VWL&HFpOq%lAmoqN_(dRM`D4%xh9_lpPKJJH-k^r$Bd?YlO6qF+rK*|9r& zqFHeWS>#h^-a~Sci`ieeZ#{LlCUP@vdtlGEY1{X)ow=|hbWe1DXa)}!7rsX9jh-#k z?w;sg(j7S8-{%d14SO)P&Eu5q7?{dA_Ly%6#_&ABo_Q0k!_31!2fx`9{o7d^v*o`h zy6n|V8D5a-V-<^5f;EEWvnRS4-Zpp}kdr^d_C)u<)9Xn?{rDhQ4_J}pxP*;?b%VL* z!8LMT%zf-1zGZz&UA6no zx7!olsq#kF%xS;Zkb>R}4Qdf|)(hfB5DD+7sP?Y}bWW_TPN6Cf0vDIm@*ty04W&yl6e=p6D^? zHQUgSL2uuNeggXNHuNp%GuzNBE@l328+twT_^Wc;-v+%o2Yn}g?}OeC{d|>IU{CZY zw4*s_N1?6cpv^<8XbIQ33avQ@t>`l9XAW8=wCNCl)rQ4e<{^+YIoJg2gV*=9jLc&~`#|*L)7q!K>X6Z5~<$w9NYEg@z_uR-whA zCAfF|t#dycIUCmbE@H{$_y@XoZYd7d2I%knzWtusicc_rN z559KzUM9Yd(lV8l@DcFA04}|g;8Wn5%W?Fw4VaA#P5hfEJ{M^x{RQ||PQ#~i+ERVE z#J0)L`6shhb|}i5ag?R@ z|8lP7?K;!Zp2uzctE0oe!&l#U0=#a+hfZ&~R)P(JdCRp9Y`}x5T${l9!A@7MD*r|JOu3$g z-I+R&Rj%XkZozBH^^afMwp`~(KYsZ`E7!6siI33X=3i}cCDJK5<0tVShkq3Q!(se< z_tNs4xkk0GN%%M6KS%r*m6qwWY~dwW6-45%@#8h%mEeuwuOM90H=pf3D|1$QlrL(f z?TNm(w1`hw*1^__Ov`K6Q-p`vG9OLL>@AMo;mYqr)Qo3GknO!dO@moXpSjT$$TmswI5nOxTr<``0R=n;s zt^11;AO}3VG0&rEHToK^WmL> zOE>=J{o+>S=aJv)Tu&{u?{4HzH@@{3l8(o)E zTFyg8W;rdFk4MMJRk8Wv=Fj0^3t8o9E%J?;{?~RY$%1 z`kSMNLQSTQs{O9Gj`sU)>#47DAGDcuFEtJaON%a2{ArJcZz@)Kwjei(+!L$~-f#Uz z|32OJnSjl%J2hMw;Jb#orLOlaUYMLDj5{fYb7pTF$w^Vx4b6wAbi z(XVDzeybyijwA0N-q$nrFRl*rOwkT{W1#4Im=2X^9ezIk&h^y&vg2cp4)3_Z-R~Qn z_BVaXS5GJNeTOoAtgu0_4lr+wF$UJ|!5ZM3BHcEy|KvXQJlA&GA^RO&qBR>IM~{Tr zE*(j96b(?Hl>a|}$=jv`^Z$!59VY*jP3&FksjtY6?>RcWV>Nf&6#Ym@{$EEtg{&K6 znEZncfcf$d*6+b&`xNQ+f$>^zB-ZZQZt@>2|IIMl)yE{!(Rp}1b%S&~&$XTM_wLo^ zTf~J0wna^MguBeMTuZr(zT1|4%$3Imue`>oA!XlvJ0lP!_d;LFn%Qq9_JAKBp^6fLKaMtpB)>Hq3&Oo1W zf3VMJf%nM!9$KFYN>wQ(QpGj3$ms_~xsjRpAX;0x#3HkenThX z*lvSGQ}r7~uV?;wWIYxC3-lW;=xY4Xdg>olPJzB|yMAK`xq0LsYQM37o+G3Feq)7l zulz7`+as`2L&V&gTQ3%x&C6aBLH{Ye%MD-f$guKbgB?(nZ^m)?p zzn?edWBq8pTg=||L!6IRqn8SUeyBoz=}pv!&)Bh^Z%(lA-<^J&fd+hfHcQ^fdeIRZ z*L=oJ%ZyVpbK&yYSN!wul5Iq`_HV50O%F_V0NF)k)nCLKe6nUwZaS9yxIbO>TQfHi z5C84D=Y0;}HjwqYPGCV8rB)+=td>i!gG!OG% z8J?0}o{xLiQy)`W`_gH#^qb+Sfv04eHbp$=z~jtIvH>c?(*n;TdOj_lr>1!Zy*$0} z#IX4u@f15ehojN=dU?j+X~5<$i09N1yG|7SfXkzK&>46tj? z7QHqy3*514+k|w$%|DlPjKH zLr3*D*HbKkL}I`Dj47Ycc-lrT-f@ZI=^7Sd+P;-vJl#e;iGSOU_wI4i3W=w`?2l^| zPmdyd+?DNlV6qFyc7De`7rT72{&@PY{pl*6E_*xAJF=PgqaS=c-G;8=@A~8EZm=P+ zT=DWS^kdu5r(~ax?vJPEp;yd#_50~-(3`fQmod2S^U?kBw90=Hx{0TMGvSR79&|iC zfX?ZEu{x)>)tPrZy@<}^|4JXEdj8IAot}95e*tHYWYvr@ZC%pyTO!>PpQItnD9gbpBu1K0!Kl z3)c2Me;M01(YcJy%jEZ>ylj6^c=*oJ}b@Ri>GJdIf~6Do<7sz3C7c_@HAkLiKqWK9vV-V;omuU zOg#PHE>AjM%!;QQR9^pK_4o@(io`$FV zCpI2@ds>e#o<0Fj&616$Z*XnP9Z#3Mi})LzCZ0a%@CW1R8hHBt)5g;;c6FxxlNC?5 ziys?IJpFi=-ycs8yqnl}|7z-mJRd55HZw3&>8$0AL;G9~+A(O~%t2d(_R|nroFtOi zvnvuy?zor_~~$zJuivd3x{IPzF*Ato&o&nccsq&E;$3{q1f$(W}lnJT2rL= z4E~S(mx5-{BO?0sM(Wno<*!zU}=4ts5<^8ku)HQxNXaDKB zX=bxeN$Diu?}h)h;?LN}Sc|cTolZHoSY5|H)3`}cdG14Q9J$w6IoevY5#E$Pv}I_n zkCe_N*byPERwy4t%2V%a-BbC9BSA0?YKJ=_nLKIwk#Ij zQSb=!JuB~qZ>BZTQH3vK|K*GeV?XRcoSyx*Fr#@rN4>W* zpMXBK!JfQOrcpX5X9}ts(m3g!fKO!@yUj`0p6@E&%&sx3cOJd<|Gl1iUAA7fCp&sI zj^9M@0DSM2-WQcPCvdxzEM@~Q6kT7ALiJq~RIn(}jydzH(f=&P81Yb<6fx7p*PXJHzi z0eIRi4}GC+6L>?}mh;}?&h)(|k!0T*a+AnCRdSa(?PYA3cnd5p?DEnw*|!tyIGAYz zj1AE%)F4SmEwr7#%;a14G=i0bJRv zHp|~nd$#KJZTh)5&-JaIO_l!?e0Osn+u@|^c{X{GNCiO?YoE<7^u~X^p6Y}@@Vs5@ z>aBvL^6!LiPv|N$n0;OeSfhpe9*>arY|#nlJ_m>a`=Z%^4q=YoS}F({9MY{Dz?s} z$MjQ~d^!Ev1(}SQ`hOSg{hECz&KaYa4?l@k3#}1aFy4}_&Cr^l6z(zfG2%}g5;9J-QSn3DCuZaSn~mL~9fj75t}wZIXp_)_a=XPQdpdvk`{PV-hZVAW8kS}FH^g7)*f7K=m3U6gzNP4=({;_* zT?gMP=}w(mPyK*<Or->yh2u=gvvoSkQ- zt@2O&em(UK?qfH*@@6f-KPUew|D3#JCy-r4_G^-T#rCpTo_4oUnYc@@4}K&Djr|DGcgTIQe4&cE#FqbuAWu7%xA6DiS_-+Z=UCQ%g-8_es`R}vyta58Z ze(lfpEQ)0saZ_hP%KQ`AWj=~*Pij4NOnIH$UN%_f3!}_$AZubtHeSN`;2Wv$Tp+zS(4>azQ-xIF0jAlKK3O7J!7Bg`<-@^sMm52@oJ?OGqQ z^T?WZ?T-xHur+iqFtXk{-b`B4$hPd*NbMkQj@{?V;!!bSAK!KLGmq!+>%|2}KQA^W;E#Qj`Hn|!q>jp$ z-*foy&@lXV^t1&&rJWQb*Ppv0{wz?PF*c#digKraoA|H$>$}XF>r#Y7E!}e{=bU6C>Q< z>NR5r<`fRankXzLEchs$ePT&Sas$XUK6b-di}TB|*Vx&Ey$d<&urr?G;49g847u*d zZKTeZeO|dkyvtvseSx-|*)OAfufjk4_>EMf_-}IU({u;hm-NwAtG66qPVd}s_G%o; z$~PxX*?bdO$&Lj4N1m{eI!k)r=klBSrYA7-f~9@0ut)q)+(^}n|4zpa?{hDqw>f@t zw&z;^P9it;qz5KfhJDLSmrqx0q~|kK-!{>86zmDI;a1lMQ)e>uO>gmPU$wXWz!v4X zjw$PrCvT))DEWhqym^MrGxp}R>opfC8#-C~n0QL2uMpM;HXgu+!NvmE1lXtt)3Y`W zHUj4MGj%$U0yBCp$xqJ$ zdRm|6*Rz727BHjdV19ZkSn_Rux?fKXzH0+BdS02Io(}YMp5@omi=GZJqvxFb^h~0s zyV9>`20dM1M$a?z)00F`?_c@#sQi1tjGiaur>Fi?tVcY2u6idDp-X3_pv22&h z2kh^m$9~7+QzkZbV%a`_K9%M;dMc_nQlH@7!%sU$K=uLGElw<}@*juynQC)B;ph*I zWq%ro0P(8Y)DrwL{M-%a>_9El<%&l`#%qnpmY==hjMwV6mkq|U1IUgd`y1I^=*nh% zOSE-}(?cInEW3!#+8P_no@AjjQ13fJV%ZXWJ^Xwd%l8 zXWg<)$F94bCk;On6etEQx(EJx8@qnN)qDEbwE?-+mv1=x_xy6{*p(qzCU#}8tN5uG zxyn~=q*`U)7k%j|c73l?56tqc$@dZXTN*Y}7mEMOF27<|wgGu!*LnDccG5Mpx<-s$R~E~L~bDQz~t19j{hzB+2fC0kD_Z3>}m4F zy{-)*vFncl0U(t~zE2|GyLTgXw&dUE$mfb(o8Yhf8~FEaq^>E1|4xVh&gj1M**E4) zBA%(kXV^1|x(n|t2wnW$SFF0$^I6)v0~@I;xp(Tjsb@5chhlbv6$O8;yLx8^!t%u= za`VV}jpPmKuG@kF*vx1%kn9=jy{Pa|Oj{g1v zzn&U=)&yqsd_6xs9q4Io_Uq|IPYamQ^Tqu1Orod#LcboBe;b(5b5DMHlIZEY$gige zpLKv4Js-_aPyOeK$6w{w(~O=jFr(+r{PYZU`EfO{PfJBr~hKVo+b43 zff+rwoL)~kb+`Nrv@fsD=m9cgziRM)aPK~Y2C%*W)&kZGRw6+zJ-eM?Jprr_tUG`W zgLMV;O@MUeF-qx=ap>* zQ-0mGHu<2->T_daVf|o30of6-(ExS?Y$AXi1Dgt9^I*pU*fQ8`0NVsx2w)|D$9hKq zi-WCtFpV2(!8XAZj|BI_HA5@8B%Ia-EuMom2(2~;Z30?j4%!T~wj8t*(7JQbHlYnb z3$9@+f8~Eq{m&s+18pn^tqIyx4w{Y}IUYi*AiV*~ViB6^MeNLX(ZKq@2RQ+K1-jPl zV2N|T-iQPIu)(i`BF@~ik>*M3#8`@K|MFSYRsC*&M(qmgy>P7t%cSI z&8_cBw-KxbELbPR-vO;Nz~2kj6T)8u{|K}}Xs_Tt!i=XqtBtdZn0wxNuGvGkub7y@ z*-mHT*I8snkm;2S15us3&U`vDhhp97VDeybM`p-q-d~O2uM@}_-+%m&&-W^uIP_KM z&*wgN$fak#H`xHazk z!`pgUem0c-1MNqiy!G(LFV9bJC%glB@{Yi}k|*yByiINS*{}-lRGz#$zeK$Fn$zo5 ze4N0)z3@IqW6tZ|VV+O#J|Odb$;{r!L}_>7qr>ClbIpFP5tY{!%q>gbb6kBq=DE(A z>@M7$OJ4)_Et8kVD>qWNbFVt+9j{;(?`&k2$MzO8T^~Q-PUh$n8>VhneVOMA9i3Lk zkeVH>z1DE{x1F5QLYkiU7I+uoy;Zzi!aBhcS7k7bL;6%6V3%+oyS3l8Yq`JAI0^p} z{I3%KB|(0>*UwotGvk~S@Rwa}`On#&UpAIZ6Mw`1bnbNti-Wa!Fg>TWV7*|U7L%F7 zGUFFL(^mzb>2`Rx^5h+Yx4$Dlz0>fs|gYZqKj0Okrae{NB7A2OIQYDx*cP39x+1 zDE3v>1Fy@Ew+7zHJbByTt?4|yUgc{L-lOn(^EC!GAHb%-Ry~-;)5j^xqSvu@s`31- zx0y2Xt_NxAu*>_9+x4_9wUPb~im++09$s1d_0~W=Wc55yuT=gm@M}MNEcKQEKOumJzX6_|_-O?GUyJ|8@E_EE zN&0+y&a63Giyn{jn3|o{6y_h(tM!gw+rCbJ`lgNaw=v}ZZm^~RHUQQdz(&D3z;+;` zOR|$-?E$_Sur4sOU)S<2fE@wTGpb9nD_}{mA%i&B7FhR9eynVU`T-V+I*gL71Y3Nw zzdY-}mcgFs(bohPx!KRx4ptJtdcbxDutBg&FmK%&1B(Z+DX@wFcHHXo$}WPH2l!UO z$^uyA8`<`igL&;!eXGJ(vagl<*l%wM)F1B-bZ0HD75*0Zzb^joI{dfm%x&+P*II(% zbq(KcEY2g9&quLg!DFl1ut~6auorRfiDMZ9AC6sSYMyzHNN{*Wt@9G5A7uuU*CR{++`Pvsv&HmW}N4>x<;GGmWfvr|Oa znw7s>0*LwMqtY27of&kNaIZ_)IM^`{RtI*Jw5P#_xsSa+J8f;2b{@sO#hGjE+`eXRbIG%OBL%d@fztIfeP2T#Tk3)Cs zZJhiJgN=bTaG$H(j>0qTk&{nmvF#|>ecZ=B`{oDq4X+qJZhVWCeWy>>^e=Bu`!nJ5 zr{)J5j??}lt2&{zOy1#Zu&*ga+JM@jm%Mc&_1|hw7%SLsr-prBPv7<{j2G~6zg?x{ z1#dF{4;S$2lfLUmee%8H$#67ZLU*4 z%{N3%{WRrj>bhBj)VHytbD=eHcd=~QL|4b%;c1D!bC&pL8+sk|<2mR%k#B{bgnmBv zwq0n{rgG7GpjC~A(}tn7<)BSM8_q$Sg?2m#Z5i5T4qD{fj88rsZc7EU_8hc2Xd^jj zEzo9j(7K^*<)95gtNBQ{Ek~ergwV|R7uqPaH`#h|yWRt``@ngo5A86YM$xugr&rWI zNY$q;9x!VhUd-aKL*^}bi?M$cY2Q=s1_#NiA#%#Z3_Ou+(e(Upi z2i%0#?6ff7%js76!uJL?X~llqZQCa^w@2rAd(6xg(m>m_^aFfzHTplH^_W9!Np}W) zeV_cx=&M0r89o_1!d?`u^~*k!7tWcm-_Jg1KCUumKCYtgZI>aF_%8kNXE#!R#l5ax zeyv~&VDWUnWb(*9FWZ-xXLX;>NaejgMt$m)0uAt`_@P zkaq9qnLm{=#{Pr0EYh!;8oRgP8-~w(-vn0WrEHG==?fW5ZDl28y8`w|#d@hXcw;>i zADB8uA5Gll3uSi~yJxee-#$?2X~y}zq%$$a`!Dj3>tnt-zUPkEp4)evXS{rw@v^g@ z?g;$Hzvy3!JO(xc=8pXpr_Y0(0Q-&N4UgV^cf@Yr!N<=J^6~R$d-O*Bh4TJVMz3^~ zgN=e+#J!%2^jt4%Df>%n-egAF&XSW;{_xMj@3o^9Y#A)y{0+h%`)bAxmBkoX1k9^< z3akPw-~27Xf8v;5ZxU<~%&WKPUumzw`n7q|^;<&U6WV+Gj;5hA_TjfL7HY?GquJkB z2Y=$ejg;)vCBHR+HGs8mqvO*?$6lkO5B~0NZ=~OquR+H!SRdHuq}2GHx?|3zIi&eG z#txe1NWTVP>icnIHjzn42HOusITwSCT|6a4yUo`uGMyG)#G`eqK>9?~}(Z5(R) z=49z65o3Rp2$DBnhNCyD!{+6PkkHXQGfHEUG`fGdky_0sjhSfShYLz)NnoDeB8e=K z$V@axA_}N`(OWi8|8)OG>OUUs=EKC(nHa;I?QGxY9^X;;85>Xsnyy4~VQqo^+Iqr% z*nUsxEFX-Y-x0lLXT20dh~tz{kbGe z(tQs|#7$(sO=LI5`YgC;+r%26?tMV^y*-yiRyN-Xr|ZML^5JFj?6nqk{hl`Vid=*X zCFWI@DUcs{l1QU(1kB3Q)qtTsYLoWsp|*s1P*kc~E5D)d6K}0-q@L}MZv%a%`M%t~ z()RtOotKt&CrW!048$%kZP&OnEKp|DlIP*}Hhl*%8iVrj?hlWFz>s zWQUdgzyp)5M|SB9D|=1;vhqVOvPX+frS8IxSlwy;pgyDUCmQq82?p9)y*_K=khvf7 z;FO^Wo&J93 zsg%Ybx|FYG>QEQh3X@u~_g%Y9`P%1!^1UZKU#8zHL+1qP6rGjHm#}HD7??NhInu5H z`!}V%C%?2m6P|YZ8+`HmnSXq)KkZtuX)tfvjre&P>@KC9x@Mbv+wnR1E>^wHE>BGr znerSXotnB#+KO+cz^cKVnB4pNo}4QGZK7uY zJ>EQ&;L|BEQzze;M;`L1lkJPtzjHHrP})6Un_%9w2T8j!Vg09%Zf;*!52#%@o&Qdd zPWSo#wAaA8z`SY4@Wm+D-5l-|`*FuMX*X)Tb{=6{;roknmt8Y?Y(?ktYpl-iK6IUG zt0vJ|^ZHZH`>Xe&({1PM*mR#pP0`(Fm)$@s_bRn=2a6A!T^4CTb_LnQji*urY9sIP z$U0-LeYfuzI-?Qkcko`!9>hQEgu)k`UDjgWPpm>m_5WkM*nP@>E|9*%8P{oY=~uSR zSfCZ&33zAJC%Sf~$9FWy2@*4JKsw{QLHK)~yXu@Dg^23O7+CzKQ>kZjuWKj2DX>1U z7Yi`^1g|w`6^MTh+ERdj39P;+oPP`2+M7<9y=_t_9c4de{uCYB@1{#>R)W=`!<-#q z^5UGKBU%HrYWRaR>1u=4fZUV0*Hy!>`$w$*fqjPi*b}cdbnrw=lU_6MN*4&-4VyeiTFUb6Z##-ier1MP? zYaXW(wmN(ld-JK(tmLo0%I1R^0Nz`mHkdW0I%w_iO~SV(z8l~({$mJd>W$W2`Q$B1 z&n<4`{z7xFHcDxz{M&Cnm0FbS^4KwC+-pOO*h#hXG`=i?bV7<0CQy%hfBUlHR)}xh2)^4p>@_Y5*~$c#(oi>?g%?U*_G ze%E|w47>(^{aa5t-}rbp{C<1h=e4KeC-evKcA?wD$MdeE&3N7^w}Zu3x*}$;LNh*I zMW$Q!JO}-+PVZl3U9iLD-GARV`Fz)*!ozAF>iG>KS9vS_n&y~JwVS;A_wX=}Nv{?i z4s>X2x>H*|i~K;}sZ_7zf9uHGv)JexHE+|Puc~Cu9-uUpZiKR#yX{o!tsXf$e`@yf z*txA{3Hv%y&Mr`$YWOMfWYX3(3fq zIM`}{uNG|6gEhm~NL`8bpGsX2!~Z|M!jzwP-N}p}GV2o>vlTXnZ`#zfsyU~3jC3Lc zr&3Sj?+DeUl?O`C+EMVG;Cn63!Re;G5p5n?QwXgF+A6euXzh|S1-KSE|(><4LDaTJ$V8)iaAG$3aq_Oioep`CM%E3xZs*Wu~ zU}a$Lvmjf>v84pe*mA*XZP`x?@n75dWsNkp-g_$jPK(lr;g?M?lg9H-o5lgs*w*(g zKWDytD3f2M(McN1U?z<-A9@^KaDxkm{F}h1vtZ{d-Fr#b^eKBen_F|MjS4N9c8|W{?6S*< zEMMmizfJw?N8gDLWYUnYM$oqiW_tQap?qwD9S8HqW+nJ^ z9_;hbW4Ai#`eHL3Ym(WnXzXwJ1?|lT{q1NASSy$}HtPgy0Sm@oYO@9`e~_l(7YJm%4J0vWeolYf`NR>0oK zz4AzGc7q$6MgE)e`|zpMVN0{`+7PQmZ*qebl|vQfa1_3%;)IvDw(xAZ=dXR+Z%Z{Y zZO9CN#Kv0Xu8b!(yVEt_i5rICk9^b_+s9Te55{Ki@!B(u-97Mj`R(2|Hd{si6f)h& z#D>tHXKYp}|H&@p{c_|2@rQlCKQuN|EYX2{<6je_O8!;Z@_U{00h*)l48&M0R7-vW z`6D0u|FoSCTwQhj|1bBRJ5d;tQBqPdMVm!NNkzGeZERx<6%`c?6_sihDH~p&pk}+_x+y7<8Fu7 z=l$>V{`~)YoIct*m*3m7^JdpsK0`tag47{ARt%5((f9v2C$CsUtu8CV4DLf(D-3De&^*g5Vt_$uJ@_s2GaRe`zrRyzB@>cIT{u|cp60lG1; z%|5IS-ks!+9yI_PNPn#KFN|lm?oSpYU;Qy%)?UVI6?ipxlkf%f ztBN6Oho=pmOT}aA9ThpQC(xjRzPaMiM;eVn)2w{+_&FvHH?x@K?olv%aGAekj{+EnbpzxR6iL0BzVH<)~) zM_3csHZZq;B^#9f+rf+t*Z%i5j3B$?zH}QVz&3#8$^ahOFa_2Q=Ju;(LjoJxz>Ezi z9n6Nc_+i()eyH5b{Kwb4{(xlHleSC2jO=3$Ci~z%?nCzEHZOjXJ&5dGU`BS%e=j?M z?4EC=%g)75-C#!c3k^#CZ8lKH+kSkh@dl@A|(|9tJ(x!q$UTfw}!A)gK$s zR|ytVzv)r*rTR@b$F^9jyW;D}*_YbArt{TnVy0iRhLBbGEltdXz|!bW+w z&!oEJEwh#%Wp>G1%xBhH^19*4{my>--g%!qjjOj2) zwAZD+DU(;X$?A%2A?*sFQG37Qk9*7>Y3o+>@hFX(NUKKdxSDtC2HOs2UV{2+qg90+ zxYP3kzLUJ&-=__7<(*^8lYa*P&UqK)nfXc1By42OH+$W~kxIhG2^%DAkaxQtHhm@2 z9?@N9(x#Zhg?5K&C7;RgtJP*t<*oc_(sS5L|01vwutKnpORmyH-8byiBc3Y4+X;8u zF4@@t)(I9oUoM}v5w@AI6M47ue2p{T$S!t!y3zQ)kMw@^ANH8N#nyRenKbl&r%3Fw zZ_LrZB9$)~d#vn=ZM5t(oFaVSd;62W6N4#ZYn|}um_5yH&q3w>gY|;%?>Be($bZgx z53?VRKFX%J-PSM*m$n~H+v$uSYT@ty!T!{F50!x?ux((Yya&@{9oyrX$Mn*kL=aC8 zJQX8;9ddiR-*ue|gR(9u z@#FBYLBdKO4wpGjSlQVAxXfjQ z~J!@}AK>qX{G9^WTizHY(}5WldnZG?4@4kiw!97nHr`L+|b z6rU*+A_s=={_|CvhE??wdq&Geb3o9b513PaOpUHo0-Eh*cg0T9ZhKJP?w)FA+ z=39Jreu>`Z^0g8+j?6E4GPk&4U4-=`Gc0U?u&MD(nW|662y6e@{^Zvr)A)rxi&?*k zcDwWRqT35yC3YQ*PIm#1k(14w z!ux3z&6x@HRT>B%n_wRV?{G1psb4WN?XPG~p(!fCfn9I<<2Of9Wr z9{rkX^8qcpb>#97gxI%#u<2JeZb!yGWVrKLvT+w!QfuPt=*B$9Tp~#3?vy&@DgC!T z$@)bUdD~BMQeA+7FT6>6|2M{E!;ivk*am;)?;IPBOtXQr16?|! zwJE;R%m*YxOfYL3)5vJ~{r+T~{Pw3>Ck@OTId|pw&v}`2U6Z%pm|ZQ?TDdE}|S>z<>1_>;4C=+y<99Qlx&rB&Yzqqk)D z{^TE|_X1n5KRwJ?mAtfZ(Hf4uEsv6wD3}ZdQd1cdlT-Cd-+xE7O-|NcdD%6K^-X zwSRMX$6Ve(K4s5TbU6L2fy(&!0m>J=?i`)`G>N>uV5VKT&X(t27hXuapmbUKAL_%u z@ArML!?dxqLm$X1q;93AF?qa>^lO1GqH=Q7JoYP(e>XgjEB#BS_a{#m|KDni@BHcN zm9ywfSRPk7+kuSgf9y|MlJP@ZhEvwl%h^!44F&kI@SlzipGmVJSkCr`*`RXKfQ<4N z=z}YNUTDj3&VJ5U&Q1z17xp*a29Q_sFZx@OSC%GkzH-(XF0a~r10nH0)SvtJCqIU* zcAv?#xhiKD`O8@`={^qKgVOu#+Klu_FK2HGDQ7E8Ia{y%Gs}2bzFJ)a1u+Cu4Hn#r&7H4J}&l}LV7`EqWJ@%Jri&z-Z+f&JR-myhWKiXqkZI@6A2 zTjnX?~e4AsUSo9GXae2U`Q>>n?x!>Ok){=w7aJ z@o`(PzrIT^U)P6}uhluK=eHxLGdGcZr{tWPDaX{Crai2oJ-i`A&dMCMKlxeF$cDoc zcH4EdEoY%^S1r87`3~>jSDQ2m%adVk*JdVx$Kdt1U46(K1v6!8z?S#ll&L9X7rrcU z&@!d*K&};yR6_T0-ktHTnLjY?A7NVw^VUgImGXjM7&m(#B!UU=?6ytPZ%iX^*DDjr3sufL zU3sS7@Y*5&IIK1H$?$T%!km+(eo(Zb&^JfuTCVJdAG8#N#iiSHmm+=KVdC|U275c=av3?E?}=W4tqX)9A<3L zIBXv>dtaMKMoe2gk4$eIwnUW$^$_~-lf67(&YqMatCF;(U4;k&pCXz+6A)01GdjD{qv0yoA*l?UDZ18>kWxy zlVt2!?)Z@Qe~a#H?a~;@krA`Pe5kf+1R2F|OxSB&Besmtw(7ef{XcleT;7{pUVQAI z570R4f%M*!>ge*rqLKBbUR$Mlzna5W&0sh4ZmqE8`P-_4)%)`OW@HY*|6={VLGJr4mLF>2jB3EN1qYB({1*CNibwLj zPTlH_{X@#n9S18vwYkyAH1ZBMrjqS#q;>UM6Ujfz_PcDoP8xW&(*{v~2E%NZjA3N# zLk2x(#y+l$u<{e#7bZjH=KwMy<%#4EWXB3yM(FtIi<#x8B8U15-tUU{@PqL7W|p6} z#nDLi+tSO=X5?95ru=Mwk4cM{Qhv50vmX8zD?iid*#O-J`RyaNo{aLNansA3oR^xN zvBynir18kx6Um3gzbcJCecbepaQ;^KYbzZ6#cBNMYhH%=DScNl6~@eXrBbEOPl7m;3LSQCktx&NRW>SLyIRxh%ZCo~NDZ%V#{Y zJiVL@B5xU(DJNaFyoHt%jR&TY*#-Z>$_ZqquUhmn#skpme7YXBePv+Vz_JZuV^v@S zV0k{Q0c>jkYXR#AJH$uV0oE75dcbhxJv&Kk7KzAC~i(!yzSvsamL>2D@{J>i+94UANL2OO{TNgLb@m6?OJKKwJ$-pIfE>IrT?<3gxNc79sf>Kes9(~p#L6J>W-lC zIzX*7YbqfBz^`|Ee0Z8kGnJ(cgmn;hw8D6Vb%XTT4(%iy&@Xf3C#_niPoEYGPS=+_7oFVyE>8jHn^~I zuy!ziUatmg16wH>Jfdp^8w4|Tjf1sF0U7?1We-`J)+wN)&%Cx z5eXXwYYbpJz#0PBZm@c=TnXb5?*XtnF#r9#`LE2BR{|E4R{ zEqVJ(E)#9YE?gU4Cb|hLBFtYVwt`gzuwk(J05%TR8o(yOy1?G0c<>bQ+Xprb_9p?# z?-UAcqCC$j4+Vv^7d44wryH)LBTjiJBkTZSZ&etN(yaALj%+W=MqRw*JL(Y1ip zf%(fr2Ur(ag`u+PdccMQ@&>?$!2IQ51Z*12p9d$v_6D#iu-ySH0X79DyY%S)+*dLF z2lJPQVz8jRa?<9`+G7K-fzu4@+MijZ~eSSsr9l6=CZM^YO zSOV-g={r3yU%Ufg1@LO@5NWir5wJ3_mkZ+&-2~V&Fn^q;z#70_Yp86x1Xyzb%Ppe* z0DGg4t{AKf%-G`SChGJv&$9RNGl(NW3&onVEhCXxq)&D%fIW!apn z32tNH9CkHq+mW#Y8SGRtGW=^{fjtbYg+>1yI*-Bbnx(K8yoUO{E@AI?H|g!}-HK}8 zRocFyN@$BtbLw(9`SaAZ2&vhAU3uYY&)2nrYhgV zU{heq-*&&s-m@$FcM!Ilu!&TdS=-j0IeLky>1d-b@>!0Ny@fa&@;J)&!N|H%JDBYA>(~_{Z`zUP zua_(~^((%9tPo7{+0T}=B5ogXU#n*j6IO=V!?0jvsaJD9)SYyjKg!_>aFfK7s3CB3E}#yG-R z?_O!20W9NtD`~?R^|{150B=csIIkH4;cT3nw$iUbjLOOsyzAi&D=U#Dj7JHZaBMQ^ z7qV|%^=>J&`DZ5VZ>-TL)F^OO&UyU1E{B3;`iG*chi*M|CrGBLKbRXbdq2-`x8s_A z=?3Upp{q~PxqDD9w2Nt#jfO_ik0P(d6&55~+Lsm4AxCy1-t=yB=ZXV7*}F0%(gA=W4Jq z7c+4_S#f4Q+l#Y!TcO(pommSdp9|{*%Rbx7-%7JyumUiXA5DM0QQdj7PBTQ9h z)aWwz+h*w61zja{#!h&pYZ|Nt%q=6;VAe6D7ua^1XZg)(JIwl`nFBX#fzH0vy66aP z2MD>&zamIxll(el?L8-9-$mMD$FCV|>A8ut^PcTs;kI;oNBQ0_c?jllx;IV$lBQ^ON-|u6Xvfndo0?ZT@P)G_ye?N zE|Rj`L?(q92f)cU%~X~Z_d$63;5B0i$G>A>JHb?cMlQ2$+zD3Dn2zlQs{`}%Mvf(a zgPkJYEA#SI*A#$l2Q%v!o_%J1+MIP}zJqIlWM67_+_kR`-rV!j^)`c52e5XqPO!I2 z@AV&!JZ|+ID*sc$pZ+9rYhoRj8?FP|O2hbBWK2q2Y!Ya_6>@TqrST!y?mK(sTz_P)XOXelE{~N%nz>XJoo*lmy zuqLpRg}J&-{?=(}wzE6wEIWIl?OXt@^28Xl13q2Cc7l!huwt;iV3S~GoMrT1g=bdg ztaIva@#Vjs{Toe*#r5ecQkW z7iiy3hu?4CUWdOGTa{P*>)zPso^RAVxPPPgnj8ZCo|XS9-a!2mu&)+uVuALxJN&9| z^{CD30*hR1?*p>)vhiPfzN10*yHB=^!B+vF-u0+l>;x+ZD-&>#av>h;jW++gMa!eI zQV7-z|JedeAA_83$_iJcIzvF|sf4Z%y3R~GHGB40kxr~=TcC|JCz9XHq@{}XXyuDu zXnUajh-f|gO&gTTOQ)yzchv`+fNvbW&pUknG&W_$Uh4?mQzIMmODVtaPx#JTrQ%I@ z*RxT6TLx`6wAs?dBdiXr%ZF8hHIo*b!M@JB_3|aod?{(`tYOloZsO`_t(VdeD0x$b zSlxfqw;e#nK4ff`j9;;OYkU$IKWM)(kcw!Ja+DJ>+b>bJyH9cp~dPIkIaM zEEi1gdXxutkO#8C)XrHyWHexWWy+GtKNKOeH<{0YrIjT)TecOPKzV@wrPx*t&klG@ zzy5=EAD|H|a)~nsdAW_Xf-MVRonY-?{_$-uSZ4s+2G$Mc##QBX6s!x(^gWCp=__xF zk*?h1W_KyfxM??ZL(nzAWBdC`)9Oo>^=A6Bg!$(p3c>aTuu`yTF#o(mCD`5oRu8rt z%v~QULdSZrDX=$6KmE0hT+pgs*-EERznO69Gw0L{+4=+4Tk>_TM$;i?P% zcF!JjUzK$mvUpTimz7aJpyQ7M@VCEyF=ym;(V~;FQl;1#8@0eY32$7yJc?rn*e)

RXOr}8R1o=$*;EVNj}QEbp^XB1Ag(^R*sWFBi-%DoO12rZ~43n ztn8UR_L>QKq{Yb_Tfuii>)Is#VXz$mY#eMNfK7sp2e5r$+XGnkTj?(cup+S009FPz z62Pj!h67jw*iZm#0UHE668rTi9vzN6Kh^^lv~K_`Xx|8!?DO+ZfGNI*7!9_LDMy|e zi#U1{VDi78H}^!!cK|B}Q~vSOm4juIZ~Ry_SU~`51S<|;tze}AtP`vvfc1h^`7q_> zZD4g^s`u=2afT@u3foRt^E_cwgtgBT7AdFxoF}Y^u>N_%DhL~zC#;^Z?em1S61I!5 zV0ly=x(J(`hi`zeee;Bk5tiK&?w3izibBFvt`Cq0$_P`wuztplY~P*|)qh3!t&;Hb z75+`aP5VNB$h0r|7_2>LlI_)RW4#U9V7w%!S^g*NRLS{BP|lUE7}HL5Bd0G!j>^h5 z!uknw^PTjLf^7o}<_Xd7B5X83KMgh>LSF%W?%VM{VV~hWLfh%xTf5P^j?SMQ+vPcR z9I$v~yiQ$}O)(k_`LY^6SAE3s<(4DUd}-Q0!s`it3$)hdZg`W)zY5<>c$*u3W_q}6 z8^E?6!hg@Z(!m*%dgn>CJk$~B(9mxZ?-ab%m;QIW#qXf}{};T~=xu~|@UleeP70^3 zGu_V?D;1?lO? zX~@UKkj4h0FN40(rGNdw>1AWnyJ%maKU%tYgtdVU_%P+!&0u3-H;Ks9vu5sFGfmB@ z{LQ#bv_sG?y*ja=Z@EuGyKRBAxg>tsH7_n#aj1ZH2wH!eyX?9bm#cW~f_4;If4ru_b_Fo&-SqE$nC4#! zNwZ>XhCt-?}tD(^iR(naT{l&G3zV!qNBo zG`@rC8-=g0!{KAoez0u}(-1jj53FcqNEe7ifVC7)F0p4n`tzhna zqvSP$^#`z4us*O03D=|Yp!83Goyog(Mt-0?@NLXM9W(^}(oZImr-}Z}LHZA5&`&|% z0KF+cIYIjL@*}$o-phOy^!|La6l|*xQ@&jWHVU?o@~|G-l8rB(ZzZ<}+JOboD!+}A zj-{Q6WRiF5q{IE`pUO9Q(93V^aS@-=f1k^DWEx*8pE{cr>}hHE#sXLi*k}OjaOC-Ud%%VRbOT^RVD8=v=@@b3`Sa@p*m!_<3M^<}0?cop z@?oyh6W&XBw~ovUr= z`oa1FbVFbR0c<u&Puy`XqeyEH&QC2=h(R? zwKnJ6=f4*lT0iZ@Np(%6iv18^Z`ZpSS9$C9+{Q`SUv0){#RQi^+W~DQ?{*)JX;!LF zXKK-;R~>uglDOrW3!iXhTN) zSjbJ=`omW+Y(10cY3xd$JKG1=;KMXV%*HqMVBNf1H)QH&!Nggg+AKuHBKH}Mfuv2NWO=6txIi;vUGo` zegBaBIzjj{!rgpZ3^oN;0anTTeCd|Gn)v(pjn}j8y;7x<+CPkad*|me8NP9|86iZ z9yJ&r`;MFf#+A(6b731I8? z1=!r575ifNeGz8uQ8tyVWju9fxXsd8g&%tfH#(pE-_hBN&V2*nI%U%^;U)LYAHI|D z`gy{Y*As+y5`IER{#>iM4hqSpMP|<%cN<#KCqr{$b&hPQs=+^Bo!^#b!g~)A-bwiO zdBWAt*-ChVaI;6tt`E55#opUFN?7UF!ozkE)-+F8g0P->!V1=5&pcsegdLbCtd_8{ zZQ-`8C#-p%uuj5y=Lzd4Y*Xe_uv2(I?3Axip z>pq$B_CwzJh<4;`1sec+I#pKbTV%{5uF*ZLYq*ECnkZ6wGiqSYE`-#~H965=5m1}K zaEiIdtN0Y^(;wOM_O|`zECgwBW-2Z6v9TJu66k))yB=YUV3R&fb!Dsa*N^craj}lE z{CzyrFED#su-@6AlFBM8a-uh8g9KhKCc$vts<=^YN;ityNp%CmSb!&^X!t zZt*_oH$RfT-#`0Q>O-)j5urzNi@^H9{zLlt<(jnP6Q+FBD)ufT*ZziSE%dEF_2f!M z6IctFsk!dYEs4)ozKeHOX;jOnKg!Q|N?#;3=<< zF2D7HZ3Wvozl={C8P2}L?aoni zuWH%yHbp7_KHAucQ4yQFshS|^hQ9F+j0u(JOn=MkH`b=FLFmrm=)SxJy~Pf0{@cu{ z?C$850xt}$emhYziIUOiJW5E?NIP;HPN)C! zXV$)SAjibR^c$Jy*kXD6Ud>&CTy`9fWrz10*W^UE=51zkST_UP-Z=f@_^P}C{^uU7 zi{Xp@gU~8MR}i|E&}g&J-XJR4Ccs)pkRd%sq*XrB)e_Js^y3b?#!zkzS&uh9iwD2fjOLp0rl;{5g*-gmqLiY3=M{ zZ~}E$hK|uJZl})Mp4G?~-D~o8W>w`)W;NuEW~sRkiHOF&b%-4%jXM|3Bu`?~o)tUb zuVc)3-K%3v-){{PV?!1qGsmVn8e#Scvwf|=w|)L+)0<^pZk>Me2F{Iyi?=bw;& z)d`X4?W(xt*b4Zo;jMqA!~6Z0#@h*RMWMsHW#PQ?!zjE(ubxSsjU84Kyk1=!@Pm`z zr?X;J@>AUFU2#JGhpFYxP%XDEr{;wGNF}^w_+a z8PhV}TB9Ct6?NowC*(&fVL#8VBx_H|KlKFIP5-&AQR}fY_MIQ(J?G3V>y_fzN%}dt&6c86|$6FBqjDfnF;7ix9u_anoFPZ$rM`)Q$ zh%Wa$+TQ?OG1%S!T{+n909Fk)6~G$7Cc)gj&C=28$aBw?7l3s-@|t*$a3724^y>pJ zyJ04E?qAp-SS?sC?|PQ<8w0Bb)4p%VN1898hIiJGm@wf8nUOgSZ6CD$cw6T){{+UA znt7zB5UeMFm4bDH`R}Eu1ltB?_8&U;Qq+TO2lK~!J=hMgVq1l=WdqnG*b*Ps4R#=a zZ3QdbG-ID7gjV(qgO!76KcOCB<6unzY!a+1fb9bt4q(|AkbYpt8fnyP{9gnXxp5}B zUl{rHW(Gj+nH6tOw-($k%Dk6?nqOncCS;5t2`MfA)fv1+YjH>qTG+*CRazU=?5& z2r%W7G3X|Jk7%RCsR?JqT$NKsa3!=Y(0)?1rhJ++h1@m4lAI{9X-&=t-B)8r8$8?L zanrpJ*3Dp3U@8x`PVYX8t%U6+?8m7v);#Sq`W$R<%%PQ6944Uc`c!&eo&wt(z!G4c zU~atif9{2>Zw9bpunl1DI;H5!!6eU*RfF|_(H%99=o-Pg16V6q(7sMbp5K;UFxltV zu`NX2s3Xr`o_9F%{Mc?so?Guo*8woa*IkpY1k1n3wvX9LCmqZ_Ja^6{dVTt&3Fo!E zITSToS`Vnlw+)}3vG23E_Ma>Or{8DMhK|jI`{TA5tOv}$f2a?v8_cciWb>fx3t(f8 zJW~hpO>5EZ1ltOoAKMEy3g)lpA{SFW16TprFqnT|$x^T}AEtJ68Q28aRlM7MsK9wN z%C_#LpkYhRV`>scyzTH7bcOS}bD-k&PnXNTDl0?qHozNJRwf8*BO3TV|5iik8ytzt2Kn3ey6Z=t`Q=2c37{f_tCE*`~SHe0&*nwa~RfccJ8& zy1=cU_+Y41a|1xNbDxEH6qgRtWE(uMVjSHci%jdcJIP8SYH6M-mmrKnbf@pigO{@4zPFdZpVdjvboQ~i?i}sC3JhC zJ4tlh#UQL6tnikZw0-*P!Aii67M-b6^%XYTznz3t5cW2O8Nbzp>e>cf9dsv(jz_vi z!8U*?&U&i(?Eq^Bi)udn#qP6cihh|khnyN%FQCI9`NbcgefaE*eP7{6?D&;~wS&Ea za6O`{2J7@;@?j%bH<;-oyZyY7`z$)48-ULBq4Gs9*bcB_-fe$*_gM@PwsQe;cR@D| zo$;4*pT#s-(dTB8D(cc)`~KJq#61;E za);hik$`uftE1i4k-I(`sl3(E>tMxTU10B$j*Fc12OAF1RfAc#dAv%)MzA_CV;|+( z?BbvjQ&>A;Lxf!+x$J|xg8D}Fn|$9xSmEt6$@eMDlm}DaP(!gQ$e>Oztb4_d+`gt={#R|1Y8b4`2mg!(jeAvJ`9|*zsa??z311mft(G zp!+P=LtDN8TG`YCZ3DEfE@1;;Z9c3RYy_+u%*}UQQD#~2B2$2-?yiJp5}IAm3_0!j ze0|tD@v07>!AaGmG*;4G@*(W`LVCMd0ahQtYQgG!SR=emV6|X><~?$;_Ud@+8G$)E zeG2=^u&QXCxwzqphP=9shiqEZ72jgr9J__4OSX+7e;4xgu19%d2iQ)qG68|I8@v-E z@?o2QtwTHCofu1@v+kHlUZ0YQm%7v^_T7oWQc+rCPdh8Sn&EAL*KcDxSUuQ_*(jc^ z4!@~K`MZwaFjy!2ZM^&Tkut9Ee>;O~1=4PAs5$7J7`ZLfCjmQ)!L}{X&RU26P}#&& z&9BMf_v$F)H*%TJZ)*d7s}8>tV;iz21NM!A?OLFHdmVnieUXpY{H-#Wyb@kMqN}jb zUoxu0?!>4?R-`XIotwZ8EYQ9#hhKHO9;J6bSSd0u7GUynNWPIQXjC$y{Lw7?a9har4 z0;l&!1+KE%0d46QXOa(O(tgxWD_?Abb`;u=h}J9DroA(LW_mHvkUKG^;7h>w1&7a{ z#<2um(+TjEn|!B=JwyI$1G4ZSiX=@2LA!8sV9Q=iTr}*4urjRAC19Ri5a=HVo7i_s0jUU7B#5e%mD0F5|zoBCu$(ctjyn^=bZf`zAc9eoee3-;b zZxwg~IdK6z!WzK#1+W&dX)ymBNe9^80M-Mx+lLh)Zvbox%(T;dZ@VkXn3B7@v=LDH zwi909vrRm^!1BSucocqsd{RkxEAQ43zcY0j-#Y)024<33^iljxxIYcb!1@AM71%%k zYXBSaVaj(c@;8{)cdf7d)})R9jHy|hHv4JKnil<`Sd7hfA%nB(oan~Tb%T>tXUX=R z=&!$LCiw>5^$6Pw)(YmvXQ=|(7(apy>D|=nW^PS2X;rHJrDI-Ba4EF;Uvbuq(&~R_ zR*-6ab&hj>k#~+G8@xbeOMP*E7+@iSU=bXFxO`B4uNe3TjHbJ z4z?BS6d$$=Y!d7!A2toP7tHS$>tn2s-RtR)Ukbqrz!u_{Drg6w?USCD;Fk^X}>qf33j#iQs({U zAbB&jmoj#%);u%U)6JTv%2y*Y2k&R@n|JH6U%Tb&61RM9xRUy0(2J}3J>6gj;Q1Br z>23T*>wGe#J;lSeAYDk{{sF1-=QzCm$mnQ4?gsTtDcIm*+T zORPJ8kNusWFBwmoyR8P1+k#wkF88)fxlTV2x$4f*vKO|c?;>tugE*_Y~`t;&gh+Qk`;rEuGStyj~2414q3 zb?ELycQ4ol7P|lXyz$j7I@gu4$JZ%)-O<>7Pq|--+3O(xsova1JQYLhK4kJ#^P5J0 z*9ddI#9wKWF&-y_I{W_B{%EszXc4c4eHrOK`XF;;^4SHh-9*?qA98AHzoO%_y4cC# z^48?6M_w25CLWqeu9hEGrpYsD;O*UVC+2loLww`Jv@_qwaVI&woU$X;3mJRkDVa9VPz`2)#R8Dr#e}i*)K{F4WiP! z4Vev(Fz3ApnZJ0>Ne9nw-X19@z1gF1hvG@vpwFM)ijLW<%zyqnz3yZGzI&(FL@-{; zAF3~pzF?1;yRy#11_#T(hVk&@_87}L&9==SUoNW9CGy?@06NI>ryk#(V#oXRw{Eh! zVq3@~n)fT^m%#5G{BO-X%fI%cy0mKp>5p!IKe8We9PBWMPW9^$*mkf{VYC6xxFt1C zpq)@U*c*HCknGzHPlWiIIbQO;$Me3_J#kgg9EpK z32(!-^jDE{obuNa;)$I%>l}msyGeYT)cHmnwx=ozvwoqrun$`%e&(&^_|M*%dF2{5 zSZTX|TK&1otjq3%xB2HY$+Hv>uPw9>Y|1sXg==%To7;Xhb!#p@>V~Hk7VGkzCSN-3 z3OPG9uheSpe)Z3Wgy(@{yS+Tvx+&geZHe6+Ro+t`_}Y1U%v_qa7(F~n*RGGV9{Cb% zR-PG!XB#~3oX#?^9mHe6jmLw}yrg)@zH!;&+IKztJd#_APe)z3SHE<*CFF(gxN_fZ z%T>HPKf!z@a!nsCEv@*fmXknLzO+)=9mbY@@O*%GE6cXU-@YnyI^%b{mlU2x*K>x_ zttXn?a_Xkhr?B-J$-n1m{*ij>%~B!Hl+7{%awvBENL< z*M-Q0f1&wHHqmsmf5yo-$J#cjuRexNg~(M~=gaFg+C}=|lm}Pl$ZylwFb=Kp+drNP zi9@E}q?<1dMm~ma&0|^*!p9@smDl4BFPey(>;Rj4&=>-=x$Ewt}*f6jqds#j_xH3*Ika!uX1(&b%!*WcvpOq@f-3?DtPfe zjXC`Olxlh-O7~{cXX#T;x_=KDUb=hp)oW;2PO+=9R82^pmG2uZJKc@%ud{8C+!1W3 zMDDe``+QFwr~dv*Q^!^3aL=amZt6R9Q}vnl?*Mjnz;E)x+ibhi+q&?)P)*)H&-F=` zZI8-v?MB8Q$U7^;9{QrGoRD7Uc94eSu5W(wq~A9$TIb3)?KGCBV9WKqTQ|YaBj4=A zmMP?3DZon~e8b`Slr3KU5^M_!@omY|PMR%GvuiWZ*NPp ze?fk$X8b+V=+rYazmR5Q{{XhMA$NJG{dL;*@0mhBvmCx%*wX#1lfNHC7I9ce{$7d? z|LNMW#kN86N;ff{N1oEg=MU5G;!Y!#GILXyQ}6L!ZR(z8e4lXbICUg=Zw`kO_;kIp7Q4zr#t@hkFNsb3U07v4yz(_VuM+?Z-)l3PO36j zOB&_xve)FSt0#<)GV-o&Bp|WUhTu-#t)dgt=EnEk@bk#;TajCV+>3d)-e$`UrX#&T zMLE^ht8SPkFWu?N%kt#yLtcX`Z{~^6d=VzEl0y1(SKd$HAa@^f z*C`I~SwI{*vSL@hNE|9j$0yNc@?|CcM8naogP-x z+i@uRH0|B=Op>KT?wLck8N;I|g-Vy)Dk>RoN`}a?w@jNJ&k;?ZlSDfu>yI5v!hn@8S+GCYq-YL)nz#6F6MLYM7A|y z+iTLF^cnk)lm4T&p8qQSDciqCzDfTMTYe?Fl>Sr5?;-uIYr)S@{$f9aGrvM^+7!o6 z%&&|ET3a(mT8)eYH#2@n{_o6%R+9#8k=f)wDT~&Tc6^<>!uU0?*NMAwVo^Q?6Ix}L zVw)aco_Y4;UY_ZW1?DMLPRjW$!%r*u-+JaT{)*jGj{lF@?9qV((IxD zZDO6o{zgUgJ9g^%`!=dGhsB>iYtHyu7ua?G zyo=N2tu}XgaCrphyBj1u*q+5F6i3fJ0b5KNcp{5$x$Q}E0~34o;Fpd3rjR?Z zYS!+j2`Aneb&=cu3u#|>A^arL$F#4qi${53*=J~9kvpI@(8I3&> z3$0Ae{SP7K{%>6cUG#!vi+_$D+e27zjY_Nc;xrS&yt=eJ2rggrP-kL+|2Jcq^FU4u`O4A zA42YK05^Q{gSIazxU5q-(H4or(=(mc$9zbJW=;K z)(;wHlMkqj?FKhxj6GR5$IMvB>${sgQKS0d_u;l_`-I8Y>raVB&P12#cim^}swHd$ zT^;AnCZAPb;q$I8(+~369O|)6i_G0X(iOcsw9T>G@(J|3(e?Lvww`?Sl-$Pn{k++< zvpE%D`@l#7^N6k%Y&w87f$atJuj#ab?FP&9@oom20;4K1kNP})j=bZA_`c0h#Gk{2 zS?AA&?(I>2+(~#j;iJ5(j`r4jLcXuW8jSo%77 zX*4T#dw2t2+8X8aY4q*7a5j01^zm(R|2$Z<`C+C8AK}W+@zi`=aWC_A7tNaSon3E| zm$zu&v$Gy#+WII*hn8|D6tfB$lw(iXr-(pl(ocBl#j|PqVTQn#g1t&SJfhnURt{ET5WDZQ3#<;TLl}1X@Bg9i zrCCr+U6;d^FV4GN-U>d?dOUn8+mW`s{ByBYa!bJ{!PO_yS&dEVZ<_D=UXwZp)kIJ| zbQR6B$zh8>O!@cH%&VK6u}NL*>F^}0)=rI(e)p=JLBtM|jy>yVlS`N*v;O?BqsQwT z1lk_X@khUoxYZde$jftdU2LeH=((XBYjT+P43!ic36F|%j-cfW^k*)eO;%#R9+j02 zuw`KP2;jS6o=-Ult&&1MsCxJjlUKGuI|^;NXiZ*XrjZ?Ie2>KBfpNko2{-fakSNV2 z!AdWiO>Rr^n2{4(T$aOoY7XDoHf?z}X*LAiYvs=`{x~DuJbyZCzx|72e+=&&rOKLA z`ugy%_^7Wpd zN$F)&Aa5V?+OM2VZj!v`f8^9V?!G_ovxTd2D61+Nq=7mpvZV}vj$cK6F5Urn1Nl3{ zPj&O0FQXr>I!@`|)jpfNN^MwUraZ5_IDM%8EM1uuHgHPqQQFbRe(P&z)Aq*g1{(u= z13LAn&Nu)z>7!GA%>N?o71)r7OnvP7C38RIGH5$C%)aD(e{JyXhA&$>cx20Fuqm)y zgV}t`O`cPZZ*ao1v zgmq>st&vyoCHl+I9qN;}6l^OP!&~#L=ig=cuOBRi(bf+h^4CFO`I2Rp#j$_S*Z+b~bso zY(D#7wz+MGx$800GS0gxf0V~rZ$^(~Td()@>_gA+=Vp^p+9&InG(BcqY08{epP0!l zRt-buDpr~~pq+QHHy%B`(v$ol|JrqLV?X+DXN)eu;~8Ax0koJ3G;7{lK%+x|8|KFU*>8 zhR;scO6?|yv^IIC^vjI*pwq|Ytk1c22I^sxcbqn2IxF^@0zvmG4XtdP0_AY7m}7n_4ycfC7>NpygrSL8m;qr=Rn$FaI-9Xx19G? z#wX+dlNCAZOlMBI!Pc+*Qb^j>-#we0k<4m4t~X2O7L8+^z8|HP^_H|{fvOz#<) zSAH%7_wuthKW*}fnP;hH=V4S`s`>J58|QRpsmo48w)G#?8g^Sef}Z?)XU*L>)?dLF zphtbZOg%LwFYH3kBd(tB*?N|ttK=^F3-`??e<|PJXX|n1+Q^U2Tpgv-O!uYjx#b&~ z@HfL>_%+%r^{qNwJI$EbYbT69oN>%VR&-COovV$V(Q_ z8~pF!#`j@yGIfC&dxzJdcHLBael+rz)AyKj_SSQ@9<}ZL_b^@?_S$x}VMFLnfaOQg z{eY|6tm`l?^RIunZ5a2mhxg1=bC6YZj0Vx)h>| zj&H4f;prM?a z)hTW~y!lAem!yty?mRT@&>Z<9v%$01rNE~*5Wih zCjXglyZQBWXYnPac@!Z}byMm4skhOkv4%DEeg3r{rCI&Gv?rtKeYy2uV_@$5MiF!y zz$UV&U1 z*4Xw`f-U>eY;v6ss|RZb`>qdL4_5NyS(Cp6D=r(rTEXglblqShU>|U>W&FPttnlGk z^BoG+`-JCK=cfdCc-^1eLZUv_fq;A+~d0*3F zi#*$|I9hM?XMdIU{*hVxj4N#NM-kWr*d*_^{?l}}l=k1N^R*);%^%b#icbT)ZI8|- ze=S~~Vty@PmD^{NRn%LmDl{9U;~xyexf!PFVWo99G%b(KCVMHX(&^08oB1Zvz&)$` zf~_^x$eZ@N5|#=0#~+_fzU8nqe#&{54-d$`eV6S zEAB?dfv0Ef{pX$xTF2;6ij*@$${!=pPCPSf_UOu2&ioc_vf4T(OzF6q$r@*87HlSd z``|0wIcuMXM#sh|`H^`P%8$9vvhdy06-AD*vS zE!t?sJ}f8LyWdDsnt6EysT6MYOPb-W{>yA~w`^d}m0aIp9Bzi+xUH3P$lBgU%0(w6 zJrWW81RvRJ;XBxn-47U-TAok=${2E|AA zSv(S=7~Ab!uw0*KDz0(=l;KNB?~?mTkAKf5v)*INI7l95t;ycomf1&Px$*%`esJqQ z)eec7s=QbhZO)x9Bk!pB zu{Y}YXPB0lCH2T|1Cr3lN0;$d`Y7Z@P?*Y z?27qV=2LR%JgH#z)xMN$5sOMSdmjQt>ExVPTa1v*Auc(2#eCW|FbmTjE0`~Wu^-M? zUSdlW!u1&e%U0zm3(kj!X&3!`c%~e_<3d#&$`JdhqLIl$c|1`eVI|cp6o&=G?hN-l zm8JSbb!=AId%~Q3pNr`?IP>R~(R=JhmCgZu#3pDrK-=-=x#YVv(M;X!Z|BVZ1k=v3 z2C>FBz_VXr!`^Jtx;;DrS(3#D)Vi=Npv(;%q7<{7b6`RZ5Vy%*eaqVd8tNh zMUL95qVF(1IcYB0^*bIzl5}X-WrE9Z&+z+lgvt= zPL+H-gsk<;=ghuDyKiQEtWND!DIar+PT`)@@AENpV~x;v*UTmF3F&)bZ0wD= zU0UtNcV$j9V!PqVt({8_%IDnW>G<56H}m=k5|N)}hA=<-`4iQ7mHs6)onQ}boDf^d zFM*!=Q|FTHvW>BxKkrd;opFXv(LI~Ft<#xbU-n(%S2vf`{v-A4PGO!{^Bwiz1K{rz z&bVHE5#cT16X5C->YmGsopsAj@ZI2p!g(})>ILgOZO*}!(*BCCjG5O*q077o;!Umd6m-M%yosya>@ep znLiFK49w7fH;XRbi*t*;~TJXE%DIZy7*lzL~skSM` zec|5Bl*V03zwsN`UrJnGC;D7Fu97o^9O+ZNYaO`9FNgUFTC+lX`0dImpi;?3j^b|Z zfSyNk4j@PVGWLw6$qBWm5jhj@b?oW)3-$qBV*D{=;qW9(V)$>~DQB=%_D z!fJ5kFlV?)cl6N<_mxHYXD@PEU3_RC**|bQTx+Kcp2eGrt0)Sn_=p7XYPlcsDBQv($|{4*Z{Ju zi>WJ9W%3}hTIc!9Bl9sO*tHK?o15qCZ(f^uck-aQ$M6#4Vya6+SM(738=!l$BAiCo zmDp!o^lQ8S-3I;U4>>gn^Gen6M>fxG)Xl*avF z+d^oE!N&r$<6sjZv{T@_1GEXSeIc~@qx8Q%=-Ht5p#-cD>1)Uex53U6?*^W%@gt;p>FYtydKHKCo^dCXu!LhDg6&@O|_VtuyX2dYpS~ zOy8y^{oa`xI&oZV7gDFvs7X)HG4!XG?MdFvyLBS+c$)bs{mVW)mu!@t_quvazr?H? znfXh99`498d+9Q}B`b0?#LVo_pJLWC3n{N%=)WAD)(dw^y=iOv(4T+lT=J{Zp9IIB z&bd{i-?Sa1LTdj%{US4p&oqG6!_Ir1==u!0Zs%|7H?}VMG#g*nUp|-oopk-()n&?< zr^}10PV0Au`jmE0KF#i@?}?rP>3PD|BcHaSXII-?@?7b8-qrKJ>r=IpE##5iu1{~V z^#hx{w(rNRk6bmE{J8)g)x+5j)4y$>v**P5TlHwsk0{Vr+kGwTGGx$a=jg76uO^O- z)QkT@hpEReuyvHdSC6a&vPOB=nDfQ<9;>gj8C{*|x|?^a*!GLF{^a#_G{R$QKdrCh zZTfXb4)+y0AZ7aU6}=7@|Kql-hPUe?ssL^ z%$MG>zZ#zwT>r~(L2d_05mLA6>pusm@iC9ePAAxQFf(4hFfU(ibT8OGuyRou8@R*Ne1E~SLA;~T<$ls>Z?3fOQ{4ep z4Yo$SEqVDB{I?sd6YOKc$m{;KU9*--yQGB+I$Eh=g!+%tQSvDE!TWOY@(8N{+W}T1 z;4)ipEm;1>bgT)iHh{H(ZT4Y`?`E(uu(wKHn$NxOO_UKd2;DB|E=hoTBtKfC#I%M-UusSfK*ZDrdC|F+r+X1#afb9k=-{kQYA@2Zr zq618Q94pqBQNJ(a?BoaD;gqKr%qqMor{zB-{_y3b$~x_&|J*698|RY8&&N+k!8y0esFpgJHpHyu!K->`2>y!AbII59uDr4_dZDS)Af zn41qw{J{pmUMYGfpQ=q0{RCm#2=nh09o zFX5CK|C|-y$Z$r0)j1r^aNg~`PaUP4%`e|$d}1}j%Tvd15}BpQY(%tGZ_CV>Q}y@j zxJ#m4b8DHMRkO!J@hBfB|9#OJ52WT#E;sQ|T~<$cFX8XyJrxJD58^|v(I&rbfNl`F z<3wljo9zpwaW7$GAz{UY4Uu;HPPD)AXMLsD(Lo!fy~UN}RcLlXa})mf1@G3aHqDkO zDdwc3AtX$FQj7H7jIJByqfgkh{y7@2pYP0X*6F-c$arGqyxn}$UmSZY`zx`@^z%nFOKz0@_x|7MuR4)@?dpHwcB5Zq#`-zs=}xcA6oVClZ3Qzq$&@k5yZSEr zh|{U|T+}jXitoxShw5`QkbWhEy+iW9hA!_MT&>pLYXbSV^3Bo6&Df@SZ0i==whG?+ z(NTn)cRO{ZfBuhodY#j*iw;oJ(o0S?+{{@k5A2eCch4oqdAI9{Q-}k*Toi|sb66oz zg|*I{!^?hx{08kiMN6L6T)rOV=Mutp6P6Ib<*rn?n#pA1c#T74&nMMFH@cO6lWe_O zWEXI7=HXVuz=<5{M*E|71k3LmM1Rkmy@!Fn3;A_}m40O|`DMwV_K&@S!pMk2^drlo zksHYOao+V5^BaY}@7}rOHqleLV;c8R(Cy;Gow87T6Yq{jPWSPtjZVN8`RPLMC}r+;ekhi6Op zn$L7J_6M4pkorm8HIrWa7qn$Mcy`*gWv$PaYWVVh!Fc1_bIH#t`Oh?a_7*R)zc;!z z^}W$g*^6AU&O_)m+aIS{p1UZY=tjF1ZHeD(-4YA;Nq|WD_!*zP#Y@)>V7=JU`GdLS z`HT3&_=Nh+xwpmJ7wgnVO|g%LyM$dDW(hlNmxehzk{Q5wvKW)TNy$};g~&tt2v2lsfA=u$!h8X zAFZ%SXqQ2o%ex-6-}}HSz|Ii>KUb-{$G?o67UY~0kh63L=TUreBzqZH6PRS`5mpD* z5}<1aTOYvM1M(EFE=S(c62{&Reeq2)w}Q6^_=myTe3<%e<6x~|Me@CAv&=r>Q}Vjw z(J9&+d+55BT3eg-sQMw3eCsLBYy4y`Rj*co6@t}+eTsQ1Tb4Vgd&ZVH*HAEMuDd?F z#`su2(NE)%w=6ErZW$ z84;&u9hSzcJ)E*@JHIo0c1dQ%)AYd}n@c{&d&)mXrl!14wk2MudJ>avO%rQmDvd0k zOzG)DX2;`msdJ1f>-}JTU}mgk($tMVpMSQ~A-Wqa%0F#1jNd8s{0C%oO(A3bxYJJo zQ~D;r+Q7amB2&Mba|d*C{C6Ow`g>c#8XU=~e1`Q@`3lhqJ~}7yWpc zoML!4Bd7jnbIBD-BibFhs@dn{<MIdjn6LS zpV_@YuyzqGj^Amv6*y_p!Oiv(PyMuSq z%XamH3b9>V_w~qc{m(JKw`(r>nUH>}SH7HbitVN0yZ=_^#5xtiEMLaHJdBw`G{Ha>BYK+tiEcwwbcd=l)XV zp2}SH#WZ|f@bzW#8JjZrD4XJ2x{LA*-?kK=nGjUbhCp3qQ-{ z*uzw9_x&m_4QmQaynB$-jvRNKhv-N$nRVFZ@xOAAF6%<`*Aau!_zo-bwOIUdEAmuq zEA==uhkr;kSH%A#K%9zThYn)r<+k;eGkF_F(?>Gkfc_-{)h6XyMQS@EYz zBDX|^Z;i%(S`zt%dH-WH{$NR@EA~3@Z^q)EFNyp*CYnFT;#*20w^@3>(~5tyB=U3f z{;UJn zi#%|sXnu5P{71(|{$}214vl~3*vMB76aLM^;?Eu%`L%if^I`Fy9UHkVNBEsN@%xUA z{M@`hn-l-yv5{oXGRet}f9BZ8zjH-%{o?oy$42g5d=c-rM{E58y-;as> zEAKeo?>s#I`(q+cA1?g2hsU2eCURr`k-QJ)#~(T-@`L>Nw~vW*z3i?mprIq;w;U7s z?GYl~dqn)+V$Tc924m-Q0N^6@r}ns9xo{1{SO84{YOV`eTCld ze?@%H(UIv_6!HGqSH@?SL>_;o=%0UOd~b2&fg_Jd6i5D2DCA#-@!uRB`QxkNcOSj@ zAFqn{9KCq()p~#U)$t!4z4*yj$Dd!a_^zYk<4YEQ^{DvhlEZf#mCyTMj#~VeC5tMdR1U zB2(slIx5^PQ!mRpG&jB_EAlQBxY*@c=eO|Z16lD~7e{`W6~Ae5M}C>oFPO2}o_c*dw1jYbnq+$3s9jB&UT z1Xk`#7*P`mVPHf?qn9Z9U&hO54b6W^_J7f-iFdYRN^x&qK@Akkb(0#i#NkqJL4V<# z@3thqQz%WSU6>-}IC&eeIa04H5zk5eO|h8i=rzS+xuf4J79VKcr$p@4dSkJC+YiQx z0X?onR0j0W645QFrsr$DS>!qIEO00JDq*me`M~`VG_W1NWEfrGkqn2uIwjR(*_0QSlENP|Y*aWdX?z)E!Es6`alacx~cxGg?QowJ*%a9wz+=3rP_R=p3qVa zJ874MrWZ~j73)sXP`CLMQuO{Q6hf~Sq+(eMa<6ScD&A_52e(^3DDppVL-A=Ub2`BC zt`biGeMl9m#{V?(Kj8l5oSTQwJx6;>F_Kt7J(LnWQJ0CIHKFo!wfq^%P?w;b;OMsk zYJ}4J0&))}{Q{rf6HrfU{a!#W50HCRfLJyJ;5jR(9}cN^g1TEsy&uwhLSjG|WJ-Io z7omp#4*YrfJM4f{CPsh(>RWX$*Gyj{LkLk>zE|VYDRD6|Oy5@MBlXmSRI;_XEFLP+ z^~$O0Nrd#ZPp7nifi=a6bkJX9gVL}0#42A06X-f09z!PjB&Q`-_uh3(*bQbX{jn0O zDYm;^XMZZ2U?iUkpIA>m=rrN{QW;&5?yB`vC6<#9+0yC=lC1YHfkol})~zbDoy)c$})HQB#c;nbn-M)&w6hrAi_iUSXGAe`QIn!#b7(?M*tLW%-sm95#HUI>UMN2GsVPOGw_oom5aax- zo%aev-_WU33dO4-HLFN`7SW(=$syLsx!1!z=J1AG4f9@;dO}cqt@OyC=?6A&^Sx$VIJvb-vdcAZiJr2L_B9cC-@v-I*Du|6BEy36*!=f^sN!9M;$*3jAZ)B0t z+VM_^?w5K*NbGR*%#c{A^yHA3ruD**nBXrQ7ZS5+5Z60IEQ3QtUK9GIt1)&fJYI41 z0KceGjfVTh7gQqp_=&KVnrD=uQ)Hua;JQtJC?#S&%u(okuu6bo+`%eEap*8Y>S+a{ zhhL8_5PKqePJtMo?TjxFALjmLP=R3fnIVpsf7O8ADhNSrO)!i3A(;uRgV zr7m~)^0t*ytUVg+;2QPM8phKw}^Ow+M`z@8f0Ra;xbHj8D<}jVVZN+*C8=g>scW&SGS!K5}QKM zurH)RhK49L%wNk-sfvb06I}DZXZ#B~q&q{@h-;X&zH*E&;oBE}PoPRv5WLGNC zz@9p0ExKxnaE}M=T4s6=EfZVmacSNN==ud(oZeh(0+a{zT3X-KaHvL|!#AB%bu? zM?zw{ue5hatO%Y3N}BQ)d0@gE<~wCyju=Q`?nRinqEBEq!rYB8bHzhpoX>qI65En1 zW=C+0Xm-|#aBj=$L1E?)N1t2`@h5UQ%;ECt=R@K-pPnB=dtN#{BsK)gKtWIHhS`zY z$3N+X5wSz67b2AFeY3<$M~}|Jv{OwFqsbTj-9ST?-)^I-+L8kW3(vxzeEO?^SU@HJb^mzTBPbpZLaAFH{~&KF z*YD(sep0`dCzdGvVIGYr7UjtmzKPDPJn;ot^JK2>moJ`<>KF6G%BbE{Al{0e2+xsu zM6b*vdhdLqKV5Jdh8YF=!vZ;@P|q!_RZmC#L|%aLkr2;deIj3c?$ays#j63mFJJ5p z>h1+%eHJ{w&eFT`^DzTA|jGx=hAJ_v}5nW@mYrfI&uPMmWB-Ufxwc&R5z zv^si^6yH!7HLR2jXAhK!?+U5E_KWTg3VFuSuLZ<71!`ZPt_p}1zMl#40)|8Z@tj}x z42Y3|vnYMgx8Hd`n4Bx-`NaDQYdav>VPNQF1awwQ%#>;o!Hzfo#jmnn3pe~ju2E&^oCkT&V z*Z{mY;TT2y6r5MFDFp6wS)sL)mU^d!INqc1k8 zz;m3I)8t%O@Hui&i!};Gc9>76wb(==Jv31VYSbS}I4klXycX+a{)#qY9M$Egu*d`V zm#yLM+eX9rY#TUTp~%OisJqr5Xwp$wtcN?|96bPsJM~g2Mo2RyIy9ROLn(u%-{^@_ zpaF1|=bQ)lV?999!ik~80e_|kNep%j1v7QyctJMN3v)$F{ZOu;anJo4b1)?KqmGzI zyc?xXqPvuORgM_$;203nq^lpThyFr~sY*}8iU7rBqK^hTGkp33pLoxQki?UIjmkL- zE0964gG%N@0i6tr!2!K0AeILZ!!1GGGfRxeFfAe~LwZU?^rd;~l(2q0BIbnk9#oAm zshXUnm!dn&q7lMQO4~l!x@V3UnXT7li`Chf5K$^d&WF!%xmbQ^3ZI)Xqkb)avRdlJ zL6LOywjdg_c5h%x;r!*JAPk=&X9dLujk%86tDA$g+OJm!QLi-Ip9M5n2L{PKI;g>k zV)+1y4}S4RRIhqV*||uM35c_FcPW0ZCk4cVgwCgwdmF1(0r8R44+m)dcdHV+s0#N} z`Wr1CRk~VX(m~{fKHXo7)jr)ri=-yXY^^`?Q;WRAosxi(^6PE^QHdojzj)VAJO^!= z*^q3xLSBlxye2FTD7`T(`uOyFVKLD6kB`G*j-DZBheax&_lMQ|z%~gQEiHw`mXPif z5hKDH-dM|po7Cc8!qxd}dAVQTg@TFFg%$}tKGw9A*dX;pg_I;R8oAL*%)!VP5B0f} z54mXX*J8ZZ7f=h;%P&6E8U$Cn&((dSyn2DuOCw^h)N?SPD?g5SQz?{HOH^JPX-X0Mj2eaYExRQLszlQs>u!ahh1^f<-I!CrE*0?!v zA*O6tr^k97TGRe`F_PkeK{w7qDq5m=PwDr3G(UkK%N~#?E%wdwKXJAgNd5ottasYL z-Q{e!$DXa>TtiNjxU8q0ZEA#{N{x#b|5`6V9xA;|i%-;i`H~ic*sJXNwDT~Ay~^p8 zEq17;a6j)GF2Bh_tL+RySq}6fWLYpDKI1|agv^R)AoH>`+-tMQ{f_J2O|xb;&} z+Ar7m`{s*TA?NXY(K|eo5E$2?wSHdWv0Kc(%k{m&op|h$dWsUCV^L3u84jqgJ9?3# znfELu#wZZnv}-F*#uR0|kLvwGpQx7Yp7Dt_j(*iA9#VRxPhyt>6q8&?>khIFwJ^WO zAJ&q$I%1gAGjQ-$>Z`;DQtx%#xeju`0fD7l`&Ldmw#7&}xviL)t1@lHp4!odF_Y*XD-#kHsb#ilZ&peUb%TFYC^@$oGJ$I6Z*wT~7YKVQ(nn)u~ z?I#iX%+m;Y`849))S+R4_G`dE{AON(w;_VJ7UPP?62ta1j+etz+^Pk*ZA8m&RH`Y?w1 z#X%)hGHy&PbO$rO63{{L(ZVDk26g9)j%M_tN6O#0M2z5mBRYcND*ac?-dsDt+Du<6 zE;Otp+J2y4Pr6FH6VkJ<5*s3qI%BR9Z${r!ORf?_8Z2l5tlNdeFymrkc;vEC*&vZE zb18yw1bV3hc|D8BSzN4fI;pL`6@y09!QaB+)ar4Gn~k# zQD%pnKZ_)5JQm)(ZN6z(N!p&T`xS`Z1twm3x9O!m(Ou1!&!Q?*;|vQGkjt8)p7nna5(BA22VQc$?ioTy)YVxY5~~7J<$#b_!V~J2(`6Ura&O;Vqo{Bp zyp3AJxtoS>)qZj=rol4QL@{K<;-v2fQ-fj^)8Y@QeMrR_LA|Y!SW7zlM(+Qxk$8p% z3WIYlCTi{%;5bllHQX;0Vf{;dUaY|~qU1}22E8qp%ZEW-=DT|>`h7BCq+i21m0EA? z&cOLO2Y1mZg%xM9DX6M{{lywA z!%Bvb9S7tUyBs=Ev(B$~HWUYFD3%VbkkcE9t<>Qx%Kjn9yK^uG6SMP91Nq7P8$o%r z;3~|9i_ZJFp%~i$w|zb;J{x|EOFlvXP}+Q-^UI+j@d+i{PXEbpP9d8ohBTauL#G&~ zH=G|%2~yt*RsJS$V*3D7t)PZ;MX2YNfNWn+Wkb7yq6 zz@Ch&z<=Wg`K%d*6&uQ#*8rBQ@qX&>(PgF`jRqd8!D#+p@o6knAv931R0cP8wZVfp z`KW^Z1M?udRF ztwxsKlq=R{>+QMXr5rsdmt;{S^Puje9Za68SKaQrt0BWuj!_6+hnP6eeRK~-9*2^7vzn<$T zlu$RCuBn+$oEKeD69=LNvvs~`4#RBT(%hyT_)3WhnS7fj`_F2P5!!S=rgUn9-&q}$ zSOCKOgeGq4tAK+lgK5Hnpn5LoJQ>2+#hDTE8c5@ilk&0DpZ%3;rVS7$+}&qPct+OZ+i4 zPW=IHtZ4UauCST|_ZYu^F{Wnv$&C{^Lz=56g2Mwq-izutV(P0X33SQVpU2dgd}8{t zK+lgUoMnM~SCO6)Q(YT89|Tg9b0*()2_~gv9A_T2BRXGil*EW1rFB+o-ATG_6JlEv z50r-%NKI^Lb*+gV^P9HpG8sRi7JplLVtee>ieY~2xX4G52_gArKyM4lVL|;+Sgr`3 zSd*Ki2bXtFy|hA#u~fA=mxmy6gap=+1K8VV5e%~RtInOI65}A?U(al+X(Eoho!sE{&_$Tib$*%^oq!-Axy62 zHX0Au2)VX3`SBxCqz;Yecclvv7$((oQj9xNJdchoNUcYElVnG9Q@Z@G%=-pUNd3OV zk~1QLuO@7k;tiWT4Y)YeX(e%};20&StbSK{_+9EUG5J86)jPy}i=;I?Qw4a#xo!_} z>=LNIky08tSNQY{pB+ND?MW~%+FX<(IIaY!c)_2k8^v{O!C@<*s}C1baST&;{SNdY z%)^%AW3xN&DjG}CprYLQxA+G~;BdvqZA&RljyeuUubWz~=KAzHEtm&C=a+g}F3q#C zggeU7U+0K!NmeKJ2dA}Z#i`6APFPF}HPR$jc1@+ooF_&{f=c0Wg?bp#r`*yu5 z8?EvmF`dGuL$=sS(=9Bt56;0V_lcPs+t%P*>`Lx`Mt@<2&* zXZ)w+;HhbS(By;2GcHR_?XI~{v74?~+@yh@6<$&&7V@gymp^`_zqRMC+>c%79Tv`aww(X7f8K7(t)afWMgaNGb+(Yg?h-j_al+U z%AaG&vImVb!Fd=`^iS{_E)~|idpKQ8(at5>V5zXs+{M8LI8j|B zmQmeZhZ$9o=#lj&A%}Y4RTEWD#^xg6|fC!#` z?$}=IuxMC|c0h)xyNEZ&bPJZ)R>2Tk!16Wh(m6B_zq}cS z=5{!l-5QkhWB;ZW)h#Po)Sx!er(wS2;&}t*YsldJILz%6A1m6)J{r9_r$YR~7%I=8 zBPt%@6W_Rs50+G4OMQu3G~7)-6e8*rZq830EH7k7i1xu7@N~!E{)6*i-A2E0kRP!R zQRjYh{*Z%2Bhy0v>aaSvOh@k4`=rE?<(+nB#bNvLb*$QRstfftDSxFuImpH~F&|8@ zwJL{F_eMS5p#$%3I$IyojlGZrZNy>f`lOGpn^gK_A7`Olr6jgbaD1TlF>VqJo~h&F zS4L6r2l_m$Y`9A6xQ~J-+DUJaVybNXvJ|^$V+OjvJ#ExQ@|=5M$QUdov=Ez}1tkkx zh=q;y3oYcLCVE2)xuFSsCp7IB0)0eFxF2t+=d~0o$Y~mt1K))X^zVuOa^JzTxb9NY zGjgvpjSmbW&2N_1Qlbr47fp`hyujOfW>j>|(m=4=5BDr=&E?A3+4|F5xgr~!UuT~N zPn@@fXSZBp9G}|^?iX`Ug?ngJkBf?B(GE5yl&}8-Vck1K% zkBd?g^o0~grnnWH(@K!JsfG&9H5A59*SVw-Mj_&{rg~~qvEa}!rcpe0M!tbwipQ5t zWK|)B^bW;iV1p47^j9d1Pm5c^nJz)l(;6x`H&PgTUFXV1xTGQ`HPy45ie-m}@jsCt z|Lu67O>3zya#v^321N$oNW#I>ExEMm@R&Rk)8MbUcgd!a{LT6Q5Pg{d@s2nb;Fj#% zRy14qM?R)P)3`7nhLm-aUaN3^;B^UrKz(*<(XP!^U@JSSm|)<8=WV$3N_pVCTMqN4;%m%5q=HLPh7J-I>J;3Wq)5 zT;u!^$D!vc4Faw!m;`huE3Zi$wV1{IRgOC@q@l!APVv&yFk9&jMPmgMRQk{iqL< zJ&n!UKDZ35ibQazeiV=zCk>PMjFm^56jEz^LPtKXe>*Gs2r7 z7sy>G(^Qy|?${6cB?iTV)TPNN4pENvJror~A{xl%$T@J2&(bTSa%#3tN9FT0j;hW+ z2cDT64Nn}^hr2SD+-q_h!M(?I?|13A4~)Jys&_@jesXe#{XYp4Uy|^aXMD(vcU~umst|z_EMdk*^G!e@Rb!8Jdy+}XV zL@q1BSfy)mHwpR>(mS!F5YE1&_tS>?aK6xp9x2H*(Yu<6{WO@bsY7(P(bYRM@_68z z#$tS-u4p0$7U^D1}Qa2Hs4$=D( z**hWfNZ`rF;_CuEud#d|RyUSk7lJ+=dO=@CdN&jo!a1Mxj&GO`=LZd|Vd2ik`qRb& z7qvb1{X7& zfZG~<@Q}IGgK$U83e2UxImv4eY4?aB2w*%2p)PxXO@8}(Pd(#e> zNFH0wSY@;K`0^%5l0@S@*Ad%ofSBC7rsmR66(gw^rPyjMM3lxl)OAgC#LHG-x)q=h zx;VsPhh%vZaUv4$S33H6oXE5SCIp=AC^}caEpbQ&a@8{YrNq%mI8BXp*L3RUW&U~a zy;lE2`~hb)#naZPAAtH(92&j>he<~=u~A2t^*Jd;9EeFQ?OR5J2)Z=&WZ;IuHVO7!L)wgzow@#Z7z+?{VM-FIFK6s~uV=$4lQfJ8<~b za2|9_vgVNGztKY-+L%Q{GDCLi?qEG0$1@OSqyOmJ6bD?pEAb?*_T!~%sb@JjrE=+% zgJtiC48@p%Jb~*QQe*HnUv@$fdW)l55O)n*CdHqAv_Mk%G6{6-5=foVD4K5JMf6aR zagE+pR&XZZ<$9JBiA$y&EbeHSMMg>Gn z(X=m>ozTp0vxU8$3U%xfhgQK?Z5Z`bsAH2j*nb{tovK@h+I#BA|DWm<#xyOk=5wAo z{&}qK2>O0>@{XQk)?M<Tp;68`KWD4h;cK2?kLZ6JS3dFZk3G z!h>|v1mR&Z_zN2XHjvQ2E%1a8{wv23DtPzV^w!TE#} zM$3lbB3ii>4zBBdMZwhwr|ZgoBh`B(i=G(H$DJ^qQeA?#SZGNBvhEnFMz*^v+d-a8 zTU%G5xl|aPU{P9zhtMjE9^>H76wGzgq(%zw$Jj8>0QVq?la&f>nS1(mwqr(n2-z-U z;JJ!g_C{UVb~1Jr%$bkfXQ{e7;pvWe9JfGdY>M#Ss3U>*zqgz8IrSoF8tbSjKDCxu zwmX-Q(--co>7KwN8ZU}qwa9(L#hROPWf9(a2(PzueOINPRAFpIy`c1Fh1b*&-dEIc zTLF~myIdLMBgb#9RPLpaw`904UIoVb3vHQ0aC%)s+q0dmN$!62rd00I*#b%TBo|W( zeI>&v#VHb-T32@8dlX0H1)Xa7t(q$FeO|cM$#Bx4TJR7~0!Reu)__{JrdbYU4)-%< zo44G1)ijU}H*Ck%4oXaMWssKbVB@{8Pd!6X zdq;*VDC6`9D%~&< zuj7!7ABU{(IAmA6`|Z=};p31kI}X{x6=;M%0kSx|od(r`O;npKUyJ8G{ zaH9k-E9owd7)K=%zV4qpHn>QZo~wtOzVLv&1g?yuUs62WbsB;&SA~~g98FE|PER|$ z_3c`5KE{4=VqMu|>KE^FWskjIZ12jUtvcgsYSUD;RD+!`J_v_?0w*o!P_4z2Pqk_- z63NO?f4E7i?Gn!8)YFg95t{nG;L!9$AI_d!WY4;-SY$YD2z7VhK)sn!yYAbWbzi`Hq4sIW* zCBpl^H8Qu;4Ik>v*2*vn$R2lv>Jy2mx~m>Fmf`KAEhbLK-2b_9=g3p3|HBU9ZmC|Q zMia>o=Oa#dkt3dVa90G+8X|h`Jj({#-IZ-8n|HvmEnF2>Z%Flx3}b4BV{lj}8AlRW z2CJPQWme`43=6R!rq)UIxeTM%8|rBExT8pBRb81THg3n*_if!wX>x3RU!^N^?0sM7 zZz&fiIW!0t(Apyw){!X2=2QRX=Ka%By&}Wt7jcUYgQtDe?LAdDdBj(5k<3rzSu}3K z0-Dy{ot8_q8bD?71*PEZ?^Bbs`ap-5_{9jnp63_1g@VlS=X2)R`#zPfE*?uCV;_3Y zamaQ&4%x5Xr1*b3o72Z3+x<9XI~|8?)^W&IZTj|UHTXDWuR9LeCM3(<;$dKJCzRyB z4pswwqMxssTYoypwpY^e#CveNlNLp*l>7{L$&|#~q;O;I0#CfFxnGIOgFC&@{l9ac z7j}JDTZa_K%k;0rtw=L+U!*S=33Ah$0=MH-uf%$HN(y)FZwuabsJUHg_>b)jPChi( zK7(_-hjPfyf5^LOp8rog{3NkuGdoO^%l#pR)t+WGSROz8% zHA(f9{lY5gcOaJXJ5$4IhCd&aO@8M&JdzS5b<2Z#MOdv5>aT*TPe^YMiO=|cm)krZ z7?qNEDVRck6)yl}OUx^u%~9CTc_s(P!1bmqg$05hIqDIm4`i#2cuX@#eWvi1v3eL! zYGy0kd)}I*Fx6h1t$OO)`{$@kz=58K~bBnFVLO1vHgI@Zs>z{M5no{eR0ooRpL z$vEEVOwaC*-EDd~VSC<9a1JiOxhOHEc&7yND4pe7+^{X2gBlHjFzROHrs>W{N_3+J z>WFB|Kaa-(;^3_AfiD|~H3hA3t-MIVxuOV)`!pbDf4-T2#%+%VVQX07I>9p$vLS04 zT`gFYkFmw41w>92g8XSAIp3vobO_!^Z49fqMR@HU-lHJ}_XLu9tANP8N$Sl)a;~b8 zdIn)-!s^RH@dQadnl)9!Jux5dIR!-CSODkah2-qdQpXgTV-5i21?Q0ejA(7cc3v}V zz;12ucrzRb(2JVMNsaWBW^yr|GGEzvk^}m?boTV~X1d!6V&DmI+A{YY=s+G{J6t~F zE>F6N9Ho8iv2vxe%O?(SzK8Flg=BX%%Ps4;+a6OtS2TC|OL(+<^J%;kLu3m&+y|l^ zo#SfOdML%)2aP(YJ5_}YW6c)3E?BdjNvl2|)M1|M^0t-DTB#e<6;RU!19?gNrPw$e zPs-QV;qQHn{MQjbPTc=h|Ep#>JJJu&-O+Jk1P8x^e>69vZRH!VSVQ;Dv2f$AHNEbH zdnmfm(;o*XU2;ui_pPJ2c91P;j_?A_DX=t(CwyrsjxM)_ahMpV0N!`#1tgHIV4CGx zl!EOlnsUA^HU1BA!k9kJ#1lw(7tPVD9PweDQFm`w?tJ-!vmv)uHd_`zt3T8M81A1c z0p1UUhX=(&K|Lu*_wXJIilsrY+HgC$@)yZ7+kyD7R5+rDHLm9r=1XnheoBS$|6LV+ z+DDHvyU)>0@QKkrVzD}W-+_+wT1q$ALGj1>AVS4r#If1&FRSA?;?nUu(D6wX$AvcN z@C}@$c&-4up*Xebw1In`3giD?6@HEeieSN|{MkM_5f2udrj=F)#pMyHmMDcC(lxFQ zxZTwj^|1;s@(J|mSo+0zdVGDvM=VyyUA1+5%e-wxI7|KVfgzk&D>m%5ujL!^H5;BoDm%I~&u-=hAnq4=WypN34qxGY6Sf3SR{o_E3( z3U^IF-iObzD7->So;I)2EO*TH-<3OGo=zuSUY9N3_v599ryPKk|EKsrAP`;{5YzCA zT|mqT=obQF2fb@xgB6`z`HN(`i?DUC{?zPs-07iqaIw^I;+PVsecZ(_%=U3U$UOqQ z&dFyL?r_h?I?klF5--;5aA?!x6Nhf3!oArE`U}thq5*PHQ2DVhV;gU z9x`B*I`?g41COoH@Clx1AB-1Z)wz%PL{GjSP;>|6(Si)q;u#;kCb^zH zim}zSQ`3{u8BI@6zplktnkpb#2hXF~(}#7_Gnb0V3pm#%>D5G6B>Fdc9~KAw9y@rB zE0^vQyeRRU3*OFTwtEg`YfKX>JW;+8kJUK(T|C>V&c*eWr)&&yA_1@Bcg5NVdO^H? zg(#?Vap4j+yFnM-0Jzh^gS+%|sxNc5=rLP&y$b1K>h+Yv9+4h6py1FEg7@&D zYIkQI`Q(bk$^h@yPhsfn=n6d8i*IeY`IqwHmEe{x&q+91xWPw{O|A6N$GBehi3Li( z?GyXexj3nfXM|lgH=7qK%Ega-l%x3Gmg`YG-OXmSp&<6q#4yPwLe2TZ!)J4-Q}e%| zl{R|va5&*B2b;sE;9|}sjzIQmxkEmW^Wq8vep~nQW@xp5-mFzKg5ncfiM~d{Y3y#O zRd`|mk7?pd0Bm|5jxG%K;d(w!+T+T3txAM-eSAg29S>7wL)v4H8Y}fP@l|i?9zk?# z(MIwXwM_uS&Gbe7{jdg}05j#V)R^eDx1q~77KAZ@`}6|0#}r>>B7&c9-E zF~Oljr#J<>iTMs5I>Q-H*QPq@=GK*!D2V*S;Q0{P~x4SKlgSYOc zJ#50cK_h?zg2quN7F-`-@Mw3VWRtBAI6{`e)|J#Box5ajv)T^wqc#0G%goq0i>ymA15pFTNbxq&D?J?M}NBn<6GU z?h6BF>z|5S3?4iQ>jr1w@p1%>Q|HF!AFE1qsK za$Z3ELo3qt)t*2$H7xW!HvQ#qYY|U1wpaX3)f>>3?N-`Fwv62kW$suQ5wt9&k znO3hy^pG6&ZbbKoP?jE+rFv!SaoGY-P4CZE=^Q;KSG}17n`^A4`Y}afhmsQQ|A@U; z$RA&UmL1nXm&?g`rAYVoA&$?5ngQ7pioyLTJy|5j<875}xgdg=y%AYStS{2K`W{LQ z`b3Rg^`kWSFX+U2bJ<||1%_o#>#mv(bHH8UD}ftd^QpbwyhcjwcDyd7+vRS<#)qU~ zVlDgdgzxoOZ=U6B&v~MWn3@N_Ou;|MS=7ykN1PfyErEPO_w0K$ZUE;zdS8WF$4FwN z!gd*+`aTM@<)86w9;`Qy4lHUQHWf6+%5G6pIM>m7^Zp`5PHvQ2-iF8c#olnQz?dTO zK|WXq6*h%)E-e>V7b-Y$z03{MuP{BE_4(rbF+y32! zVm`5MD`*O5A7WixsNn2kS&!A$BWp!DIJo}1IEFRk=S!ZBiQSFxw4?m2v7Q@~xQB^N zouM5x_9KcRoVVS8?5N4&T>ab~$z$FxYUD zKGgoyKhaz3E`nDg>5ZSCiQgIAcAi<7?&0G^^L%&? z40AZm+Q}B<2*H@_3#Eop3@cT~u0DmgmT)B2y>a<6mEoF}i`K!K#oP4`(gB)B@On8; zngr!@N{Er2Ys`+ z@?es=vQ6}_@u1Qz;;Mu6tfQy>O8fvx_lqOSUX3BtO`@z0-*-(rTs#g5gX4S%9dWKh z^PO$d&r3gA`J?4)xES9(35Y$;0NFo4-%Xkj5QBVrWPlX-s1F3Rf8LDoU1yTGsgflV}z$VD`j9hAP5;5-Q;E>NOSZQ&X9bm)KWCWio`%RLYmKH9k;TtFDA< zP6v?2ON~ZvVnp1%(e<+7HaFlqn(CcOoJsSQD^8*{c5Js$D}*W6N{LxIYA2qSoq{KV z@IeXZCse!j6Zkj^hTeYq;N&%8luy5+F}J1kTTe9|pZNSrivgOxE`YBBUL#)S$?%Wx zfiSG|2laeBr54hk7tx30J}43xnRRO*s=`EnBv%h;Al660_)(tTQY600)9Z`G3x(G% zFA}qh$de*>nOQ(MY$V-wqqRKYGU&J$$D^ft3VV`+CWB4{pqX%wV%Y`>>dqTQoi=7_ z?==>0;rlI(#Q?uv(^$M1)=L`G*RvUYA0;vH;&aa%gTotMpQhRa$haCG#Dn4j{rAd0 z><{VZPM2%)^o-MG-$MP$=_*yCSDdZ}HX{1IM%UmLKy%%%ja+b|?%qbOK7|;!wLLp?=;n?t)ACb&1|dpw-s--)ss#a<7th02mPxF-VOJz-|N|J=#$fH z+R(=`C$*smWCykp_`vj-HeyeZ{^K+0OWKGL5#8rh@j}*bhn_0F%pIjRwh=Q6^m}c@ z7eyNGo(=WKU}{YN`^NM)ZREBXxp%dq|6ST>h#_eDx$g!47^a{R7*|u1Oup7zE0IvA zCUoCiT7}%3gU`zA13BU`TwENTEA|D*V{GUNLbm2;{I69;a!L`@4>cBLenMR<`LqND zuzsIYc1xWqq7QFBQzZIny%HP#;qw<3;WO?}D}XNxHU5(-+xFb1$KVT5NIOl-4wFpV z#-33cCRAe!IzVGw{I6xhX+Ouf?KX|Ix`9}?@!^s!t>mEqzT%^+KX9YkgYI_ikR#a! z6MVnMxJuJkr9KN>kJGn7J<#oGeKeFO?X(&Sh>wsPhb#7LxG@e{>KDu9SH4w#^D#l> z$FJothsbv@OvZ;ZKQ9(t{dx<&;T?QL&M%h9u>PP}b&qJcF_BwetmfyC`}rKbycnMg zp5X(swQvS9_YE5Pjw&W!TgoV}BTf3q`4VfmXC5ql6z0!gqUwM(?p}p-r+I84KKRxF z1L|-W`EsEghld~w6~1*2_mnI>r%)}Mwn49Bj;`UiUJ`~XJ2P9hBb%EM*Tj*~_D})^}BzzD`26@82NOrgox4^LiIaNLpz#~Zb zZWf)8f_t-14-Y6j`40Em{uvr@zz{AJHQFq~(J$=eSUwPMIuA!Rs6cYJ>+dCR z#+{wol;1xu(VW(zG{i}wk2P&^^uc#B9QusdYrfGEBx0gA46p=+=SfX>qMk$N=ja*O zRq+v}7Eb|rIHfcrBp6iiphty)_~}43t*8 z-{bZ1$RyYtTCTx}lr;0y>g;WDt8Z;oyoNW1@svwQFN=yV!sH$n(et8WLl(JT$)W!{ zbM#wLF*8bTQbEs-07mKL`Au|CbE#8_FZ;QE*BZYQ$?qZOflWbbFkTLdluyI`p}u=- z(EZSaJ5^|uPg_=a!{3aPDrtg@n_u)e0Q5JeuJSs)9@hxmRZc8I?}8M`Xls2l-qxpcEBDF2 zU=seIDFAi(4)^_#JQ=x9uXOKc;yN^oxpgp0ps~0CdjEotVv+|;MMmHwM#gOWHA3$b z-$%oP=D(wx+H~59lA<>5#;>hx@*{j1w3kmU52)9DSI!O4$11i3)JORCML^ljO7M1m zn$iQ`(P$RFQ=G3K6c?XQd!JBzkm)Lyr=g5ox*To&YxSw7l0{1bdB=|*uO zPV(MWM_d%TJUGvP2I&7lbD{A$8JuMEwH_5v%e4C1uloBH+-{I&)RCD+cAX;gn}+Yk zD+t{%2`$CQrN%HjHks@4A-O2`VsnfJgbH)m)M2EAuS&b+Cl$XmAPEG zSJGhTK8?5c9+qa_8NE|K>&~;EqHYQ_$}^htY+cm|? zzYF6E?Pl4}K;QJK#J_Wu{ zf$vk``xN*-1-?&#?^ED^M+zjeFa^Lb7BDcuFv&2@Py~&CoMGDHAwy3yOoka}7-Ri5 zw#m_WGX=lQNgUqE27Yt{7R>2~t#JDND#3V`Sta@pq-5 zrFht#ex)oI<9JrQ%k+%~#@OHk zv44#9q!}jIztrZ>2PXW)ZUa;M*`99C1S6ajfRK`jU*N z*gs|EZMrdD#rBqAbD4h0_Ze0jSoW!b8Rn~Im}b4$Kz8M@$?U@DK7&U+>6Pa6s^an$ z=X5D$eJL)-g7qdDPjUPcTwcU!a`+XkOnlRfS1}YEuNar3sKpryd@P!NarSo+{JSG%`k(5g(QD~R zrdQAwR;}MerpK9oUtc4iVd(AOc33@MV<{NF(sPU*sUdzBk1@;)Hn?ECY^cG@7%yk& z3gKVp87AEL*nmr_7-wK=kb%+323r0~<`<6|dM0IHVz7b9VRiX;SpLz>$8ss=PmM72 z3dU_XVwSNhHpcjuJ!W7M9|ojf>L~*)e@Es|v;H*m$A>aML(5;z{AFxclEX49ggn+H_=CJ+Q9b)vPbW;g_?%a*k&i!%~J(hSi*2Ri1P! zSz^+yqAQM9;uq^~VEJDREWOu2*AxHBn7^tE(|a)AUkxnpT$jH$^NXaRM_I0%`O|+l z^aSHJoYYcdS2f#J*3Iyh{msDiKMl0}8<@Y6!>QnSMDH_T_JLdh?$mP_7FJgad^)1Y|g6Vnn;H%l6 zhuz|D%(s#05yt1`Oc^vLC~zm>a{ z<(hct;vSqC z^m`eSZu0v(~;0fPugY5!*yKVtevki|Fzs+5S`+-f$2Z>l+SKlu8KT*HZlKZhGaYGs$#w^ zOt;~_!}vCa)E-c{A2I%khkyNrrks7sbesO4GybKA|7*sD$4c4;ExUiz=N{&wc{v!n9K%s-7GjhZQL zNBet^d<8MO=XEaPM^{q6SnFY(~380XQwsEt#fw4D8I__cBJU(fzFzO`}k ze}nz0U!q@aocy=4zwO_>_)2}v8VFuaX z+E*JVnG@Kb!lR!TZ@~U`9OlK1)PL`PI}YFGj~8#n{&t+?#gAm!*(`6A{Ce^G*x$y# zHcn;Ye)hNV_u}2y-q8i(7*1q3gW+=w zUt;(Q!#5djXZQ(2b(_(fc+AY7QX5SUc7EL8X~wH28r;$|_0Vza&Nbi5AM?;{cp2`u zt={-HBVWzwVd+Vxi${$eR$jbk_${9B;AsyY+g_JH>A^D|JienYf69Z4opt>a9z5;A zWAE4HPkQi-2akVHmp{e0Eh8nI9#y?eE1F@5&x*M$)fVqvx0Rj9>6_y9qzuD~i);-r zA#7m2H2X)tF)h61v*}*3-`HvME6w;^-oLT-Rnb2Tw3=?MgCU%IlMsp00;3gsC5K4}ZKKdXnj79{zMa^q4gIZGExvuV(o&din&v za)vgYYT_R@@-`lE#;rcfm+7`7!^3@*sSj2=oocXNXamG_@Z@M14 z?<%ZocLn3E#+mwU_3dMQ(UE54Q_4^)mLz^F!9F7e)?FrZN zWteVp(ZJYk!?X6MA2)VIaaE3f)r?!dj+`%5OfO|VVIeb?dGgQ7m(MhMEuJ_6pN&_7 z?X`AV`6%aea)!~HVrcEQ@@bZ@DF@b0mak&Fsu|kyV4=5MWM*?Z%`z~-xJ}<3p7gcl zG0x?!+*9sq!eM&CLM{g}UKgr~_Y+({UST^JR$g4Jp zK3G2WZ;6^thtPcnWTr_aCb1?k?|_VJ29TI@{I3eyffp~j8`xow01Bq7>_f) zf%$Fv)CbcOOu8i*CK$#TrpFuq6hp5b8_)W}>&$l8^t0(^(`z65+xXdd+4y+F^Wwuf z-ZuX#Z2EIL*mNzk>EuyR#^G1hlU@^9Uy7kEM|ZHk1Vfv@9`zz<<7dNXd1dSyNIDi7U;6MWL-cV(d&??j90j(cM4U&i!GkAFw@ zuV#8#gSzr%>|eq3YKAr*@kXW{_Qo&ap<8=*u)btR6HbPq^%p!okDX)ulMHQmN!DxI zQA@92`gNZ1ePuoLs(R?v_0Xe@58qFgGTn|-tUd91=m`(q#@pJR;&E&IViSKmPO^OE z9KQtnC+p$s&3q~LPuIhjV!jOfi%Sk4?p)@Jv46ZCKAR2+_7|5PUf&L@kNxBI@QJ5P z`A)EZvL3z?=1Z}E+QVo2wIrv1<^Z>oj8pp3%)*vqJIfe8$?#d+=5H0tO=N$oPc%6= zE;$x`r7XA4qc8C-^;NK3r^&{CYhU_X>Z@kC;jGW5L$s-hZ-(u*^wN6hiF)W2OfU85 zudIijsfQkIX6%Uz9zXE-sI(q>!b7+9%;u}bEwtmmV}(}U=C8#qJXU>{-^$y3wz!3s z?^vOgxA|>x3y)Qw<+t*-yd){U`e~ZuQ#olVQEF z>kOZ`o#7P*M#~NK>dpMg(5pRqlUyznY-ft~R^P<>SZ~!Whu0ftKCj*?)|+I#X{+~U zqbJ6C%Wpiq-VCRgSMLt1m(w9_)AtUer z{si+U??1fW^xqA=+@rTM>&>t}@oU2uyUoA~%m1&#>y5JBl;yJpg7v029Wrcp^e&?( zZSDQT;q|8e#&nO~POLY^`Vwq+{BFZv&HPpO9$s(!uZAvu#gOf-uzETEafao8HheMW zFTd~bdNW+EOFeo^SZ|usL9o4*TrbM3-hUrnZ-VPv!lO6AdgGi9NvrpdMo*IY%Mypz zTfurOJbEXx-UP=#$uPy`p_2Ji^_1T<>rFGC?f;S|)a{>xo9p)P6ZssIW4aGv<lelb3enGTq6su+qqgI6$& ztv&iqL$U&!GW7?@x@&Ugj$r5IK+wDF0}H0hb*bFdjs z&)8VA<66p4OfYzQih*TQ?T)O`bRFvvEMGd_*qyfLG)EY`-0EWkDp)SY>6w~n_$tO2 z{V9f-Ck>u>is_RLEM+-ilL3?3L8(hE5_l(nXimtHOI4>!%0pu;Y2yS1oM?M zOft0fBX~;P`cc9-*>Sk}-HN$&>x-QawPLw_++JCFoaxbdM$X1>1M8`{!tB(R{>s4Q zuMMnVm}XdIA>X&EWd2l7GjpwA-0HXCRk8ju_K)3Y^j9$~zlm{%i5u7shG~WwhNZtX z{&9v$hSdyh_^mj;Q4Y8Ke<*yL?nzE}o6gp*)U%uq*PD367#?rB+w!!dg(*)K7cJ}J zC5&4;OBuK85|*A|dZ+ouUQ18b!=JKxncuee8KzVG4_BT`nBSBlQ8OMAt&H8rDi=F~ zTq{p_HePX-%Xs6<^obsNn(5wji?ud(Te?k$B-87QPse)f%CKDJg1Y$-Z)3tKVLIuh zpUtoMZKixx-fm#&?-|}dyvN-fdt-xq+q37iU<;(1v64x194c&9LeMv!9>3(7+@^ zD_6$lqLTGhbGm-l_T9nZRB<>l&bI{P885%eoajnjZD3`4KH+sX(@!z5>KdlA?j1ILSWlGm z?|Ai!g{D2ous*@{yS{Q^+o9O0b=y^2e{K6)-~2S;k+bd0k>pYyIa@!EB$x5X+4^=Q zx!7rS<7dmwA#$F1QNkl<%g>SIQXV;5Uk{OsnF3++A>)zjxWeS;A#$GiX{>GC_yvzr zF5!{8<0$1)9=X&}%4Ixq@s;(&&yx?a)9c3Xx}%g!c;q(JXQwA0QXVE0 zx$+~}$<2Z2xY(pan(uW9dfp$uYHlZmZEudyUzW3;ie5%O!+I*q4IbtDW!`>%BFmNa zF?>~h4g9X#>x>QOAr9wZw#)VtwtqOz{xQA8q-R-AqrZ}2^(=#n*#>47u>W&RPc!6< z*~fZfoSx;Jo)vsQFZD0OA7_0mCQ6r@@T)kUWgO20hhNUHdcKiQaQI~$eu`m|`6?Ku z7}{{|u;FmNm2tjBnJ>n$YM}`yy~w~QhgZ$vlrmqOVHrakPA9$}SZ?nt@;%1{-;0bh zj4>1pGhFV{488qelJ%A)ja?bm8|QnCF@}O+#@>^(>CdooggLov$L(dMroFJ^ZA(uw z-L{XGo~nmG&2-xi+jd&CtJ@ygaBTZf-~1)^E#=}zkZV=XJR!kywtcRNFVk&%Z|NDP z+xS>|{EWKkY11LabSftlcPnSpp}zTxIMe8}?V}AR!F1bB+wy1gD?ZnhlX9*%rSl9P zU(C=`4`bZk$C;zSV}Wx{}l983QY>;&o((@#%&ho5hgv4ErZ$ z8hWLbXIRBB&i*NeHvH%s6Mmfe5)5Nk^ZGTz3Jx#H;g>RA&i-PC3BR0ShW#rnZlNdq zRvdoWY$KmySh?Nc=|u)sZ8fm^Jp(J#2Bw}fuymDyRZ9)5zJ~2zZ1A#`23EXdppAc= z!_U}wariO6xv^Ku`s2#r32k6ChaY2D`U>k`V_^JR6Mp#;gQs6KFe8k7O*!gd%8R#r z#m+MH6>oaV5!3J3UYDL?`rJ3_(lbmyq@12@^jCZJGrhvA-}1A5n|`*OM~h6n#F+;E z*YnSF3Dl;OwW|gmFh9Iw?f&ZHi>)*1R=L)|4GcRm-FxY@oa=Gf*<2nvaQrzO8=mE> zX1>%}hHqbufyQC;(?b?P)@NaTd>OX0oZ)bW!SyCS-tc;}{Rz&mRC{BW4aY*uC)hvE z@$~Ae&n~OS!g~3RGC%iyV-m!|`tmdA(P!(0H+^k9syUtO<@1DFAK&m-OnO&wx+fV< zWLV1ZI)*Xk-^ch4#?uVF@knvLRh(<`D|%kt@?_&-`Krz_{#BOG6A#N*_Cv#$I^RH> zPPV_w#F_qE1OMCYqqn}PRR z@GM`&Eyll^`E0qecG~vT;uhL^VPSoIX|}VBVP}Rr7<$9oVe2>NS1Mubv*B21`2_pN zIlf+f_1R_hSXeKgr#{w~PqtoLSRbFaUQ~PfC7ZrB9=2Z8%jc;V_3?GyV9HPB>jowm z_GTDm*pZ=N{tb+;U_8ap8xO(#PQ~v{ensyv&>IiSS9P25ud;lecv!x&+YMjp4+hqZ zKe%7F_YZ8kZLoIUW%$z!D;Qe&SVuFC=*Fig#O>ckZvPm@8Qx(b^Tio@?Xdk`X>XIx z)eLR?Z9TJmmF!>fkm0v>T4?#onJ>c`^Xw%Wc`uM!@u=#2ASZM9Cus*&! zc-)-fbP6(F!T4MYEuG;ZcG&vB@lN$I>15+?)6=#`G4_x5J$!mvz6A4CGqm+#BA085 zFEz=wJ}Qo|S!7^kv4P(6q}5#iQp_LabE-#@v-KczKCdfZ zVBoQygN^Yy@p3+YS{XKW9;=>?tS1^W@)_2X`oQ2749oX(I{3|tMHP7l#+n%zZEaxs z4Z~NpiS@n3a?Ed19q)K@xTPF!G-CMDKR0?xyBa*v!@#nK3`{<3;QvS4d%!(atn1rD zQL#r(o^<=0g z&AjqY3;Y~b2QKw(HBOkzpJBFn%>sy0(r{YJUpOT*MaW` zl+cx0(b;-kL03grBA&{0`PLs%S-O$uH&fp>lms}0dTaPK{*QhI{IZO<{Qu)T7|ZJ{ zZ&vp^ zlaoG+@6cBK?K-4@zD{YrR+_HN-_twG-_8SSS;*k9&QMu@PGybv#VWimH-z_trs(hX{!sB=J zMXa-SH1KOpXZ2axnr`0L>W2(vo&0y;d5P!KD2wnRl!Ly}>(i8RJKPugyL(LikbR=L zKdc?5%Rj2WH_%!9R+_GiU-?PtEl-`PufRO5GC%G8=llwqx9R0omb$3S^S*O~*Jbt+ zFYaF7bYBshf21e6w}R;#04r(&oiqWh?uV>F*SOg?MLD4uab_Hs3+SUt-?oZC#Gm6Vs)b z{|$7p-~ToKq6J3TT0hyiw6axQ>}UJZ5w~{OyoirqCb#;mY)v<_p?*kFR>}Vy>j%mS zlzDXhDSPsH6h~RK04VeHTcfIRlzXaqJXt$TmqX{Cmd@h0(sZTA_4f)o+po`ZT({>% zo?BRUUQ)67Y@auYKL1kTd6m+R@Aml@JH9vgyB*&hes+9M@!aaS^OhPs&3S;WKN)z| zd?;=GDe(NS^~dzK-tgSkpR&DvlKMHlwa$C&JSfX^yYGhO7*7Nc;D$^5HI-aK}vy|pH0lzdpS;|H$es%udnxD19{H?U>28++0|99~Xwe}Ks zkup9Xc7v4fcpoqYx9{KE^+*OD;%jMtHQsNte#x~`Pabaf2QYoH6@9f8?zU~Y9qEW$ zJF@WB+R^Gh@&EF5qyL-NwYpFI-@LBXePUi0-zO1$~xbRPgnFj z{=R$tN5z{%U;Tf4oqZ2nwg2m1o4@~ml~$9@r)pOFih1rk_dmT)z@VSh{w((aC{9wI z{--{9eCqgA@JXG%q(Y{wjo0(qRVpht^7ngG)*n`x9j-EejLPD%Dyya^5u>TsmFaKl zt<~{aj@NflS?H#+(p_a^b(QtCRF=?Lo=fDIaBBlM^=36PFek%2) zn$yPqK5>FXo%!_>f1JZ$)S8e$n!Q zE>Aq=oa%4vtg_NyWojdprCH7O7OA(4U-kd!HvzvC<1Itk+B~r1S9J#+zwGw|jHh>O z=9aG^e`tM9Etg7An$mUF^DNJE#(80Z*Ex8GvbL^XSLS(z(&BKtC=NTnG@gaW=Nm=1 zwa4O~NB#MEs?W_=S)a>ugsFe3eVL!db5{Nz=WkDZQ~0GR-5;u_^ozhY^|xpx@B964 z-ygJbS;5bx74QG{IAHCl9oh1Ha7T&TbzM(xIG2HUXwx|vI(8nMg9jMi=gDzj(?s;Q zf6~0JdYIy`Q&uSLIx#m?fB)~U6D1z;pYUZCnngVa8vGoiEx(Jga(^ z=XDd#)cozr^E_o2%6a^K1)kgcZ*%|o=P?1zA_l%8|P~UwfigB=ie&a z=fUpVX!jee9-LeJ}0zLhSuI`<|=)PJ%5{c3(&P{gMjTgSKyC z_q!_dyIS^sf&E^JeZJ4`J87TutBh0o?7o*d;{5A=S=_J7;;{RB*ypU$4;_b0g3O|kt3h>J%79Jg?$dOh_8Jg-hAzIiw*K<@6Qy;W8U@)vUbGOD@%+k z+jp|xxv}?E(p=Zt@2A-P(yZPh`%-rQ5&K<~GWFT-epGpG_g!`5xxw$X+50hn-4BP) zZ)J(UM!W08Z@(vF_usVle~QeT>fRdv6<%k*mt*&>tWbZ!#wov3l43kGsJBA@+3&*G z=R)oGY3z4K%DmrY_W>>2_{GmYU)mrZ`@I|c{Tutepp^X{9ruGRGXCuSG{=5riSa&m zbM>eFzLD)?rZ3Pq{_FR1$V-mAI`%cQ%j)&E|7gEoGlX$krGEQe9lOtKhW6R-D2+vL z_r1%qznNit**;=}yxV;M)8r>jd}TiGn_(PhZJcnw)fu!mTVlTRJAU@P_#8g=drP(b zG!E?dYwSL-_P%A-@DYaGi>woNAEgHO5zOFcuP^gFk8jcD z2lqv^`vW$(FR$G%s6Zb6x=%6phiWh`?f!ap|KOSQgY942ew}?z)bpn z@>I$(l;==hKzRw}HI!FUPNJ+(PN#gC@;%BgDa*9;T7C!iYxr64%zTZPZ{e%M2l6{l z4fq83`Ly#F?hkw;{8Y+4a>{={p1(%DZZ+}hcdG9Pd{51b|HSj`JNo-0yl(7)`uorP zeG%$khO!ssdX$?|Zh>!kIlcZMo`1iup5L;n$~m-SYkqHj-^0Z}M!!9N|Df!>pZ@;+ z0V=OUKN|hRJb#MkxA1(YHqu{ukjhQqQ_$@~x%1Cz|M$do0DMR4Kalbm$}=g?qs%{` zjg4$Y>xAw1*zYy!Y~6pai}z)#e9oc9?-7>RSG=FHMrn&o=ff0#Ps;w3+f(jKc@*U- zlowD=q`ZT2I^~O$_PY0YZuMIE9`V#EKcW1B@*B$UDd$qor~HGm4gL#IE=*~!Tb$=( z+i0EUV`zVFv&9x0rhD#w(5RzFj!O5<^jW`8X05)XlBa!7TPM>evtBQ-Hf%QZfrlgU zaU%~b9Cye__xknfm;4Cj(b{#?u!D{pdC0+|N4tX$9C`3i*FW21ME`XE>{|UZJ$sBe zXml?x3>!cj`2YUyH|C!I&Tr(<5yza6_#HCL8}=A++%UZQM_yg;{qMX+9Qrr6(TUrE zqrJ<2{b=WRWOF(lX%e>cpMWW}$lJM6i@d#?(js5rul>KjSJ2M+_SnYQ-~Q0fE#z!} z@Nd}XwS%*Lvu3`qv;DSazKFAZy=K1XU;BT}+;1A%zSZCU(9SLH(k=2OT!!oEzsY@^ zOS)`}Jms=Qo8kX@MLW0DU;C~9qG25QwWg-^rkOA8;_(^&-p(!K4vEIC__D6r#&$yg z<&z>sWOn7-of!ERZ_7#VE$1qMVWZ~A z!83=5UxWStzwQK|+M(i)z`uc)4i_JT&)WX5ozy#2yb8Y_p5r?B8GIJ=OIy&_xqj?I zKYk3q{(K2}8^mqx--rnMd*L>MkA=S$@mJtKM7)nb2qo=0PH_%oeGNZ<5qQT7RPQ~+ zekGCgNYfQzhw#qwntD zjt@Sk!I#2655MSQfqC@rZSZq17q|EAeuUo$zZw7i`~V34gRhX@cm>{wcsqak6!ceI zDg9sL9DZ}e&+@#DKi*Y2&+kvY7omRuz4haC_*)VG3Z9>Nn5Bx|(NvrqQqH-sv^85a{h|H8%4g*^`QL;78hj4CUA&>fy#e3(PJt8Q zz5E-`A;KeBW%18N@4|u1Ki0v=j*rD?ok_LQt`$5F z@$7MrD*OPSW8v%FEB+GvnO1z>N8k27>HV2a@@V7VSP%Yb_-^pt@R9J*@I5?lDgSx& z_5QlfwEUk1FAor3oV+~;uWZ=N7xxQ7h^M%T_>LU-cY$v+MFz{_GZDV;{Q@@eng{E9hlzPtU{pQ)b*|@i__oWe-ZY1N=6)E6e9)_)Pdm zk$%yYRd1I0aw7WGJa1{d^+TVzN&csxKM-DlZ?3T1IQYvC38?p-n+A8c$maokX2V~P z^h>UyIIHN-M85+(H(5SK_{s2@kQ$$=~r= zbh_F#j(Yp_XgLo9JP+gf3iRz64|~9`<^+(*s@ z>RriqbZA#4igPn~nmA2A3|@=$=flfzi}QAPDdI1{-CE>X_@FLvuu+W-{zYy_N z;g!f|GkCtY>MaxhFnB7`pAXMO{7$$de)DK)8P3?KNFsd_&j(v;$8g$7{*T~;sZSo>&ax+lZn*3H~RcQ z<-yu@3Ooz%fPMmeY{YBua^$n%+NyWUCp4fA$7coj9q{eLeJ+x4q#XMSL>6^sM6dmnX^NdH5Z0i}P#v z^hm$Nx~g|(q|dN&fAOd^_~;gD0S{z`1Wv%C$*mH-8a&&10Nabck{fZ zyd8%AEcEM>hYI|m$mezV^AZ0U{%+)x^@gEeQqQYh7XQKUbi~i`yrnoNqR*iBPm{+7 z@WbHNkMrSUBL8Llc}0lllE`Nd_>9QsSokNAPv+Q`5Qc^YEhQEw%Rp z&%^pw$Z90mc=!`uig>qvtcMZb9G;8#VemBE`eiIU74h5PF5)l1>zgXVH2v~5yac!S z7w@k)D-mB4o{M-6UWoWecouH)UjffVd>T9*@ps@3Zt?%>c^D_l&|hWR)n|bC6nF)G zApDRQoBQ`<&s*x>3(?!}t}l+yEO_IRg%Xm6AG0Cz=+b81VI%QO#IJ+rBEIg%(ibBB zEW8A_c$U~i`ZD}p;+Y7~^E>DMv_E-t8Yq1UZa#a$%kbsU-vqbcOE>+G@EZCw`g1px ze2v1@-PLSy+ZZ+%lYKdXA9{IaPv6^ zUW8j79)XwPAK6e*|~@-o5G9+(tgrBK^tmGWwhGufl6lJc|sHPwr~PWBOt6&m#Rxa5qu< z?eSl5+pzw0akUE+xu53AW1#0@zQ_6#;JL`Bg3r(kn|&-{vLQW(tm}2f8sR%RefTEf2`jh zp1!s@&Iz7}_I8MTUTsCc=nnEP;$v}c39m=~r+Oaz8&N**Z$; zEa|U^9}3T0-<*eQJrDWp`9O30Z?&Rda%cIM@Ui%}g}WP?<2l3g;9n&_HXo<8qHn+p zkx#E(RBt`v2f=eUHrIQ#=b_#L?Xr4bZAHKEuH+4$qv)5-;F+7`Z~R1f89oyIG|xl5 z`Dx1MQ25WS=-2lHKJ-`mX8D`XNY8`MJo08f_qL+{9$t=oGP}!XGI=ncqdgDx#`-(q z>06rP`5K>86i@Fxh(FQ~gO}l_kcY{ppDcglpPN47tL=&ZtCw04gOuyD%;+!E)IeTVy+{TJUy{w^(lfBKg^wo7;ymyPu2q0dJ8XVH(2^v)k> zlK9bYfd7DmcX5?SKLUL<(%+7LPNe@Bz3bkbpRW5UpXu;Mvwv7VcTIRlmyPu2qaPCK zpFm$kZ~2^$z7*;E?XUJ$(OW)8CA^E95$W$k?^bTk|M%$K{mt?B_8UPVpIP*l&w~@* z#r2Q$6VVqV{hR0uk$&+!@uRo#wpGHrxM`98RP^apn)81@`bMPx27Nx#_c*ZS>z(yI z59`SVFKeQtoF2QvCr11@_#F|S1fLG?hR>VucO(7J@Gm1i_#nmeYs8O&FY-#8#M$C} z9Ns13pTm1cJbSSGH;ni}@WBzE3g0{8@4%0UcpraY4f#AN;yc5~Mf?`{)e)Zozb)b` z94h~ZBA$gmAMq>U??!w&{L6?hb6CscWChPdyM9H#68*a#yi2XQU-oRp=V z2^oGLeRa6)C*1{uuj6RLO?I%C^)-KzxD4!zz4fxo8 z#R}-HUArAEpWLa^-;MqS_( zi~3)r2<^Pc_8(&XU;8291GoNRKDHlH9^dTq*M3N(x9jd4+@H2354-NJJS!i6I-NZ1 zx;xg}K0_t)v3-UPv@3&;?K8xB+s8f3b{=l@S)bE4P+x|eTxBY?iSADVKeoS-KDRke+uz9HZ}ZglH)6f*SCk?j+plm> zH_ubsuZZ=wPvXWl$7A~y1-M@}lZWkZ)FW=!`?>SvGZMXB@0W?k_6_WMKi1nmMlJHO zeT=c>$9!xbBi7qKMs8elJhqR~KZ?ipF=D;#&(tCx+n;Gf@!0-MthfD&-1&;<6!K&H z619liK1S|>X1(o))FS>X$Avt{g?OK#|KrW$!S)%_YcyZS**-%d(%U{m9=%-`+djkO zNN@WLW%PDkZ2JuLNN@WL^+<2~44t27j^Fkf(rYSyyDqkUhFqk#eTICbw|$1Ok>2(h z%INL7*!CH!k>2(h>XF{|8RkWL+h<6xrT8tMw$G4xvbnvs&yYuN`Lun8p^@J98Oo8~ z_8H2N-u4;l=q;bN&oDF6+df0OPjmilpCQFMZ|m6NdF?ag(OW*ZN_ZDHDALe`zrnvA>3bjB@^#b3o`>_p>96U0FXi;O5dLDs>#g{Fi+<>v@>va^P9s{bcLmSG z`}HaABheoHCZ30QR()GOz2L{R;xih3Plen4`;E_mKaYP`^eg%UN~qU< zFW@uyUaj!UjPpAHOQV0>^RVyge$@QR!M|xm-({5Qwci^^qu&OekNih@9{ekOPu~2m zZ$)2&7x6LweYV}K@Evjcp2(l@LGOychyL)<@>!J&JHAff-hqGcp7cAQ&-gdWL%nNqfm?(h z>v>D@+dRs0f0!!znZ8Wo$EP3sB>dfWT4CnFKQO+%_-YEv?Rk=XKE~$^^jE?U`9MPB zAHqM4_=+dX=dcf@_p;=%2fPk9pA!7Qy7Z@_e;WQl#M}52n9$yRW;g3MfzOP14ZizF z&HA>!qTury+~Vm6-}U2WeF0vJ_$2rapET=d!=I1%vZtxuZ9Z+*?*e}+;y1%L`>a_% z6aHw#mp)zo8+|VQI^=U7_;C0c@GIfp!Y9CM@N?$Krzd>rqWtfIUk)Dx-{Onrde4H7 zf}8$c_#$6Q-`VLg7rrvw;_2lB4*m5Id?5M@;q&1BY4Ug*UOHXl{AevhE;B|xCw|o? z(XG`^`tk7U80ot%Dn18(^S9DZ5_TJ(DW7e=6F&of27Cs53-~MWMH|xl;gLL+I7>dM zn^f;U#94xmMSmIk<<6FVh41CFkP5dCe3c&rEN>-DY1eYmUmujKWi-^<*m+xUg>o*C|asopChz8?H}_|E8$gRk(b;^_jv5556>EBM#&Q{el;4>@1; z&V>H~zYYG@Z}J}u?{k6l>EFfofZy+VOUJt>(bu@I`B3z)z_Uj#m5}Y=v*0E8RQMh7{6D}e@ZHe2y-;zchD(1Kyd%5_e-ge1Ja@G8z2O5)54Yp;-ta2?CG@AlOUE>~ z>k4=segyg(;W@q-x)1y@cm;k9{1ww5D}RfB7Cb#d+{W|Q<^!+eGap_$PWlhv3;7eL zFi#63#kXV~>*RSjFDDgNU5(w~93@+XWMVT6J8!8 z{UqA;2=%5fR=p+s-$I`|OZs{E&o)l{b{_RJyl{^6i!Y!TEKK~VOT?d{-mdWarQ&Cx z?+q{AB<@d>lE(me;VN+s^KKA4f4%sp=y!!T$WI#%0EfZdr_w)w{y2CQzTv|9!|CQT zSNbpM$4kuTJMnGXNk18$Z{INi75FpoN?Y-p$irLk+;8%En0P*e*XN1bdBS|t{~&%D z{)?1YAAT3Vf`07nc}wfq2IyD&LxI@&&+hQ)@EwTfIM2g%`ULKC*#UkfybK=%e-NKV z{we>n;jBK z{6NoJYS(b|TSxk*TG7u$Z@*8m80}iX5BLy|{f@=b@IIc0b$B%Qt;@mpXhnZI+n6M*1wr@%7*fFQ9yyeg}B=9O*BigAar+jo#uv30@yB{r;@;7s5M7 z`kT!Ea_L9W-l?94d^++;nC@BhD@Hyaz^hltXD57qhp!yzSMmcOjEB?&=}$tx5q$MX zzb|~vh#v#*8}Tvl^hEhvelCM=5a}!MjUxUOJR9+k;af%gSI=7-w@dmHxum@}DV|P@ z^B(XFd@6iBcmsYTd<%H_X8CMR-tzFlQ9NVJ=N9Q#Mt>JY;cL|18v0(;yDEIINWUfA-6{WYzq#<(0lt5v-v?f~Tl#jK=Nt_`IMSa3 zuih*D?F@+PJrCnN$2hn3b85m@bkm}B^-=VB^hMhBGJH_v^QPya--i;9&Fi1xg=vcC zV%ClJ6GJ>5-4N~rY4I$T@NO;}`FHU=_>YL%yB7NTR-KbP_Dufux5I*W-df!Jw}p3r z+kD>`o{IE&&qKW@MD-r;c}wH}!dCbsd>R9ELVZdX1-kw}x!|^jrAA=qvm_pFfRE9;d-;lb1-I`|XS5@jg5?a7l6M9ag4Z-q)~t z$9mpUJ}*UIS(J&GxH)$@ydLq%@HF?&MD8B-Jj^e<&nMHxJ)iJ@zwhYx_~av>KN9`F z-@kN)NiD~}S}S~A&lmjbSET%HNu3`1wxU1W^Dxfq6&*-7LVsr~`iDIa?X7da9h+b8 zx1#?NfA^sLXX4-W`j*?(%kw0jU9@04+(s`r8eZP5nNKmkm-qtc=ff*|i_fOst^I{b z@GtKp{wVxqc ziTlgj>*pEWbbiZW!4*Akah!V|;;&`YQ#OzOnqLubZNB`F)Vr)Z zq=ozOwp6dXg*>xia|H2U1$Pq`Oxl@NbKPWk9=<62DR|>n9ne;UFEW{S-6HN!Q`|DE+`x5?e|FZ$UL9-S4IyAfV` zO7-&gqRyRVfV_X)>8(%(=VqQ zXI#;}?k0Hs9mP3{dO!5MO$+zOo{K&+LBh?ccj5bJ*D!G#w+F$q{p8<{c+P{DW-F0H z^k?@nyfH`oSoDick$$eh|N$ zdfPo9eYPlmJ^uaRDf)4LcnMxksowthyaq3hkk8ie9sLDVvYwC7IOlc-?v82VncfO~ z6#nnRvvFSP&axwJlz_VM+=Wgt$MSp+ygo?r3{x}Qau3PB z%*OVQ_z!^Bmy!O`#r1~7bqK`#>LtML3JwQD?i zs~g`+0iI5rnd$PceJcNRiE|{pLVxv#|HJePNN=A%xd&d~R>oK8&#v<$@-MEe2G#M& z!3)bs$lG#m0=#ji_$13CKNsWkhUs^bp4-K`RiBhkBbrAW!3&&+birpIc&4a$>^Qi_Q~3O;de20^9lRL% z?**^TP#$hX|C8}6#n*tZ_O$%VeU)HN$K4^ur$~Pf`I!hWyrX!&#pellW*zD6I5Hca ze^>gC(06%8^|}etcgKGuyg~o647h9I>Gh@WfzQk4bB*F>+PDGF%0F|J^k<_#9$w*w z(?`N5!pm%s*!xFsz;in+m?&)>+i-^b^XIis_?4_bPr%)}s&_BiH5;Decx2;eZJ(%Q z-5#a!*$4dqc==`dSU=8$r;boOQ#tUj^g;-u^S}L`MaJ{s?+VJ#&iIdqr>gRQSbugi z;hAFue0r0|e0XVn)%z2??~C#;Z6Ll29rhtS^OgGDjtiY%l0HX2+WMJ=7fzDTp$g0G z^Ro2yJ(On~SMR{TzE2I>hj`k(B7N~084RXf8^Pq`8u^LV zfoQ`LCU@cMev+juw}p8rgI8|LYA@Dk(SKTRHA!Lxrz ze6aDI=iwEuJ9c55RN*DAH}Ary^E>j%a$da#K5N7Ct7u-F!Z^POUU^aR z*gpBU@G9%7joTI9CC>MxKbZWV4$pljemi-43*JbHpHBSqjdMOQhd6VyjM-y{ScqZB=!4&@U|byC%cY(wuW!-d5Ax^ z`Vu1a*9GueT{YHhJ%N`N^>zEl!FrWjr!Jq$=hF9ppWu0DS3Rc$lV*22`eFz9=wIi) zL!Z4>Gp>S9YPS5-*DjI}Zd>Ng^E~9I+OxS`7hc!arCa!&rq{hb#M3xTc|M?xD%j;C z=k@>oIMVZw=L{P{3`2K);NGXy+m8wVIDnTv?s?MQP1MpW;BUjzUy6^1|An`F^1UC`_ji09o zzs0BD9DJg6V~poZwe9Bb)2byw>~>whAkI~kpBm$TufY8{FP^YK;_w7M zZ+jl%Pv0gVTmBaQQoPt*<6#T*$HFu7)!q#JB6zl;eq0s)JiI<-P`*6)x56pHX5H3(N_n^XE*ZsG2G44IJWs~S_lqXP`u7ERX(iQb^LK}Dq|fZ79`Wf-9%sRGTg%~e_#LM2F5U}1 z%kz+*>}=&>Jp32*^<|su9q_H@W9>`@)roR(?`Q#-M;X2g2%=hvsW)zQ~ zX~|=E&n;$9QXJv=r11XxW^%Uia4tTTX#T#M`1m|OykPQr(|?CPy@trfRMO)IwRghw z=Jp=rd1!BSW$Bkke+4{qirO`U@&BRcALs;n2tGe}9>#fz>zx7c_2$wq>@$zD zc;MNx;*pzkPkA1Ea{O+sW{q=m;HgiQf8NG+U4N#%+b^CtSBY~3yu|N;FG9Vyc^>@J zD|JkW`F{W}ZzZxJ`d{IxKGN^Y_*~={)tgyc@vp#q*~jy+zIC`xE$WHSDd^KV`Roe+ zGU$CoSedq+g0ev~G@zw+WrtzNQ3&T6i zSAOF2z)d_4{`Khm>g2$EK2wWooY?VVIy}wy?{u{C=kmWwpWa@17)-qd&zJIf=s#fT zgs2tHjYZ#hLj8L?`j_FQapG!)a|`??|JqyXmmK;GJb$jZtJv^^CSA&9*Soz*0&@5zzg*@SU+vvT?Ee@s`+U7 z`3zopUE`;O|FUi6Q&~}Y+Z^5to*Sw8rP`fa*YmLcXJ%_e4MM-Q=OO?3Yvga^ZGU*} z1GV==^vC00yiW~!i*b7kyl|y_Rz&|PK8+(a4p)P3@85_FdC2|NJl@8_i+`xztI^-$ z`BFaq^v#N}Km1wr`ID80^WgK~*=dSrPx!L!Rd4Zmahva(!*gef?})wvuXWHkvG3V^ z1g~$Z{>q_W+<#yu8CQoY^F!ckz)O3pUygzg^gKCk{+UY1G#1dKJP-X<{iC_PKP9}Q zt8b$9b|ZY&T~PIw-j~0f2cG45SO=<`Nxw1rr_g8DSG#V3{{~MNn)9>1{{m)cS2@~; z84a(6A5Qg;lZpRfc&bqP{a;~fAA)az)>5cF1dB{UO zIuASpUTi1jK2kcZ4p%CNHP+!daO`B-H>4njW_ zeJNVcpU1!Qm>dS9{|R0ktoC+=Z|mO(4)HX?5B~ax)mscajED2I-d@dl-C|2fpLtUa zeG;EF;f-^|ZJZqAd1zNQ%Ks(kQx{2Z>&%Bi@9S+GrFCzA{5M)s_10L&Y#lxW-Z)j` zzk&Wf&qKY9`_v*^CtWJ=e}Al)aG!s!LoE+k&y(ZSdzu%vj-BLrckfhYzh!kSZwmTQ zZ**PxHoU@lX$Jid@XSDs2aO`X@3NG9io+F24*f{aTZ(@i`r2X2r^Wvmyux|@3iy0y zd};NR{&nu?quM3ow&(R4x5oQ*R6M1}<=+jTli<1D;`V;lL!O8H7gt;=QCd9Tc^>kX z?V@$S^10~J@-MHi@wp}bnZW&caM5}DVerx$>K8jdxdESQch&d-<93y0RBwI-)w?$S zdw3rDtFoEuwKz}nJj7qEX#6W1&fl*@@uZ{u>eun9U!^>#7Uz2U4VmEY255ZR`>;2{ zOP^>x=}tUzjBl=Z{OL{dSf&$kE~jx~zvsRYytu#W-5#GK;We)JZCt(Xd1zN=XRU{d z%DLs1Q+|r<)2i2;ThsFpf9Wx;59<@p(7;2#eAt}-Ytc7GOK<+qdmiR>ZDU>ORETr2 z&WfkJjpErCzPab2-qe!nz!kYb8tD(XfoB#}ehxu@iRYnRsW;VMWY67c{Oaa@d>mfu zrrBiq`2k)UB8N}$U$~3vt-YZPff{qgX^p33kr_!!TFe{oOc)5h&B=*v0zY(YPE^%v$LpZOk&NB{co zcfji$FE+#fWY2?tuA+LY@GIcOtu=Bc!=DH~zTe~bvwEy3pZpjdLHV{ zc2%5q{cbtz z3n@a2vs-uh6gLzxpH1MYuQU!1z~>}*3(JMgfsKBZcEP}LLo7Y=A1hx6f?>%~_^-_3vC zv86aST9tl0Oh-mr_b&H*l7GeO+v`Y2`0ioPL!Rf|syz3^|5f-L&MS=1_q?Tgm*_!1 z{;Y8#H|I_a+_$$Hoexa$Jk&em7Ae!z`iZg3HvWgei_;Z}M!RztdmiGcJ*(cg5 z&KYpWd0H>{?BL_aNjX|?JM|`h&WA1j9Xt>1o%x*FYsZmcLGOKvA84JlJY0uQ>2S3u zPrYx$3-c7G`TPVgKBk3vZPw?F*HAq5hm@a3@j1)$ke@XBLUukm5q)-s{Kqlz_F7Xu zCEhRF2A^x;nKiVI9fZF9TGHo_RJ}8a=PY>oDb4p?@p;zske|{$%Fht^H}FDqox4CE z`4`y7vw4w*XQKVXT|E!&Egz*gRg3?aiuv$<)+*F{8@$*@fb)-dwL$`U5)oUPJkcedFYqagUXnV&k^{z!!^GwpO+cud|0jU(;WZQ z4E6h-_`jO?cXY+=Gy-kkBejm=EU+JbH2Rf2U&zri%YK^s8^6dgJ|~Q{a{J z)h`>Pe+*uT&KrOCJhZoVyCS#o*{z@abJwU|Tdy*n2YrY6(x>s?0eyXz^qZ0A%RCQx zOGVeSuc9w3q>+}vr=$O(N*JH@XnbzqdGKlEH19MTog3zPh{w%RJfra`;8TlyF84h2 zSMCty-^Ncp`1|pbaSHezMt=T@Go8~-V6Oy^zr+% zuLr%aw;CP47TZuh>9@7MjVGT+!gHHw{O^Q+(esd>I`0Fr%DE}%-P7{93H|HnOBv|;^%K0ZkMxJAaKkqV@%!t?UA0cy`g5x1A5}W2QnVk*A*on_jH>F?)$fPmBvF){CD#_sdsMk@#SLwdBTv- z;-cbfqo0aTk?%EFerDp6c~A}Ao^i71rn+8EMc2!#cpm)ITu)gZHupS?L-)DPqpZE7 z1NZv;wpv&F5YH_1^=RL~X zd!F>y=W3TftxX{rEQigW=hZ;`VuidyQYy-0yX`E2-X1@L6+^{Bvune;eB&U*7~T?IHbO z^v`=9`Zv$#`po}*&%67XT_3CwZs)x#3|76aoBTi3uy%)fp3Gm)i!{5Py9=J?I?IkP zt8J(8*7=d(rxcOWQ&)lteo@Bl+=NIbWljCzutJB_{;MHh7 zoDMJX`8OLUe|X-~`qpU&?Sswa{{NP@wLA~?rukfbhI&td7l&*9+Bm-jUXDH|@D4n` zqVzVN7u`|*S@sFdXQ1a{J(=@!b3TWlFWj#YX!`N!^U?cU51=o1)JV4ZKHq$(SF^^S zx9p^NQgy{So%|mJPe&BsUI!Ri|6RC!xd*+*0&AdjSh<3#?^`N)b*;@_6^2* zo}8!cq48k)JJ46UX+P}`;_SGy@-`^i=ULbD;L})HK0nisInR^+jXt+9F7fH;DjYX$ zy}bc{_jq%^%)meWxz1beW8wG^eJ+|8?RHVUmCrTu?YOq7=V3oK72SVtPtQaA)y);Z ztpmpe?$@Of-`m=fcAXLYJ+E_~Z0DI%0}npY=keCwRXp>C;@OFO9si5^EcNchVNA+(GetY0Po>cTb-v;{9eEIB%e$ejnuSD+`jDVN9UyAMjPlTuM zRetLDEVGC5lb)#y4mh`<)J(JE8*EE#BCqrPPpU!WB zThLzv&#$bN*7o_IhgV-#y|!L0wzqt$cPIgeF+R_R7dd~n_2F5#D`_Iy`R$VXsDDeF z$w#Bw@Aty9M=EdrbS`=9;CXl-ZOi4=UmPCY!HJ&6{H-|N^Uz-@J|Ae;n>TtM#zSgF z`K-Weo=Uj?T@v;OhQdDx{(ioscThtQX5(Y2edS+SxOx5D)$=fJ3-762c0DpY;eQK| z|1F}=a{gd(&hq!83CEpWbR4-9eRWyQpasa!GoB}U?*G{n|BuiYqxU2JfY;y9I=L45 zrTlK7uMdRJP-9&cTs!o_;Niw z#qZ!)o~xdRc2%R#pZth_YP{;@Fz7ZtQ1PU{(fnGTcnY2epZfZm7pv2*YdjC}epxLxONa)|O%SWqqff_hJf*N5nM z`WktD)$`C_CH8wQCtss?U6p6+M|Y_F^Vc=!xliCe&LaCH7U!Yp>o013xPcCsjlLFL zzqdV1{*5l0K_?Uc>TtKB47$V5fY)Boj93|dFFf}E=SA>2=ELW9R)hZlubd+N5DiCn z?BR+hx481~oYf1jEGusFalGlLXddl~zUq1C_d4U*&Rb@~M}MdhWqjeGs<+Jd)cWFc zDBNwQ`S>vWN_grj@yFoLc^>-LeWLZj&SySBU*$Z?^44vb>dmtcpw>CJA3Qrn`LQ_5 z@Eq^&TOQstJ)eKGd9l(F@^@D$!50wc9`M>i8lU%QnQ)zsRNnf3-#mY}@I17uzOKf@ z0UY3O_B^Z)`RF?Cb$F?*`ehp9f9a#7uimKfY45w84o{C$J_iuz6nJ(|`D_QD19!)0 z+#W;xx#99p&Cq=5gMMP*e!euK@9DgQK08DHcHXpKciZ z@X+DFQp z<>yy;hWnJRN<5tl@^5^v{67!h8=l|3dHp#bUTm*;rqGWs!0XRy1loB1&GQha<35ll z;lKH@8do#kRDRO%qdiZ?Pe0Xb<9q`8`ahb-;fJ0l{yQq3J@Dx@g8U5Byt97a)brrq zh|WVUgu9zrfAG0Ia6eAUUub~ab<-!FclR|rj^pOv={WhyI>H^I;K zJgiHTA8sBex1&$-ezA?iUXR6G0&56GDQo+I_RH9pCUiD&VK;UEv@!y z_3+=FIzjQ|KUIHa@Y%)l;2+;Vf4K3XgrU7N& z!>xE8eDYf=|H_hc&%@oL%KvZpe1lIdnvWZvB%j<+jr=u*;M`89$Upx4z{T+LZL0T4d>({Xzf_*>{Ow22 zLw@QxId8*y-tScLGW%4Pw_QC?<}aVeu>QIbePLPk*P+x~_B>qIOpdN=s`zC1T(S8t zwHdNGkm&w9==ze{!{+8kGCHBOtg<(foCUaygiQ3bk9S3OVRc9Tk!b)9;=+L zcyfz1&%3?gndimrJm(O2WpyR;Wc}IQ>3OKP%8hV-A)e>a=bw?odGJ3x57#L(zEWmv zK4y#ZaeJ!2eno$d=OJ&UBQ&oqo)Wyw^|eN+b3M*zl3cqY34M*p+qlR8HE z-;U$gF~+0M`H%BF98af3@84YqA6r-d+WA=3^AJyYrsnTgwD)_s<9pDm-S6|Ct$1?0 zue3bz5B5Cq;l3``@8<>{uFIm&A3ljsv7*HH!smU@!~40#?mF{H5zid_(|rD%Z7sLS zIn>MN99G8X$rBey@-UC@Nk00lyiOPfVVfdte(YR{Mx^%DSq2G&~SLp1; zxfjuAHq*GW_47A)^==t_NIcu0t30IN)p?X1Pp24faYU5B-&i z`s*WnT(oZYJ74QhedDDQXIp0u@H`pMYpQ?eQ}5HBhwmX4qwfXJ@jRUGWvf1X@T1XZwo`wd2cG~haK3jOd^Wtye!HUe_fHtFdNYT~XG`Mm?|D*hU)6gX z^JpYIznpjt|7rN-_EY?`;oUEie`#T@JQ?^=@XD(iw;H9+oeNL%zLKJH?itTRJZbhH zY+q8IONEf1(xoJ;imR&9Cn8%ra`w!L;iwc#U~s>&b8M+}eudX8hN=7=QRG z@KNwA>!+=^_jn$zm*+*-%P+zENAKf&gij^!ef5-ifY<<`oUgY}=>+_mB;rXX@Kw+ zil;PI+^*wxhNr9IZK(G|cqRIt&P|?&dWS}zgL=z+c2@p3C2xye!Tfqz=OI5b0s6t~ z`--1|z5uU%qIJp6i*60vuQNH;tA6O8@H~wF8lN}bQR#CFuF&#+^(^z}{&jcYle$tq z1wIe6Ieeh;P8x5Q!;gczscNsqKOJ7`q;}=e&kj7qAKjN@tqH2P$o<*W3(jo>ukt-p z^}chb8y_X5ts9TRE8A-vn!eXn%76NE#WS9Gw)Q++ca)>+j>A0<`7FLJpGoK^cpmz_ z;_s0f9z)>M&}W~Keqs2N@bo`b@7eI#o`-&{ZnQu`Y<_jPTJ<_U$709v9pLrOYVSt) zTmdi76W!1oM195--;$J6)WMLxf=9X?(DA^+mis`pR$ z(eT=H%D+FINFHlk%epa1`LXqXi08>X`dH^(){oc0^LNYN@;nQka?0n+)Vt<&_*~WO zb0s`|milWj`X$TK=Pp!@{%P_U3r~F@J-73A(>xF3C%)h8D}noQ8-L%h{Ur5o^$+!L zmU`C@+`nSpsyaike%#0N*3ykd!N*j z>X*03^ObOSweoDo@w(~xT$6g=fByDH<+&KWFS(}YVcyM*-j_KF-k<$a^FI}z)KMCr zAJMKEo`*QyW6J-v@D4YL*N#>`-+^xouk=^D?0u;FjPrdx+jsrh^DusD!#5X6Zt<4AB(=W znS6?jhxgD|c2j%xufGq~9m?nAdCF%VpJP2w*0&2)@A2?^;MIlYKLGxW=ixlO9-W7O zfWCO2&aYI9{|&c0ga5xjx_TbkmE(IZTAloTgnD^>+ojx0z6WZr+|TQib%60;$CqR9 zsehn(S|QJ0z{@)-Z+2bZ`!3a6;rp0}P{FpI2me9Q=S9b&Z@j8;vPOHo;01X4MR7k( zlE?aY%RkM0v3Yc;=ZQbxd+JZU6Fd+3tVQ{}AD`5ET9=kZ|DorhzX~5}eY1HqAAKhJ z{%K#Ikg#rNW-0JN_#EJQh-b#T>M4uou%Hk9!hW^oXEMC}wc7hOKHtGBOKK(G8Q$X_ z`DAm7zZ?8qcz!AA&x79y&kU7*pp9pE?K1V_PUsiC7k|!I^;hS%g6H3o50}U8S$OFy z^@yE^taG1yGA|N8^&So{t}dSp^e2be-JXXyOVNErUQIZ`{jK;CeYKY& zv~j!E{fe^|-5+lVJl-dnK6&(&W#qFT{A|y|=M1ya_m8d(+}}q!-Bl|_1O0T*ll;7^_3Cr#eck-|p2c|d zou-C({P$j?`;Knrc`_cpRy?*3yuatkJi15g(m9;yyn{affa)EEf4^y7@8@a$ZOv2j zIn(oyhsHa~gU!>sgWmUV`eluL8_y5HOY9HWIQ-4@A4~rZ?cM4@#b3)Qe*Np*NuCG) z_;*o%^L&zT@#~B?Y}_&rNuO<_`C{upZ+L2&B3zaBp5l4Pr(?g-+IyAf$v9bCeV@{7-m=`FxM91zzU9ly+YF9lU;%dfe9AgCFwIY${z6X&I#hjnHs*HauW+#Q~Wyj8hx zgIyPV1TXxi_I6VG+-grq-{APT3Gwe7xX)RQ`|$LFUxq%-zNlK~+-vac(#nIaSMEvq zr{^o5_Io1xz;n^}*{}6{l5f|+y>&#hdHpnc7kwYL`&05S@jbgeiF2Ump&!fK7sb}M zqtO?BQ=B%=-$9?>LIdh5e11S*8K(>nfRBAz_2w?rnQaFCIz0cN`f)S(QqO4ptaATt zTR%5|4|-nxI|%)*o+s;1^gi`)&qM#_qR)+A2(L3AZC|m5PyD&xZ_#J@UWT2YcY0R- zMZV8v>%)%lI^Q?6dHp^-!@RTgXW<$0sYLy|I=sw%R;^zyHGRkC@$a zQqRf1#C^{O!u!D;pA)n3a2UM&u=?du^iw?#$F=^SDF1ez@FDuf&N^;x!9d*gdBs!N zR^xd%J{Nf&`X#53I;Hhi0&fC8CbAkK#tDMj4tj6E3>?Qe6 zj`r;j@I3fe_`#xo>h!`r2Cql=1MK;-*0(~mzHR1t=&#Om6u+|Szjx_*l7BwmYwt%~ z?|HJGGp~(5gue8&^5&b9Jleg|##v5CO;Rl8dGJqhe=74?)AQip;QbE!T+JTnYa453 z?T7y@@HF2ywDXV}y!xa@f{oj`@ZxWZGtcqv{+jA7@_vxA;ok@MJjwHP&7K}q@w%6T>-Dmlm8H^uyki04YrL!9M#y1w`rJ{g{gen)98KDAjICmk3+dEd^kpV|1VUE;7B zJ~w(E`f+Sqtvo&9k9r=)PpP1I-huy==>2^#Hc}pxRp%C(Nx$$t)?Vm8n%=I(@z4`} zae@N0; zz4v(@{8NW%#W)!L1^WD_%DkfT`+>8hcYHq6*46Dj4|yxzqzfZ|x{^FjMqlST*Ypz- zPGx^9?l67y{k3O;zmK!b_db@#f9C&3*SUaAId%Vkr;r?)qNE(|QaY$iI;S*5XElUM zr>RIfF!Dx8OjJtBBqFcFM5z!%p-`qmMHo~P)i|Yu#-W4`|F!P#cm1#0uitZBzxVn1 zw4SxsUVH7e_r34E_bpuK+dHPfpJ*NVPQq8Tlh0q>Sw;)tVY>`LzgtBw4<| z^Flp`8OZ98}w(r{rLmQT`%ON zB<24@p5c9f)=#GkpDli_V-Ji1GK)%TP$7~)xmOSw0)z6XV zcy4zc?f*i!_B+RWC(z2y{XrhtiircPb*}8UC^y6NI2e7Ln@S$*j(E#)zHyK|`YHN5 zqTRXkzeBmne$bqxJ;Q~E{fp1PA0q9#6TSye@?KW7vU4rS6a21?*?BX0Fb#1ynEH$4 z=^00kM;C5~{_J>+7aj4-ZBZ`moAB<(t|AL=p`AI@s3Y}XP97hP2DJWut8nc{Nsc>~ zAJW3r|4U?i)*s8mFOtU=qNYQbXTGDJ9eK2r>51&1J#A2KecE#YdE#>Te=hahAzbs- z;3uJ{7UiF$e1YS5l;i1#d~cWE9t)6Mt33)V%r z=HZs!x$ojyo}ayu0MHdE*u=Cop+l2g^*l9 z{;YC|L;sxPYSZ%({9l6h>?KbRMn17~WPN{zKmBu>qlN3dB2gI;6=%6m2-kWQE5QE= z@|ENPST0ii}NAEwO$$TdG>kbQf__%+VOGL>o@Yu zZRnufj_K~%O?jT{v~{xso+JWqZzdE#iuFC+gzx%eTr^At}KJxF#GiRe-wk}#$CYGuv%l$= z+4ykSUxj(^58)cmfw$kj;U4HuF;7~%Od(JFiFWTo(-x6OxDWp#@_nYKi2Cl}fO^Yb z=#O#S>_qtmUYC*oSh9-h0yi!c{&t0(M&b+@l1JQt=R zK5cxNFTAQ)n)dD$Sws2!UKA+9U-Q6BOe zX#aNd?AyrC16bc)2cSPQ^T>R-l04$w2eq9%{x$qF9?j;O9fW^UeD7&-(p$LtC;b8J zxsdjcBKO~q{3JYV_d{rRi>pJFFY=tlS*%y=5X$xMcj|6@C&rOkl%G#t>_xnavjO?TjvsDr}WdJ_nn%l%EitC?^m(s>!sxWcXsv**SL-H`z)5vBS+B>KOxRn z(w@tNhk2${xsX)F@{r4r$G!I*%gIw*uP}QyQh%Cx)#_VH?#EaCIkw|zEH@CY^>WW5 zZoehJn7l9uer`)X%DDIah&jTwzKM#M|JXeC1IkDF9Cs1*oKOno#`qnjRpfPr2S=Uk z5+k68VdXBMe3JJ&#VJ2rxYldTXOL`6elO(%?w3oGzpC=mzVVrG@Fw!Fglm7<$M+qB z$q$73`5%Y@X|eq6m{ARl=1t3l+^>8P)rbNN!ZwpZ$6_}S(URb=C67!O=8twuXL30FTy zPenhP&xW~;JjU*%Ij+9l!L z^ER3CIo{i5dfpYTe)GRi^cCe(-aYDV%AnjL-}{)IIYw?{F4N}YiInCCs)c5b(ZaJ46L2?oY2^>igquSQ(WA^%&r+L`8fXMQ;GMCi#h zLR>vX`Ih8K@A+aTd9D`hFF`w(3)glm+zmaKkZ+@WGzR$}=+6t~VvsO?1|r_VV&9^l4yLV7tGwvX9YFk;{&$7zyglK~ z+qY7GFbIAgLH{3L4*pDbz_?ij>Re0V>i?qm9nYc4HLsox!^hH|sgzGlMf+ObeuVn{ z^JO1}oPT`SukF+m@%&k{JnV7Yw~x`^xdFm89&!O@s+JEYkmtSkLF>um!ywNz=e`a3 zVTSPkJs@23Lx%gf>XFw!8TMqj-`<`>ZzYeWkskuezf4}_ebF|5`&qfhi8o(5=M?Bq z@p%NTCd;to1%3x@4D}BZu71dtN5B4ne2U78{+M?z`(xo6SGgkMY82&9ssKHS6X2iQ zIFEWjco+}74{a^wmy$a^7ko|r4|&iAmfLp;Z>b3V@v6{&D&zkZ;bFe=&ddBj`4rpt zLh3(V{!r~t@VU(9=e>lho;3473C8)|%JsI!bl3U5MUVm9BT>a_4|NWKn$!`#EHXlB|GUTIk z(6II%^BHpgzR;z@)t(gh8P=zrU#YyrZDbP$M(fun%fgG=lbr?6TizQYTBM!m}Vhv42e@k3EPu zSx)^AlPBIozOsDssc`k1D}#Pom-4&G)10r`b6*8HuoJcm-?P}b(2+dByf=Y*7LrE} zA(M9_KRsZ4zJu}cY1X$Fd1^ZNZ!p)*5gyLpeuSO&ob^k{<-01o5f5?duU{2*28~ee zG`Q8hB3$d+)_V?mpWMIytzI?g$(#;*tUrzyuJ29uvD{HCcMIj??cjfT9T5JUB;%<1 zEzSE#SuNMbIPcrB=ad`B6Wmv6>kprjNA8A(i7dBdb?A?_gM~ZEqvT0`PsGOSF2*M# za4c{9Kpr$l++IOF$J7x0(oY@lk+ykqOXX6p0@pJyqx>l0+Fl8MXWZsjON58-Q@r=u zpHfe*BoyeBqE9v7~93S5UV zJ;TT|7r+npT(*FEA{~$qEf0K79-o9js6qY7bD=+X8}!(`E-PH?>qg_mmbs=9&!vofTM+sN^)15Kj&NB|@sl3k9y!Xi8Qjh-~x7zj4Uxs<}{ELOFodxb^ zp2K?mOdjxDyv?5*)`xtmJ?eD_+x;H$B){)q{p$nr!ft4=_$+fC^hCHm*^1?!AzbU5 z+YEo&I!|-T7nnaSerA#f-agfJ*|Ba-zIlFPh{ic$qgW%;W~!3 z%Vg!^|CINA=jFoH{=nPk^9A)Jx}qIFrQdSrLx0jcuYF!a=<(O>`;t3v{dSyiZO07X z>osS+(!w>~lHUAeHs#Yx(T>$9zm7ceAN13&$qxz-+r@it-lh@C4bDW%TK|2KyukP4 zHjeKRu6knLKG+i*LysGAq@GjBWBg9UxwNM@d6w@%?ES?%^U`2)%&J_GMQ%nv9Z<2YWM@;ij9Jz0K7%-%aR zZAL#F!aU^vzXu^t{)T>vXp#GNO#UC#*T&!Xg{%HFzh7znYnSjaKD~R%TyvD0$Ri$X zo_RHSb`Q#p(*D81Re$nE@Q=w~7G71x&0-mhn>L>2O+W8ZIfL>?wP3l=qeh*WZyypK z&O;hOkIiG(3fJeXmVD0Q^w52;@=|VQGv=A5|CkG)Kd1)}*mzN0csLK-c;x)^2H`r6 zN4;@;l5l9I;r#U^^(VZ0iq?|Hyn9xE5w80*QvUwWmasF{3~@e&ao&?W@;v&*G?sfW zd9)7vX7j-1 zPd&L?;H7oczn1c`{;+2rxw{bhi_f6JZQingJh~q8HEI85^2{p8ze+tdWFircr#x?t zXq0=ZjSoV7El*A-PyBXX-^S$qvU1j`JNCwn1 zj(YNZ9z^Y&d!0P#jdwLKLb)mKyRJ?>BgtdlI{)j!wLd1dVL_+|<@1!6C-snYBX4~% zy z>)o$g;}YnJFNFW6QBQmF#1m*Q+2#@cOeD`;iE@XK_uAyJ@47;zP%ePDTO;yXZo(_K z{H6ci-|Grj|M>eLtX_<sd!K4_K)KnI;OEz={~B_Co&QC0=k4p>Xq@MFEDszaPkZl+&+W)^z4J{o$dg6% zmvd;(%fhw)`sXHAQa+J~f9!eiXVcRhM!~uH$truiOcgFGdjOHh(Ax*LgyY^OJhiQ?840c@M~Y zEUms#;r|wg?S*T-;=E_?F6v2=$5z2_Hou)|^4y2nhw^WdCrTo54oA0l$*$1v-h`iR z-tu4J+KzFaH@ErfQsL@{!1Ke=apboc?=P}>LKER?fBFwJpw+iMd5+_|=^sR%e*pGG zY5!vKB=@Vs+s^GJFYrBhcgi=v9OcH&M0|cuK7`!yTuFj_rtxyxUCuX`VZ?=gp2+z|L#}M->)H4X=%BXGrH!0+6d zJ-sNOxe9)kVLJR7ZF(lc4;F{}gopF4SCN4&ZYx}katrH@jFSfB#dpwNhp7J=^31i6 zw|+XAJlP!b>)hn-PAS0>1h>jC}# zJ#VeZ<1fHJ-%!3kdC&*-nn!-S@X-IO5Xo}=a`=-acYJ=de!7x8JrH_qTsyHR^u*b( z;U(vqlgCPe1kC5t$P4?yEe@BFC&xm6HQM>J@NgV&fN{JndDCkUC+;RFHa*t~SNY3Z zL!Q%2H%z$J*S&yp7t@|Gsz-R5>sqy`{}JJuCzD>D{3g_2*%iF^iTkNPxDl3gp`K_j z=+Ari#a%|8>V?R>mGWuwXn?F`^Xf&y)&8I>;w?`36MEDC?;M%`>yQV0uIWtqYlLfk z&wB%jp)vUll=siSzd@c}3csDke6m`&_AkfzFtVs~hp0c2M2A>M{jK|;T~f8tE|-!| z60Y?s6d{j)b?!lOR{{QMMfr{7xs{N&JkY!^^h6rKKNToHRk+qS%Y7z2$kz$iIEisx zy%~AwexgU$XRgHn`xzG|?o=*%lHUE9D}}3m|GN*DBp@HBBfLe=YO`{(ejH=<%r6 zXqI~$d4&54pv}1%D;hG160~isk9}T5^a4GzAJ@r3A zUK|B(d44r{gy$(NzwIHWTo0Lm^v!^3JbfZ19 zjh93`n4f<2`J! z*131d3;cfQ{gnUK^!J1P$I|{|hoD^s^Bx<^w>^Z1<$C*VZY2-A?}jWTFEUSF%yJKr zN3TP>Oee2D6ytT=yPvSFaE;F%-o4F(gsXoN92ab!_Ox)dGgS}uno0eiP~QKp^e>dp zOo2U5Q$835JwZ+IC+MFE!gYR|{1G#g*D1e@@{aG_Y~FSJaJ65aLwPTO<<$-$m+yvn z=NfJiuJNDt?(do{T;GGZJmwXAd~{ji>W82mc#QL+pHz?f!CPvm#0O$MJg&mM5=NF7iq5p2H`N^L&~0i*@9MPf#w+cO`E|x&HTX&lIlu zBRm&x&yV+#2mBtHjr;Ek*SJl2`;E6!KGOvKcLV)gZ3N<^QcYwG)6-D7tXJf?UQvtk zU4^SXQGSQl;%z#4j^A-G|7;eH2%!T0`X%HM7vnuzHZIh>1@`B?_0k)KYq@c*3&pAD z8ROg!Y0nogk!N{NT~*50{}1i=_UHE{cf4=Y^5^5^S-u~%c&IQEdK~Yyu==(UuKv$> z@4tEo*SL!P7cJhI_ACfF|KqSXZWl=9=1Lua4$GBc?{cDNp5j))+M4gS}?^E7?A9Ty@ z(4X?okGw#h*@}KTi1}d)d7S&QV)R4lF~~Eyvnz$f)`iLoSNn79?>3&sgsXpo$*6CD zU+zY7_cMUaucn!v<%qP7EO(`Fjkl=RUrx9K`m;6QhtkZ?7Yh&V*$Ex4#qh zZO{8c1IphhTph-%p<5_wTI#UU!%J=YM}j30FN4uCG?3$ed7Kcq8by^Ln39 zKH&R>IOUH{i5`i=81Mb)M1Hw)(VriSnb?VptNVp(I}YY~oLZEhK_2z?M=e$^>&!8J zw+>c0x0d>|+&^Raa1VK$_ZZtad-6Dx+k@wq5xug{TzI&i#_xt$-WVx7j34iw##hNB zZyy<-yT~2iLov+ViFa$cvcC5NTA?lL+g-Tok9+O)HhE$(`eR-C?IYv72Ovp3CGVmA zGT+pnhUB${tN!R~h)=tBWifeS2;$%NT^}URltZR^oO*_gNB?qnp++{}TO?fD-FfGm zb}E;0-6YK4>^pQ9PXLc`9pfD8?@OL2z@DD0?^D7xZ)CY}X!&yod4cOub*QK0MCcFx zK?_>Hs81f}{SPt9&mb?1fuCg<3V+@cuJgda+n@OjB7RV)M5LD4)9v?O1~TS*~3CpXU9dM^n#k%E!+| zzq_3Lj7carPygdzC0@ug8Tifm(OB}>K-6>|^}L{5%FX%v_b8v_J}zsQ-NH5gqi3RC zwlA*iWZ2{1M^u;Gaoo9(<@OS;>y0t*`Q=H<$Gv+D){*D={rdB$=WpTRc)bPjY|n!g z??XF|`WhZ+Px%JIwY^fOAU=6rj$0&rwrIMiA?n3uahrv!e)k6E8{?>_;uOZo8_=I1 zuPMem%#oRIU65Bv2R^<=(7JKFoipUAWCBVSGC-<)+n%1yq7dRhOv znmohzH5TX7g=;%zxlhdU#v;?R8XD|*=Xdhh0%)*)eTaH;1K~Hz1GT4$JrY+bFP^Va zE`CUCfS$K${}kcc?}}XCuzdbL<)g#l2U`y;I}Lg=+&6CL3S+`m&-_2oE~clu$=`yR z9zVC~J|$0o41bnj!`FR){^U8nA82QP@*=<2vz`1w@)$29YePNT$Wuj>i(c>CnQ6pB zhWAz4b3|j|q2G8RXgMzEKSTLA_fgn*(O^3L$?xJ>yAL9dcpRz8xau!> z=cy+v7yaqk@UY3hPM)0w`)wcQc@INR%DZpmI^k+(gy+aCA3hdx8hzNW7gdkSzYYIe zd~P5Qx`MZ0yj7YB{pn4}SGJy6Pq@}A@dHL8%aenYi+=yy@jUX>N!i;J>glfNKlb>21D+sFHba4pxLhyOwO`QALOaR%k) z-$%LDudflV?HK$3|66~YOZhb4n_Iv5ROO}IWO@b__uj!j`At$vGzScUSR&OO$Swcn(g>5BI+gbzT|0dJ?$0p+)~KjP5Ix+6ZZJIy~=3fK8qf$Nz8@oB z`3v&&U8vAp>N)9I=!wsOJqe^&cbjmH+h*SWgm);PzY1|;?f!@9=>iY5q5fv`puZ^d zdi}Ba%tyjC&t%uZpHa$JnooQ99w#8bh&=Co5BDzNs%J3o3G6}nRg{l%K8DtJuF3-F z_s<G_QEX};fVLjBR_pvRwgO%Sf@Ed}oXw|V|N+lxO zL&;-lv~PEon-#A9NjHEe>yv*-`QSIq$A+@pgX9rj6v1hVyJ#WG&DDec;gr9d-0{4j z`9C8ZnTiGS*J6|R_Mew{@!#bu3fF!SkDc-oc$#_7Z0<(x-*Y~LJje3_@P>1{$qRGPkH*nIf0IYO@2S8J1CwJn8K-Y)u|H6&}8m@^=W=dL{XO z!Jdy6l1KUdulp&#lX{{jAfL}>ziYFIe!CBTi&6e|;X1wqT#u?oo*{Q^Rz0O$-I|J|ev4e2+Ps*DwjU~@{>yy6<*SwVe2a##}2O_URfALIki`%xsReyx{ zsF;7oQQozOoxNGFC6v#NM8D`p{u||^FQdJxl9zc+?UC=9{(NLU94K7N&0K~2R)_Jw zO}WIIn}vAmO+z=o4*BdG@c-GA-$9v-riXd;KI&PjTuthY0PJ; z(xD3|U-Z@|-xIEW+sE$@Hlv<>sz>zu-!rPTOw0Y>pO(UPUR24O&yN!xw$}@&m*uOa z##_KK8>zD8@A6GDDL20W6D}TKaaEQ>PcDzRHUHNnk9p_6E)}kNa^5`yH&Q;$eL<$@ zHS!Giw_itlwoy;k^V>ekC%KMf^O+OhhMfiOuSTzt`4xHmR^$Q8dtJyQJcrwrQao;o4p?u9KUdH06uD z$3Drt@w#$}x57hcuL{)jp>U0>X!gkd_!IT}-wltgVEbN&7P0l%TgcQ#_;S0Dk{I5kPQ+LQ3!Yb;hS?U?3$XviLNp9bY~+<$BPGfTb$J@HGBSEsRF?a0$y zm$NwkFL~rH%oAS4aOIA97kYx`=ohEbpXZai03848TtDI3FLE(>IAFQsD4+G_nJa{= z-y$4mZ5{Y4m6!S^s$;@(5A_@*4|u-M@H@`e(&4z^GNda_vl|1&#$T;ZQpOv?zaAR z^cv{T@O`w^>vZAaxVap92D984dD?q_(MPz}H+L>-I*IbrLizG;6wm#km7SYS`6BPT zuzdKHa2?k=d*fP>yphL`T8na{?NRPLmfM^>-wJ#*c^~86{)c(wktN6j<0xMgu70S+ zdvB~=qVKbPx&DAwb8Z58?k8l(&#C7P@?ve&)cSRe51^;O?>{c5{BYsgUP*6X@$yif zLWlj@O!@rgNJ!^%d@sLF?ALkYWVBQ8(7V+X6e)b~;E{qh9iVSeC#9*dI| zlrKIG{U}|&V?zBg&ciLwocba3|?eU&u!VbFq%BI5$%2{ zUsEohj-svYvJXjT^#+4sFu&33J=@m82HWj9O0oq zuK+RszfSqsGpN@>mYetldZLXHpZAl`AWy%Fe02@;@Uy~Ie{2G{>0c^bs`weoO|L?H+BnsMJi>j*!&vV1!vAgFJI3UB9=|r_Un7ru`>X#VPqV#j zJ@bt9u%}Q&UMj_U-AL}d_3D>}YyU012K~|I8y`~MzmKlW2Ken-@BC2};i{*Scb@1$ z$`|-uKa}F!V&P$XdG{_BsArP*-JBCPqTB-SF}RxksV`jh6yHOf4B>#0RW9RT%G+1J zo$}eL5VXA1>T~GHm4F_bhj${6diOZ(CC~neehP2P_c1r2+zj7K+PtxwaE-SF@7--q z`-iH$@Z9^z1GZi_Te!|omU!#h*4T5h}}N@>J$+k6TCWcePpKKWqb8YdZk z=hX7jT;-xC>Fsm)Hq^sEKJ3>4>dzcNUbXyl?pG}LLU{fp`fV_Ig6lko$e$Cg<>tNn z6H06W_upSPAa~r?Vfp8J;Tmtb-iT-O`2@=679(P9d|YYz&qsc4!n*At&+~nX>F=-= z_QWrP=Khp_Nw}7qDUTV;I0nQv%17=-o@__?&fB0T(Gca%Bp*Yb+zsB6dR7Y8ei8Nh z#W4lZBkdU9g9m~)=+FNMS9=`4Pi^aRb5ve<70=OjPyQ0h`{(aUehWSEUeIIh+nhY*otIxg9u+_7PX)Hi3E#o~!cvrL z^=&3x+pFNMKin-`?RUJ-{0aJPDfI;2cRI>^uloP@=d6%Ryj_d_HIgDX2v_}a-Wy|i z{tN zxt^`yBjVdGBCozNd}oV9p< zg1qnq%C-Kxggno4M%S?1zlG~K63~8&naGdOAN9UFJnhp_I%x5xVBe<=WA^KlOWG?9e5V?yd*sA*HzH&)tSfMA&>u#yxola z{GXsd`#s`+8ufG~ck9s~Z5?KiaMhoykCC)JFKzi>4M zmbK)4euY0{-no@|!c{)Od%x|uX^V34XR-w1q!;z{{0;t0wnUHnhq&$AsLp`91~2|dL(p~vRW z3&=A(?`HY==zZ|>s4eg_qQbeBzm*D~>vLRxuy&7%yygMNb@hPdwid4Sjd<_%Mk*Ko z$9NAe<$@E z{SV4bZ%5v%$ML!ed7kTv7C)oOlLLfql{Q;Yxc!nNEO&yCuAW<7a|&!IM7+Djhwz6Td60X>BZ z@ScsER|?nq7CGOrc)OE4^AFnB)>q#qcYmY3?q$6;P=B%qGSx=%5l7K}-lGyDe@3{L z8}-K1edHN0p3jr}-BdpC&MS2#&&@^Vw0<{7xcaSl1KP{t=N<9_zsG9*XdCrJHlRTs zrk%}8q1^NqNVaExpGThJ`CQ9mMdA9r@`(4n@>7q7p2Rfxb1(H*6|UoHd+sN+IO$Az z$8{2Gmx;nP&qvS4%yTXE%vCP+jd}ZmHd0TP>jM_gmmZ_?|NC=|aP@QYF2u9FFMf$U z#`6)i`KO!6i(L2H2eaHo$D&^IIiIw69z>q;=0#cIYJZ09V)Ncjluy5p7HrRQ4^TeG z`9(p2=z;AYr>0R=y zcV1vOdFuMop(PeSr<{N|DSQCSE&f{zS36VXq5lx=A50$SdhBWB%Y>^Ra*Q9$`keco z^2I-(rwirJK2ggp?_yU#GDd#AaGft@z3){$qg?bCc#pS@FN=)x{7W_J*=C&gfxk%J zNba)>^^8Iuu)NV=y&zhe6~+g{%FMBK&y{`3vN+ zny^34I4@lu^7&b4ueT`QiaeDBxB1mjljnYzu9P1qJhaC<7yLNoBNd>>3~*@;L7?Zccs^c~Bevx95(}$@3}n#}ce>gHxbC%6)DYpM!*}{e|+# z4-=U;J{BI1U%$Zrah6-Q0_5`-LjD=@VZzn_iNVM}ACW&z`OFjGmd|s-RsRy+8-Ui7 z{e;S8y*KBr_x?fsIljlYepII->`Cl{h9_C>HNw@NoEL`^$P+w2Vt#mmJhK<^WA>~e z&(?us&ZR#ao{E0$cwWQC+z!GupS$KqKA-j$K3n*2%u7_`rc+OX_Z?ZDe?hp~?k*VKvf z_lBJRaoDfNgsc6rCdjLs_-}tI7yrk-@4`1a9r95=M_Yb~3)lE5?m|0S`;Jk0(Ub7* zMPE$$@!om%FR4FO1^$1W_Ov?#^>UnNTEDnkxZ0oL`%r7grR3R0$TRh*XA60e_hro` zKjlp5akCK5_mg)b&-1;&)#Uw!YkL(>M?bRp|2@Lh|Ni&;o}iv+DOkw#=W3mWa&ybU z2T*?>@_^rcuzAZ=ljrwpQ9I{$kr%w@`k?{zCmN!qY(D%bdFDBeBaHL8!bAJH{%rG{ zcPJm_`zae|zcc+mLQfCssZ>?{Q`zNrAU>_!9>TS~0^TQM_ODW|{rv#q(B@Iwg@^r@ z=SHW|KP9VC59dXr$t#i5evI*?C(cw9)Vz50{K>mVAcJ-+&$yaOo~(iVvyJ+f3fFdwUWs;0lK(>a;sD5_6z9&U2l-TU zjE`+7e+hZujgRAmYu;E>0vWg#<)0R=?HIco`mG&*CXXLNiAyQps6NW|@9F9yg8Iv#$wlzhF(uQ@W#i{v@xlkSv1@jU2H^1cFC>s$}v>bK%6$S1b`KP2S* z0gNv$o#fW)mXX62i$*X z^VPU;)#EsyH$7v>GrZu(>a|9>=524k*@+D>PPO;OsYb$8-v4g+)xx#iH~os5rs#`% zR9@{YixSt8KSG{ZjePha^Jm}lA)n#=wl?JllSjGls4e+I;pzwf{+11t&)$SQ(1r3% z8bUth-N)WfxZ0VVhqziyds@rA389~P-=pQXLCVDs`Rmax4=``f6|Q=UIe>;NcO!Ys zI}dnVW9WBn@tkGj(K+N9p8K=@m>^FD$P5=!|HI_55zu4z+HDlB>mEy(SL2kgEc0)* zGr{xP7C$|eOTGN_7uQoh)ftvFqn>BTV_fI4c>74W&O!=}uKv$x_So#c@j=)Y&NKbC3<`NT4SlgY0j zkCcGlMspl|kUV`X_;Zv$BwYQLZiW0@m-aMi1^xc_Pdf;=v6!OauYQzw_dtI;{^K_C zJfE9vygT_q=#TAze0|z^GkJ>p%)3+1Yvcuf2f^ko`^fX$|KEx7Ok-kV)FPUsP!|H-$tH)5qTg-UN;8)(W8(7Y(6=hJTe|}_&W3C z4)U~jUa9s)(35QlJI7N05b`wd+qr>!yl}NY>wUleY2}i~++}ER+ef{NJd#7b7EsTz z7o%L)8TrTj-$c2NcL(sCScCFCDPQOad7JOuD_r|~vk8d&fbILb>F4-+5A_@n9`@gn z=t0xT+qHo`xoSt|!yAqBJ@QP--$Pz_2mPfQ`D^6)y>R@GwC4x%^oeLM>!;-}VYyAg zEpD$QkDLK+`tKqyP`)P1-AtbM?jtIFDe7C!`#yVB;ToS&eivXe^;{`jpO*{XIlFYo z&u|I5&xaddPHam(L(yL2nV6m=FYr6mQR@HMxc8l-v)gGq%DOA>2|1neZG@|x=|PxJ zE+)U3JjU}ECjWx!k$gMfyT|WC%14hv`!=SY&Ez?L{}JAHu55dhTj&aTYnSVVYy3oc zzm1KX6DVKw_DQ}YT=(I-lQ1qP84qW4fSy!ej1;?Q&-LVqF5pS>r-iE@;@t0Hd1jMv zeU6Tu1rnkDZ>cBx7!thAqyD6xg2bc#e1qwf>(`O(cr)@qRhBzTc$lxaFVX6|l03!t zViwOoQcrOm0^wHLGqV%)yQo-a1}y27>G*t_WO)?a#(XM3Z+ABW=I zm*mNd0POw#SzVwf;(d21PG01Cb&U18g*;jracJ#$zi_SBBz`A1p!^c@$R^Y`PX4WM zZO4G;?<~$6bcH<`ekU5GIM+eA%4fWD^uvW~ei-FFr!1kKH22kaXSo~5QceFO;>yc-R$j^4}<0kURt!RzlM-IuEW^;Z8~{|@9Qt6Js%0zaVO#32mUSPBjsSfOxMGobGoD4 zVA+xNy+pYBEw>E$whr}=q^(x%rg$--CZc`N&&{bIXTk_kjKg_obgp{r!b& zJEjLg-s0yG;o84yy@^OewsdYG<>M1kum4idZ^~ufmGSO1jrL@@r4gT_7+0-@Yq_}- zP_L=f(_46$Z`Y$-%Rl#0KE?0VHlh40{?Xe10qvh6T>TLD z&gZTrPn-n*%%l95p&lvMJ9mFbxy}>3_s(^DQ@?kw`$NJt-h%fLZ!+wLKYtp(6zz2x z+v~JG(Br&&!n={jSHRE6iq0(;uI(8A3hik5@JI3;d%&%q*69oRzLKCUUTLoT+5GJ_ z%4fMBo9W-xPf*VrX!jK~Xfe6ty>S0wxvoFt)BWJL>&Y7nSHHFQ?oWsd*XN`79w^4s znR6-Srt`4hGpIj5^2m0{3)l6`sP}$<2jx>WkeBTHN3{pQZ<&iwuURZ3COq^T?@vQ( zIya2+ZZ+a+2Ia?7KFM{b^T~6RkMLZx>G{&+-$Z?z@p+-fK$IIi01xnS-DQMpJjZT= zoq6itC0yGv;jL?(doA@i_~%K=-y~f1xbL9H=BxLGoI;2F%1}?1>vGWM+*ayIeFr~u z;op?Mj{cmFc>bLM)JnMeGj}EOu#Kk)@`yL?Pb7Cde|k6dA2&$!NSs8!fWs~(Zz^2< zkh=`|ryu!aDlg?G=E9$i$d9@nJjwevI+Aw~uJJR1=W~xDA3*uUp3fALqyU%`B}UAXq6ee6fgDDQ579~{4L z8<1BQ9{PVD?6)`^PG01?M{ml%OrALh<46gX`vrNv6C%OZ6WR`e{`@7-e;nmUk{1_1 zej4@979RR-HG21TR<3Yu#|-yHSiagt`GD)IX8%$0Tpjv{_xvoTo;%6?^F+^(7kKY9 zMjz*jTC0g>xJw4%B1%__q!;cZG?W&nSpgs zc-SBLe&5FB(}sil_hwuuT+7WKJhK0Gp?s0^D|>z!M)^WLl=}|4tJ_EU|%ZE z+z9>oiWuo`W1i2DXFH+2(94`Fa}(rqyf?$KUUkU*=Y<=EYx}zP(156rJWu%y*RLAT zo=u^=eD}&bhqzz3`Yq4zkXk&PlY~8y1JJyHdd8E-OM%;Z?0Vt4{xIZt*uymJ_ESE| zeKqj59PhnZ%l+SI$Ehm$Eb`D`)SQvpeGtYvpq+@MILb7&)Ve=@&dnu)`j-Z z_z(TR0{ZVG|5CW-)l0l_`A^D6SD>c0PFruJ_*wd0(fdwNd*SNm*c7y5l=>&Dyv9Qu zEoJSsobtJ@aKJH~uby)&;xOgy>qrV${e_R9KcM~($Q|!j>`#8ObPz2!wFMoE*8#ip zglpc2dEXbfR=Miu{&|brspOHe=(*ERmt-8`bkvpJ2 z>+LUHAYAij-kZ07K=}gqMfaheKgc6X&@Sfx)5kJyc@Li1Gf23`ZQ?5gn#IHO$~A6z zuj4t?zl%KA5+muQX#Bp7QR^n=4%N@T1;$(%+=K ze~;fb;c92Z`(9OaBFaqYD|28i=pn9}l|BQY*gZc3Kdqt0&w+c>2OBHF)c;TAgQrw3>g8Xmcs>gZzs4t#G zKaYl;-6%gnxcVpc6~^TS->>z@()Xj>fbZq4 zzceLJ@_8!8dUYU=Ux9vy)|Br^D%ZFwAg=7WX(r{fH$mR=Mut4&?PJ_xoc9cye@>W6 zJ9)0z*2k_Tcjv=n*U`>Lgll~>O_1R&udbwgrYGjZb`MXfY0w|%{`QBdr=@Vs13B-U z<~@{;dGEVl4CSTVQ&6sr@9TyCTYvn4dQzhh|MgjJrw0%xxo6;EWNEoqmOS+hW^}tK z|DbSWURZsR$*wcl4igIb+f_IPEnoy6tzxM8r z+Cn`=_80r!+(F^`e3#_&o%P?k(@}2WWb_ofZzo2cD6A>dCc-JvJ^3ATN5~w|aznier&CQq=!B<^B7zT0DgIO6^2{wEZo2DwlH8o8ixg zIBvc|9_4qb?x+6mg=_xw&($6vFZPE$pHM#bF!V>cza81txx2~J7o%P5{diXRzx9iE zDWB!JZ;O+XGpT{%56J_558Coug;~&3d>48SQT_(f{gh96 z<5aiDQEp*4{4oYmwYESWPlpCe~GEYL@@m_t4hZ@3loK1M&;p!k<<3D;3{oV5Rs8C+k$-VD! zJV^P>GiXPXUr8S4{p1PSbL>;FC&u?C)5vQH*K+e~puy&!gYNqG`%(r_-VH<^w!ATw zJaQ0mUKY(J7rQ{e>xX(-9M)GZ<71M~iPld$Qa-}>K31jM^lQ`qGWA6JAOm-19{AbhdA}cKYtGf1qxtzv7w0)IXmjpT;p)$?K81qDw10r` z&_DbRl*!K$uKg&x7d2`|`RB`eoCwioRWxV_1x+@p`spk;?(Q(k%Z$EHN;bH%}8kXDod;@aV6!}xGr44^x3HAJMySyh{ z^M4P1|1L$5qh5pl;zMYum&vCJSNUe%xto_LpW{9MNy>jLT-z(g_gt3$f25wMw_oc3 z^~eX6Lk-ri`@If({BxZzkVij(W^2dVOJL{x9P)n;+H<>b^;_gF=(qa^{vmhXzU4+s zA@6wqxwZRP@?uw%*p&M36|Qlc^5XUd%14et9GV}#6t4bBaGzLx>iL!ON$x+aL*Dxh z)TFME_vMRN5{O4_Hz8rh^-TzN1o+9lfP1b zM{@u9`gY-Aym3En}rvhwJ=Yf2hiG)8vI85v6U(H&aiN_aN0K|3|pa-x6cd z<9H2+Yq|>M#&ht4t(%P%uJ*hAup~-7%Yt+MV^IYGU zMg6Y}595dLgRC7tR4(@C9)bNBC7nAUT=!|GcwV3`_0)S8dXh0@w#ppe?*D?)Dsd z^lHdQnq$I>v<-oG_w63aKSdtp`#4)y zSwLQ7d_GC}ox=YuKOYdT{Uu<(XhZo+-iO~RaedYN)?IkmuY1DIh4jNZ^59JL_qo)w zhdjFig0GUtK7c>{?-4v8T-$4jcQ4Zi!ozZ(Mnsu^PFqL*E8@rIy*0=)JdbuE%k4~F zI2Hc4dv(T;NAE|!{)6$qmOR3JP&VG3{2}a2c+YE1g=?JTdH;zFXW>s@;i3KQpuzTQ zeM(-q7Q74XEb$TaXBfA&$SVrhyp-X(BBIo}hQd{U!2QpyDc@hX&O?&kJS0W=B;OZY zO!*n)#rxm~w6dI2Q!eF3c>kyI<3A?<5%YvIsi%!_wKM%C9AN7Mx2n9@S*VJP)PV9Y z3J>G33u-i;yh$G1algU2eCQGpV;}-vynW{eXT|E@2DrkeYrKr|291%&@Xu1v#a+R z^d}krQOdU#9`OG^{8v}X`}b!qAousHe`4J0r~AkYJlBk9bguq-*b{#PWHJlCO}Ms8 zmiG))B7cDL{{H8e$P?UGVEJJydEVPMb?ye}FAPMSG-Q6BY`hGjt})A?<8FH#CWfl^{=UvpXAMxpQC)h?@ioH{kw$!TfZp% zIrOI{AwDh6XOjo~ZmIS6wd9H6s1c&YxzEV+oM&RzA=fEvqJExhXi0n0!gXD}=Zf%W!QlwVI? z;C((e?Hs9-}TSg&KZLVxi!L~Iw@d8%-gk9-7q^XKKt<@syWX7D)m z^roJ`yU*pZ^y9D*zFI@eW^UgOtD_r9w zel*4}J16x4^`swz|81PwK%SWcI|oz$gI_~`+I#=?m2mY>{(bl}OFOH5gK{(7;s2fF zoygPPy=wi1tNoR{dljA#uJPu$zuNM{=j5rY5V1DC|3y7(yzj}@_!f3%IUlP>d%BYs z-+>=cYv%?CSHHO`$kK08{#Np+_dWD^|Q^VZXi>9>!H=%y0(t-~JJ< zen@XSGJa0~j`s7uZu3JE;c92VdmU}QI-2qso-aV_IQJ@fp6?@2igRC6Ph>9g$yv1L zci|f6+j&nfMkP7-{XOg{c;9dRliV#wd|I5JwHP$N;>;TXFfp$0h&mnh{Azy`x29X!}KHA2SC&_a|Kx|%7ekaSl5s_)_+m1ZX z`&+8fo_WH z0r?EdySvJU#PZ2O^1{jBSL3n7UHfxM(JtT7@b0xs3J=S@7XG*VJV&_tC&Bv*4p3_ahHBLY|-baZi!wx*~qMQU1i;(39YPOPj~m7q0D+;{5pn z$`7Y}hUZM{kna?(_Q(0WX6pkbi_o9{2l0Ok1hb?!Iba)E6RMI4teGhgwhh1mj^m^&j^;{2BA^SL`f2?7uD0AL~>8 zHu5Cz3AFb8jy$#k<54}!1AjnIj{Bq9QBRgU)faiV3Hi6ewS9|&kb(QLz616k-EStL%QIc}LVt|=+-%?V1LXd9JU=6k z@Lr~BwC9*Vp(p<|>U%W(Q<*%ia}@cxnDYIE>$$Di9OQ=x{g4u_ag`nh1$`;MnR*iM zpuHxOm)M7Lv)(+s6M149%6*9XXBp@Ix0%$l#`G+Q{w=h>&R-JGvi|IjK|E(D-(R@4 zOO*act(|+EJl7R*!fBBEl)T7wKm4oQ2S%ReefXAFe;2O)$?;rUdzO3Z-zYb+94-DZ zc^~0A|4(yYRxR?oDDOT)p0sjjlc#wOXNgn07p3&s*8ZU=_x|aMO^2n>uZ|xHN z13OcLj|(N!lpjZ)c^i4`PV(10@}AG^?yV8IQMaNC9iY<<+>y^bRoY?xax_ugdQ9BuNSWU zJ@DR7O`)FR@o16i)U!dk#DCOVx2$*&<;M5I|J5iT7q0WMz*{dJtn#8KQ5(;*pHY53 z^Vb&&Bp0=W^lNUQzG4V6MrpJ2HNM4xp!7-aGkd>gT-3)_JB159Qy6{9xL- zM0j{Ug8BJH@*?#F_al*8oD4e#`qP)f4?`%Q7OwF;lLzj5kiSfM$Mwbz?Gl8r+**jv!=&;ZvB)z z!i!;^ru~(VL%9*&<7exiDd9SQ>t6@`h-SJMg=@L~et@mQwOs~#_ivwB2Koy<(2qW) zq9l3FJ2&wZxuYL2I!N9i _+WWX_$3uT~8uZ`GdFdkZVrBG*I;?M*6Cj`W&hOVI zFMfjfG(X=YTmB(^}H5x{>NdzJ{7L5pjCUj{D?oeR!+za_$Tl<8xe+b{-dje)l|TbTQ+k zg>a3-uHO1#PvKgxly{Er0p(I|-1GB~!gbx=dF^t5@zd&YUs9->t4T`3R!d9K5kN4UGr!c~ud zZ~TAAa}{9!Jlg*}dA=0JDVxv#L|%9ge!hqD%}<8@gttHZ9^qQw#CkM{<-@s@PoIf+ z?oT^+s=UrOZU&e^{bf&q{tWNwg|*JL7OsBI@ZMK@&h1V4;z0Drm#Ak3d5q`RqU5W| z9rpp+I!yTrqF?6ii89Dz)~_1~5AzuJ|JXcjpzzSoRZ*{v)W3xCvGdSU@TzksR)n4y zzfWQFnRA7!p5y@}BpWv`G47rFevEoDXCT9rWC6cWKGGUsmHG2jjpy=izjwaxY~fmN z^gh^ce(tYa+NJO{@_^O%Ny_K@Lf-8BjNGjP@5XZf5w3pA@VhEsk+-PC`g-R;M+y() z$Gd;*G0OY*C%hqC)X8MfpSz#O-dDd-Q4W!#>XsRfMY_0)C%jBIPevE`CU^ zhaW87CR09L8TH*k`QON6-u>Z`%FyqBhq@1Wunu<4V;);={1x+|MZ$DdFxZ0Csf3*3}YVycn*t3jw?h&s2tHAF8btf+! zu-|$6#_N*Du0b9fMERcNfwwPotZ=obI0F8(e6mcq=ARS1b*fLOC+^+7~G@%NWD z5w7tW=X=juw5Kh3tu05!?PbE%o>(hbf?7B?M)m8sb1d2gf92dH%KPKOXDTmx@5t`f(i&q6n9jr>n*y^KVs6+HwEAdno;Ilj?sl%WWhc;Jr6j6F-Z1BlTm)m+t}>KcD4&eKx*& zi}V$IN6FG}v8R?h>g*TY6}Z$Z!aTqA4~GI5`JZ>!m&qsc%|ickANfqKQ~m5o`S;mN z`J^~Mok#pO;G(wx*LQ3`eZu1O=ev-8=lM#X{fD-f^-FQ!(vJq*^)=wv0)LG8bKCDO zwtSW=QcwO_;;B!n9~-4#nk4Qy_l1V`hCJvmjlU@z2Rj5uy;96u+VSE_;@*YYzihrS zun+aH$GeRrXR+Kfh-Y~Zs*N}9C7yELr`v8{_D5%*a5r#~$K!sayI9{Z5TE3EBJE{( zN0@lzAKD_nq&)B2kNkNKWj*=q0bJ&5$2j|W4gqfN5&E#UxYa`(xUt(8)K0AZ-%S3a z&OM?(050-RKBw}0i{R|L_m;Y2-SowTJmZ zm2-^svg1M@aO3}-eM;AozG9`;>mn*{w-DQFk;-HF90FYA8Go>_AAM4A=s$LY^0}9K z_!jw$@SQcgj`L5_kMX@)Td$8)DxU!NeeF#?Yl$~H_i=rRcgh)Kj`h1i0k)YPg=3`gXXt@(-sO8vs-=)A!`$kkA{a?IKO8Qu@3ciE7 zGq0*v=|^r=|CyznD~V6kDTgHSF5se{;cqJaDa3CfKH!g1#Y37erGBmjE_{ZQYPa)gCx0NG;`>21-?Hx_N0hqqGBZ;{VM#2a~T(c0B7 ziI455?QZ$+wS@X{_H}28yYK40H>~uHyidT&b0l!FlbB;C*8mqiH*TtWUO+j&4_xeR zoagRsdp%D6S>F3?wrtS-c_3z4)(sXQ-GT|b0_Uzw*QV=KCfxL ztl#)M@nPpaw*`l(oI%cKZ95(bTs;^C=U?5xrQF7lmTTj>Pm#}<^PcS8!~+95zFRr} zL_EfKG4xl@`*0KGaqhKP4P4^S9i8|y30(9O;CNx};T+--!Sv-T0(#8Oz;W+wnEhuK_OpeByDP$@a4yFAyAZR`8wEDCzGf9vD?ZTkihL)&7T^ zb;(7*g->>#YOIlbjs|Y@!1XxWjsq5dQRTdV^xg;j@1gn}`A-DYpVl9qcp%l)>{OC0;Gj(65y{T;X&cQ_AHuY&tX4_E#ZUsHMN=vSM8 z%X-jb2dhW2_A@B-;2%UBA%CN?<}hu{<1e{G!n6Y`0CT_tQLpErTaeDJVGb%qile#k17$7@vo z{2o^9yTFD2#F*Drxf zdks6|)bped{9QE`ru_RKq4LCjqw?5!@yWoAA9Lq0R#t|n!Falik*2sJFR#MKa<

guyN)-&D4*RZyzGw7}F7F7xLMB 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

;hP?-a_*c@MfW;siN=Mr7&&B&U!y||w zxXp%Uo>Sygp=>ZS*`SR(O$XvADeLRBP8w%%LMJblzX2jwZ#uNDLwgSkhnL0l<(-Tk z%5?#(izW_ov91_|Ts-wU@B<29B0=YfZZ&gUCn2+ogZHz==vqr0dNk_R0dpSFUdvT=DN=EHHpb7C&05Wqu%TgZ%kA)#I5$6f6q!BB5PC{!iH1<=> zP5plV{Ls9r+9_^gX*RyQQgh>%0-<1*IlEoHj#!sP$>IThdB|i;Vj?_R9nN^>$vCX$ zi1s8>(ntt{uZa{#9+$n9|0zBVR>|wF>{4oBrjwCQyhpXj7F$qcX^KV(q1@@EO;?l~ z<6cp3$9fMfx~4oUdQo8CsdpeRyDvCuMa7I|Np-gB_B7RHYI+e$@OK z4SZV^9+oi}bKKw#p&|?F12Et%RE)y^G&6y1!c$c;UXds0MKNlYsrDv8k`(a5ievf9 z2?&;}!pbB@(4JFYzz1giqanb3#Lk0T4a&WR9u}n>8Z%2EZp_@-z$!>)ZBQgSI=J7Q{=mZxU z-8uA6WL9k!7n3gKOnHXuac>qP<)yNDRS(QE4ey zlxNCjO%Lqu4(E@^_@F*$5J@%|rGq9SxF}Pih}Se)1>}OEx{~dB@AMhtC{Tx%HjB`} zXjppT-8?&rdeZm#BJkK@0t@_^yRauW^*p9i*y>@?B@488V2@AM;Y3;^DwQ)usAkE^ z$&%$=;hxtw5Q75d5JkY-!Ni4=mMrEle=QIRD29tZmD$k411X976|^B-M3wnZSS?Fw zVqZI-6*BzVOErm_Yd+fI?2M+&8Wl=;7vFVGJpF})*?15ntI77gsw;TM2zG192QNCO zWo_ZFUJ=y8DkIdggFmo6@~A&81*TcLBHtri7lw_17@^wCzE_>*hiCO0j*;53Dr61E zaWA@%REl6(#x@k(-*-xOW$k9U}>+xp;*qMvS<-ud{ z+nX`EnqUWUy8cVrDyM&6Y~O$UQ9gM+-Ygd1o+c}7jGCYu{BLyHgzx>c8LEm}_mWi; zyrgK326Y6a@&|dZo6`IUR3qkxS2dpZ(bz(nRI9+kX2+~g(qx$kZ*2k8MT`!fv@IOP z(>U`g;5e4tk;~5z(^~-A!Z}|&fByCT3PZU*lkKD%@b4Tx;L4(&NXg|Vsbd1dgr3Q7 zH~%puBa;vw{^U*+PKrJ0i7*m~(|)|kwYD$9MYk5HrD``@?PhNqfRJ=S3KC_v9qq;V za}+U!csqr7VL*TIxp9=m7=`ZTW+J`wvULeKW`^b2;EO2lZ@ARv`~hOyX-s1}kXieK z_`7v1^Q9=-`;G`%<5@FP=lv+0SOnV5qje>S!v`}2H@VL=TQF(PrwA$)*ltX_K{C)- zEEGc|vv8An&t@wkJUV&5en6$`?urAbpN|Q`eWcjLrKZ3?2B}`zG@vo6B)Jr^v*HB_l7(#Uo7QhyGhA{ z;C*f2bKU{LW5V_d0?I{Ve=5ywW-F@DtK~zk&Zn23rXMeVX|l#O23wxWpgab4!tDY5 zB5|K#Sr(VwK>(i$uN>F=Lp|<6%++HMRVUq1v}isolcsucqYjO>)#Yw*`uQr^L99|G zXPq?m#fszJfQ^a&j?D^HPXg?-*5>g7VMXml-{z)&Vri z=+x-r&;Fj-sAFYP&qYXLzCalV1(I*Nka}O!&INqfdGJY={?lu;9jDPdR!W)*gYY(S zf`fgx8y>@aabQRaj-`aYk)}LCc(HFSPG0sm7}wpO-BD@V*f)05Df{h>IA62FdyP zC?Stl%S;SuwS2&EM*E`CvC2yrKOpePw4l+s!*MX7^yAqSUCDV6;!MA+*0-2~2!gKW zKACap`LKDg!}Ess4a)+p_aoRfj4ly1Gs~nKuafZI^t;;61=(RJB*F|(O=d3Bgi2u~ zowvXjv6aC&83+)Vpro%|iTf(IKvm%feY%yDhOcSuR=KYD>OPjh>ipDuOeu0K;EG0O zTiUK)QzSMx*f&5XmB}6R8b|S5x4y$}7U4!qdr_k9{&sUm`;V9I6|aW{>XD&H21>`; z7A&RD+M)?A1_5*Q7<`}nBQ(CnJkuyLMB;<4z)4Ti z!Hvy_R0O@t9$=0QLtWg37Qo|p*%0;W>Zp~LotbQK$} zvc^1b)mu9UXM(~eWtm_Kg76Zz4()eT1C{p3>Ja_KY*8JMn4zP6IYt@!iKcN{wUT_M z);n5cD{SbFhvj$HM?*9LE~J_+FpKa@2&vN2{ca2)C}FOjp$DA7A_v^zs+@DcCyY*n zDxzZ7kmN*fn9TNQjP_s{bu#_^cyt;7EKnT2te@WiX#MkLiRFXn3=K$ua0!iyb^cf` z#7!SSqz}DBH2qbYQpDcMyK}P@wsc;t{L7OJ5rFtC=aH!HFFC3D=P>tSG61R01TC6W=REN7Oo#X6iJoXlX;m!% zD>_lifW)Wv!Vm=`d|w8lp2G>Lf{%bBcGeW4SNjKETUHf9mtC%i z6L0kC^tX>c=3Ji9aorK444m;^0URn+hR{A9CY<6_=>~$3xMcIXj(cdVl6AF74|Zp8 zVzSF+*j-q2NMM0~PM4akce%hICCN|NpY{gFY*dh-^J+#4g>yJVqwc3U=VA8h;t_v^ zkR`$ZWbZV88dK3FO@4V4rNmmigc2CnS}O}ES#g0KP_Q&#&ZP>_#_{yW6-ouuuS+mb zU{9{nc-7o^mLKN?ON!9eo(;Z9L{|dW=qE^~Qy7zOId@S1hIH603C&`ild`$rS%(Q( zk)bCEhp|U|CwS?#OUKZy)fA1+Rv2Qyeyg{T`J3rIm_33$ z5je6_3Le@FPj9&51}L^z!d7e18@&)I5UGeIY4#phfxt4BtpWDL7D4`{IC@m^4eaA3 zbcd^Yx6>$`qFWW}tSvgX;ck@?U7Lq#maoThzxK$_Vb?T#M{gLq#i#K1m#~<>Ai+Fl zTvCsRsp88&|7kuv{&0`Abu$q=Ejge#a&*1AobY)13u;UH+D0>P?zgvd0@)#4=8Jsvy6p|~Yx6y4f=Ny69_=8^siH9^Xa(SW| zYH)J+12^G;L9UawLqXNDRKp=bYj)N2>uK#pSUAS>4G3IrMQ?VMEX4Sl6Mo*^Y!^>Y zV4?n#uPc+Og>~d3rLCsoY<>$KYg2LFa}$2u6AJ`%1>TfRq0DA)!v8`OsPYDcKoetP z?Bb7)Zv(o;Qxmn|>VNG;*V5c?H%mwif|3bNA=eydEtti1JHjzJ+aS+>elx#RaT!PB z<>r(0j$9%AA|fC)mdrID>{PP$chwPwZNfi!tPa6h&SR+K!(1N;Zy8NT%+h#p`j=>u zcRRGDGb%pe$;xR*cpI42OB87FA42v0y z9ZgpECsuoH%-7EFn?vMaNXTYz_keLZiW6d%yPP?vUG)Y~ZFwH8#_pM7sdJ{zV_=bR z88N}>7HI65<;cx|%9NZJ0l#nrKFLGEE9QOLd3B-Dqs>cj80im3LdFxnJRt#>(e@AX z{M=(?<;7H57V)TtRl>(O25|!K@bq^7AW)q-y@-_~NL;OFuyc!*Hdl64MIhN=#arN- zIJod!Tq0}G413tXR@He*ogrPu>e4z-t~sLFoveIt0^{Dpiz%-gJBOm61XsvR02X;*{6X^V5BC@j zSoeDJ3L;KRM4}LCD-7S-ER}^Y&dRy8pDbrTDX|*IyiJbptpa$88@F*Adbq1qj24T4 zTzXXDJKoJspheFqwcW?^#^YOALEBKIZve`WnF2_Us(q`eMc^^f!o7v2@jbiPe~BT? zyhqXB;gotVORFPtLXLngir7NrtLlf;o8#>>{69p{y>YKP{cz;QjYitjtqjP+N(JFeW;KY>SR?^<&k)8? z89&)ca|v4e!DTp`V-E1+dUT}t)*5~R1s-Hp5U~KFjCvdh{b;B>ou1#lKw$%7oR?_S z9m~I7{<1yrVrRX}MYbWnT2~Q^nC)rYJc`5ETejM>*008`#^*NaT{|K#N~!@lsN#VZ z=})#%MIKZqLb<}_zP^&E!{!f{i`V6XVJjpr7T;qumo3rgVv9=W6wTwJJMe}{VB4=D zf{Ll4tz#-8a;^Hq0;3aHBkDe2HYLhe@pEHx^)5)xhA&Ry+F4TWK!|upCAEztD-ZoS zB4Ca|z0tTMHzHCG=8W;>ilmfwEy;PI^Wci%eLncpaob&;~3K#`m+}G~Y@JUhO!A`=kahkY5)HM%5Rw!&KaH)ToUf)T;;z=GI z@hAr=IO}OVED^#J*$Re`ugG89a<7=B3=gFQJauMxzlBw?l}*oq%Jd03c9##Bgr#E` zCA1_h1hfh=1jDTnXVyVzQ&b`Af6{pGqMf*OlzsAydTQS5dy5om+8F!(X4^Q)6Fn7J}>9@zsebPu@3NgxKzDNNkw{G1Q^2=U~SZK{=5CxXi# zQXty@s*zu^WbpB4&(aKv8^(xfILd0!F~6cL_z<)SRjK&d!)~5^Hl0BQ`p~V+paua> z6~YnOsnJhR(tUore3*S%9G~jQ3(dVbO%5X4>u1O!3lQUHg93E$ql$`vs};Zv{Mu=P$Sx!OxP zq86tQeYjW+!J}0XYCs~qc@l%pzX3(~f|3TnugtPqd-OgLDehElZimHaX*KO@tL<#H z*MJo01}2;}g(C*cZTtNZ(f($$4jnYpIsXL=Zv1trLsB^@fRED#ix*^K$>ju)3E~zjWWVZPvz)2uH7yVOlg+qg%PL8SM_zL* zUa(K0e;YbDzfJ)Jgb_9}8g_$>mg!nLG6Tb32-T`&CLUNgTb@Ut^FN)we?`i~^`IWS z3^o;-&M9>|m4X0iQ|a6@j?JHBm>EcH;aGfSKR3XW2S@R zp$*E(_HkG^+KgxOl9K@6_w%n1d7W)j9pIFw8EepB?Td-`Vk_6grb5I$vuD#hUQi9o>v;~gCt)}#x$Yfk; zIr8S=A~;HFsQJ?82Sw2@UkXaeKt$xzW_2t&?w_tgaKM>vKsa07cPACenshfmPE*Xtx2v|0kSYobQMAksJ&xKumtNcyho?!w$N!8{6_v*#M?L0XddXRp@K#@ zYKes#(vf|IBcd}N@!#rkS}(pORajr!kmA&-hnCjG#zZMR)*p9d-EL)+$sN+TV?oQQ zX*NH58F87`T2Mz1IZ$d=4f;7W0CZp-~Eh>Zyv=yuwf=r*6m|Q_%@;v^{BcxWv zK3<0wqL$UxJC4wzNh%PBuh9cBxd>f_3-Y-@_RR#~9QUYxPLQABD2CG<&psHDJUrRS zI5dVI2~7^M2FWQC)@M^40(YRHJ@qwZl3(HNze;xZaf*w{C&?s-Z~i`ourU7b^-856j?Z*W z!y`OVY@Lbl7P!*ooP+&FCn{xP`&#quZHu2VRB=)8YyJl*+fNgm^hJeRCfW<3vAz>76=&c z*Q{Z{%R~*1qPXN}cA&H&2sA#V)o<;KgL3t75lZsna~|i43>8Zf_$!=!k~1=)Bq6M~ zHCJ)9GILSZC_4huz2{nGdU0UkEq-K7VH~^UA&oFrMv(_QVylOjUKrm@JQql)uq*Js z2xt|dM^FE9u3-~vY14)}>7sJ(a3@ZMgJfpjjc7H-8u^|2_8Xbk!?WRB}-GfdE^I54&}OMRyRX?p`*3lEVR>$0a&_+Res&LhAqM# zy&i;)s~QfFMSpQkc5LBPejnaaQSz4X{51Z>PJ5+2-3sG5@hN*HZvW zRPV$_w0l9Dcxo%>9cD3#P0mKEgVgdza;yox)5gjMtJh8$)~Fy)n9->U$IgAzz(?LZ zqK9ixqO}pV9NL94qZ8=Dp~E7d zZYh0U$C}8if9B`F8m5%kF$pF!p2suQ_u(cbv-Bsj55#5Sbmz(<$50kI^^`?$idzz9 z3R8K|27aTk31Q_<5uY~FWg7rMyJo~HL`W^l~bsW|%dGr;+Q-|Bb9TiyOJm{RNls`$mtxTR+TzL71FFHxSlV;-%UB zSuM)DAXW3Ey#IntP#C9xB!^e?0%_|4?YJs21du5w!nUDPNN&_VBjJkWsd4;+hKxpI zju^KtzFfEXXD8?Y;Gf)VpCE{XEhsAB#?(h*DVaA(_YmoX(#g+3=cr3oA~Vemr3Be+ zkBi}4_gM4KFy?rL!d2*Ls?C$<3=!YjJI|qJN7gSDjZi4P+I6jhKtv3v@W?eLrf|mO z=BEHJN94Q&wfAqqSVS zRu#YxA9io?fzrr=>&bOIiTgNv01+=gH4DtvdWT>JI%!kPRVm|yvC=S4Xy*59Qa3v>@WsXKHg15#NiP+ zf?;}w;65U!d;u9G>zloLwUtSm*FZ;vzJs5mqm|lvD)w_(1_juBuN;6Kd01bkGHeWP z*)f3KT(OFf0OS)cUUpdfk`mML&+-ReCinH6TL$Z3Vp>^FLJTlYg(9O-r$XhI#f>(d z^QLYH2L%t+gc=Hb$NB9E?uzh@ML3Y3Q6%f!+MJz-RgU#Yu4s0-`&&FbE0D1`ub9=r zCHvGuQQ;=d6#nbgO*UZ!nv*f9w5-{%-tP|Acpht`#=VkL1XB|U*XD{D5>i~Z-d9~35SY0o2ADu@? zD|RnEJ;m2cMyI1eKF#fExEUU{Mtkm|W=&}KO%q%)VvO`i4OM9{xqO|B(DJ)OVz)se zx4cKH2r0K1a%a_UlLeG`C+Y5W`o-fJy6Aq`&A02@jL(AKAW}bz=H) zqY*=3@TWJBq_U$G4Sx9=&IQ5|M~0N_(sa4Oa+C6sEsoK={ZlRwt}2U{jjVZ06x!pL z+oiw{QQ+HQo?+7v-9g?p(A;7L`VO!u24&73=Zo7Gz8eTq*MepvbV!^egKmlZh&}fJ zHD_^f#c!F-1U&(=1*T}uJaFq~f3{M{2q)4e^0ap(BX5Ph?o3D?}_cS`F>c1+V} z?_<$gAlK8uhk|gdY@0hAW>Vd1O;{IO$G(;Qp4dRtK+xUt%yM>M!NWwW?kg(a2exka zCUPds0xfxVH2P#@mKtK?dO!%{&0_KGOAE&zOCq#_RLB^%o#r7sqbgV?Z88081pVT% zL1Jjs?wsge_`lNpIT=LEKadLIrYj?@tSTVj?_$Ts=jneH5!_C{g9$}K6q1BZLSTxr ziPm)a_1Jok<)uHsvlP0hR?Ax?W)BM?;lM$red;1T24`*Ip$?{D%mc%_ML?zuHi;pp zJOKbDiGwBHGs>8Aym+OPJB2C!ir*vYj(=MP73WG+4XoA8(_+54T#~JNJfdgB zHbcIy2bC4s>gW0DZhQYU4UTAXjd_v$#$+-NE&^otFl}{5>qo<)AIfIVW_9f^P}{67 zoZn#IKp5+3V%Wu&9}vN(8vaoy-48HHDxKe$p7@NJfYbIh!nf~ zfwG%ENr3j!Dh%_)!S-aOtzL<0*foE+{h`GaLNs??>kW>*pN)gZ!DwBYlL}tr)z6^# zlAR9C!+F;9l&t+42p5i-S9GMlAv4P=*vZ06Cw^%xn-}=(tuq~EjS_s;N}eXaag~E_ zwZbU~#cyxq2|zmSjuu)!jCg$L1qz>lF^NyJJGZYD^JMvV?46IfC@?MfgjF>sBm|D` zX0TPx6pNx)$nkc?MnzQ#eRv3kbA}U5=AK}Mt1O8Z#Ct)h#YCK|-(XS0s3TrUn%#jA zdKimKx(XI*y2TuN!PM{Wvd*&Z?8rGlnpS{Zf|v4ox$&@)n0an3gOIm<53A`*!xtSN z-NN=@X#EV+y`Xfgr+}-oFQ-cE6+}@eE8H$)UiCGsZbm3^j@|^LDgtc|dsQ&Mvk{rn zl_H9%Oub-~FC-a-AzfUsVMWDMv2Z>U+=p}ceA2DSVa4ebBOeOxz2#guZxLc5wmriz zg`h~PY!)I!-;alHwq)@mU4Ys7uAr@*$&nd_OFqTR)7(#K!wXSFi+s_1T^d+dEVB(> zCt>=5i5^!fhn(wx4x1PDV^pviOE;BAQ+q9ORYr_r400k;quB%0h!nNUY{X!gp5%k3 zE=9XcStK9nEezzNM60&cTEj^TvBZsfd+%792_sclta$M<7Q=Y+gyxGD<^s-c-0Kw3 zg*4hZWO^+cvAfAk!C_rug{8YiG+C|a#oGXzjE=nd>vozZlp-Xs_pJmJkI(QvA3>+z zet3CW0Z~J_@5kpaFBEK#uNhLuPC4mPRa_j5wtw+yj-f((KYLk)dED$1yMs>(AQBlE z9X%48iWV-1ErI58c|+h*$W}V*np4^Lm{-B+wVl}I?ah%h$o0ajcD5KSi*}MKAX7#= zi8~EN7L^epYc0egvW5Lb4uLmO zKkXJY!6UcC5H&rH^9KQfpacsfXaXdqdHQdyyzEO=R-p<~`#UGvXSyX4sM(n;0h6L4=a?zI&^$spE+lfdk1fH$=K?F&ge zgF#+5l!?xtaS*c8E87gO^k4$2NwN8*u&WD}%Rwh2*07gb`n&FX5U*s3q^b7)(?Rcb`zR3swQBR z8BIQQ)If!Blu{f_e%ij;UVF8`FNxQot{tX=Z=nuLEi_)aXviL{Ru$})JJK5yym+8L zq22{_TvhMtc;~<-sClFa=u#UNKgDBF1U$u&(};X)@PQ!rW{|7NOlf5B?{(MylVT01 ziDd@Lt-3z&M?xxa=O9>p#&5@ICf+?j4bV@>Hj@FZ2nw@K3ZN|bFEMMqLYr)1a|-`z z3$KmXTD2oxLJR7dCgbQ$>;cV&hXotOY?7+g!Io0klsWq-yx~zdKDL;%7tR4XFH_<{ z_PYg`*~$PAZWQHr&>n+35l}y?DWo_5#ok$4X2Kc%`RhFdh3Dt_Mc)B>Pmx0HWv8;> zWm9RbrB(QNq(n-IR08+pit$o%iCs_Qcttv%L08;H-RXh00_r%0$qa%$-9J<__YBUbrTM0&j>y2BEp5wE!rzoT8fbb z6z?p5XCd>g>y6gH63IX*qSHcnnVhJ*6rg z)HqRX*5F33;seYqWw`^)y%7rB-jE0_BY6z0(l=@ZrGh`kF&e#dwh7s2@558zGiV2T z`W`vqSQOLxqxIu>`xT^0-#F2JyGqyG*(#X0_L59`c`vA-^rpDnz;a@i?dkE6qyg8P zwaZaaiizyZ$sNdKBVx>x*@t(3t4g3p*cQP)pf0tca$yuB5la}U1TB5tu!P=7hF8@| z@rORn*r+HTHWo$Y#Gy37HrO@*qLNFlN;365s-`EsfQjQoFTda%c)kGB9b^~f4ga9VTGjMc03(mF;zu%FirD$CpRu7I)O;Gm31k%VpqUnp13MxY)5NERQsS z*m^sZqX%MVp+ejOGjD~rl=c>TV@3mZ`3_xu74)-bSr`Z$I8GQG*5xDC;X|iKpQ4Q| zEYz>bLTw;)Tw@UfjdM-)e14S*wv|l6Z+zQWA!rg2<1F9)&tD&xw|}J_YA{Y0l|enX z8@NwK>GcqFC*0l+yW<%Hd#f?1PbyE&-(eu;>+j3E&Et?)Ju=as&;9}q4@{G`!KLG$!I>7i)wb-1CshTT43HQJk))6>3d~`lri|QG zn+$He=Lq3UCCeAxWFS)_Kq6G_AoPTgbTM^AOi3X+yb#P)Q~E#cGv=Y8qgPl3`UI3P zKnJ8ht}t`8*tUkH(56=FFnP_Qq5EkJ@U7QH4j6?N0hbHYw;X5n6gPc3*6U(PT~4fs zmP{pwsN>dThsl?us>#SD;qE5YKNDm>EQF?z&e#wp0@J$wv0Gw+<0F_KxwOD)xk(Cq zbT(PVy5UfAZcN_D;2UC#-RjHJ=4ne#F)gF)^+vd_D1l+D^5y;s*ROkIJoj-mokpru;|gdZOJwo!+AJ=6agSl%Pf`hF&E@%7iaZJ~sew z^3C3t!vk?2kLWf|SOAqh-|nVs<0e?Z^lqh8kM9F3Bzu5Q*RyXJQ$$vQlmcsg0GuF} zOBgp%ce9T`Ah$)oRdlKFP={u0iRF~yjG! zt=p`1;E{DK$T<%4u=VFFhIO4!J8VaZ)k!<&s!%F5o}CH%MtAeYS8Nb9t}~38J<@he zZAdG7)-odvTVVM|3ky9K5}}a@@Qly`Q8fr0oEwNWQR|CKWnVTMt#Y!I0)Z5)#KqeP zWkAJAKd@@R5E8}`xTg+erMAouE5YYRd33-1JPp9YebjnG7Z%k@9@PuBXfOpmIA6ca ze{8{$!pzgNo&@b3&hIEyX4zHNTvL>_?wPD6-+A$}Q8$ki z>TD~kA?OgS6^5f|#uRv{&aIs`aNaO9u|>k?m=kWGCL6_y2{3P)Z%>%&rP(LAUQs?` z+A(az(#G%P83d^8b9?u})9scB(o%%~A}~9zW=Y*^a)#ok8_1kvQ%H8)cF(+!JFeR_J(97cW1i zt4rw&As$e!b14(PyW7c-v5gvq_?BuMJ3$gq7C4-;s7yoJ`LcBjUH*EvJC6^s`36mA z8r@0*sa6GNi1eQCS|}?9fQZgA8@Dn?HKH>F6r@H6@i~$%{n;W4tJ5BrO(Xztd71`9 z?n-mAoX=PrYe%5*WZ0bip0@l zI3TN*a%%lplBio^DM=kdQ{f&dcsen@Iw+GKcyQ5+_K{s9O52&vGV%BX=6>wLAz8j& zZb}M|R*LB8i5e$w9#DzGl`iREF$^VaH~#6ZP+Gxk_`E-Z^2o~zieEWk?O>TM)TbLr zw<_Df*-wX=`4*CnOYHm_UVS0$`1K|c9VqO`Jk=nv|L^-3lGMCo(0xyA1?@ zJ8$Mu3XU+wfg;ar@@l%ig|;cQ=;(;$U&a`|CKezo#P><+D+N(j#mOs><<{C!voqc- z_16cO)Kry_5L>BIV9aWW5<;^wI_s#+zp0DzIp`k0O(zB2tDK)53@Nf#glgcP6@Z`t zpO{M~Zm0U+(vhCu@3!8L5Nw`?=+f`)DdK^_oT~XpAxm-fO@EAfpLr54Gy+f?!DuqC zUcviwCHIO^f4kqAXZwCt0-*3GK1ogh0%%;KQPIAFI!;~irnYvgm=;!On60kCENGw> zNtJ;fct8sK4N@;~7Z9O-A^vj*=2-0Qz^x_WOT;G1jpPgX1=h2P}Cmn?)uWUH8PAF0@w9{ zeM&&p(=c(L-_0KGJixOn=yk^_oUHjb@T=@bNjidg=S)*4eaC*+#X}FC4{Z}uM>#Q- zB-hD{&%e(;{r9;j2VQM}HPmnE@lz*K)vl&0_6Gw}#!+rJ>BjLr8esryiY*9KM#B1| zcUJ`5BFm6$s>9+sv4?#iy#li;FS`11myhYuelr)w+d%hHw+k)V#aFhGp|4O)p(#w= zydt$Zu6d~g<3x*S;ggO1zD7*80r!$QxRk#V%q3{BPYHf-unKWGuR)hM4CD&5TCMJS z%UE_~Uc%|$IFk4*-VVzb27#xRXFkf$gUBb($66mePl6o1iS zE+%`v^Z^4CZ<%1&lG=@j;&tUpfmAZ-A6R2UX?YI57CaYNS?M5nGg<%pJn9*~1$^Lm z=WgK55jIc*^P=DdkF<(P&g6(tM)VQD=Kw&ML~8!dxwP&r`-zP4pc0Pl?B1&nVgo-u znvTKl;B@)#r#V^EHCz7txh#8(yFPnQe-E4BDWGCh-|)dAy|&#hjf>gzSU1L#FOMs% z(gYr|i7AiUE6A*1KcYZ6cqEI1IS4V zt`XT^bd(7dyCIgsii(A-4s=nLN=#Wru(9|L1@KO=<^-wGGL(uOfxo zXbL+nz7sLM0)SiXMy$m^M4@-%-0Z_V}Qarc)85LLJI7%xTi z9l=QMky5`X<^S?Vkgz{Dn_N6!t8FkQx5*n|)bZeek!^QNVBa1e!N$L`bfvhB1c1x5 z;=uvS%Clx&yHhecJqpg?Z_?}j3jh8HDZ5;Jbj{v}ut~+li7^*T;j>~cuE-afZvhAB zh3h)uE-`+VZ_BomL6sj7$*tqnA@GSG%Uk`9+g@MIO6+#Ai(sD(f3J(8Yk}@OV_*jW zIGA5ty+vC@{^h^$FQRlUq`?{w{Ek2N`~jMJaf$uaR~Pv2j4D{cQ8sI~`C!atbw10R zCtywX&9g&}Xir7wCiaw-s1?WEJg8ffzQ3uGBa5l0OowHA;v$yb~_!|4M3v9jm1Ua}A zSwK)FEfahc|M@R5r`195oNFwlV~HF5kjFxr19XJ|rJ=_RF9<~@rc6DOZdM0^(Tuj| z>^=CsnpoQ}z0zZwUyXXuyehA-J4FaxydY6Z58vE>+4k>sbw7m$&0nPbYGqjNhq}iP z%Z05hFx_3tvV<9vGx|#$*yrC0sUPX;)54IfH$%(C)m}nvT4ujCoI#8pmE;?EAIVK{ z_?}*MlmXm(u@+VYNeqQU-m)M@RzW);VE52S1I*qbMdnX&9pc0=Wc%0rw#C$SEZ1JmurQ zHNZ=(%*hUQ%o0{g`$#DkEz*btN-e(wBIFj;*~t~zVhI0hntK9@*>xCqw$jkrKRmS1 z;UP*>P3l30whSHMnn9*HtN<&CW)HsysuBUeM;C*_=h;6IE4X`2CGH`^zBZXbv?&KA zmfs&he7*bv&{H$g8#g!7juglKeq5f~Gj~!{5nLxE4x5}I1zLk{P?kMP_a~cgwz}b; z@CVZ8rs^?63Q|1(%%KKnc+WNM%!3p`JAG2-akfTe3(z9@yjjley+ZmDk+vvQa3k9K#$@l`%i<48IUUji)QxV-}5Z#DEY zAJ1#+$5Uz-WduVUpbkBO%hg}~~(qC}gSW-}IsHXE%sC|!YLUka#M+^f2UZB`llJt9{(-214zAxc?b_h$bl77i&c&&B=UJz)W$gj8hUs$Uf^t7!P!3|_zGcMHf=1{5qV0bSbP4g*;3y87hI3L`B z;ztvWqUe2TILh1cmqJx@-XMPO6MaEWLg=n$%e#l&4^n}k;<0(0e_2wnE05h;Ejl^( z*(Ke3$e_fhm)a!GuqgEEUII!y(gM4oMMbV6m|%X44cw$aa4_Ulz-f#DQG){4@C+8_ z4n;2CqkD~EjT26A+H#7k9nfA={2>Q88Vf66&Ho8bFbzx(RrAT~VnV01$j%W2gL#|DJ&PlU^Z;23OKZp%nM&0;hcTE;Nn_P#z7_yWvFlr_>84&USel& ze*eP?-xg`RC=^$}ufY%ZOG3ksVsK&I%Z*h0)E?N;rV3>P4U{z3OE#EDTdeM>AfOL+?2GxJ(sbLS~Z+^C6m*DI^fnM{yN zEM_;WFRR^F9SDCRpXwWM#NBU+BW1M&5-(O2#gmImw059ZXfWkbfzNmm8$#aP_PA2Y zGJke}*EJz6jjwA~|8zfD_k>*sAq@sUbKMppe8-adu2f>1e1ErzlSBcTvf6)EOe5bddy zy%_4(z9A57^)Gw`-Yzo}txcjw{EVn=ECXW}yo1|;9(2B{E`qSZZ-@Lab`DLQnuaSte2(^bsvO% zaW8So5d4rnfh%DTUYO^rMdQ8# zs6ZaSw09{qzGk3KKr&JQ#-qxEQjBt%3Bwxy3}plX!0F=LJa)VtGHuV}W(Bc_j$ zTW$;kLacERAHaL0Ap&>Ry(5KX393i@1@-EzaDK*Kn2(-A`fS!TFR7ZWj0nPU=@mC^ z+PH?2E=-g2TJ>KlL-^cHAYlYoc!V1@XBQI$Wuh795Bmj&1}o0P`*!z5iita)J0@bZ4~bNVbG^2T6X z5q%@g6Pld?bNaxO`Nm%QPvQy6PCU-2l(-Y4ld3xQZbxvd z-T6E2qO7~+KyF+iK{z#jEayn)TL;~eHlJyx?o~^Oy75X{z3ag%!N>+x(jj=ILfjge zWv6a7d85iPqKrrHp)Ni{lWx1!;=1A)n}{|gIjCDjW#8yjC+kO(GP0)>d`qD7^R?WIe~m2SLe{(LiX%7B7vSje@6j+iBQfR25IH$XC!#2KZ-^A2 z;CI75SW6iW(Dkwh>K0g6stcSeq51&rBgmY5JZ!%CbPv9j<{aT7F+H(Snc$}a>x<(IfAqFqGz?XHb)f;Ww>+} zOriT$qCmOls~a(A1^Wj=z2*1C@_}pVsS$;HKQxgMu|Y&Ld*RCB`HvC#jE5toq0I)^ zFFp{}Bs*JGIU~EHAmly&{9!er}yw#?K#@Ye6yg z;E?LyNQcwn|J6|IjqpDTiW$E+u#3sy>ebB9PkT6D12tD4Fc_w0^AlKfX&oSefTA%} z6Nli2MGg0uoxq^d9#`#EhTsVuq4{DTN)NI`x_H~9d2vaI(g|79PTBOEz{ecD0=D9X zATpoXHFC`wBvWd-x<2}~4+sJ|8Zy6LJx`cqY+Ib%F6SOFjGqXRfZ@yI288>V;|8Xk z(#bV^Al`j5lVWe_?ju*#dDAdgkgfK{#>TYqE6saZD!l;zD7lY>&z0KR%Kf8je6#(! zc|pzp2h)Fy+dl3#FN+{=PZe0L<9tARaJzom`Wm~Q5u7z4(l2JdLyl6a`H^sl>+VeCv^UnudjAX?i1B^-z%S~ z?ohknRn$>Ap;6lEv!_=T4iS$paUBnW@hW|x!FVN0O5ZdJ1miS_$WC054$WSpfe%Qv z4}3_cIkHKG+-x*czDP|_+970VoU@gxiOP-Fe}n~EBfM8atk7R2LE~6?-w9V&Shwwq z^TvAzyxrX_RHR8{i$y63AeU|c&%Bu5-vinKPEls$*uZ#i5e|D;fow|_DjtkBvy416qmHP6BtLI&BGk+97jZa9^qptlxA0i^ z3@(h$uKH$;dAz`f#~S4JPam#9B4?U!#i;QCP$;#!qh*`19w<3WDGo+HC)NfebIEn1I`j!-Ms2XaCcbb1WEji? zQ1%Sl4dD2*aSGD-tlUoNw9xNHa72(#y}b!1wtsii0>M8%_~B#XG&5y)`xYttdONi} zMee9_KeDVu4~p5w;2?Fsh~gj*j@g7L1O_nUFpL)=mGTfZ?lH3nL;A{3?Zq2Nu=?O5 z7#w;96-&(i#HD05o{|M zDRNdX5#=U{I7w(e#&d3x_KRK(Ybi`l=q-!Vkvk9n_EJo}ZQd?WcB?o8XY=Tmm<@Zd zBW!mGx3`#6cjQIytb#r;z87Y&ovGr<{4E>x*3Q?lRgico<$8kH57OANS(XQYQw3%` zZ@wv{;SCYcnyZ~A)sgwT1X9dvojot%|3MEQQ8+~Tqjb0&X<9aGmu9j&avB3kv zN--WA_?ugc;3B)N(O?d4e*p2rcenPU{yb6ITPBf(hc_7x$_ zH?A(cMNmY42OwZCJbabl;VXxSZ&B=MGHv2?Jv1%N)+qHjeY^o&)n238`Ie)kAwpe% z#g>}3SR~YQG)}S!wP~~ESTVMYAcCuuf-ZhPFnBh9l#9g6e`7NLrLVjzw32jWkbx%g zvL>k0tKV2$5IRxl-3^%Zi{44!XBWqbm#x>Pz#<&X0RzQ)+JX^@*ol&kv`V+Eb&7BK z%tEz0Uoi$-!}3TVmQU*#r6C>8h#^F-FFp5rvR(b}GKrRh@s7VPzfb>iyZ8zmQwv-& zEDn%tUVyd-AKM2Sp>k9EYpB5tL$ov}G^?Y*6h8<5;8pC6Nn1@mrQa(eHEr_c5T;?n z*uz9B1%>Hw0QdomG%Y?;R&6U%9*F)hmoi9Fkv!lTU_siFN*i|=xIN1Fm9!q8S!35x zzM&~YA8!ky=<7#hw3y$;+Ib69@$=1o;yDv-=yWbUMny_&b#|B*hgU+(Dn#H{5~xUN;uHQ6oWylUk%^{#l_-VJ(R%K!ld`88EUUoGYQ|K-F)`310p*#5GhPtHuhhlO(Oru8T5FU!CmD{ zeu7LOp**U)UbtC=<8LndvC$#Uzu0~FBzz=Mc5?%SJ0GtzOJjuw50vS-b}sX;hB{R=9zFN>BzDzcw}mBFDKY86GG7m=|oNh>NS z5tjaLzJtq)3`m`PFZt&CaDr9o{!U}yPZ|W%f=Oc^oR1DtM+(xh*J>4-ZHt6FwoxD+#O<8!RDm1(-C|XweQ=n*keHV2u=*yh7~g zg<5r>NO$VYCxtfr(a=FhpW&rs-(;rfDn(H>odUv|$#KL@Hmq7Sw!Z6h zU;C>?-dmFtBB%cV{j46VjAEdka%9vG24y9e{GsKvc1abVm;2;()@3fb3N0mEa2A=4 zK(cLKqxkC-O=VxvQ$-=$hUPdkp&-|3f0U1KTk;X^&TnmmK>!y36Y_AgwH{jzbc6jY zo3g15=HEM8Nhy7p$i_ay2&RP_7WgMG*VBe~ighhx<7k?p6Gr>FvF?8NwG~Di5%uJ# z+)(9im&sn6xMDTf&v9Fxre%!_!9}BW1iN zTIc)ie3$*(89$=1_zk%aK1%CR)yUB44fj4!KqBC);qfq5Kw38`WEsQt{OLP>>1cND z=rg2J?Dw@6N#JMLTfXEc0KfKk>E+=E&u5>m!B4ov&WU@#obhtlVo?40J;sk@_>b?| zYp&0XhDgser7p-oEpASKbd3DK>Ucd7Uqn>pV`JU3wFSJ62ch*@MI9jJ4>@g4zvMo1 zDwdpzeMGd5;9t0>`|mk$7uIAvF6a<9x6;@Y)x$9tvzp?Etc=XkgkNYhhdY%-5pfog z|J9T#`LLBpa_bGHK};qJz|7U45Z4`u@)Qv%A_4UMeT!YE{OV#V8v|l3R!IGY`x
7Ov6uBteNHFm#fRHf_C`)PF>J*BL@cbQ}1;OZYSC_b~vxhXeeTH0g%#^<}x{p6sF3Q8k(DYw_8_=O76 z$R-a7Kv~M;C;icL1JT{OVgyM#Tv@mQwF&_XjmuRp0y)}c#cIV^`NOWCbmg8gy=?}5 zZ3JNDhz>?<`2p0Ew1A$eXx1rW8=>aEZfew*wz7aExBUmSxcy1g9{h!Ukg0g+G+Au& zf|#48j_p7v0uKt|zApsQ;7e@~Bx;qUN^G)(WtCeC$k3_wCMUC@jdVC?(h38U8EtNr%le^uC^%T?p9x(Hc#6rcV774 zQF5*9FmgP&%8h$$Qdy=gzHFcq9U75H^^mCKpiP*UY8=)YU`kRP zb8lSPhE}>#WrbKV>e)&~Q$JL<4C0b5v?24TD7(R;9vce5E0ui`RNPxz{X3%uWPCM$ zltvleJql2YC2lsoMJ*}8W2#=Li_EJ>F*dmTf>MyMTX__R%jj751Ox}~xlP5D@s~gr z1-q<}G3Q-YfO{n$ESne7X2>$eJtN^O6fr0#vS-s+TV5P~eH1}lVsRX15E<1g6?HOJ z%uBwkH`myQ4ar6OlCD#@^{Otl$2F}qDEPkV8PHY)2V4q-m%(5WzT#UN0m7jLj9>Ff z4rkAy-VtKbvUmM-Ul3q;h_{l_bl%LMBT;}AtB!IB4!;OgE;>+%v95m*)-ufa05Q2+ zkY23_Sc1A?pEmk<73z;o+gygCsF8 z%&}i(?)X!G^Hz%L8$IYI?&&8?+>QITTMeTLr@_*G5JdRJ0ZLx{!r{p1wpK$j%I zzJj@RxUcg(s#!zu=3Ex3z!@L=VoCq$0uJFzuZ@|V22*yyH5{(kUE2b_09WSYQf+UL z_*6BQ@&@?XIOz7Wu@?`1{AwDN-@wYLOK*2P@bK8^D{`EVB(N|z64f&8zp-hLr7y{Z zrMVNSi|jD+iy1i~udNEy4Ly`b6~d*)cJQO4k5}(dkJ-Khh4zQX+kc^T`sM9BA{;i8Wf&?j;Ch&fM^b@Rt|;H7DsvgGXSAAC(VjX1?B9mRenCIRcr5<8%ooPYdG#0Ak$-zZFyZArww*=$vW{3i49=6=D#a}>kiVNHq&zK#Zp6DWU z4q+jNwI6-ntZt-*2L3VmSwoy(fakz|V=9ZzQxjH40F2&Y#RczN#mS#XlXW^hwZ-iC z8vQ~zeka99pHYp168on0==<3f?I&Q(|df)>7{)`wB+##aaa17Vh*}KtsG(uE7 zduvq3BPHE8<=cn1e{jYiVW#Kw36d97z2y5!oGZ=bM6h@4eX90 zy45La%bEQpgv zT@uemPMKLE^GRN&7+WlyQ-?`J4H{0#%wB#I0l2y`Y#e`N63nsDK4SI&wo|tR*Y&to zD_SmXShYZy#wB8II?$o&bF$D7@p*gyfV^RMoAGZ)e?8@+6vY`{Xb3|h9>tUHZb|Zj3!5k1=DLLrpg=IG!)@EGP zcwBGekVYV02}L1w89p-7fPC3K)hMDC(!tDby>9O(n!NJ1zKQf@`WlA}I*G5)R)^`O zp?EEPf^~SiTi$7xpH-q)v$LD!4vzW^ktp}5;SoVZ#HOrIU}S-c#^3{Qs{jK(5!~Uy zfqcJ)BL;Dk<+qMFS&&p=2xrUx`msQ3Xe*c#nN3Two0o8`3MJQpO&i%M<;5txxQH7;50*yL%DkGmX@!c5Y&Nc*F2D&gK$ zC5i@saZ;+K;lHVNU3Rhy67V9W4}f0^L_le*8#Ytp-cG`mB zZ}MScCXsSS-&#wR#kCF%ae1o>vfH~@&0+KDxz^p^x4x8|IbV|N0 zcOxd3VS&sRm~(45zJqx}swQ;1kQ-QM?dcEmP7iZ17T_1e5ebw0{qkjojxFb|Fgdql z{|NvKEgq2C{$tvO=aCd<*OBqGEUDKUhL};a2hd3rRyG=f`WQ!KKl(gfF~%`&#n}8I}Lzsd_>@A^f*t6Q4=t^NY-!tlfe76y5mUJiaS3X9Hf0LNkn{70H~ywR5T zXRhsaJ7(r7ltmnbn}0+QUu>Var(LyB9N9+h3PL`4^-&g~e8&1ZJTh?Bc=r@A3=Mf4 z3CpTJma4;^qK+V>ea#T0^o?2t5+{(&V9|LCY`oRE;sX`aCoG`O^MmAzw*Y~HIdm8! zb+q#x1LLpx@<1*Q<`D+h+MMo|>-7T_TTpmPqJJ}cUOn!f=2rA9=7s{#ItBdv;m7SA z0f+FI^5n_K+{s~Fe8$-M@^10)1whxNLloG8Vun#8fAt+O(iDk&U%C2P;oe4%pc~9)lLEKRbwXiF10cU)hYtw zo=vUi4^P+a4ZJsNv-8W@1N?vFbcR&C$Bd;aCyFu52|5xxWaeME$^$`KqS1xs0>nk& z!|(dn#H2oA8(NuC%QM?V$}Ah(>SYs52_JS6zWZAh>>lZy6B6Rp4((H9;gT+Z zV5Pt3Yg&Cp^n7sF5qv%kVk38CsftZIGoTLJUNq{+DP&9%=>unx^wy*y@HuW3OaA&q z2{D<>Z~pbP#Ucpl8)`YF(dqe_dSx%y9og~Lt2@xOCVg*ID@O6^$NlG^P*L*gTf~2a zVOflnVZaj*DMJL?;wHJBEju@J7(I-xTrLt3L1`C{m~JDXoH5-rguEMfO@_u-AQ2sz z2{!s5%#B9`U`e8+$5*4TK_BS=FA_zY+>A9&5n%K%l@3x z%UF3Le|0{`h{F91rxa-G^e9cjPVP6@@1uX@=XWsh)Kll2V)l(!6hYE}HYiG&zt6BB zO3#~&MVv5}aP5zZE|0TT&v&gIZ~Bg_*Z3`2BQE`|3eat4z)++Zy^hFY7oe_ZB zxaP2&fXaPi`cI0blnUJ9^2?(Tv#N`{xR%&1n9@@Uxr!R8U9MYRwp#~OAPPx}(O^rl zZed_)x?Hr6vJL;!UwDticp{(B^H7Ib-xjk8m0`b#0FoL z?(eML21TjP_Su6TtrfLeySfHjg)mO^^*Jty*%5xvRi43r$&cm{W~d9NZ)qvsEg zCkP1~@ghCPe(U{d2}we|qKbPd^J^qW8QANw!7H6{XOeq5Uju{1zo-Rql%-cTP7#&G z8UljJxcjH3Y79(1^t#D*f?HRf57ZLEw-lNkyf`pgo^RQs9;1i}D*tcfn+wc_KU!vrpXQ`37HpEH*mn8V^je6TB+U%XcjOGlEU@?_){<${ zVTf4hDAkYLljN<5XEk3qt2w)dM?g*O(HcZ;OBlV&DTz&OSz6^}pu?zSES5LeJNN=_ zgdCFjkr!XEH`qVG6yeMYl?WWb6ux7&Q%UpE9Y^~8+MNYwrZL2b2~nw_q5Axq z|InP2oIwb=(Er0Rlg7!Be^AvNd5sG##9R@wQO;h`Zv;v+qGi9Qm`4z(*d zLDEhyi|JNDltR^qL6DYzU4CuS1lIT7siVLN@U;{i4aN!dJ$y{NJ0o=+WQnf3dT46a zO4NgA0plErxAR8ILKBZpKuf?DNQQ}Qf84FHSuaX&Eo|;vF?8llllR6*-yzw-a~^8f zL=ku%jHoCQ4(+A1oF%SbtP>oFRY!IU;I!FV+@1|k^rs<96fpSp}^*P^dl+rlLKk#Msk zWh9_XOku0|U29b5;hkdCz`N*FkRiDaw~_A~iU z0KhyYz~|f>Q3IfX(hK*s^B^9n*3Nf)W9OSof=7#AWUu+L%ie)jHzvVep$}Ipqit$;ty+{RCYF*jNN?_XsJ3+kY!!FggBha|c|&%_U2ej}x+BDk|&} z_S{0}nV5j3V<>aiH@EXOJ{P<;O|PA81mAFY)a}hJiqY&XH%Ta~Oh<5IdgALO ze1E&8v3K(aZz#AB_wHBDb*c2W#Yh!TXgJ;_aXvNZ5p;Q;dLn9oR!<@_}?f!(z<#< z-(=FZA)wqPtGm(fM3(Y{Pd#kDt@8!!Qdl1=(Xf*W1u3V4`w6=4s?&~VW1gN6VJOz% zZ}oV#CVBV}R7eq%Cic*my8-N>IJT;rr1qiF*v8K^=Np^26xxh~kehzVjp#c#*6Ew= z*Ubye#1D;DbTX(3SCI5s2F3ytRf2HnklAIz00A_f}FbaE@D$IhR&npT8a{$k_nJNK5L z8{t=qD^+m(>s@K1uea5k8Yj!I_2hhm(bSw*<=OvSN7`4z>D!c{NO8s;QD5+`DsCKW z1Yw_q&ZO&;@LAeUm1!8F@q9&@p7d+(LAcmp?(ET1FX9y>i?VU-e?Gt>N6r&)b}U@G;5 zw8y2e~9tEq~ ze{KPt^Z=BS*iut(fEu{`|+Q+x%)>_1An9{as74ZcBxh}Owu7D7O9}SiM&fiCfU9+{!;*3;pPrau@4;v#c8Dj8NNcD zR0MEo+GzC>TC1WOm{p&O?xpY)E<9A1;GWKCxnxq-+7r!XWjT&Z=Nkil@ahbs_TKJ%HeWpCY6>_z%1$KV| zEiPt9n6TrXwZ+EUY48QL@@e_;l>N7EDEPu@1IJs+{pi+<@sDNMJ3xh4oq^#cKR!Tt z(p*j(%9mRf&OVA+W#Z&$lP8# zCXC1g`=-8;pkKZNDx~NTi$YNj_$BY*kn*4aMZX42QM$p@B*8t9GHak6w~veI8nbY^ z2ZqB=?4~ci!90CKC3UsVf$9mqqS~+*)OXApH=?h)#surs4y*Qt9!X4oo$JwiNfx43 zydV&T#^Kq=x4^mAR;~yBqDU2FSO(l)0IjTNLTAp%6`i{;kO34rZy!-c=I`}p_b4{# zTB~4m{y!3_%67Fzz;v#VU>geAJ}ej8i@&{|0pdBC9ZeRSy9cC!7-1rA*hfa>FDJ*^ z-ua4}{Th=a{C{shFV;7^+lQHLsGEL*w%XnKAX1A#GXpnLf9T`_AR$;w^SNX1T?&y^ zD+JaSACiiv31));7u^Uflm1_Xh8h^=G8s2n=`t_iTfls_TC6zEwZ)_+#(6M#l$LCi zv5wZd(yYS=uR&p1QBd(oGEtL*Hng&+A5KzE{~4$&sdG=Yye%p1O;|?t+IC1Pfkr$RSHn z*_(^YuI6G6D)vF7@ZkL7*#$};A2BU<2eL!E@}GpJngKvahXS@M9CkjeZe|!>d(vg- zR+;y+Z)3YUy}&t$Js)q^n-`r5ZZ;aRr9!Q^b{nS)X?ilVvBp*hf%5Ce8@OLv4^crA zv*&;hqIf^Qn%(2wcyS()`^0YW)VX@yhoflq%$r#AgKY*bS}M&~Y3{IQf7F-i3&FAY zF__&bm9r&w!8xc8N76a_4$?^?tR65|tuZt>@?hUh`~pxzKXB~m^k%i4bI%B42*`b0-riuKMSl%KlTegmJ2#qlRhZvE;eog3s3L3+ zBF6O1i?r9bv_-A}VthF9$c_(&&mdc`%W5AOK9(<0QB=ZDN}|nyC-|(TC!TMl=Qt)v z*i5p2d!ri?ypvkjlYBS>L!(o&3K>bv79-8t;-ojoGSf42bh<1@CrVAk1-56lB-q1e z7b5hAa2V_)#8(fp_6=8!imZ^pUNp10*cGP(ZG;fa<30WXKBlz_0nWg-U{Hk~vFr{U zpQf2$Kh*SvflJz9OXy+e|WKkG;PE8(z7qTsT;itE5Tbd%jo)LBXK{eWz?U(8XOp4on z3^Gbt*NLo^sww@o*TN>}?@+b)`a9NqJ^r}T^af^$v*4)$O3Pi^HZ28*gX{Rwl$pFi z@xz8RUnKN1_p#rcNI?;PcX8LA?HHdPq!PlN4TlT1p#j9PIK=v<=JX>t;S}BtBTv&c z4n;W&ukhc1*4CfU7aWSQHl~|g({7i`N|6s|E2RRLtz8>(K`Rhue}Q@M+NKDQkO!2j z!tr+SQiE^MBa}g=;dG182^=i%Wm`7h+H<46Lkvm|MIG8bc)L=O2L+0N;Y`=uMbUy@ zYYGY8t{O}}{u~S(r5re!w5)vxDB^5!jl9M7CKplTF{nH|TH7-KChJKD(Dn07>s=2v zaxGm**i$al-bx$v4n3kNYX4B+ z*h^X-#N7?JvIudDGi{tssNCnf&EY6u36zZk?)~-RvAB4CfOohhX%3o1)`v3;H;VEZ zBBCoMfx3~|?=(|v!OXLVXvEqmczJ~x0{0&tfy#Uj>D=E&1C0Gx__8b|6)8i!m!cen zSb-2~ig*lPoh4$V6+DqVjq;QVmj_~2wrIRF0^${x)kti1wLGlq*tDh()ipF&K780D z<=D9O(4_{agL1lwQ!{=-Za6u{yfjFgv58eE$jo%6?9HndzL@(^WG+r5GK`}m*#3G9 zPWJ8UQM*|}v^Ru%m&P*}jbEm^dX-nmhc*q>+Z?O!98nw`>6 z{sZkJ$X{4NiMHf!{#}a?dii~hv;k)Kz-QCb?3X%|JxnT9iBq%Rs!COXLCj@|qOTEf zc!4HbSETp$H7d#0#z|Zz=@qz?@&3AgqZH3kB!rfw@sPaoBz@rol{CABDXn+`@ z%1nz00YDo{1{v4H7Q!LQn8$%*HUMGz966Pth?gW3h;B5rGhTeGm_9(lEXL3PDR6;x zMc%3tqvKW&?wiAF(UUoMhNe5cj4Q>c$N>225xp`Br)UhwtOSY+GRDh>lxb>(T+Ycs zvp?<~G?uBq+&`s(U?}6$?QDS-sgg+HQ>9RsLfW9T@8M|^V?n( zbSn7Rs8W}HH#i9;pYr@rK0v4CFg3rr+Y%m^*yBljYYN1h&4M5S;*Wc( zCmuUW^`d9TI3BE>b%JT2EGWGA4!0!hG#ZU3Cd1W6jZdWS5Ik_p4Gg}6RPH|#7C0Ym zfxQ60GDY!)MwPK0Qn$9ukuiafwGT?gxE=W?-0gx}@2DTxGk}A*-CSNi%jAB>d`yON ze3IM4M55O*$#`PPE{X5YaQEVUqgW^ihWbGR<>%G4>VzejA`XFX*EwZZofw>wc6}U8 zz`>@gK5%ZnEJoq`nV!}MLV4I5>;^@xvN9gGRO1Z4Xe_4MfZotx( z0CUqD(%H!h8!Ehk6((m-yW4Xe;>Ucd`anPU@?t#;D2~+viuz(ZZznT7HL`@UTiFb= z&1coU?}^rqCFjl7<%b$t39m>E^^wynZbVeZoU5pxm6(nDRe8OwvHKs zw^U;ifX}S7Uc58-Jcu0zpKSRBt*ZXZDAke@AY+1S_rOj*hi4XyiWbiwaX ze=Cms|qTqCU7u5vc?Ds>afh z96r+=280s1Z8Qq03X_3@?7+}58WfA-R3Ab)Bj$ll)EiJiXu)t`zJ8hiK%}%`tw@3; zoy%ij2g`x#JF6crm}H&JCnBuiGOw(jdkZ6b!Q5p**ue7z0}X+QtJ{lzZXfm25o@Di zbOVOZ`C@^=8ClqK0VF*?`xNFAOK}iN+jbhjN>Eiyf6A(&Yyg?!t5LFhS~B%NohcuU z|JVgMi#}bw1&Z=5iju^+BPE*RqxjE%G25f}$cd6#L4TPn-HWNYzJ?y9+VZ$7Z0VX% zIJq-+|J7)s%d@SdV(W0{9pTQal(zO(k4qorFZiq56&_ub=Bs0_m9~y=1nKN+--8}K z7SN&+%&2>u9Vl4Ns$y_E02XL6fM}8jsC4{t)9-`{V*2GkI5Va2N=9ZNPGynn;_Y^N z3S|Wt;uAG0F$i-+14v!`?-HE0n6b?G`2xN%?9O$=R2ukbMXZroO%dw@>Gh_pdlFTU zsyLz>Q57dNZzdFnMnnL6G#c<%H%PKRUP&tB`SPzz!!<+NvfV*Li8Q#K8%<7O>6Q1^ zbz6Xgtt4tFC`RLd=k6ZZVIMLcxOl$yTzSyg_?T@K&S6f?$2L|T*dgoDQbu@iAINj= z?8&pRjg!@1_enu!RfcF)nOqW{D#tXPN#01TVH8kA>dTD_zt3d76Ku;)a{HIEEP#cy zZ)TrXYW>`d#2J0?`D!{X2pC4w$X5RKi9NSis5*AD& z83xz>Yv3jPuQwb|(8!*(=1*4}p@F{nfshvStd1E&pwZ{)H1Vzu2&q-7y~~wGMl?9` zIL?Lbi^^*a+#SkYCtomtlAtPO{x80G_jU8MMcf9G>!mJSMdZ5MfSe}}<{tg^lwRNp zN9zKUgDHH4%95uso^3|{;6!%Q2=0T%+p9rs<-jOTb8uCni#;8WYP^ZgH~b1sktQc_ zznFntc*VB~M>#_e@EU9V?Dg6YnHyb2NZyF^l3aDd%3(p_0hmTm)P0t$*cAg8q>tb) zQ)Eoz^vk}7DiXYnX+UGt_C)I8YEe*YQwk!^*-l<5(-47V(*wZ(cpzIJ#b-J~ybtLE zLp4~1k(l6Qa2`f6cflmZPhhBPh3-5TL`t}(^%?;MULu)jo6Xu1*=fTm@+=jWTzHpQ zq~kROWZZBa>6W}1n>L?>iU4wQM1H-*g8vp>csA+VjzGj;olF8;LI!9OP}~y zqLJ?I+t1OkM-@5R`#fB=7mLGsLb;7nvf~uH9|R=#oCWN$*oV1!%&pR#UpJK5g+{k6 zWcAM=nXT$hUw>W z&kEefesaIIJAF5@J6+seVVop}EAY1|3n^5lZ!BN-scGfSoEo#bg40mU6>XXH$Ai35 zWcFnC+cT1JhWCUP3h;;}NMgc1oX-9mf9t)S@urzXLW|}IyAEL#0tZXYi|YLNAYRfC z)fwAi0DYf8uem|LQK5fF=qm40{SqF}TF5eoEy4N#sFn#APhA(V|Lk5@Y4B2QdRVMB zr(Ps(PL*WAZ`fl5Z$M?Se`s=YVA5gA4plp!eY!@GZ%L>EFiJ88U;XhtN+D7K(R1*GIu)vw+|m32GS8bbV?9>ZoSr* za*u!XxoMYx3KKl!jodEePAZ{S56~3=3BVMN$Q#EXixOBwi<|?gFxSiN4=}RasZUj2 zXL)HLfcgpV60r4(%e(On6%#x<46K2fyt)u9z(<7FxSZofq;u%~`h2G_{uwf4yRPyai*h{vuCk64&stm{-jaNGV#ABP2Fb z>=(2T941r(P0OP*`NNF@)R0RfG(RHa~e%|zlzUl{!4`sr|i8( zKE-fer7rN9E>qJ(nw;p4Ddu_W`2!f+-(QK#>%|Kej2VRtjGCx|NuaNan0o5D?o1k7 zd{u63>=WI_l1j-Vny~)pa?3=*Ocq?FB@)GxlvY|58*es%RUpev5ZNb8f8wgifj z9or{`Ye|*};4piF0e=Gv1{wvXq2(1HF)Z~Ya-ZyIO{aJKmMCwFEI{5upUl%ZtPk{+ zT(4~#@`3?gar=B4cD7QwzkT~uwc_YEB)v|BhW|G)G17i%?;9>-lz|lnHonAW(g{}u z-zv&cx$e)*f=jj9gN?D^evr8;+h^tR>!@Axb z=YcwldMNrEmwTbU0}l$N36FVOJYwSMOu_a8K=7D&Nae7g>#xu&i>Y{837eJd5Dc9- zF`URAioRqqbbqAPza5MyQPcRyyxm!Oz;Btu?Gni|T*#Xi8`GhYqA#XlBT1bh7 zM-~YXS^SI#jh_j%#^9OQgsYV7;06&ss5VqM-M`)c_?^=O`><@Rv-|(1HFbM{NA++$ zOcS#{6&7auwH1h zCE0A=?M?ARn)LL*h8`~mMzoLG7HZc_Ovd@6Y%!AV1(}UlgSOA=G^Pn}-n7q0*?t1jmMG0ur54^}%oA^J5y@x8}!svQo+__?;0W82##cU!kuN+h4wC zr4RD5NApitch|sO;){Nchroja;}0lO=%G_;*^PKFHBCVThLGSZkHs3L&fo&4r@Q5P zoftE{IO=B>{RTw0Z$Err11|VDm7vD*n!Pkrxxh4`A-IFFA{DW44>D>*%%bpR)+b=a zIthkH*w-e9sdSSwhbg}H=oKr$^T)^ekJciFq0SsUtJM6+GxeVm@x&TWH{bbWyz!`Cyt`g-h&zRS2gRR= z+==*L82G&Trl#l(<5@XM{Lh7a_c(h3Mwukl-&KTC9@OOUI-ZGCQqR>&BKR9W^FL2e#bCv}!v_DvO z9zU(rMc7fGB?kF|!tULySzc|T*m}?sof0&8EgLOv*97A8qjt#Pv@nE#`hf&P1Itf}fh)>)vEOR{Js5{H})sdmDrengtBQd=|zOlyLp znkv}bey1m(@yiWt^QiVowp~SFMKsrBdrJhmoo>;wxt#?sX zAkLUC(3}15du)EbnZ4UQE|xd?ANUYdVA1Dw4}2iHs+e8qcUdwL^ha)FjA%*O0JVgk zaO@nxKOkU*`~pcs`!}aWpwK{EkByc>W>Jg_6o$&}Cb)@QN*?$A!NgUMQ5B6f%D~wcJO|1fXyva& zMIi+$4@N6q^KtbXGp5eu4S{@^uV8T`abqtwhWW_f3;_86a7{Q+0{IjctPFCktE)1I zjHe(gh`8d5sKgCof1>y%A?F0XRizbz*KDrfYZB2yWuf#&i{5j49*KFRN3n663Ns$g zU=(LkTlGMj)Es(~I2%KJPqSPN%N&5FZsOYlxHaCG(M#0CO5$2L|0-i>W`1}`ZRge(0OVG7Aqxk8VZsTW%&Laz%aXod4!>>mH1+pzu_;n-C{izE zmXx-BqJ)o z8Z&%ag`knd0Dm~9#f!Fcb%gkgB|E`Um$^8UgT40zMusqPA_k@dN}-oWyQT>_xE`ya zlT=`&EWS8}AfPa}8qLA)2cu+xO|rIuLy?F(Dlj*s zDHWUTGnkeOS7W~ZEdMb1e-pdX1-GgsPtPuweQl5fd1*Fe+uFQEpcQHLD9DGeq=tgic z6y~RuJx^o{w<4)UWITglFm+9H;lRri`}lF|Is?l`4;xS*3rHOci=VN2c`_@?4=ZBI zR?eHz69B_Yk=I%VG&oLz^Ydj1lg6Z@JGSwmmehM2tlVX(5=Bg|W(_KpZGZOpLi}&! z3b`1hZ(vL3wZ!li!5g>506rZ<(nO?di!MT8X*os_IxO|hzCBk+8Que zHki?~7WVdk{)%zpze?y-A#$3l3(QKThx=K)IZaz+wQIb2ar@%{1J=p&sx4;B`bJ(S z6Z&vRhl}4raInYVI&x=WeKPihf6ee2E+?%S_iF1EWGS8@09ac%S}_z6xGyvm zDt8e)C+BPM4W1qJ^|I7sLbUMnEo^y{1oq9%T!m4EwDR}H+8QH<1T$}nPXL;kwCb+-o^(Aj9F*JI zC}&O_7D}a7nb7Y+J$9E{BftN7_D`^dDaT_8%WhUTURa$CFBM$BO1Y0|^mqm!VO1S+jJ4*JlyFE`<_FKzur;e5v>k=`6AlZ>*~ z!OCt*uV=gO_jA~n z&5OaWXKyF?ue-a|&fvG($?^6pnpxjwI|wY4%d)z3*AB}@0n=r^Ps7T<8RZ(YE3Z)P zn&}ju1sW-lJllR-J-jHO60w=cD%q4AI3~7c3{kqnx7Efk%s^LQX2gRFyD`^ zmGNcLBuL+(eoU_T2Uorf=&E=*qR{KypML@P9~g` z^<+ct|7!Ib^0Fqv^fGZt#QR=~EYJmXJRPI75pDJZ=5fBeSfVi7YQnx?T2Y;{i^)*! zMlK|)li@L2*J=*U^Q)?-^YfRHGWTH_3}ZKU1I@^i*Spgp{LQL;jz6u;fS? z+e&zBBELNXYS`;n2U@zp-FxQ`Z6wJsDiw?@$ypamM?XD>)R&kxcCxmx3R;GzWdVda zTeZQ~0@9-T<4~#}cTm=E!)i!)MW>aXUEDpaJ!3~;P-HWaHLn9=PrIX^EP}{xvysrv z%&QW`6d-^w@9j<}+=UBA6#%1^C$moUagUp)2hQvr90PFFLLK|9giI|9ngf%3YaJBh zd|H_=cBjpQ3V|rm2{P<#aHdGuFt~^!+z)7sVvxV}76*8!cneIQI|Ls**Cf$bqwA%z zlk~|Y4F-7tFs%%MGKHTQbu?%1w;YYFxqAJldhP~#kZlo%12LXpvxD+|M36q;ZkvaP zB%vGHD9Hj&HwVk(F8#1zxu?Q?R_;dZbt1zz2!vWF!fE%!k){)&k%Y8 zgOez_e|5jBqG|3Qt>|pXsfDc-I8}UeMV6P&vl<`%h5cIDh?UK4O9(sKsa{0Fp?bqA zY5DPHkyiN~7+{P^rEc}e&VK_54JILls#x1})`$D$F`C~tg7UqCG`OxVz|*#qrvGZQ z1_6O|(xrL~B$^ParlyZoOBhz=BF2N)ElBQ6cUvpcC9g)?B^^lIQOdf6z@-q2>ZhM93(J68(Zm^UL=J zhbin%%Vz{)q)9w6Pv3!npP^I==D)26)`}>*8Z}Dzb8}x}czX0E)#(MHel%0q08Zzq zBqD@+qSwt_aICp>M+Gf)(Nl4Ypx#?xbSV4Jungu-il|~o+IbGu%Q|S4fJ8JF zt=Mq^DIP(xkb^(KLNq=^^27L0JW}2#imP@Gre?JfDeY$lNS?Clkx15_HyA1`iGM{6 z?plE~*|gnC$1iu< zQsgO%Z=S~|Xk1^{cHD$S15$)J_AQn>uzGs&JUxE^24(eq=~Kh$;e%R+B8kiOf$>nh zJA*Ve6@#B%(sFPNGV$P%Ztm$a1!tJTnxg3-dT;r91#}JMGp{A9fSii|rH-{zu?S0D zdW+!bv~_90A>4NAHX=ETI`igFR8xDroBFM2w$w8%ja_Rhdp95DtLfziJUWG;2rC)E zo#@l+v$Zm2$-UY$Xfh}yi1c`elnxSQEJV<11s3A+>&+v^E8dVe;(7JBdqRiR%l&eg zdju>Jkk{kXtvIhvLC88(*H?~|_)IZr$+k7!hwgQN(u58pWqYCpQ4KA6$r9f-2u#)A zwE|8EY}TX%fNAS5979a#^oW3aSdryG*IYn{3-wGxCM3G!*@TTfnSFTow{ir6ZBi44uYI zq?lUP+e_Z6v}9^)vx?ya+;9QE9SJ`I|L=>Xaz!UcJelc6Mwsg5#Tr+)wvoF6QFAwc zXyN4jyQ(+rG?MXcr}t|0VoWY;S2;BKA7(vI(3QMFe7=f#SJip+_#|m|EwM*kn_abq zD`|@-r@}P>Ozv*=-`<3U8^6PY;GiSjW^7Osi`n!@=k6Y)3c zml{@Joa({xSo17pYsW0FH9mA;tabuWxruy29VHw1L5hh>{bW*sVDIaSY*JsIxHUpt zU~$)j<3oHPloVgQ4keeM`YuR{K8v4N$6$-H6bL+67hs92ww9`XLe(48IpHX{vz&7@ zDUj}dq~nCq-{Ux`1VD8zznz`5I$2e*G{Of)ib7EkB}{G}2l96%>>S89szW#_NjWe$ z6OA<<9RLY-*1Nm-mqSMYASsJ8y!d*ApVgY#`a2ta&9i~vwM)X$aY!Icdl5SZ3R|l^ zmUICeAkk3o<@?>W$VLR$fpxIDa7Ut<%w8#lR)!gYc)y7e??)3wyaQ~-{ON~=NQoudpg(+v+Aqx5?J%%ObD z+==c(cREM}4ZKA6G6y~dVyxtk2O7*Xt57uo4DC>kf`bQ$fb<&cnQ@6G{JfoxyunCu zSp1fk`lGbCovE6+gP;t6$CA$}y>#jo8Z(TYc_#)sa~;}B`GUEK`A!zJxQ4PwH54Wo zDi2MQAF1-`?HY7K?*D|?12Z4@%ST!JX$#7EGt9`nlb)C%n0ery;_?( z96WtMbqk&L^V!A6*}IE>fG_qHaQkJ|ALZ%g3r&~`M9MG*57|pQAB|McVYxkc2Wa2m z4>&H`yzG>L`2`Jq)#6|qfqjpAggZzO8pFW#aI9R`1Hv%~pBr|~;cxbnP~C|Ki72RQ z?;c2tS_lU~K_sFU2v1gSk!I?1CbqKgt}Zj!htieutE{dLZmBg1JT^?7g^Y$ zJU8v#%JAePl9QuDVPbj$&bY zsP?;^kfU>6SJ+v^@%j(#XXWdnRIO7Ds$O31w^%Q) zFkORl)#4e|=%lkAcmx7;W4X&t(&FyCr@4sAt_Z!oTK>DN_Vo04qXo{~!OP9Mc~vt7 z@nGDFzH_R$ysqauU}t^`!#D(;KenQwb9Fyg(TM7hhOUv>al6BGb3+>QZdzeLhkhe_rh#!hV$o^h-n05eZN@e-hn0B&tKk24C@SdE%U2Th2{Nv;1(F2mo z)2^DHHg-pQI*X@|H$dh|T|b8sDFVy1c^%l5L@V9yr3$+it{J8C!IfNzLng023Iycy zkB6ndc@gmp^eG8%zOM?Jcws~s#F(#qj*yhFE1}2BO`Bkd|JccYCb}~1_7+CTOSeft z{3fc5v|l>gwaBzdmZ?*-%cr>ZYWa~GjP1#y=!!EZC?;h%5oWUreGwoaFfhKTEv9`W z%>Af4n1CtnrIB49zL$hXzRZ)1f3*_j}>l{;RYp`@sK`!EBuW#xdozer+< zazyA`at=z0n&4x~#8iUVM$`!pqtBijrn;P=g^)Hsnxtr~_}fANHF6nsi2w?b_;v~g zTjYeOiM6{i%9=3+T@oL)R{>xiuLSXV&L~b8vP+Q|_{?@Bt|uK>h?x8b0@AWyfo=h3 z{d65Kog>TK$Ez)@Kqi^XU>~_1yNh6R0~jw^eI`PKPNg0l=(xM!@znDUHeE^?0ZJ=q zB47nusdj=!`|GzXwa0%w;q{eqeJP6uH>U3ZqM*uv@D|TPZ&HWaW$`o;ebXTP9|^KM z3X>Lq?=#N$F~}dvQV$<}&ZQ8K-~^|XK#d(C5*7C1FBr`Oq$wZG(O*wh2|Hq0D5*s6 zMr*&%i@^&_753cKL#B|*US;4B()c3&Fy!Tqtcqz!hcia}XZ})5PHYX6<$1G%f0Z7h zm#y$5CDIke7NK~Mg<|nuBjQ`i;i2o@=4H`5U~78}8o;26AZ7xPF8n9WjIk zxF4=;WYjD_}h9Yw# zqCdKo^wm{TkMa=2Ld+my4Q%17I=2a-*g?kA)Slc~p#>XW51w%Job3!WNu71<1w9uo9>99UUVZ6XvsG>P&BVxId?{L2~u-~gnvQd z(Q6am?Q6%8#g$xff9vClLu%eV_d);L6)CDPQ$|VyQol_gf*Sl!j&iMFb2~K>t!zX3 z3TzW$p>56#im$Ko5VK|U`M4=73Uoe^g&N784t$YB4+rfjLSz3JiAOMVjEpa_>2PST z923{tilEp1*BlH`KYOQa*t7raIK0lE=?q61id!6BT=T)55C*tVOE#(NAzrO9)QA3p zqOt~>_JWPF)RC2?Xt-#x0gAa>-J=sA4ynfZOzL6k$(!}^79%y7IE8G0k$!c%YYkR6 zpQaTv>ccs9{21DrNKv(GjK_sl)nhKkXi~P*T=Ia>5FZWKFx%eu*y;|W%?}&G%se_T`R&amSPtBn z8?druE@0L&861+@S5cVa@d|~N6SqXD8o3WXY%1-dNMYsF+vD+RF@*?1PY^5l&I`Bi zCA-)jMoJ~M7-{t~wQxsTN3FVv1bxwq26ohot;qmqov?5^I2}D|DPO6Nk>ez{K6SBK zdjFut;B^K+OVChUQkM*c6@k**>?ho8xaqQx@){<2^8haR$OL!3b+d*!RFh66v<3kr zhIE8yB>C;~h0-;&rfMnJUM^BBfX@0rQL+JTM7Ys?KVp{BCzc?zqiB$RHF#I12C7{= z5Q@T?i^f{GK1^eA$n41CpUTU&hs|^_pEBr~u4qm4Wzi{)TTClUzFH^<^X=)%2U@u1 z{6p(=oi)>-S~-!yzY#Er`H5tY%c@$2C_sx*_{cbPTjs1kV3q#doheaa?INxm>tJJ) zi(Gyz34E3-V6JkVWs^LzbVRMIa+VMN+p+6I#YG7^`Zhicys5J-HU(pqvh#TvDAwZw zjxDu1cdbyX>Cl?ClGW1_Sh8EdA%PM8vO+iq(*lkPUBdcp`D3QM49(&*)0Z5N{5j&! z4Fb9WsWkWX`33r=@#X3D^2^G=>&34h`phUuXWZz^%^cM9k6P?-=;-Q_eOnldq*E=! z0V^!6WayF=(q>P)+vXhtS#RliLtwjyX$$5dH!i2~m+ z;TD@5U=rXY$@OANaEVig3Ml2UtqobeS{{XIVhhF02Y`M6bU$Abb`vafp zP>)aBJ4=3>uy>cqXt$Rb2wFIgt=pNVUZEUE*V<}2<5%zga?7}(J;HrZLEyC%1a4Q4 z89g8g7458uT8_wi3fKJMy0O5%b#vZ{cjxx6(|YEjv&1aiy@JtV*2UCq{0E#Sxmsg@ z>$s4BACr1fIhXKUt}2iO60By(OIL*nYT!RRHPH4ti_9=V-1_u_(*nJEx?lbKX(^0C z$RDFnu;}cZ3PU`Qf5$V1*0|mF1D^(ANr%Evae&lfO63gY-{1|sQZs2jEgLvhX@TH&W zMQfKZ=p|*`5h&wMLdv*&F`;h?v|4L0RwirLqtN^1{5oE#U5|lg9-L&00^0DE1Yd(2 zypnNiChT*dKw|&x{>Sec&s8mq7Bd~!is=8?K8IcQTF3?}vALZ|J=v8VFIX0Oe8x=> zY>q#JnZl<)_(u2XM)3W#3mjJ~OaJ;?-RuQ6Af>Q&poZ3Go|JV|6*Y?}l7iPcLSPg$ zxB+y2=8GO*och+&Qu>W96lYeNlq@yJI|w2#ZBG42oifeamBOZjSNhnw>^$n$k^x}; z7>LZ|7d8<02Udmf!Zj+N@pd1iVRBqV|L6xY|NIM}{ENGXX1b0iCUS6;&2t^^kphGG72MjHxFqb2!(H zISjB-W_g)E-X!|P*>3)Yr<7ChLFOerGJ}_DRE^R(W^4?_QF6by&)2>z{s@mv1HQEo>t?D^FC# zlHz~{_fR-sk?zLz<*;^43wQ|C*FF&b|K5V`CkM|*Xll>ESTl)OatZ}615VlCf&s{= zvDg`jN!TMjf!37L7#bEI$@WkF9DJ@`4UJ&V{wf$pWutqvhh>A=!*N9 zXfH378a#y-joaxAh6|YFoh2+O-affNeF(+As~Nc;U@l%(yRW#+o7G0VId3MTRssQ- z8Zx8JXQV-dzg5u?Ia_XSuhHnIx?Z7XJ^l29|5{qF{cE0B4M@C0ILtal^&F?p#eY3L z2aQjipPwKC%oE9ZKP++b zr5N352T);2p4qor)t)3k>g$rbuQ%834L-S(ev1lbLA4T6oqyj# zIPYO!k=3l>6J>uL`&FI6=iBBazqp;Amq=Dm3MuqaqUhB~w-+rct+Pmg!AZroDD5&p zXu++4;f<9ns^({w>7bV#`wBhfgUL(el%uD}21n^n>vvE+wdMN6e>69+#h4?*1`SH~ zgMdM6hRAN>$hIfh_bLxiH+?JtC)@cmWbbOz!QXvmou`9=E0YNkK`&rn2LQxUgwoEn z$}>c;;KHOiG$2Xz+`nPRO3evOQzz$Ja0kU8V3LWjSQGrN-Jh1nnoWaV{sb!00I*UL z*zVDaH}^YGPD+X!hOiwCTSLUVZN^8OFAt)lEMSeqt5ZqfzDi0wIIWkD zs3q__J=DTIYo{@a1%eMIQm+vUd>>h+Xlu&&hZt3yZr60H;gltJ^zlr_A292*1*utA zDgP&$Nad7anW4hg1VA{{gV|uSB-`zg*U&bok>p{j;BwWpdMJQ^D`?^Av==Pt5azO@ z*>C8ajA)LsG5Rw^>_hCkrzMcX9Ee&`r;3}PBt2nT)b^49)m7_&EQYEjk1zuW0d$}& zoiC8igUjXh>=Q>0Vj#u1yh3GNtu!B!k`Sizfrylwhg`lAyg3m&R4^28eMXx$<&=HGt^ur`vg}=C?bxn4B#(PpDcJBw;%1z(wgks(Mt7PyC`* zVXrpKzAP5&)iq#OsH~!n`vsdz7T}}iIJyc{uj`CZfj>7a>>U=zg2qvK3Tcjx(D1b# zl?9!%?vlFV$aN&245b@D=rnTu$y_OIVKHZ5fGJJJ(nEIomLT8OvXi8-Uzb?y$WD;VezV=&EfM1@h@cY7H|WLwkabfXaw##g{Lsc0bOw@21LUtYP*#e4ec8c= zfXql39BQ8Qw$*!&&Z1y8VYsxXe8pKyzcrH{9wtN^oUtUv6l3;M8nf-0uaLJS zqCE{K>dah1M>!HwA_N>LnOAo(wZKuSzcWHj)YIkPu6FCaF4-PJiEIhwxXflKH4?^o zO4B-)0&+)KL_`{e7Jnrz2-wStetZAD$fxdtmB~_@w57`JuDx)wR;9V(bPp}POoM`+ zqf@I;^QThTY&{}36{vEm^*M$5cmt&HRYTib$aA18Zm5nQrsJW`!)PX zxBi8uS&S;1>b|Tim_nm1MNshcumE8$&XSuCF0Cu;$Dixv<#ciMw~kSG-;))}EUzeWl7ZU0KzYgyc3W_}m|1 z4grsMP+|uB3aPMcMTZ~w(4uKVs}wRv322qu5s6 zJDw{DgY-CPeNvoV!Vw!Co#^sYNiQd60c8plSLenjGIDNRE*rG3MN={!)w&?XJ=6;c zu8KzEhqSOognH%28(YMZ%XZBZp&vzI!gg!&sQ0L{pA9anX^Nwx)Ikifo(;^8T&qM0 z<|R_Q02`zh^LwoQ1a^$Z2&VT~wj-TBF24W^DX`V~{celE_{aSYJ4ZAKmlg}8sNMwa z6tg4IB!$ZvATg552)3gXwIK&ooTq(HpIJgpOQt?dFgpSCnGQiY*ip;5UQHPQOV@_h zdIPBV^NyqJXkZHN6O6gNx)$88MjS+Yh~v6Udwv|UP{3$(pwY`Hb~e59sJMJ}5EBUNZb36lB=M|F5=diIMC&%aw-{NPrj!2?7=^l0~E_ zt*PqnarcVE?i!~xj@@#1;z&U%S65Yc7q056R8@CPBZMNsA`yy+kPun0felD(jKqc& z-XKDno-w@!X0~&!BR)axX$^QKEJTQVbFSvL{^3O1tt&x6@h$kD8klqoXlo#+)|+>&J*F3V9;Qf zI{4I`gf21`zCy|o`;QYDl$knOR<{JHx|5boI|Gcy7(M*piC^C6e~Dg)>SeA+$89L+@}#7}nVf%)*ynee~LF@y2M;eKM-H z4PEZJdYu_os-A0PDq?60tbkz4sdhnFN6qbaXMBP5P7hbzk{d)5)(b%3bdp&^FPQ1NK9j z>~UQcG?-rXFSN2kv@aFWms>44Rl6P3zhqAC>XAi`1jYB!;$(99h_Tfw4zqvdD=g%_ z9lhhRwNff`k8O?2%K67IolXL6oAggXKJwh(n`D8c2(!fqRvN?>5u=-EAv2lQ#$C>+ zWGL=BI45^CfeZDU=TzntYb#hT3x5o(P9u^BR!@*^2^p}aY#S=QdfYarN3`T{al?1S zwW_H6hc?dj*UWQYCaVf=Dm(}97T&uX`J}fP$_s#I?wS*6GK6}D9s-ne*(EX7p?pE> zBLfol1~196EXT?TI7uW@FWIO8k`ts?!Zb4bRZJS$p%O?5m=P)Q%XNPa9>(HllO5)y zkD2{RrQSWRB!-k}Hp6hy4K2Be+q0*w-41l!qcGY=#;QyMDZ#vLuSZK>OEOL3BL z_jDj}u_atkVWudr=_x`gxQwnUWy+M~fnw$(3&IpMOsRQTGb)JZa9WVGe3__A(SEO@ zjcYYTG3N(_+7FRIs3Yl?DoLWB{H07^A1p*>_7?s zWkY^p)9!F~o2^e%WsV}f;2`V+Iw|xi=DS~VdI)j6t405U=$Kfz=x(&H{VuI2Qb*B+ zW&aZ8&MuG;+SORQ?`50YfKjy-3u;uO3lFLDu&c34cNc(65ToVZ7QBCK>p6&tu2iRY zEK#ps|5j3zfO>!mhLxM$pPaT2AEDXb_18GB`b;WlBYz2OP!0ESpsta^t@$TxJ&r^riip~v}JqOZX7 zisustJt(ud;FCf^c@Y5cQ`~Og<~52k+%Q3RJZ`vjg-s&}I9hGTOow)5raoqvUq{$r&acC6aJSfq z%Vj1gUYX2NiuP37Q=gVS&Vzf7-wc_Dr16W|vu!Wgh z=uk#$Np zNqm4>UNvaWQc=sxPIP*3$K!G+bmRdSllHWW6;e2GzjHL-3k>dlVb zkTJ)MwNz-(jce^T=wlM$*--NgCaB;`Xk*i6joh^^2Z6tdT~wGD3>i*N@5F@=$dUMV zOD8B`Lqb|Hmn?V_q2%-KWIp2+{ib!IC|wQWFHTphRv=L@^=3#qt}D3bwBxiKjv1_A zvj?N;d?n5(aCY!TQ0e&c-sKbb#wgfJ^aa4nwlo&^!ooC)+KC`}mD#=2ePdEU*Zu>6 z2$QC<2_n3;+3086y9@}F1)gi^9ga{U-~i{GKLv2Wm_gtKB|2}M`NQetZ9y(D+(MVa zzyUKARhdmhetreARWka+`D~65zK?_3z1QW3PEvSoNT#UjM^T~+8Jer>+3gZ3y-QT+ zkuH-gdvlIb@omZ@+xf7wq}$x^Rs*?$LICW6E}7l;6^+kxO>(y2?(5BqZ}XN5D8 z2!qt|OHhSAFcDddfrdI}9*zL3x)p;aZ*Ou{+epyX+529*ar~{eeaHnlv4qgIsE9vz zi_@|z#H=r%lkHPId9A#B#+nd2017@eaL{i8KQG}9o*&{2rJf^>2lOZF{yln!&4ARp zW9^=qpz7vT3{O@YfFu-m)IQe|aB;0*Fni!5iJT=7>o&XZGaA@CSx6#RgoMNwDk0m( zSk%_G0oQ@UDDO$03*S9HHNp-sgLs2D6dY=J-2*y*+d0Ey_u}H%?c9oe3?&? zGYNB|zROQ9xJFu(Vu z4cq&U_ni3-X^e}kF8dBe8|X*Pn6SAs4Tk}&Izw(RG>(3&JrlUD>iJ+AG;gbZ#>7#x z!LiDe%xs&o4f=pffH#{j53`ItV$OET;5xt?YKSt1D~lZ6r5+_BR&cVt-YNcx74#ef zq|Vxh$79q_1%mSG7OH8NNMDyTaR}wMp4YNXOa&SyPGhBdhQV%fL9h=lOf!m~Kp9Ck z@0z6!(_SFMl3kH`a`j@w{fV(w`)aHbDBtqhVt^`k5`JfK=ES3b`6S!~b|-nqxC*GD zFofX}H^LaI`Xpnf#&M$XRv2FgmkVqw^U&HOB&1d9 zu5xzeCQS?w|9xy}lxRk>xH!i^B)LcF>zyV%!GX!P^ovH-q94V*Aw?t>t zizO+zy;aw8J1PI@@$oIL$tj)3O9US*K^@oCdai@+A&lMi7*%meZjhqLyP?vSa0{~8 zoJ&ZheJD-)(9#cG>A?uc=-QZ}9AXQ&Nv~%#V?o=NLrd<~NTFKBFrOeyix53~iS6;w zj8Ai?iCYx1{8_~L-r=6%K;Ty8nwgXY0*S}4wn}-Su;FvHxKJ_(kq#A(9`FW@l zo7AosN2_B%PC23^en@!5Qm!viU=$^e1kP;#D3Hl^f>=V`aoyzfu~Br{pc zhB9@T=<=eM#ew@#7`H#8uHm+}i6W7?7`f}J&5*X`>VX{N3dl4SiVd@HWL(32{L=K` z!2=RB<8F5!%e+=ux(R~jfPI`2i7?*6+f@ah8SR*mW@0~o=9y!`S0I+m2=s^~D9Awk z0^f-8&GNA(^E%MCnY1N}5m9pK4R^Lr6ZZ)YXQgMbchcwwxB}%a!CTS4xLBYM8w3U1 zM%ieEb4fTWrgW3!o;$7zL$hpNl(buzv9OB04mVEw0mA*%=MvVQQK_cBJ*Q}8`50c% zL*yLw2V;#@&>jkv6x)E+yd0n%__ypzMKnn6nGdcQ_G8Y#8h#67n6yK*l6i%L9F-bR zABE6$QX^Dv4zw_PK$b!_yJUvIa9g1`<53UT|G_OAAAzeE!wPAvj|bcA52!YM*fj^e zqvh>|v@<;cvIZ(6eOO2!;l5Xb0YbmP9@4i*z#yZ7^vh>o?SX{3L>xXDjto&{PZ;st zs=SSWwgP8YGez2g&g%HPMzSn+qs86}Q7AG2IYD~3!rat|l>km-kVqcjgw2ud0m4o~ zLB|>%8aeq@KKV9TR$K@sMwb-|S>WbHR3s73lxIkU6C{*k8#`q7I)dEFML>z<4%^sy z_{!M}R1fQPF&n@Qe6l>Jl02xkG#a9~>6l!z2-nY+Bku$0>>ebG)Ce!+HrCAA07INe zTO7c07|%{&yQWYHEpr+WtXF-T(JN;+l1*yepE2W52|4=}OavO|3Etr!nG2dM-RWqm z(2JuLibr&TkG>(Fx|UUjc7Tpo>&a}5_QaEPD!28v67mvNO-WriTo03&OkIwEsG=6!#SWtLlF2e_4%t>s{NSlbz z;LjxQ8ssie(AwO)Qmzu32`eWRMEEKPFr#w8K|Gr80MuHqw2+Yv>>Y)W-~qDeNx{pe z#0<_>siFSCOVhm$$vITJr>Tu0#+kD2go__7rsEszHr2A-c04p>8=Xl5kQr?igu@&w zY}+y<6<%9_Rl%dmDo$`Dl$f!x26!B#(H9l2&+DL?I`4@o6J>Osfuf3|Ynb)zDK9nO zBi5{j7KJS0tX{+p&f=cpIrMgAp(I^1HVdQ4th=iDXLvc3nKS4^3f`vsVBOR+A~dg} z9MssbjeEWUWEL*@ESRc-oJJf`(~{o@dEyFip!h)(nF8W6UOKKS_bQx`R-6UXD^Pq$ z=abb6_y8|Yjt}G*v?Zuv4y|4scdi4$J1}Fj^)|*5&Zy}8g@qWA;hrM713@^CULnJJ0$Lz<{xSe74q3(ef)Dc zY79k3v-yQ@d~4Am=%c_Bj|Jgfw!w==-Zw1U5M8FIWYdK6(!l%3e0hVQa#F7^?sShv>Ll1mmh>@^VUV%CSA-+cHAzf2uPJTZA-L(-2a?%R5P6_0 zWGBIEz^O&jAdwA?C{DihmSvKnSQ%J<5}TqH-#I@y4~hDJhl-yh_6sH8w8>ZGTp-(y z(g~>U18g5{YJiJne!LH1J)x69qWe}p!NPC<;P6MCQ=VZEKID5Kh`hj!jJT?u7rL&z z9iCFWDf?CDL`nZTW38^=lR48;gRew8gz6}zVpidZF@?jN%see^uDi)p)_gzJjvcweV%T>0%iPUh&O1cb9L`~r z7qOz_*LGne?SfTfU*WE`AO?*NStFGMxtoqtV7mz(GTMy*qm3b2OVtL;b?~7DQd3F2 znyZxuSGQ@3U5#o2Q3aQPZ8kIYjP9JR z+DzeSFzM3D8f2T3K@5#iJ|m^j&!WvmK_U3BsgLC?r`Pd)ZwhF@j*^NlN2HrcK!a`k zxaM9*<0pcHdZ23z+t(pO%`s4jT4ZE=cOMtKLN#MC+QBABlsFH5zH8Z#EFtWy!UbqG z)568dx16Wspcr`e+yNCysQJZBA4r!qr^e~?RfO`*>W4J7st~x1P6*nC!GVv0P%PQk z(>D;YEo^uCU0|gN>W>VTvPd5WV0%GRunzGjgK2ks%KZUYndBdk1Mbmu#cnTY!IZsF zwx6;zC$%&+hg+jsU{Gc(nuGpq403)b4#1>BFe@vl=a7 zuWC^aP>`vqyhCRhUrvq~5rD?(YXT^y^u#q43S%K_$vy_9ME&0(Kez!rHU@W*wP#Ig zvx7_w-=hu(W2QOkF{2~9dHFD3tTGiC^yW=7%TLLJySaG$%9x`OkL0GFH(k%KfT zU3H?mZtO3iZxE@2aMwHz^?DWR233jl0$X99s<`98d&Ajox6zXn2rTB0OauN2>nAx- zf{I2|usS$H5THGjvXanb_OSmFxCG6R*Ui|!W+45|R=H{OILDSEE+!5OxyPy7nVn~* zp5Ss4{DCX}fSD*LQ<3iN94*b1A*;^V$k*h3k{JiLOFrpvozVI9JrsQuEwYNqCL+sX zsVs$-^T`+uc#sOG8#U00Q=PMfK%+AHq>*pQ7h9K?liTHWf$4yCxHC3WrD}0nX_ZSF zL3v}-G{~P&V9klb?NB_Mxb?U8S$=T>TB*AksEd)%G${&Tw+LN6*p@D zUSV*J>b{hu$%&e-PC-#q%Iv`|XA2q9XpE=;nEGb*r-41`E4r#ZxgBTp4bL%k;(0Km z+m-!O;Tv*7D2=x5Oz^7VofEwHwF$?-_RjrsaEGcS8fP)*swy1Wz=N-842k1|A(U1{ z&m(5Dm0HNH6A=s~T7YA-umCKJj z0+1Hcr=gnxVgWcPie!&(E+u9)-k+ndv*T*!8LMJzIIqj8c7CF&N7r^UqHYW$od)MHC6V#Yv zu3oO)o3}Cy2e_*VA}R7a{{+|`GPF^CM?vn$A;&fp3UrGT&sFIenX}R+)^1R2yQT#Ts_}Ag$!RN$2hhcO zv&&0Z{%%)h%6y0rRyD`naA6io*YLR|wmmM>oq(qZZ0n2~ypI=nU$nhSQYxich8tq=)-0sd7Ku|7L_rXUOx8uq1OXHz_^p)pNzO?FJwfN_Nab34|5!b~f zp)0NW}NF{xs)rRWEJXb$$9NHotthAm*L0g zPsg~vT#*ODLC96EWTx~cTJOi7-^NKkgnu8_lbwD^m9AVZ^J*I!<&!epN*gE zcsuTdKgR1{NZvoh`*8dZbi5rupZxx#$@`OJ{6FbT2l7trIoza#_c8ENip{BO#~tuc;tNgMy}v+{)<|Lht4p&rut z|2956cK>!AJN_|#{G)MC^l8k@n-+qn1vg0q?5A~SN-@od3TmRPEGTx4_|80DNo%n6* zN6Glt7r)NGu%oV~89YUaydje_cPf zgN?W2XEFX$_|nGzRImS2y}tdfZ2adi9)I2V)}JZ^S;_HDVlcs>lg94J-dvQ|G)6$xA?{P c{vw`0yKnm~ai`q)fBeJ_|KwZAfaGoK=W~j6VE_OC diff --git a/bin/s140_nrf52_7.3.0_softdevice.hex b/bin/s140_nrf52_7.3.0_softdevice.hex deleted file mode 100644 index 639927f503..0000000000 --- a/bin/s140_nrf52_7.3.0_softdevice.hex +++ /dev/null @@ -1,9726 +0,0 @@ -:020000040000FA -:1000000000040020810A000015070000610A0000BA -:100010001F07000029070000330700000000000050 -:10002000000000000000000000000000A50A000021 -:100030003D070000000000004707000051070000D6 -:100040005B070000650700006F07000079070000EC -:10005000830700008D07000097070000A10700003C -:10006000AB070000B5070000BF070000C90700008C -:10007000D3070000DD070000E7070000F1070000DC -:10008000FB070000050800000F0800001908000029 -:10009000230800002D080000370800004108000078 -:1000A0004B080000550800005F08000069080000C8 -:1000B000730800007D080000870800009108000018 -:1000C0009B080000A5080000AF080000B908000068 -:1000D000C3080000CD080000D7080000E1080000B8 -:1000E000EB080000F5080000FF0800000909000007 -:1000F000130900001D090000270900003109000054 -:100100003B0900001FB500F003F88DE80F001FBD8C -:1001100000F0ACBC40F6FC7108684FF01022401CA7 -:1001200008D00868401C09D00868401C04D0086842 -:1001300000F037BA9069F5E79069F9E7704770B554 -:100140000B46010B184400F6FF70040B4FF0805073 -:100150000022090303692403406943431D1B104621 -:1001600000F048FA29462046BDE8704000F042BA47 -:10017000F0B54FF6FF734FF4B4751A466E1E11E0DA -:10018000A94201D3344600E00C46091B30F8027B3B -:10019000641E3B441A44F9D19CB204EB134394B25D -:1001A00004EB12420029EBD198B200EB134002EBB2 -:1001B000124140EA0140F0BDF34992B00446D1E952 -:1001C0000001CDE91001FF224021684600F0F4FB58 -:1001D00094E80F008DE80F00684610A902E004C8FB -:1001E00041F8042D8842FAD110216846FFF7C0FF7C -:1001F0001090AA208DF8440000F099F9FFF78AFFCB -:1002000040F6FC7420684FF01025401C0FD0206889 -:1002100010226946803000F078F92068401C08D030 -:100220002068082210A900F070F900F061F9A869AF -:10023000EEE7A869F5E74FF080500369406940F6A2 -:10024000FC71434308684FF01022401C06D0086838 -:1002500000F58050834203D2092070479069F7E788 -:100260000868401C04D00868401C03D00020704778 -:100270009069F9E70420704770B504460068C34DE3 -:10028000072876D2DFE800F033041929631E250021 -:10029000D4E9026564682946304600F062F92A46CE -:1002A0002146304600F031F9AA002146304600F0E0 -:1002B00057FB002800D0032070BD00F009FC4FF46C -:1002C000805007E0201D00F040F90028F4D100F034 -:1002D000FFFB60682860002070BD241D94E80700C3 -:1002E000920000F03DFB0028F6D00E2070BDFFF715 -:1002F000A2FF0028FAD1D4E901034FF0805100EBAE -:10030000830208694D69684382420ED840F6F8704E -:1003100005684FF010226D1C09D0056805EB8305B8 -:100320000B6949694B439D4203D9092070BD55694A -:10033000F4E70168491C03D00068401C02D003E0C8 -:100340005069FAE70F2070BD2046FFF735FFFFF731 -:1003500072FF0028F7D1201D00F0F7F80028F2D135 -:1003600060680028F0D100F0E2F8FFF7D3FE00F05B -:10037000BFF8072070BD10B50C46182802D0012028 -:10038000086010BD2068FFF777FF206010BD41684E -:10039000054609B1012700E0002740F6F8742068FF -:1003A0004FF01026401C2BD02068AA68920000F065 -:1003B000D7FA38B3A86881002068401C27D020688D -:1003C000FFF7BDFED7B12068401C22D026684FF051 -:1003D0008050AC686D68016942695143A9420DD9EA -:1003E000016940694143A14208D92146304600F0E5 -:1003F000B8F822462946304600F087F800F078F831 -:100400007069D2E700F093F8FFF784FEF6E77069B1 -:10041000D6E77669DBE740F6FC7420684FF01026DB -:10042000401C23D02068401C0CD02068401C1FD0EA -:100430002568206805F18005401C1BD027683879A5 -:10044000AA2819D040F6F8700168491C42D001680A -:10045000491C45D00168491C3ED001680968491C07 -:100460003ED00168491C39D000683EE0B069DAE747 -:10047000B569DEE7B769E2E710212846FFF778FEA5 -:100480003968814222D12068401C05D0D4F8001080 -:1004900001F18002C03107E0B169F9E730B108CA63 -:1004A00051F8040D984201D1012000E000208A4259 -:1004B000F4D158B1286810B1042803D0FEE72846CB -:1004C000FFF765FF3149686808600EE0FFF722FE1C -:1004D00000F00EF87169BBE77169BFE7706904E06D -:1004E0004FF480500168491C01D000F0CBFAFEE7C0 -:1004F000BFF34F8F26480168264A01F4E06111439B -:100500000160BFF34F8F00BFFDE72DE9F0411746B3 -:100510000D460646002406E03046296800F054F8EF -:10052000641C2D1D361DBC42F6D3BDE8F08140F69B -:10053000FC700168491C04D0D0F800004FF48051D1 -:10054000FDE54FF010208069F8E74FF080510A690F -:10055000496900684A43824201D810207047002050 -:10056000704770B50C4605464FF4806608E0284693 -:1005700000F017F8B44205D3A4F5806405F5805562 -:10058000002CF4D170BD0000F40A0000000000202F -:100590000CED00E00400FA05144801680029FCD0C5 -:1005A0007047134A0221116010490B68002BFCD0E0 -:1005B0000F4B1B1D186008680028FCD0002010603D -:1005C00008680028FCD07047094B10B501221A605A -:1005D000064A1468002CFCD0016010680028FCD08A -:1005E0000020186010680028FCD010BD00E4014015 -:1005F00004E5014070B50C46054600F073F810B9EB -:1006000000F07EF828B121462846BDE8704000F091 -:1006100007B821462846BDE8704000F037B8000012 -:100620007FB5002200920192029203920A0B000B06 -:100630006946012302440AE0440900F01F0651F80C -:10064000245003FA06F6354341F82450401C8242F8 -:10065000F2D80D490868009A10430860081D016827 -:10066000019A1143016000F03DF800280AD00649C4 -:1006700010310868029A10430860091D0868039A3F -:10068000104308607FBD00000006004030B50F4CED -:10069000002200BF04EB0213D3F800582DB9D3F8A1 -:1006A000045815B9D3F808581DB1521C082AF1D3C3 -:1006B00030BD082AFCD204EB0212C2F80008C3F8CD -:1006C00004180220C3F8080830BD000000E0014013 -:1006D0004FF08050D0F83001082801D0002070473A -:1006E000012070474FF08050D0F83011062905D016 -:1006F000D0F83001401C01D0002070470120704725 -:100700004FF08050D0F830010A2801D00020704707 -:100710000120704708208F490968095808471020B0 -:100720008C4909680958084714208A4909680958FA -:100730000847182087490968095808473020854923 -:100740000968095808473820824909680958084744 -:100750003C20804909680958084740207D490968BC -:100760000958084744207B49096809580847482028 -:1007700078490968095808474C207649096809589A -:10078000084750207349096809580847542071499F -:1007900009680958084758206E49096809580847E8 -:1007A0005C206C4909680958084760206949096854 -:1007B00009580847642067490968095808476820AC -:1007C00064490968095808476C2062490968095852 -:1007D000084770205F4909680958084774205D4937 -:1007E00009680958084778205A490968095808478C -:1007F0007C205849096809580847802055490968EC -:10080000095808478420534909680958084788202F -:1008100050490968095808478C204E490968095809 -:10082000084790204B4909680958084794204949CE -:10083000096809580847982046490968095808472F -:100840009C204449096809580847A0204149096883 -:1008500009580847A4203F49096809580847A820B3 -:100860003C49096809580847AC203A4909680958C1 -:100870000847B0203749096809580847B420354966 -:10088000096809580847B8203249096809580847D3 -:10089000BC203049096809580847C0202D4909681B -:1008A00009580847C4202B49096809580847C82037 -:1008B0002849096809580847CC2026490968095879 -:1008C0000847D0202349096809580847D4202149FE -:1008D000096809580847D8201E4909680958084777 -:1008E000DC201C49096809580847E02019490968B3 -:1008F00009580847E4201749096809580847E820BB -:100900001449096809580847EC2012490968095830 -:100910000847F0200F49096809580847F4200D4995 -:10092000096809580847F8200A490968095808471A -:10093000FC2008490968095808475FF48070054998 -:10094000096809580847000003480449024A034B54 -:100950007047000000000020000B0000000B0000AA -:1009600040EA010310B59B070FD1042A0DD310C82C -:1009700008C9121F9C42F8D020BA19BA884201D97E -:10098000012010BD4FF0FF3010BD1AB1D30703D0C6 -:10099000521C07E0002010BD10F8013B11F8014B7C -:1009A0001B1B07D110F8013B11F8014B1B1B01D198 -:1009B000921EF1D1184610BD02F0FF0343EA032254 -:1009C00042EA024200F005B87047704770474FF0A6 -:1009D00000020429C0F0128010F0030C00F01B800C -:1009E000CCF1040CBCF1020F18BF00F8012BA8BF1A -:1009F00020F8022BA1EB0C0100F00DB85FEAC17CDE -:100A000024BF00F8012B00F8012B48BF00F8012B90 -:100A100070474FF0000200B51346944696462039C1 -:100A200022BFA0E80C50A0E80C50B1F12001BFF4A7 -:100A3000F7AF090728BFA0E80C5048BF0CC05DF80D -:100A400004EB890028BF40F8042B08BF704748BF5B -:100A500020F8022B11F0804F18BF00F8012B7047CF -:100A6000014B1B68DB6818470000002009480A4951 -:100A70007047FFF7FBFFFFF745FB00BD20BFFDE719 -:100A8000064B1847064A1060016881F308884068E1 -:100A900000470000000B0000000B000017040000DE -:100AA000000000201EF0040F0CBFEFF30881EFF3ED -:100AB0000981886902380078182803D100E0000015 -:100AC000074A1047074A12682C3212681047000084 -:100AD00000B5054B1B68054A9B58984700BD0000B0 -:100AE0007703000000000020F00A0000040000006E -:100AF000001000000000000000FFFFFF0090D00386 -:10100000C8130020395E020085C100009F5D020008 -:1010100085C1000085C1000085C1000000000000FE -:10102000000000000000000000000000C55E02009B -:1010300085C100000000000085C1000085C10000DE -:101040002D5F0200335F020085C1000085C10000F2 -:1010500085C1000085C1000085C1000085C1000078 -:10106000395F020085C1000085C100003F5F0200BA -:1010700085C10000455F02004B5F0200515F020026 -:1010800085C1000085C1000085C1000085C1000048 -:1010900085C1000085C1000085C1000085C1000038 -:1010A00085C10000575F020085C1000085C10000B6 -:1010B00085C1000085C1000085C1000085C1000018 -:1010C0005D5F020085C1000085C1000085C1000090 -:1010D00085C1000085C1000085C1000085C10000F8 -:1010E00085C1000085C1000085C1000085C10000E8 -:1010F00085C1000085C1000085C1000085C10000D8 -:1011000085C1000085C1000000F002F824F083FED4 -:101110000AA090E8000C82448344AAF10107DA4552 -:1011200001D124F078FEAFF2090EBAE80F0013F0F7 -:10113000010F18BFFB1A43F00103184718530200B0 -:10114000385302000A444FF0000C10F8013B13F032 -:10115000070408BF10F8014B1D1108BF10F8015B10 -:10116000641E05D010F8016B641E01F8016BF9D103 -:1011700013F0080F1EBF10F8014BAD1C0C1B09D15A -:101180006D1E58BF01F801CBFAD505E014F8016BCC -:1011900001F8016B6D1EF9D59142D6D3704700005E -:1011A0000023002400250026103A28BF78C1FBD870 -:1011B000520728BF30C148BF0B6070471FB500F011 -:1011C00003F88DE80F001FBD24F022BE70B51A4C45 -:1011D00005460A202070A01C00F0D5F85920A080F8 -:1011E00029462046BDE8704008F082B908F08BB966 -:1011F00070B50C461149097829B1A0F160015E294A -:1012000008D3012013E0602804D0692802D043F2FB -:1012100001000CE020CC0A4E94E80E0006EB8000A2 -:10122000A0F58050241FD0F8806E2846B04720607B -:1012300070BD012070470000080000201C00002045 -:10124000A05F02003249884201D20120704700208D -:10125000704770B50446A0F500002E4EB0F1786FCF -:1012600002D23444A4F500042948844201D2012565 -:1012700000E0002500F043F848B125B9B44204D39A -:101280002548006808E0012070BD002070BD002DD9 -:10129000F9D1B442F9D321488442F6D2F3E710B52C -:1012A0000446A0F50000B0F1786F03D21948044459 -:1012B000A4F5000400F023F84FF0804130B1164847 -:1012C000006804E08C4204D2012003E01348844209 -:1012D000F8D2002080F0010010BD10B520B1FFF75A -:1012E000DEFF08B1012010BD002010BD10B520B1F7 -:1012F000FFF7AFFF08B1012010BD002010BD084866 -:1013000008490068884201D10120704700207047D9 -:1013100000700200000000202000002008000020D3 -:101320005C000020BEBAFECA10B5044600210120B0 -:1013300000F042F800210B2000F03EF800210820C8 -:1013400000F03AF80421192000F036F804210D20AD -:1013500000F032F804210E2000F02EF804210F20B6 -:1013600000F02AF80421C84300F026F806211620D0 -:1013700000F022F80621152000F01EF82046FFF7A5 -:1013800025FF002010BD40F2231101807047FFF7B8 -:101390002DBF1148704710487047104A10B51468A7 -:1013A0000E4B0F4A08331A60FFF722FF0B48001D4F -:1013B000046010BD704770474907090E002804DB20 -:1013C00000F1E02080F80014704700F00F0000F1F9 -:1013D000E02080F8141D704703F900421005024018 -:1013E00001000001FD48002101604160018170475A -:1013F0002DE9FF4F93B09B46209F160004460DD069 -:101400001046FFF726FF18B1102017B0BDE8F08F87 -:101410003146012001F0D3FE0028F6D101258DF8D8 -:1014200042504FF4C050ADF84000002210A92846A9 -:1014300006F0C5FC0028E8D18DF84250A8464FF4CC -:1014400028500025ADF840001C2229466846079523 -:101450000DF01DF89DF81C000DF11C0A20F00F0086 -:10146000401C20F0F00010308DF81C0020788DF822 -:101470001D0061789DF81E000DF1400961F34200E6 -:1014800040F001008DF81E009DF8000008AA40F011 -:1014900002008DF800002089ADF83000ADF8325020 -:1014A0006089ADF83400CDF82CA060680E900AA9D0 -:1014B000CDF82890684606F090FA0028A5D160681B -:1014C000FFF70BFF40B16068FFF710FF20B96078AD -:1014D00000F00300022801D0012000E00020BF4CF2 -:1014E00008AA0AA92072BDF8200020808DF8428049 -:1014F00042F60120ADF840009DF81E0020F00600E5 -:10150000801C20F001008DF81E000220ADF8300094 -:10151000ADF8340014A80E90684606F05EFA002874 -:1015200089D1BDF82000608036B1211D304600F021 -:101530005FF90028C2D109E0BBF1000F05D00CF023 -:1015400021FDE8BB0CF01EFDD0BBA58017B1012F1B -:1015500043D04AE08DF8428042F6A620ADF8400024 -:1015600046461C220021684607950CF090FF9DF826 -:101570001C00ADF8346020F00F00401C20F0F0009B -:1015800010308DF81C009DF81D0020F0FF008DF834 -:101590001D009DF81E0020F0060040F00100801C98 -:1015A0008DF81E009DF800008DF8446040F00200A8 -:1015B0008DF80000CDE90A9AADF8306011A800E07E -:1015C00011E00E9008AA0AA9684606F006FA00285B -:1015D000A6D1BDF82000E08008E00CF0D3FC10B9E3 -:1015E0000CF0D0FC08B103200FE7E58000200CE7E9 -:1015F0003EB50446794D0820ADF80000A88828B112 -:101600002046FFF726FE18B110203EBD06203EBD45 -:101610002146012001F0D3FD0028F8D12088ADF843 -:1016200004006088ADF80600A088ADF80800E088E6 -:10163000ADF80A00A88801AB6A46002106F0AAFDB1 -:10164000BDF800100829E2D003203EBD7FB5634DF0 -:101650000446A88868B1002002900820ADF8080070 -:10166000CDF80CD02046FFF7F4FD20B1102004B0D7 -:1016700070BD0620FBE7A98802AA4FF6FF7006F0AE -:10168000CCFF0028F3D1BDF80810082901D00320B1 -:10169000EDE7BDF800102180BDF802106180BDF8B3 -:1016A0000410A180BDF80610E180E0E701B582B02A -:1016B0000220ADF80000494802AB6A46408800218C -:1016C00006F068FDBDF80010022900D003200EBD11 -:1016D0001CB5002100910221ADF800100190FFF728 -:1016E000DEFD08B110201CBD3C486A4641884FF61B -:1016F000FF7006F092FFBDF800100229F3D003201E -:101700001CBDFEB5354C06461546207A0F46C0076F -:1017100005D00846FFF79DFD18B11020FEBD0F2033 -:10172000FEBDF82D01D90C20FEBD3046FFF791FD1E -:1017300018BB208801A905F03AFE0028F4D13078C2 -:101740008DF80500208801A906F003FD0028EBD1E3 -:1017500000909DF800009DF8051040F002008DF803 -:101760000000090703D040F008008DF80000208831 -:10177000694606F08BFC0028D6D1ADF808502088C9 -:101780003B4602AA002106F005FDBDF80810A9425B -:10179000CAD00320FEBD7CB5054600200090019014 -:1017A0000888ADF800000C4628460195FFF795FD26 -:1017B00018B92046FFF773FD08B110207CBD15B1A4 -:1017C000BDF8000060B105486A4601884FF6FF7019 -:1017D00006F023FFBDF8001021807CBD240200200C -:1017E0000C20FAE72F48C088002800D0012070475D -:1017F00030B5044693B000200D46014600901422F7 -:1018000001A80CF044FE1C22002108A80CF03FFEA9 -:101810009DF80000CDF808D020F00F00401C20F00B -:10182000F00010308DF800009DF8010006AA20F0AD -:10183000FF008DF801009DF8200001A940F0020092 -:101840008DF8200001208DF8460042F60420ADF806 -:10185000440011A801902088ADF83C006088ADF8E4 -:101860003E00A088ADF84000E088ADF842009DF849 -:10187000020020F00600801C20F001008DF802001C -:101880000820ADF80C00ADF810000FA8059008A8CE -:1018900006F0A3F8002803D1BDF818002880002026 -:1018A00013B030BD24020020F0B5007B059F1E461A -:1018B00014460D46012800D0FFDF0C2030803A206E -:1018C0003880002C08D0287A032806D0287B0128ED -:1018D00000D0FFDF17206081F0BDA889FBE72DE96C -:1018E000F0470D4686B095F80C900E991446B9F164 -:1018F000010F0BD01022007B2E8A9046052807D0BE -:10190000062839D0FFDF06B0BDE8F0870222F2E7F3 -:10191000E8890C2200EB400002EB400018803320E5 -:101920000880002CEFD0E8896081002720E0009635 -:10193000688808F1020301AA696900F097FF06EBC5 -:101940000800801C07EB470186B204EB4102BDF89A -:1019500004009081F848007808B1012300E00023DA -:101960000DF1060140460E3214F029F87F1CBFB27B -:101970006089B842DBD8C6E734200880E889B9F12D -:10198000010F11D0122148430E301880002CBAD01C -:10199000E88960814846B9F1010F00D00220207328 -:1019A00000270DF1040A1FE00621ECE70096688885 -:1019B00008F1020301AA696900F058FF06EB08006C -:1019C000801C86B2B9F1010F12D007EBC70004EBFF -:1019D0004000BDF80410C18110220AF1020110304C -:1019E0000CF02BFD7F1CBFB26089B842DED88AE7BD -:1019F00007EB470104EB4102BDF80400D0810AF176 -:101A000002014046103213F0FCFFEBE72DE9F047EE -:101A10000E4688B090F80CC096F80C80378AF5898D -:101A20000C20DFF81493109902F10C04BCF1030FA1 -:101A300008D0BCF1040F3DD0BCF1070F75D0FFDF1B -:101A400008B061E705EB850C00EB4C0018803120F5 -:101A50000880002AF4D0A8F1060000F0FF0A5581A2 -:101A600024E01622002101A80CF011FD00977088D7 -:101A7000434601AA716900F0F9FEBDF80400208018 -:101A8000BDF80600E080BDF80800208199F800004C -:101A900008B1012300E00023A21C0DF10A01504609 -:101AA00013F08DFF07EB080087B20A346D1EADB24C -:101AB000D7D2C5E705EB850C00EB4C00188032202F -:101AC0000880002ABCD0A8F1050000F0FF0A55816B -:101AD00037E000977088434601AA716900F0C6FE9E -:101AE0009DF80600BDF80410E1802179420860F3FA -:101AF000000162F34101820862F38201C20862F3CD -:101B0000C301020962F30411420962F3451182091B -:101B100062F386112171C0096071BDF80700208150 -:101B200099F8000010B1012301E00EE000232246E5 -:101B30000DF10901504613F042FF07EB080087B290 -:101B40000A346D1EADB2C4D27AE7A8F1020084B2A5 -:101B500005FB08FC0CF10E00188035200880002AD7 -:101B6000A7D05581948100971FFA8CF370880E32AC -:101B7000716900F07BFE63E72DE9F84F1E460A9D70 -:101B80000C4681462AB1607A00F58070D080E089E9 -:101B9000108199F80C000C274FF000084FF00E0A46 -:101BA0000D2872D2DFE800F09D070E1B272F374566 -:101BB000546972727200214648460095FFF774FE20 -:101BC000BDE8F88F207B9146082802D0032800D07A -:101BD000FFDF3780302009E0A9F80A80F0E7207B9A -:101BE0009146042800D0FFDF378031202880B9F1EA -:101BF000000FF1D1E4E7207B9146042800D0FFDFFD -:101C000037803220F2E7207B9146022800D0FFDFA8 -:101C100037803320EAE7207B1746022800D0FFDF19 -:101C20003420A6F800A02880002FC9D0A7F80A8089 -:101C3000C6E7207B1746042800D0FFDF3520A6F832 -:101C400000A02880002FBBD04046A7F80A8012E0F1 -:101C5000207B1746052802D0062800D0FFDF102081 -:101C6000308036202880002FAAD0E0897881A7F81C -:101C70000E80B9F80E00B881A2E7207B91460728B4 -:101C800000D0FFDF37803720B0E72AE04FF01200A6 -:101C900018804FF038001700288091D0E0897881B3 -:101CA000A7F80E80A7F8108099F80C000A2805D034 -:101CB0000B2809D00C280DD0FFDF81E7207B0A28F4 -:101CC00000D0FFDF01200AE0207B0B2800D0FFDFDF -:101CD000042004E0207B0C2800D0FFDF05203873AF -:101CE0006EE7FFDF6CE770B50C46054601F0AAFB16 -:101CF00020B10078222804D2082070BD43F20200EF -:101D000070BD0521284612F0D1F8206008B10020EE -:101D100070BD032070BD30B44880087820F00F00FB -:101D2000C01C20F0F000903001F8080B1DCA81E8BB -:101D30001D0030BC07F05DBC100000202DE9FF47FE -:101D400084B0002782460297079890468946123051 -:101D50000AF069FA401D20F00306079828B907A980 -:101D60005046FFF7C0FF002854D1B9F1000F05D04D -:101D70000798017B19BB052504681BE098F8000053 -:101D8000092803D00D2812D0FFDF46E0079903256C -:101D90004868B0B3497B42887143914239D98AB2CD -:101DA000B3B2011D11F0F5FE0446078002E0079C66 -:101DB000042508340CB1208810B1032D29D02CE063 -:101DC0000798012112300AF060FAADF80C000246C3 -:101DD00002AB2946504608F0B8FA070001D1A01C12 -:101DE000029007983A461230C8F80400A8F802A0FA -:101DF00003A94046029B0AF055FAD8B10A2817D227 -:101E000000E006E0DFE800F007091414100B0D14E1 -:101E10001412132014E6002012E6112010E6082008 -:101E20000EE643F203000BE6072009E60D2007E665 -:101E3000032005E6BDF80C002346CDE900702A46D4 -:101E40005046079900F022FD57B9032D08D1079895 -:101E5000B3B2417B406871438AB2011D11F0ADFEFF -:101E6000B9F1000FD7D0079981F80C90D3E72DE98D -:101E7000FE4F91461A881C468A468046FAB102AB4C -:101E8000494608F062FA050019D04046A61C27888A -:101E900012F04FF93246072629463B46009611F0CC -:101EA0005EFD20882346CDE900504A465146404613 -:101EB00000F0ECFC002020800120BDE8FE8F002017 -:101EC000FBE710B586B01C46AAB104238DF800309C -:101ED0001388ADF808305288ADF80A208A788DF85A -:101EE0000E200988ADF80C1000236A462146FFF742 -:101EF00025FF06B010BD1020FBE770B50D4605218B -:101F000011F0D4FF040000D1FFDF294604F11200D4 -:101F1000BDE870400AF0A2B92DE9F8430D468046AD -:101F2000002607F063FB04462878102878D2DFE803 -:101F300000F0773B345331311231313108313131D6 -:101F400031312879001FC0B2022801D0102810D1E9 -:101F500014BBFFDF35E004B9FFDF0521404611F077 -:101F6000A5FF007B032806D004280BD0072828D023 -:101F7000FFDF072655E02879801FC0B2022820D055 -:101F800050B1F6E72879401FC0B2022819D01028B6 -:101F900017D0EEE704B9FFDF13E004B9FFDF2879BB -:101FA00001280ED1172137E00521404611F07EFFB0 -:101FB000070000D1FFDF07F1120140460AF02BF9BC -:101FC0002CB12A4621464046FFF7A5FE29E0132101 -:101FD000404602F01FFD24E004B9FFDF0521404622 -:101FE00011F064FF060000D1FFDF694606F1120020 -:101FF0000AF01BF9060000D0FFDFA988172901D2DB -:10200000172200E00A46BDF80000824202D90146CC -:1020100002E005E01729C5D3404600F047FCD0E7B1 -:10202000FFDF3046BDE8F883401D20F0030219B100 -:1020300002FB01F0001D00E000201044704713B5C2 -:10204000009858B10024684611F04DFD002C04D1D1 -:10205000F749009A4A6000220A701CBD0124002042 -:10206000F2E72DE9F0470C461546242200212046D0 -:102070000CF00DFA05B9FFDFA87860732888DFF847 -:10208000B0A3401D20F00301AF788946DAF80400C0 -:1020900011F047FD060000D1FFDF4FF00008266079 -:1020A000A6F8008077B109FB07F1091D0AD0DAF81C -:1020B000040011F036FD060000D1FFDF6660C6F8AF -:1020C000008001E0C4F80480298804F11200BDE812 -:1020D000F0470AF091B82DE9F047804601F112006F -:1020E0000D4681460AF09FF8401DD14F20F00302B3 -:1020F0006E7B14462968786811F03EFD3EB104FB02 -:1021000006F2121D03D06968786811F035FD0520CC -:1021100011F074FE0446052011F078FE201A012803 -:1021200002D1786811F0F2FC49464046BDE8F0471C -:102130000AF078B870B50546052111F0B7FE040025 -:1021400000D1FFDF04F112012846BDE870400AF01B -:1021500062B82DE9F04F91B04FF0000BADF828B008 -:10216000ADF804B047880C4605469246052138462E -:1021700011F09CFE060000D1FFDF24B1A780A4F877 -:1021800006B0A4F808B0297809220B20B2EB111F81 -:1021900073D12A7A04F1100138274FF00C084FF060 -:1021A00012090291102A69D2DFE802F068F2F1F018 -:1021B0008008D3898EA03DDCF3EEB7B7307B0228D0 -:1021C00000D0FFDFA88908EBC001ADF80410302172 -:1021D000ADF82810002C25D06081B5F80E800027BE -:1021E0001DE004EBC709317C89F80E10F189A9F8CC -:1021F0000C10CDF800806888042305AA296900F036 -:1022000035FBBDF81410A9F8101008F10400BDF852 -:1022100016107F1C1FFA80F8A9F81210BFB260894F -:10222000B842DED80CE1307B022800D0FFDFE9891C -:1022300008EBC100ADF804003020ADF8280095F897 -:102240000C90002CA9F10400C0B20F90EAD061817B -:10225000B5F81080002725E0CDF8008068884B464F -:1022600003AA696900F002FB08EB09001FFA80F875 -:102270006F48007818B1012302E0DDE0DAE00023C6 -:1022800004EBC702009204A90C320F9813F097FBDD -:10229000009ABDF80C007F1C1082009ABDF80E0059 -:1022A000BFB250826089B842D6D8C9E00AA800906F -:1022B00001AB224629463046FFF711FBC0E0307BD8 -:1022C000082805D0FFDF03E0307B082800D0FFDFBF -:1022D000E8891030ADF804003620ADF82800002C55 -:1022E0003FD0A9896181F189A18127E0307B09284C -:1022F00000D0FFDFA88901460C30ADF8040037207C -:10230000ADF82800002C2CD06181E8890090AB89C1 -:10231000688804F10C02296955E0E88939211030F8 -:1023200080B2ADF80400ADF82810002C72D0A98955 -:102330006181287A0E280AD002212173E989E1817E -:10234000288A0090EB8968886969029A3BE001213C -:10235000F3E70AA8009001AB224629463046FFF772 -:1023600055FB6DE0307B0A2800D0FFDFADF804900C -:10237000ADF828704CB3A9896181A4F810B0A4F815 -:102380000EB0012020735BE020E002E030E038E096 -:1023900041E0307B0B2800D0FFDF288AADF82870A1 -:1023A0001230ADF8040084B104212173A989618140 -:1023B000E989E181298A2182688A00902B8A6888CC -:1023C00004F11202696900F051FA39E0307B0C28FF -:1023D00000D0FFDFADF80490ADF828703CB30521C4 -:1023E0002173A4F80AB0A4F80EB0A4F810B027E046 -:1023F0000AA8009001AB224629463046FFF754FA5E -:102400001EE00AA8009001AB224629463046FFF79D -:10241000B3FB15E034E03B21ADF80400ADF8281023 -:1024200074B30120E080A4F808B084F80AB007E093 -:1024300010000020FFDF03E0297A012917D0FFDF19 -:10244000BDF80400AAF800006CB1BDF82800208097 -:10245000BDF804006080BDF82800392803D03C286E -:1024600001D086F80CB011B00020BDE8F08F3C21FF -:10247000ADF80400ADF8281014B1697AA172DFE755 -:10248000AAF80000EFE72DE9F84356880F4680468A -:1024900015460521304611F009FD040000D1FFDF8B -:1024A000123400943B46414630466A680AF02EF8E2 -:1024B000B8E570B50D46052111F0F8FC040000D117 -:1024C000FFDF294604F11200BDE8704009F0B8BEF4 -:1024D00070B50D46052111F0E9FC040000D1FFDFC5 -:1024E000294604F11200BDE8704009F0D6BE70B56F -:1024F0000546052111F0DAFC040000D1FFDF04F1EC -:10250000080321462846BDE870400422AFE470B5B8 -:102510000546052111F0CAFC040000D1FFDF214669 -:1025200028462368BDE870400522A0E470B5064641 -:10253000052111F0BBFC040000D1FFDF04F1120003 -:1025400009F071FE401D20F0030511E0011D008817 -:102550000322431821463046FFF789FC00280BD0A0 -:10256000607BABB2684382B26068011D11F05BFB17 -:10257000606841880029E9D170BD70B50E460546F6 -:1025800007F034F8040000D1FFDF012020726672EA -:102590006580207820F00F00C01C20F0F000303063 -:1025A0002070BDE8704007F024B8602801D00720F3 -:1025B00070470878C54900F0010008700020704796 -:1025C0002DE9F0438BB00D461446814606A9FFF76E -:1025D0008AFB002814D14FF6FF7601274FF42058CC -:1025E0008CB103208DF800001020ADF8100007A872 -:1025F000059007AA204604A913F005FA78B1072030 -:102600000BB0BDE8F0830820ADF808508DF80E70CF -:102610008DF80000ADF80A60ADF80C800CE006986B -:10262000A17801742188C1818DF80E70ADF8085031 -:10263000ADF80C80ADF80A606A4602214846069B58 -:10264000FFF77CFBDCE708B501228DF8022042F69B -:102650000202ADF800200A4603236946FFF731FC69 -:1026600008BD08B501228DF8022042F60302ADF83C -:1026700000200A4604236946FFF723FC08BD00B585 -:1026800087B079B102228DF800200A88ADF80820C1 -:102690004988ADF80A1000236A460521FFF74EFB72 -:1026A00007B000BD1020FBE709B1072309E40720AC -:1026B000704770B588B00D461446064606A9FFF768 -:1026C00012FB00280ED17CB10620ADF808508DF821 -:1026D0000000ADF80A40069B6A460821DC813046BE -:1026E000FFF72CFB08B070BD05208DF80000ADF899 -:1026F0000850F0E700B587B059B107238DF80030D6 -:10270000ADF80820039100236A460921FFF716FB64 -:10271000C6E71020C4E770B588B00C460646002511 -:1027200006A9FFF7E0FA0028DCD106980121123053 -:1027300009F0ABFD9CB12178062921D2DFE801F038 -:10274000200505160318801E80B2C01EE28880B2E4 -:102750000AB1A3681BB1824203D90C20C2E7102042 -:10276000C0E7042904D0A08850B901E00620B9E7E9 -:10277000012913D0022905D004291CD005292AD00B -:102780000720AFE709208DF800006088ADF8080049 -:10279000E088ADF80A00A068039023E00A208DF8D5 -:1027A00000006088ADF80800E088ADF80A00A06875 -:1027B0000A25039016E00B208DF800006088ADF824 -:1027C0000800A088ADF80A00E088ADF80C00A06809 -:1027D0000B25049006E00C208DF8000060788DF841 -:1027E00008000C256A4629463046069BFFF7A6FAE4 -:1027F00078E700B587B00D228DF80020ADF80810FD -:1028000000236A461946FFF799FA49E700B587B0F1 -:1028100071B102228DF800200A88ADF8082049889D -:10282000ADF80A1000236A460621FFF787FA37E75A -:10283000102035E770B586B0064601200D46ADF88C -:1028400008108DF80000014600236A463046FFF765 -:1028500075FA040008D12946304605F0B5FC002180 -:10286000304605F0CFFC204606B070BDF8B51C46DA -:1028700015460E46069F11F04AFC2346FF1DBCB2CA -:1028800031462A46009411F036F8F8BD30B41146AE -:10289000DDE902423CB1032903D0002330BC08F03B -:1028A00032BE0123FAE71A8030BC704770B50C467F -:1028B0000546FFF722FB2146284605F094FC2846F2 -:1028C000BDE87040012105F09DBC00001000002013 -:1028D0004FF0E0224FF400400021C2F88001BFF326 -:1028E0004F8FBFF36F8F1748016001601649900248 -:1028F00008607047134900B500220A600A60124B55 -:102900004FF060721A60002808BF00BD0F4A104BDC -:10291000DFF840C001280CD002281CBFFFDF00BD3B -:10292000032008601A604FF4000000BFCCF80000DC -:1029300000BD022008601A604FF04070F6E700B555 -:10294000FFDF00BD00F5004008F50140A4020020B3 -:1029500014F5004004F5014070B50B2000F0BDF9FE -:10296000082000F0BAF900210B2000F0D4F9002172 -:10297000082000F0D0F9F44C01256560A560002026 -:10298000C4F84001C4F84401C4F848010B2000F029 -:10299000B5F9082000F0B2F90B2000F091F925609C -:1029A00070BD10B50B2000F098F9082000F095F9E3 -:1029B000E548012141608160E4490A68002AFCD1B0 -:1029C0000021C0F84011C0F84411C0F848110B2094 -:1029D00000F094F9BDE81040082000F08FB910B560 -:1029E0000B2000F08BF9BDE81040082000F086B9FC -:1029F00000B530B1012806D0022806D0FFDF002044 -:102A000000BDD34800BDD34800BDD248001D00BD65 -:102A100070B5D1494FF000400860D04DC00BC5F8EB -:102A20000803CF4800240460C5F840410820C4359D -:102A300000F053F9C5F83C41CA48047070BD08B5B0 -:102A4000C14A002128B1012811D002281CD0FFDF83 -:102A500008BD4FF48030C2F80803C2F84803BB48F1 -:102A60003C300160C2F84011BDE80840D0E74FF4A7 -:102A70000030C2F80803C2F84803B448403001608F -:102A8000C2F84411B3480CE04FF48020C2F80803A8 -:102A9000C2F84803AD4844300160C2F84811AD485F -:102AA000001D0068009008BD70B516460D4604462E -:102AB000022800D9FFDF0022A348012304F11001FE -:102AC0008B4000EB8401C1F8405526B1C1F840218C -:102AD000C0F8043303E0C0F80833C1F84021C0F85F -:102AE000443370BD2DE9F0411D46144630B1012834 -:102AF00033D0022838D0FFDFBDE8F081891E0022E4 -:102B000021F07F411046FFF7CFFF012D23D0002099 -:102B1000944D924F012668703E61914900203C39E6 -:102B200008600220091D08608D49042030390860C2 -:102B30008B483D34046008206C6000F0DFF83004FE -:102B4000C7F80403082000F0BBF88349F007091F09 -:102B500008602E70D0E70120DAE7012B02D00022B6 -:102B6000012005E00122FBE7012B04D00022022016 -:102B7000BDE8F04198E70122F9E774480068704722 -:102B800070B500F0D8F8704C0546D4F84001002626 -:102B9000012809D1D4F80803C00305D54FF48030CB -:102BA000C4F80803C4F84061D4F8440101280CD1EA -:102BB000D4F80803800308D54FF40030C4F80803A4 -:102BC000C4F84461012013F0EEFED4F84801012856 -:102BD0000CD1D4F80803400308D54FF48020C4F882 -:102BE0000803C4F84861022013F0DDFE5E4805606A -:102BF00070BD70B500F09FF85A4D0446287850B16A -:102C0000FFF706FF687818B10020687013F0CBFE5C -:102C10005548046070BD0320F8E74FF0E0214FF401 -:102C20000010C1F800027047152000F067B84B494A -:102C300001200861082000F061B848494FF47C1079 -:102C4000C1F808030020024601EB8003C3F84025C9 -:102C5000C3F84021401CC0B20628F5D37047410A92 -:102C600043F609525143C0F3080010FB02F000F58F -:102C7000807001EB5020704710B5430B48F2376469 -:102C800063431B0C5C020C60384C03FB0400384BA4 -:102C90004CF2F72443435B0D13FB04F404EB402098 -:102CA00000F580704012107008681844086010BD6C -:102CB0002C484068704729490120C1F8000270473C -:102CC000002809DB00F01F0201219140400980002B -:102CD00000F1E020C0F80011704700280DDB00F083 -:102CE0001F02012191404009800000F1E020C0F85E -:102CF0008011BFF34F8FBFF36F8F7047002809DB40 -:102D000000F01F02012191404009800000F1E02005 -:102D1000C0F8801270474907090E002804DB00F153 -:102D2000E02080F80014704700F00F0000F1E02070 -:102D300080F8141D70470C48001F00680A4A0D49AE -:102D4000121D11607047000000B0004004B5004043 -:102D50004081004044B1004008F50140008000403F -:102D6000408500403C00002014050240F7C2FFFFF0 -:102D70006F0C0100010000010A4810B50468094900 -:102D800009480831086013F0A2FE0648001D0460DF -:102D900010BD0649002008604FF0E0210220C1F874 -:102DA000800270471005024001000001FC1F004036 -:102DB000374901200860704770B50D2000F049F8D0 -:102DC000344C0020C4F800010125C4F804530D2040 -:102DD00000F050F825604FF0E0216014C1F80001C8 -:102DE00070BD10B50D2000F034F82A480121416073 -:102DF0000021C0F80011BDE810400D2000F03AB8E5 -:102E0000254810B504682449244808310860214940 -:102E1000D1F80001012804D0FFDF1F48001D046025 -:102E200010BD1B48001D00680022C0B2C1F800217F -:102E300014F07FFBF1E710B5164800BFD0F8001181 -:102E40000029FBD0FFF7DCFFBDE810400D2000F0AB -:102E500011B800280DDB00F01F020121914040094C -:102E6000800000F1E020C0F88011BFF34F8FBFF366 -:102E70006F8F7047002809DB00F01F02012191408D -:102E80004009800000F1E020C0F880127047000087 -:102E900004D5004000D000401005024001000001B0 -:102EA0004FF0E0214FF00070C1F8800101F5C071D2 -:102EB000BFF34F8FBFF36F8FC1F80001394B8022F2 -:102EC00083F8002441F8800C704700B502460420C6 -:102ED000354903E001EBC0031B792BB1401EC0B2A2 -:102EE000F8D2FFDFFF2000BD41F8302001EBC00128 -:102EF00000224A718A7101220A7100BD2A4A00210A -:102F000002EBC0000171704710B50446042800D3DD -:102F1000FFDF254800EBC4042079012800D0FFDF43 -:102F20006079A179401CC0B2814200D060714FF03D -:102F3000E0214FF00070C1F8000210BD70B504250B -:102F4000194E1A4C16E0217806EBC1000279012ACD -:102F500008D1427983799A4204D04279827156F835 -:102F6000310080472078401CC0B22070042801D373 -:102F7000002020706D1EEDB2E5D270BD0C4810B57A -:102F800004680B490B4808310860064890F80004B3 -:102F90004009042800D0FFDFFFF7D0FF0448001DE0 -:102FA000046010BD19E000E0E0050020580000209A -:102FB00010050240010000010548064A01689142DF -:102FC00001D1002101600449012008607047000020 -:102FD0005C000020BEBAFECA40E5014070B50C4658 -:102FE000054609F02FFC21462846BDE870400AF04E -:102FF00010BD7047704770470021016081807047A5 -:103000002CFFFFFFDBE5B151007002002301FFFF41 -:103010008C00000078DB6A007A2E9AC67DB66CFAC6 -:10302000F35721CCC310D5E51471FB3C30B5FC4DF2 -:103030000446062CA9780ED2DFE804F0030E0E0E2B -:103040000509FFDF08E0022906D0FFDF04E00329BD -:1030500002D0FFDF00E0FFDFAC7030BD30B50446CA -:103060001038EF4D07280CD2DFE800F0040C060CF6 -:103070000C0C0C00FFDF05E0287E112802D0FFDFDA -:1030800000E0FFDF2C7630BD2DE9F04112F026FE86 -:10309000044614F063F8201AC5B2062010F0AEFE04 -:1030A0000446062010F0B2FE211ADD4C207E1228C4 -:1030B00018D000200F18072010F0A0FE06460720A9 -:1030C00010F0A4FE301A3918207E13280CD00020EE -:1030D0000144A078042809D000200844281AC0B26E -:1030E000BDE8F0810120E5E70120F1E70120F4E7E8 -:1030F000CB4810B590F825004108C94800F12600DA -:1031000005D00EF0F5FEBDE8104006F08CB80EF0CC -:10311000D0FEF8E730B50446A1F120000D460A289C -:103120004AD2DFE800F005070C1C2328353A3F445B -:10313000FFDF42E0207820283FD1FFDF3DE0B848A4 -:103140008178052939D0007E122836D020782428AD -:1031500033D0252831D023282FD0FFDF2DE0207851 -:1031600022282AD0232828D8FFDF26E0207822280A -:1031700023D0FFDF21E0207822281ED024281CD075 -:1031800026281AD0272818D0292816D0FFDF14E0C7 -:103190002078252811D0FFDF0FE0207825280CD0DB -:1031A000FFDF0AE02078252807D0FFDF05E0207840 -:1031B000282802D0FFDF00E0FFDF257030BD1FB5FB -:1031C00004466A46002001F0A5FEB4B1BDF8022015 -:1031D0004FF6FF700621824201D1ADF80210BDF812 -:1031E0000420824201D1ADF80410BDF808108142DC -:1031F00003D14FF44860ADF8080068460FF0E2FADA -:1032000006F011F804B010BD70B516460C46054620 -:10321000FEF71FF848B90CB1B44208D90C2070BDB4 -:1032200055F82400FEF715F808B1102070BD2046AF -:10323000641EE4B2F4D270BD2DE9F04105461F468C -:1032400090460E4600240068FEF750F830B9A98871 -:1032500028680844401EFEF749F808B110203FE7EF -:1032600028680028A88802D0B84202D850E0002878 -:10327000F5D0092034E72968085DB8B1671CCA5D3C -:10328000152A2ED03CDC152A3AD2DFE802F039129A -:10329000222228282A2A313139393939393939391C -:1032A00039392200085D30BB641CA4B2A242F9D8AF -:1032B00033E00228DDD1A01C085C88F80000072854 -:1032C00001D2400701D40A200AE7307840F001001B -:1032D00015E0C143C90707E0012807D010E0062028 -:1032E000FEE60107A1F180510029F5D01846F7E666 -:1032F0003078810701D50B20F2E640F002003070F3 -:103300002868005D384484B2A888A04202D2B0E7A1 -:103310004FF4485382B2A242ADD80020E0E610B587 -:10332000027843F2022354080122022C12D003DC5B -:103330003CB1012C16D106E0032C10D07F2C11D10A -:1033400012E0002011E080790324B4EB901F09D132 -:103350000A700BE08079B2EB901F03D1F8E7807917 -:103360008009F5D0184610BDFF200870002010BD60 -:1033700008B500208DF80000294890F82E1051B1B2 -:1033800090F82F0002280FD003280FD0FFDF00BFD6 -:103390009DF8000008BD22486946253001F009FE6D -:1033A0000028F5D0FFDFF3E7032000E001208DF8CF -:1033B0000000EDE738B50C460546694601F0F9FD19 -:1033C00000280DD19DF80010207861F3470020708F -:1033D00055F8010FC4F80100A888A4F805000020E2 -:1033E00038BD38B5137888B102280FD0FF281BD01C -:1033F0000CA46D46246800944C7905EB9414247851 -:1034000064F347031370032805D010E023F0FE0394 -:1034100013700228F7D1D8B240F001000AE0000092 -:10342000F00100200302FF0143F0FE00107010784D -:1034300020F0010010700868C2F801008888A2F826 -:10344000050038BD022110F031BD38B50C460978B1 -:10345000222901D2082038BDADF800008DF80220E5 -:1034600068460EF087FD05F0DEFE050003D1212140 -:103470002046FFF74FFE284638BD1CB500208DF8CA -:103480000000CDF80100ADF80500FB4890F82E00D3 -:10349000022801D0012000E000208DF807006846D6 -:1034A0000EF0F0FD002800D0FFDF1CBD00220A80D6 -:1034B000437892B263F3451222F040020A8000780A -:1034C0000C282BD2DFE800F02A06090E1116191C71 -:1034D0001F220C2742F0110009E042F01D00088075 -:1034E0000020704742F0110012E042F0100040F05E -:1034F0000200F4E742F01000F1E742F00100EEE7CD -:1035000042F0010004E042F00200E8E742F002006D -:1035100040F00400E3E742F00400E0E707207047D2 -:103520002DE9FF478AB00025BDF82C6082461C4675 -:1035300091468DF81C50700703D56068FDF789FE31 -:1035400068B9CD4F4FF0010897F82E0058B197F8A1 -:103550002F00022807D16068FDF7C8FE18B11020BF -:103560000EB0BDE8F087300702D5A08980283DD88D -:10357000700705D4B9F1000F02D097F8240098B372 -:10358000E07DC0F300108DF81B00627D0720032151 -:103590005AB3012A2CD0022AE2D0042AE0D18DF8B5 -:1035A0001710F00627D4A27D072022B3012A22D0CB -:1035B000022A23D0042AD3D18DF819108DF8159042 -:1035C000606810B307A9FFF7AAFE0028C8D19DF8CC -:1035D0001C00FF2816D0606850F8011FCDF80F10AE -:1035E0008088ADF8130014E000E001E00720B7E7A1 -:1035F0008DF81780D5E78DF81980DFE702208DF868 -:103600001900DBE743F20220AAE7CDF80F50ADF82E -:103610001350E07B40B9207C30B9607C20B9A07C9D -:1036200010B9E07CC00601D0062099E78DF800A013 -:10363000BDF82C00ADF80200A0680190A0680290CF -:1036400004F10F0001F0A9FC8DF80C00FFF790FECB -:103650008DF80D009DF81C008DF80E008DF81650A9 -:103660008DF81850E07D08A900F00F008DF81A00C1 -:1036700068460FF0E3F905F0D6FD71E7F0B58FB0BD -:1036800000258DF830508DF814508DF834500646D2 -:103690008DF82850019502950395049519B10FC92D -:1036A00001AC84E80F00744CA078052801D00428F0 -:1036B0000CD101986168884200D120B90398E16873 -:1036C000884203D110B108200FB0F0BD207DC006A4 -:1036D00001D51F2700E0FF273B460DAA05A903A837 -:1036E000FFF7AAFD0028EFD1A08AC10702D0C006CB -:1036F00000D4EE273B460AAA0CA901A8FFF79CFDBF -:103700000028E1D19DF81400C00701D00A20DBE7B2 -:10371000A08A410708D4A17D31B19DF828108907FE -:1037200002D043F20120CFE79DF82810C90709D045 -:10373000400707D4208818B144F25061884201D96B -:103740000720C1E78DF818508DF81960BDF8080002 -:10375000ADF81A000198079006A80FF07BF905F064 -:1037600062FD0028B0D18DF820508DF82160BDF8A1 -:103770001000ADF822000398099008A80FF08CF90A -:1037800005F051FD00289FD101AD241D95E80F00E3 -:1037900084E80F00002097E770B586B00D4604005E -:1037A00005D0FDF7A3FD20B1102006B070BD0820A4 -:1037B000FBE72078C107A98802D0FF2902D303E0E4 -:1037C0001F2901D20920F0E7800763D4FFF75CFCD2 -:1037D00038B12178C1F3C100012804D0032802D0F8 -:1037E00005E01320E1E7244890F82400C8B1C80799 -:1037F0004FF001064FF0000502D08DF80F6001E098 -:103800008DF80F50FFF7B4FD8DF800002078694661 -:10381000C0F3C1008DF8010060788DF80250C20835 -:1038200001D00720C1E730B3C20701D08DF8026094 -:10383000820705D59DF8022042F002028DF8022091 -:10384000400705D59DF8020040F004008DF8020005 -:10385000002022780B18C2F38002DA7001EB4002DC -:103860006388D380401CA388C0B253810228F0D360 -:10387000207A78B905E001E0F00100208DF80260BF -:10388000E6E7607A30B9A07A20B9E07A10B9207BF7 -:10389000C00601D0062088E704F1080001F07DFB96 -:1038A0008DF80E0068460EF0F6FC05F0BCFC002812 -:1038B00089D18DF810608DF81150E088ADF81200B4 -:1038C000ADF8145004A80EF039FD05F0ACFC00284A -:1038D00088D12078C00701D0152000E01320FFF721 -:1038E000BDFB002061E72DE9FF470220FD4E8DF86A -:1038F00004000027708EADF80600B84643F20209B6 -:103900004CE001A810F039FA050006D0708EA8B37B -:10391000A6F83280ADF806803EE0039CA07F010748 -:103920002DD504F124000090A28EBDF80800214698 -:1039300004F1360301F0BCFC050005D04D452AD04A -:10394000112D3CD0FFDF3AE0A07F20F00801E07F9E -:10395000420862F3C711A177810861F30000E077A4 -:1039600094F8210000F01F0084F820002078282817 -:1039700026D129212046FFF7CDFB21E014E04007A6 -:103980000AD5BDF8080004F10E0101F01CFB05008A -:103990000DD04D4510D100257F1CFFB2022010F044 -:1039A0002DFA401CB842ACD8052D11D008E0A07FFC -:1039B00020F00400A07703E0112D00D0FFDF0025E8 -:1039C000BDF806007086052D04D0284604B0C8E571 -:1039D000A6F832800020F9E770B50646FFF732FD01 -:1039E000054605F003FE040000D1FFDF6680207865 -:1039F00020F00F00801C20F0F00020302070032009 -:103A0000207295F83E006072BDE8704005F0F1BD8F -:103A10002DE9F04786B0040000D1FFDF2078B14DDA -:103A200020F00F00801C20F0F000703020706068E3 -:103A30000178491F1B2933D2DFE801F0FE32323210 -:103A400055FD320EFDFD42FC32323278FCFCFBFAB1 -:103A500032FCFCF9F8FCFC00C6883046FFF7F2FCAB -:103A60000546304607F045FCE0B16068007A85F80D -:103A70003E0021212846FFF74DFB3046FEF75AFB5A -:103A8000304603F0D7FE3146012014F017F8A87F26 -:103A900020F01000A877FFF726FF002800D0FFDFF6 -:103AA00006B05EE5207820F0F00020302070032082 -:103AB000207266806068007A607205F09AFDD8E72F -:103AC000C5882846FFF7BEFC00B9FFDF60680079B3 -:103AD000012800D0FFDF6068017A06B02846BDE803 -:103AE000F04707F0EBBDC6883046FFF7ABFC05009A -:103AF00000D1FFDF05F07DFD606831460089288137 -:103B000060684089688160688089A881012013F01D -:103B1000D5FF0020A875A87F00F003000228BFD1C0 -:103B2000FFF7E1FE0028BBD0FFDFB9E7007928B13D -:103B30000228B5D03C28B3D0FFDFB1E705F059FD2E -:103B40006668B6F806A0307A361D012806D0687E71 -:103B5000814605F0D4FA070003D101E0E878F7E7E1 -:103B6000FFDF00220221504610F097F9040000D137 -:103B7000FFDF22212046FFF7CDFA3079012800D05F -:103B80000220A17F804668F30101A177308B20815C -:103B9000708B6081B08BA08184F822908DF80880B2 -:103BA000B8680090F86801906A460321504610F00A -:103BB00074F900B9FFDFB888ADF81000B8788DF857 -:103BC000120004AA0521504610F067F900B9FFDF82 -:103BD000B888ADF80C00F8788DF80E0003AA04211F -:103BE000504610F05AF900B9FFDF062106F1120025 -:103BF0000DF00EF940B37079800700D5FFDF7179C1 -:103C0000E07D61F34700E075D6F80600A061708999 -:103C1000A083062106F10C000DF0FAF8F0B195F83A -:103C200025004108607861F3470006E041E039E093 -:103C300071E059E04EE02FE043E06070D5F82600D7 -:103C4000C4F80200688D12E0E07D20F0FE00801CC8 -:103C5000E075D6F81200A061F08AD9E7607820F00C -:103C6000FE00801C6070F068C4F80200308AE080BA -:103C7000B8F1010F04D0B8F1020F05D0FFDF0FE754 -:103C80000320FFF7D3F90BE7287E122800D0FFDFCF -:103C90001120FFF7E3F903E706B02046BDE8F0473F -:103CA00001F092BD05F0A5FC15F8300F40F00200C0 -:103CB00005E005F09EFC15F8300F40F00400287078 -:103CC000EEE6287E13280AD01528D8D15FF016001A -:103CD000FFF7C4F906B0BDE8F04705F08ABC142030 -:103CE000F6E70000F0010020A978052909D0042991 -:103CF000C5D105F07EFC022006B0BDE8F047FFF715 -:103D000095B900790028BAD0E87801F02DF905F0CE -:103D100070FC0320F0E7287E122802D1687E01F0B3 -:103D200023F91120D4E72DE9F05F054600784FF024 -:103D300000080009DFF8B8A891460C46464601285D -:103D40006ED002286DD007280BD00A286AD0FFDF7A -:103D5000A9F8006014B1A4F8008066800020BDE8D6 -:103D6000F09F6968012704F108000B784FF0020BFF -:103D70005B1F4FF6FF721B2B7ED2DFE803F0647DE2 -:103D80007D7D0E7D7D7D7D7D7D217D7D7D2BFDFC81 -:103D9000FBFA7D14D2F9E7F8F700C8884FF0120853 -:103DA000102621469AE14FF01C080A26BCB38888E9 -:103DB000A0806868807920726868C0796072C7E7FF -:103DC0004FF01B08142654B30320207268688088C3 -:103DD000A080BDE70A793C2ABAD00D1D4FF010082B -:103DE0002C26E4B16988A180298B6182298B2182EC -:103DF000698BA182A98BE1826B790246A91D1846C5 -:103E0000FFF7EFFA2979002001290CD084F80FB0D0 -:103E1000FF212176E06120626062A06298E70FE0F6 -:103E20003BE15EE199E1E77320760AF1040090E856 -:103E30000E00DAF81000C4E90930C4E9071287E778 -:103E4000A9F800608AE72C264FF01D08002CF7D057 -:103E5000A28005460F1D897B008861F30000288041 -:103E6000B97A490861F341002880B97A890861F379 -:103E700082002880B97A00E00CE1C90861F3C30030 -:103E80002880B97AAA1C0911491C61F3041000F0BA -:103E90007F0028807878B91CFFF7A3FA387D05F1F8 -:103EA000090207F11501FFF79CFA387B01F0A9F828 -:103EB0002874787B01F0A5F86874F87EA874787A85 -:103EC000E874387F2875B87B6875388AE882DAF834 -:103ED0001C10A961B97A504697F808A0C1F34111A6 -:103EE000012904D0008C504503D2824609E0FFDF4F -:103EF00010E0022903D0288820F0600009E0504536 -:103F000004D1288820F06000403002E0288840F08A -:103F100060002880A4F824A0524607F11D01A8697A -:103F20009BE011264FF02008002C89D0A280686801 -:103F300004F10A02007920726868007B6072696887 -:103F40008B1D48791946FFF74CFA01E70A264FF016 -:103F50002108002CE9D08888A080686880792072C8 -:103F60006868C07960729AF8301006E078E06BE01B -:103F700052E07FE019E003E03AE021F00401A6E01E -:103F80000B264FF02208002CCFD0C888A08068688C -:103F9000007920726868007A01F033F8607268680E -:103FA000407A01F02EF8A072D2E61C264FF02608C7 -:103FB000002CBAD0A2806868407960726868007A84 -:103FC000A0720AF1040090E80E00DAF81000C4E9CB -:103FD0000530C4E90312686800793C2803D04328FF -:103FE00003D0FFDFB4E62772B2E684F808B0AFE68C -:103FF00010264FF02408002C97D08888A08068688D -:10400000807920816868807A608168680089A081F1 -:1040100068688089E0819BE610264FF02308002C19 -:1040200098D08888A0806868C088208168680089E6 -:10403000608168684089A08168688089E0819AF819 -:10404000301021F0020142E030264FF02508002C0C -:104050009AD0A2806968282249680AF0EEF977E6CA -:104060002A264FF02F08002C8ED0A28069682222C9 -:10407000091DF2E714264FF01B08002C84D0A28003 -:10408000686800790128B0D02772DAE90710C4E91E -:1040900003105DE64A46214660E0287A012803D0F5 -:1040A000022817D0FFDF53E610264FF01F08002C20 -:1040B000A2D06888A080A8892081E8896081288AA8 -:1040C000A081688AE0819AF8301021F001018AF815 -:1040D00030103DE64FF012081026688800F07EFF91 -:1040E00036E6287AC8B3012838D0022836D003280B -:1040F00001D0FFDF2CE609264FF01108002C8FD0ED -:104100006F883846FFF79EF990F822A0A780687A5A -:104110002072042138460FF0DBFE052138460FF0EF -:10412000D7FE002138460FF0D3FE012138460FF0AC -:10413000CFFE032138460FF0CBFE022138460FF0A8 -:10414000C7FE062138460FF0C3FE072138460FF0A0 -:10415000BFFE504600F008FFFAE5FFE72846BDE83D -:10416000F05F01F0BBBC70B5012803D0052800D07A -:10417000FFDF70BD8DB22846FFF764F9040000D15F -:10418000FFDF20782128F4D005F030FA80B10178E3 -:1041900021F00F01891C21F0F00110310170022182 -:1041A000017245800020A075BDE8704005F021BA7D -:1041B00021462846BDE870401322FFF746B92DE995 -:1041C000F04116460C00804600D1FFDF307820F029 -:1041D0000F00801C20F0F000103030702078012893 -:1041E00004D0022818D0FFDFBDE8F0814046FFF779 -:1041F00029F9050000D1FFDF0320A87505F0F9F9C2 -:1042000094E80F00083686E80F00F94810F8301FD0 -:1042100041F001010170E7E74046FFF713F905009F -:1042200000D1FFDFA1884FF6FF700027814202D145 -:10423000E288824203D0814201D1E08840B105F09A -:10424000D8F994E80F00083686E80F00AF75CBE781 -:10425000A87D0128C8D178230022414613F084FBB1 -:104260000220A875C0E738B50C4624285CD008DCCD -:1042700020280FD0212825D022284BD0232806D152 -:104280004CE0252841D0262832D03F2851D00725A0 -:10429000284638BD0021052013F0E6FB08B11120A7 -:1042A00038BDA01C0EF0E1FA04F0BDFF0500EFD10F -:1042B000002208231146052013F056FB0528E7D0FD -:1042C000FFDFE5E76068FDF708F808B1102038BDAA -:1042D000618820886A460EF071FD04F0A4FF050095 -:1042E000D6D160680028D3D0BDF800100180CFE798 -:1042F000206820B1FCF7FAFF08B11025C8E7204676 -:104300000EF03BFE1DE00546C2E7A17820880EF0C6 -:1043100086FD16E0086801F08DFEF4E7087800F0ED -:1043200001000DF0B9FD0CE0618820880EF0C1FCA1 -:1043300007E0087800F001008DF8000068460EF0F4 -:10434000DFF804F070FFDEE770B505460C4608465E -:10435000FCF7A5FF08B1102070BD202D07D0212D3E -:104360000DD0222D0BD0252D09D0072070BD20881F -:10437000A11C0DF065FEBDE8704004F054BF06209E -:1043800070BD9B482530704708B5342200219848FD -:104390000AF07DF80120FEF749FE1120FEF75EFECF -:1043A00093496846263105F0B7F891489DF80020FA -:1043B00010F8251F62F3470121F00101017000216F -:1043C00041724FF46171A0F8071002218172FEF76B -:1043D0008FFE00B1FFDFFDF705F801F0BEF908BD63 -:1043E00010B50C464022002120460AF050F8A07F6C -:1043F00020F00300A077202020700020A07584F812 -:10440000230010BD70472DE9FC410746FCF721FF52 -:1044100010B11020BDE8FC81754E06F12501D6F8DB -:1044200025000090B6F82950ADF8045096F82B40BE -:104430008DF806403846FEF7BDFF0028EAD1FEF7AA -:1044400057FE0028E6D0009946F8251FB580B471C4 -:10445000E0E710B50446FCF722FF08B1102010BDBC -:1044600063486349224690F8250026314008FEF74C -:10447000B8FF002010BD3EB504460D460846FCF7C7 -:104480000EFF08B110203EBD14B143F204003EBD42 -:1044900057488078052803D0042801D008203EBD65 -:1044A000694602A80AF012FC2A4669469DF80800EF -:1044B000FEF797FF00203EBDFEB50D4604004FF00D -:1044C000000712D00822FEF79FFE002812D1002616 -:1044D00009E000BF54F826006946FEF720FF0028D7 -:1044E00008D1761CF6B2AE42F4D30DF01CFC10B12C -:1044F00043F20320FEBD3E4E86F824700CB3002725 -:104500001BE000BF54F8270002A9FEF708FF00B126 -:10451000FFDF9DF808008DF8000054F8270050F8E0 -:10452000011FCDF801108088ADF8050068460DF038 -:104530001FFC00B1FFDF7F1CFFB2AF42E2D386F861 -:1045400024500020FEBD2DE9F0418AB01546884672 -:1045500004001ED00F4608222946FEF755FE00280B -:1045600011D1002613E000BF54F826006946103030 -:1045700000F01FFD002806D13FB157F82600FCF7D8 -:1045800068FE10B110200AB02EE6761CF6B2AE42DC -:10459000EAD3681EC6B217E0701CC7B212E000BFB3 -:1045A00054F82600017C4A0854F827100B7CB2EB23 -:1045B000530F05D106221130113109F011FF50B10E -:1045C0007F1CFFB2AF42EBD3761EF6B2E4D2464672 -:1045D00024B1012003E043F20520D4E700200DF0D0 -:1045E000ECFB10B90DF0F5FB20B143F20420CAE753 -:1045F000F001002064B300270DF1170826E000BF8A -:1046000054F827006946103000F0D3FC00B1FFDFFA -:1046100054F82700102250F8111FCDF8011080889F -:10462000ADF8050054F827100DF1070009F005FF5B -:1046300096B156F827101022404609F0FEFE684653 -:104640000DF07BFB00B1FFDF7F1CFFB2AF42D7D381 -:10465000FEF713FF002096E7404601F0DFFCEEE78F -:1046600030B585B00446FDF7BDF830B906200FF02F -:10467000C5FB10B1062005B030BD2046FCF7E9FDB2 -:1046800018B96068FCF732FE08B11020F3E76088C3 -:104690004AF2B811884206D82078F94D28B101288D -:1046A00006D0022804D00720E5E7FEF721FD18E038 -:1046B0006078022804D0032802D043F20220DAE70F -:1046C00085F82F00C1B200200090ADF80400022947 -:1046D0002CD0032927D0FFDF68460DF009FC04F039 -:1046E000A2FD0028C7D1606801F08BFC207858B18A -:1046F00001208DF800000DF1010001F08FFC6846EB -:104700000EF0FDFB00B1FFDF207885F82E00FEF7EC -:10471000B4FE608860B1A88580B20DF046FB00B1A0 -:10472000FFDF0020A7E78DF80500D5E74020FAE776 -:104730004FF46170EFE710B50446FCF7B0FD20B907 -:10474000606838B1FCF7C9FD08B1102010BD606881 -:1047500001F064FCCA4830F82C1F6180C178617098 -:1047600080782070002010BD2DE9F843144689465A -:104770000646FCF794FDA0B94846FCF7B7FD80B9A2 -:104780002046FCF7B3FD60B9BD4DA878012800D1E3 -:104790003CB13178FF2906D049B143F20400BDE8AD -:1047A000F8831020FBE7012801D00420F7E7CCB301 -:1047B000052811D004280FD069462046FEF776FE62 -:1047C0000028ECD1217D49B1012909D0022909D065 -:1047D000032909D00720E2E70820E0E7024604E0C9 -:1047E000012202E0022200E003228046234617460F -:1047F00000200099FEF794FE0028D0D1A0892880DF -:10480000A07BE875BDF80000A882AF75BDF8001068 -:10481000090701D5A18931B1A1892980C00704D038 -:10482000032003E006E08021F7E70220FEF7FEFB0D -:1048300086F800804946BDE8F8430020FEF71EBF19 -:104840007CB58F4C05460E46A078022803D003287D -:1048500001D008207CBD15B143F204007CBD0720C7 -:104860000FF0D4FA10B9A078032806D0FEF70CFC9C -:1048700028B1A078032804D009E012207CBD1320C1 -:104880007CBD304600F053FB0028F9D1E670FEF7FE -:104890006FFD0AF058F901208DF800008DF8010035 -:1048A0008DF802502088ADF80400E07D8DF80600F8 -:1048B00068460EF0C1F904F0B6FC0028E0D1A078FB -:1048C000032805D05FF00400FEF7B0FB00207CBD9C -:1048D000E07800F03CFB0520F6E71CB510B143F290 -:1048E00004001CBD664CA078042803D0052801D024 -:1048F00008201CBD00208DF8000001218DF801105A -:104900008DF8020068460EF097F904F08CFC002840 -:10491000EFD1A078052805D05FF00200FEF786FBF6 -:1049200000201CBDE07800F01FFB0320F6E72DE916 -:10493000FC4180460E4603250846FCF7D7FC0028BC -:1049400066D14046FEF77EFD040004D02078222880 -:1049500004D208205EE543F202005BE5A07F00F090 -:1049600003073EB1012F0CD000203146FEF727FC93 -:104970000500EFD1012F06D0022F1AD0FFDF284605 -:1049800048E50120F1E7A07D3146022801D011B1B0 -:1049900007E011203EE56846FCF758FE0028D9D113 -:1049A0006946404606F04DFE0500E8D10120A0759D -:1049B000E5E7A07D032804D1314890F83000C00716 -:1049C00001D02EB30EE026B1A07F40071ED40021F7 -:1049D00000E00121404606F054FE0500CFD1A0754D -:1049E000002ECCD03146404600F0EDFA05461128A5 -:1049F000C5D1A07F4107C2D4316844F80E1F716849 -:104A0000616040F0040020740025B8E71125B6E786 -:104A10001020FFE470B50C460546FEF713FD0100BB -:104A200005D022462846BDE87040FEF70EBD43F291 -:104A3000020070BD10B5012807D1114B9B78012BE6 -:104A400000D011B143F2040010BD0DF0E0F9BDE853 -:104A5000104004F0E8BB012300F090BA00231A468E -:104A6000194600F08BBA70B506460C460846FCF7AE -:104A7000F0FB18B92068FCF712FC18B1102070BDCB -:104A8000F0010020F84D2A7E112A04D0132A00D309 -:104A90003EB10820F3E721463046FEF77DFE60B1C7 -:104AA000EDE70920132A0DD0142A0BD0A188FF2985 -:104AB000E5D31520FEF7D2FA0020D4E90012C5E9AB -:104AC0000712DCE7A1881F29D9D31320F2E71CB510 -:104AD000E548007E132801D208201CBD00208DF877 -:104AE000000068460DF02AFC04F09DFB0028F4D17C -:104AF0001120FEF7B3FA00201CBD2DE9F04FDFF8BE -:104B000068A3814691B09AF818009B4615460C465A -:104B1000132803D3FFF7DBFF00281FD12046FCF743 -:104B200098FBE8BB2846FCF794FBC8BB20784FF005 -:104B30000107C0074FF0000102D08DF83A7001E084 -:104B40008DF83A1020788846C0F3C1008DF8000037 -:104B500060788DF80910C10803D0072011B0BDE8B6 -:104B6000F08FB0B3C10701D08DF80970810705D56A -:104B70009DF8091041F002018DF80910400705D594 -:104B80009DF8090040F004008DF809009DF8090027 -:104B9000810703D540F001008DF80900002000E0F6 -:104BA00015E06E4606EB400162884A81401CA288EF -:104BB000C0B20A820328F5D32078C0F3C1000128CF -:104BC00025D0032823D04846FCF743FB28B110200A -:104BD000C4E7FFE78DF80970D8E799F800004008AE -:104BE00008D0012809D0022807D0032805D043F2B5 -:104BF0000220B3E78DF8028001E08DF8027048468C -:104C000050F8011FCDF803108088ADF80700FEF7BB -:104C1000AFFB8DF801000021424606EB41002B88D6 -:104C2000C3826B888383AB884384EB880385491CEC -:104C3000C285C9B282860329EFD3E088ADF83C0073 -:104C400068460DF053FC002887D19AF818005546A5 -:104C5000112801D0082081E706200FF0D7F838B1DD -:104C60002078C0F3C100012804D0032802D006E058 -:104C7000122073E795F8240000283FF46EAFFEF78A -:104C800003FA022801D2132068E7584600F04FF9D2 -:104C900000289DD185F819B068460DF06DFD04F02F -:104CA000C2FA040094D1687E00F051F91220FEF798 -:104CB000D5F9204652E770B56B4D287E122801D0F9 -:104CC0000820DCE60DF05BFD04F0ADFA040005D130 -:104CD000687E00F049F91120FEF7C0F92046CEE6C3 -:104CE00070B5064615460C460846FCF7D8FA18B9C2 -:104CF0002846FCF7D4FA08B11020C0E62A4621461F -:104D000030460EF03BF804F08EFA0028F5D12178F9 -:104D10007F29F2D10520B2E67CB505460C4608464F -:104D2000FCF797FA08B110207CBD2846FEF78AFBF5 -:104D300020B10078222804D208207CBD43F2020072 -:104D40007CBD494890F83000400701D511207CBD5A -:104D50002078C00802D16078C00801D007207CBD4F -:104D6000ADF8005020788DF8020060788DF80300CF -:104D70000220ADF8040068460CF03BFE04F053FA44 -:104D80007CBD70B586B014460D460646FEF75AFB4C -:104D900028B10078222805D2082006B06FE643F239 -:104DA0000200FAE72846FCF7A1FA20B944B12046F0 -:104DB000FCF793FA08B11020EFE700202060A080F4 -:104DC000294890F83000800701D51120E5E703A9B4 -:104DD00030460CF05EFE10B104F025FADDE7ADF8C8 -:104DE0000060BDF81400ADF80200BDF81600ADF883 -:104DF0000400BDF81000BDF81210ADF80600ADF8C3 -:104E000008107DB1298809B1ADF80610698809B18B -:104E1000ADF80210A98809B1ADF80810E98809B108 -:104E2000ADF80410DCB1BDF80610814201D9081AB2 -:104E30002080BDF80210BDF81400814201D9081A83 -:104E40006080BDF80800BDF80410BDF816200144CC -:104E5000BDF812001044814201D9081AA0806846AA -:104E60000CF0D5FEB8E70000F00100201CB56C493D -:104E70000968CDE9001068460DF03AFB04F0D3F95B -:104E80001CBD1CB500200090019068460DF030FB61 -:104E900004F0C9F91CBD70B505460C460846FCF780 -:104EA000FEF908B11020EAE5214628460DF012F976 -:104EB000BDE8704004F0B7B93EB505460C4608465B -:104EC000FCF7EDF908B110203EBD002000900190E4 -:104ED0000290ADF800502089ADF8080020788DF8D8 -:104EE0000200606801902089ADF808006089ADF883 -:104EF0000A0068460DF000F904F095F93EBD0EB5C4 -:104F0000ADF800000020019068460DF0F5F804F0BF -:104F10008AF90EBD10800888508048889080C88823 -:104F200010818888D080002050819081704710B512 -:104F3000044604F0E4F830B1407830B1204604F083 -:104F4000FCFB002010BD052010BD122010BD10B5C7 -:104F500004F0D5F8040000D1FFDF607800B9FFDF6E -:104F60006078401E607010BD10B504F0C8F80400F1 -:104F700000D1FFDF6078401C607010BD1CB5ADF83B -:104F800000008DF802308DF803108DF8042068467B -:104F90000DF0B7FE04F047F91CBD0CB521A2D2E913 -:104FA0000012CDE900120079694601EB501000783B -:104FB0000CBD0278520804D0012A02D043F202202C -:104FC0007047FEF7ACB91FB56A46FFF7A3FF684606 -:104FD0000DF008FC04F027F904B010BD70B50C000A -:104FE00006460DD0FEF72EFA050000D1FFDFA680A1 -:104FF00028892081288960816889A081A889E08129 -:105000003DE500B540B1012805D0022803D00328B2 -:1050100004D0FFDF002000BDFF2000BD042000BD44 -:1050200014610200070605040302010010B50446DE -:10503000FCF70FF908B1102010BD2078C0F3021062 -:10504000042807D86078072804D3A178102901D84C -:10505000814201D2072010BDE078410706D42179B2 -:105060004A0703D4000701D4080701D5062010BD64 -:10507000002010BD10B513785C08837F64F3C7135C -:10508000837713789C08C37F64F30003C377107899 -:10509000C309487863F34100487013781C090B7802 -:1050A00064F347130B701378DB0863F30000487058 -:1050B0005078487110BD10B5C4780B7864F30003C4 -:1050C0000B70C478640864F341030B70C478A408BF -:1050D00064F382030B70C478E40864F3C3030B70B9 -:1050E0000379117863F30001117003795B0863F3AE -:1050F0004101117003799B0863F3820111700079FB -:10510000C00860F3C301117010BD70B514460D46A0 -:10511000064604F06BFA80B10178182221F00F01E5 -:10512000891C21F0F001A03100F8081B214609F08C -:1051300084F9BDE8704004F05CBA29463046BDE809 -:1051400070401322FEF781B92DE9F047064608A802 -:10515000904690E8300489461F46142200212846D4 -:1051600009F095F90021CAF80010B8F1000F03D03A -:10517000B9F1000F03D114E03878C00711D02068CE -:10518000FCF78DF8C0BBB8F1000F07D120681230D2 -:1051900028602068143068602068A8602168CAF818 -:1051A00000103878800724D56068FCF796F818BBA3 -:1051B000B9F1000F21D0FFF7E4F80168C6F86811D3 -:1051C0008188A6F86C11807986F86E0101F013FDD4 -:1051D000F94FEF60626862B196F8680106F26911F2 -:1051E00040081032FEF7FDF810223946606809F0D9 -:1051F00024F90020BDE8F08706E0606820B1E8608F -:105200006068C6F86401F4E71020F3E730B505469E -:1052100008780C4620F00F00401C20F0F0011031FF -:1052200021700020607095F8230030B104280FD061 -:10523000052811D0062814D0FFDF20780121B1EB1A -:10524000101F04D295F8200000F01F00607030BDE0 -:1052500021F0F000203002E021F0F000303020702A -:10526000EBE721F0F0004030F9E7F0B591B002270C -:1052700015460C4606463A46ADF80870092103ABC0 -:1052800005F063F80490002810D004208DF8040085 -:105290008DF80170E034099605948DF818500AA92C -:1052A000684610F0FCFA00B1FFDF012011B0F0BD3C -:1052B00010B588B00C460A99ADF80000CBB118685B -:1052C000CDF80200D3F80400CDF80600ADF80A20AE -:1052D000102203A809F0B1F868460DF0F3FA03F0C4 -:1052E000A2FF002803D1A17F41F01001A17708B0EF -:1052F00010BD0020CDF80200E6E72DE9F84F064684 -:10530000808A0D4680B28246FEF79CF804463078CB -:10531000DFF8A48200274FF00209A8F120080F2827 -:1053200070D2DFE800F06FF23708387D8CC8F1F0FA -:10533000EFF35FF3F300A07F00F00300022809D031 -:105340005FF0000080F0010150460EF0AFFD050057 -:1053500003D101E00120F5E7FFDF98F85C10C907F1 -:1053600002D0D8F860000BE0032105F11D0012F017 -:10537000BEF8D5F81D009149B0FBF1F201FB120017 -:10538000C5F81D0070686867B068A8672078252890 -:1053900000D0FFDFCAE0A07F00F00300022809D0A0 -:1053A0005FF0000080F0010150460EF07FFD060026 -:1053B00003D101E00120F5E7FFDF3078810702D556 -:1053C0002178252904D040F001003070BDE8F88F25 -:1053D00085F80090307F287106F11D002D36C5E953 -:1053E0000206F3E7A07F00F00300022808D00020A7 -:1053F00080F0010150460EF059FD040004D102E096 -:105400000120F5E7A7E1FFDF2078C10604D50720DA -:1054100028703D346C60D9E740F008002070D5E773 -:10542000E07F000700D5FFDF307CB28800F0010389 -:1054300001B05046BDE8F04F092106F064B804B948 -:10544000FFDF716821B1102204F1240008F0F5FF9C -:1054500028212046FDF75EFEA07F00F00300022811 -:105460000ED104F12400002300901A462146504634 -:10547000FFF71EFF112807D029212046FDF74AFE1D -:10548000307A84F82000A1E7A07F000700D5FFDF75 -:1054900014F81E0F40F008002070E782A761E76152 -:1054A000C109607861F34100014660F382016170D7 -:1054B000307AE0708AE7A07F00F00300022809D06C -:1054C0005FF0000080F0010150460EF0EFFC040098 -:1054D00003D101E00120F5E7FFDF022104F185009F -:1054E00012F005F80420287004F5B4706860B4F870 -:1054F00085002882304810387C346C61C5E9028010 -:1055000064E703E024E15BE02DE015E0A07F00F01C -:105510000300022807D0002080F0010150460EF061 -:10552000C5FC18B901E00120F6E7FFDF324621464D -:105530005046BDE8F84FE8E504B9FFDF20782128A0 -:10554000A1D93079012803D1E07F40F00800E0774D -:10555000324621465046FFF7D8FD2046BDE8F84FB9 -:105560002321FDF7D7BD3279AA8005F1080309216F -:10557000504604F0EAFEE86010B10520287025E7E7 -:10558000A07F00F00300022808D0002080F0010175 -:1055900050460EF08BFC040003D101E00120F5E73A -:1055A000FFDF04F1620102231022081F0EF005FB49 -:1055B00007703179417009E75002002040420F0026 -:1055C000A07F00F00300022808D0002080F0010135 -:1055D00050460EF06BFC050003D101E00120F5E719 -:1055E000FFDF95F8840000F0030001287AD1A07F46 -:1055F00000F00307E07F10F0010602D0022F04D173 -:1056000033E095F8A000C0072BD0D5F8601121B386 -:1056100095F88320087C62F387000874A17FCA098B -:10562000D5F8601162F341000874D5F8601166F393 -:1056300000000874AEB1D5F86001102204F1240115 -:10564000883508F0FAFE287E40F001002876287898 -:1056500020F0010005F8880900E016B1022F04D0FF -:105660002DE095F88800C00727D0D5F85C1121B34C -:1056700095F88320087C62F387000874A17FCA092B -:10568000D5F85C1162F341000874D5F85C1166F33B -:10569000000008748EB1D5F85C01102204F12401D9 -:1056A000883508F0CAFE287840F0010005F8180B8C -:1056B000287820F0010005F8A009022F44D000202E -:1056C00000EB400005EBC00090F88800800709D58A -:1056D00095F87C00D5F86421400805F17D01103271 -:1056E000FDF77FFE8DF8009095F884006A4600F083 -:1056F00003008DF8010095F888108DF8021095F8D8 -:10570000A0008DF803002146504601F05DFA207894 -:10571000252805D0212807D0FFDF2078222803D9AB -:1057200022212046FDF7F6FCA07F00F003000228AE -:105730000CD0002080F0010150460EF0C9FB00287B -:105740003FF44FAEFFDF41E60120B9E70120F1E76A -:10575000706847703AE6FFDF38E670B5FE4C00250A -:1057600084F85C50256610F066F804F110012046BC -:1057700003F0F8FE84F8305070BD70B50D46FDF7AB -:1057800061FE040000D1FFDF4FF4B872002128460B -:1057900008F07DFE04F124002861A07F00F00300E2 -:1057A000022809D05FF0010105F1E00010F044F893 -:1057B000002800D0FFDF70BD0221F5E70A46014650 -:1057C00002F1E00010F059B870B50546406886B0A7 -:1057D00001780A2906D00D2933D00E292FD0FFDFFA -:1057E00006B070BD86883046FDF72CFE040000D15F -:1057F000FFDF20782128F3D028281BD168680221F8 -:105800000E3001F0D6F9A8B168680821801D01F0BA -:10581000D0F978B104F1240130460DF00FFA03F00D -:1058200002FD00B1FFDF06B02046BDE8704029212F -:10583000FDF770BC06B0BDE8704003F0DABE012190 -:1058400001726868C6883046FDF7FCFD040000D18F -:10585000FFDFA07F00F00301022902D120F0100039 -:10586000A077207821280AD06868017A09B10079E8 -:1058700080B1A07F00F00300022862D0FFDFA07F8C -:1058800000F003000228ABD1FEF72DF80028A7D0C6 -:10589000FFDFA5E703F0ADFEA17F08062BD5E07F73 -:1058A000C00705D094F8200000F01F00102820D079 -:1058B0005FF0050084F82300207829281DD02428D3 -:1058C000DDD13146042012F0F9F822212046FDF7FF -:1058D00021FCA07F00F00300022830D05FF0000020 -:1058E00080F0010130460EF0F3FA0028C7D0FFDF48 -:1058F000C5E70620DEE70420DCE701F0030002280C -:1059000008D0002080F0010130460EF0CFFA0500EB -:1059100003D101E00120F5E7FFDF25212046FDF757 -:10592000F9FB03208DF80000694605F1E0000FF057 -:105930009BFF0228A3D00028A1D0FFDF9FE7012012 -:10594000CEE703F056FE9AE72DE9F04387B099467B -:10595000164688460746FDF775FD04004BD02078B3 -:10596000222848D3232846D0E07F000743D4A07FD5 -:1059700000F00300022809D05FF0000080F0010170 -:1059800038460EF093FA050002D00CE00120F5E74E -:10599000A07F00F00300022805D001210022384634 -:1059A0000EF07BFA05466946284601F034F9009866 -:1059B00000B9FFDF45B10098E03505612078222865 -:1059C00006D0242804D007E000990020086103E0F5 -:1059D00025212046FDF79EFB00980121417047627A -:1059E000868001A9C0E902890FF059FF022802D080 -:1059F000002800D0FFDF07B0BDE8F08370B586B0A7 -:105A00000546FDF71FFD017822291ED9807F00F091 -:105A10000300022808D0002080F0010128460EF083 -:105A200045FA04002FD101E00120F5E7FFDF2AE06D -:105A3000B4F85E0004F1620630440178427829B17E -:105A400021462846FFF711FCB0B9C9E6ADF804209D -:105A50000921284602AB04F078FC03900028F4D01A -:105A600005208DF80000694604F1E0000FF0FCFE0F -:105A7000022801D000B1FFDF02231022314604F1D9 -:105A80005E000EF0D0F8B4F860000028D0D1A7E690 -:105A900010B586B00446FDF7D5FC017822291BD944 -:105AA000807F00F00300022808D0002080F0010170 -:105AB00020460EF0FBF9040003D101E00120F5E7D8 -:105AC000FFDF06208DF80000694604F1E0000FF0CA -:105AD000CBFE002800D0FFDF06B010BD2DE9F05F3F -:105AE00005460C4600270078904601093E4604F121 -:105AF000080BBA4602297DD0072902D00A2909D10C -:105B000046E0686801780A2905D00D2930D00E29B1 -:105B10002ED0FFDFBBE114271C26002C6BD0808821 -:105B2000A080FDF78FFC5FEA000900D1FFDF99F844 -:105B300017005A46400809F11801FDF752FC686841 -:105B4000C0892082696851F8060FC4F812004868BD -:105B5000C4F81600A07E01E03002002020F006000C -:105B600040F00100A07699F81E0040F020014DE0C1 -:105B70001A270A26002CD1D0C088A080FDF762FC2D -:105B8000050000D1FFDF59462846FFF73FFB7EE1C5 -:105B90000CB1A88BA080287A0B287DD006DC0128C8 -:105BA0007BD0022808D0032804D135E00D2875D019 -:105BB0000E2874D0FFDF6AE11E270926002CADD025 -:105BC000A088FDF73FFC5FEA000900D1FFDF287BDA -:105BD00000F003000128207A1BD020F00100207281 -:105BE000297B890861F341002072297BC90861F390 -:105BF000820001E041E1F2E02072297B090961F3B2 -:105C0000C300207299F81E0040F0400189F81E1070 -:105C10003DE140F00100E2E713270D26002CAAD059 -:105C2000A088FDF70FFC8146807F00F0030002286A -:105C300008D0002080F00101A0880EF037F905009F -:105C400003D101E00120F5E7FFDF99F81E0000F025 -:105C50000302022A50D0686F817801F00301012904 -:105C6000217A4BD021F00101217283789B0863F3E4 -:105C7000410121728378DB0863F38201217283780A -:105C80001B0963F3C3012172037863F306112172C8 -:105C9000437863F3C71103E061E0A9E090E0A1E07D -:105CA000217284F809A0C178A172022A29D0027950 -:105CB000E17A62F30001E1720279520862F3410174 -:105CC000E1720279920862F38201E1720279D208EC -:105CD00062F3C301E1724279217B62F30001217317 -:105CE0004279520862F3410121734279920862F3CA -:105CF00082012173407928E0A86FADE741F00101EE -:105D0000B2E74279E17A62F30001E1724279520826 -:105D100062F34101E1724279920862F38201E17219 -:105D20004279D20862F3C301E1720279217B62F306 -:105D3000000121730279520862F341012173027953 -:105D4000920862F3820121730079C00860F3C301F5 -:105D5000217399F80000232831D9262140E0182723 -:105D60001026E4B3A088FDF76DFB8346807F00F02A -:105D70000300022809D0002080F00101A0880EF065 -:105D800095F85FEA000903D101E00120F4E7FFDFA5 -:105D9000E868A06099F8000040F0040189F800105C -:105DA00099F80100800708D5012020739BF80000B6 -:105DB00023286CD92721584651E084F80CA066E0CE -:105DC00015270F265CB1A088FDF73CFB8146062213 -:105DD0005946E86808F0C7FB0120A073A0E041E045 -:105DE00048463CE016270926E4B3287B20724EE0A3 -:105DF000287B19270E26ACB3C4F808A0A4F80CA081 -:105E0000012807D0022805D0032805D0042803D094 -:105E1000FFDF0DE0207207E0697B042801F00F012D -:105E200041F0800121721ED0607A20F00300607280 -:105E3000A088FDF707FB05460078212827D02328F6 -:105E400000D0FFDFA87F00F00300022813D000205D -:105E500080F00101A0880EF03BF822212846FDF7D2 -:105E600059F914E004E0607A20F00300401CDEE7FA -:105E7000A8F8006010E00120EAE70CB16888A08073 -:105E8000287A68B301280AD002284FD0FFDFA8F88B -:105E900000600CB1278066800020BDE8F09F1527C8 -:105EA0000F26002CE4D0A088FDF7CCFA807F00F00C -:105EB0000300022808D0002080F00101A0880DF026 -:105EC000F5FF050003D101E00120F5E7FFDFD5F87C -:105ED0001D000622594608F046FB84F80EA0D6E7BE -:105EE00017270926002CC3D0A088FDF7ABFA8146FE -:105EF000807F00F00300022808D0002080F001011C -:105F0000A0880DF0D3FF050003D101E00120F5E7E3 -:105F1000FFDF6878800701D5022000E001202072B1 -:105F200099F800002328B2D9272159E719270E260E -:105F3000002C9DD0A088FDF785FA5FEA000900D10A -:105F4000FFDFC4F808A0A4F80CA084F808A0A07A89 -:105F500040F00300A07299F81E10C90961F3820095 -:105F6000A07299F81F2099F81E1012EAD11F05D0CF -:105F700099F8201001F01F0110292BD020F0080003 -:105F8000A07299F81F10607A61F3C3006072697A99 -:105F900001F003010129A2D140F00400607299F8D8 -:105FA0001E0000F003000228E87A16D0217B60F37F -:105FB00000012173AA7A607B62F300006073EA7AC1 -:105FC000520862F341012173A97A490861F3410043 -:105FD00060735CE740F00800D2E7617B60F300018A -:105FE0006173AA7A207B62F300002073EA7A520878 -:105FF00062F341016173A97A490861F3410020739A -:1060000045E710B5FE4C30B10146102204F12000E6 -:1060100008F013FA012084F8300010BD10B50446D2 -:1060200000F0E9FDF64920461022BDE8104020317D -:1060300008F003BA70B5F24D06004FF0000413D01B -:10604000FBF707F908B110240CE00621304608F0F0 -:1060500071FA411C05D028665FF0010085F85C00EC -:1060600000E00724204670BD0020F7E7007810F01C -:106070000F0204D0012A05D0022A0CD110E0000939 -:1060800009D10AE00009012807D0022805D0032819 -:1060900003D0042801D00720704708700020704703 -:1060A0000620704705282AD2DFE800F003070F1703 -:1060B0001F00087820F0FF001EE0087820F00F0095 -:1060C000401C20F0F000103016E0087820F00F009F -:1060D000401C20F0F00020300EE0087820F00F0087 -:1060E000401C20F0F000303006E0087820F00F006F -:1060F000401C20F0F000403008700020704707205E -:1061000070472DE9F041804688B00D4600270846CB -:10611000FBF7ECF8A8B94046FDF794F9040003D06A -:106120002078222815D104E043F2020008B0BDE82F -:10613000F08145B9A07F410603D500F00300022895 -:1061400001D01020F2E7A07FC10601D4010702D5DB -:106150000DB10820EAE7E17F090701D50D20E5E749 -:1061600000F0030002280DD165B12846FEF75EFF5E -:106170000700DBD1FBF736FB20B9E878800701D5B3 -:106180000620D3E7A07F00F00300022808D00020FB -:1061900080F0010140460DF089FE060002D00FE0BC -:1061A0000120F5E7A07F00F0030002280ED00020B8 -:1061B00080F00101002240460DF06FFE060007D07E -:1061C000A07F00F00300022804D009E00120EFE7DF -:1061D0000420ABE725B12A4631462046FEF74AFFA8 -:1061E0006946304600F017FD009800B9FFDF0099BE -:1061F000022006F1E0024870C1F824804A610022C2 -:106200000A81A27F02F00302022A1CD00120087139 -:10621000287800F00102087E62F3010008762A78EF -:10622000520862F3820008762A78920862F3C3006B -:1062300008762A78D20862F30410087624212046D2 -:10624000FCF768FF33E035B30871301D88613078A2 -:10625000400908777078C0F340004877287800F04C -:106260000102887F62F301008877A27FD20962F37E -:1062700082008877E27F62F3C3008877727862F3E6 -:1062800004108877A878C87701F1210228462031C8 -:10629000FEF711FF03E00320087105200876252191 -:1062A0002046FCF737FFA07F20F04000A07701A92F -:1062B00000980FF0F4FA022801D000B1FFDF384651 -:1062C00034E72DE9FF4F8DB09A4693460D460027DF -:1062D0000D98FDF7B7F8060006D03078262806D0CE -:1062E000082011B0BDE8F08F43F20200F9E7B07F5B -:1062F00000F00309B9F1020F11D04DB95846FEF76D -:1063000095FE0028EDD1B07F00F00300022806D0F2 -:10631000BBF1000F11D0FBF765FA20B10DE0BBF126 -:10632000000F50D109E006200DF068FD28B19BF860 -:106330000300800701D50620D3E7B07F00F00300FB -:10634000022809D05FF0000080F001010D980DF0E7 -:10635000ADFD040003D101E00120F5E7FFDF852D4D -:1063600027D007DCEDB1812D1DD0822D1DD0832DCE -:1063700008D11CE0862D1ED0882D1ED0892D1ED060 -:106380008A2D1ED00F2020710F281CD003F02EF96B -:10639000D8B101208DF81400201D06902079B0B1ED -:1063A00056E10020EFE70120EDE70220EBE70320B4 -:1063B000E9E70520E7E70620E5E70820E3E709200D -:1063C000E1E70A20DFE707208BE7112089E7B9F131 -:1063D000020F03D0A56F03D1A06F02E0656FFAE74B -:1063E000606F804631D04FF0010001904FF0020005 -:1063F00000905A4621463046FEF73CFE02E000007F -:10640000300200209BF8000000F00101A87861F341 -:106410000100A870B17FC90961F38200A870F17F03 -:1064200061F3C300A870617861F30410A87020784C -:10643000400928706078C0F3400068709BF8020043 -:10644000E87000206871287103E0022001900120AB -:106450000090A87898F80210C0F3C000C1F3C00102 -:10646000084003902CD05046FAF7F3FEC0BBDAF890 -:106470000C00FAF7EEFE98BBDAF81C00FAF7E9FE1A -:1064800070BBDAF80C00A060DAF81C00E0606078FD -:1064900098F8012042EA500161F34100607098F8D9 -:1064A0000210C0B200EA111161F300006070002018 -:1064B0002077009906F11700022907D0012106E094 -:1064C000607898F8012002EA5001E5E7002104EB2A -:1064D000810148610199701C022902D0012101E06B -:1064E00028E0002104EB81014861A87800F0030056 -:1064F000012857D198F8020000F00300012851D17B -:10650000B9F1020F04D02A1D691D5846FEF7D3FDCC -:10651000287998F8041008408DF82C00697998F8CB -:10652000052011408DF8301008433BD05046FAF753 -:1065300090FE08B11020D4E60AF110018B46B9F1A3 -:10654000020F17D00846002104F18C03CDE90003A7 -:1065500004F5AE7202920BAB2046039AFEF7F4FDEF -:106560000028E8D1B9F1020F08D0504608D14FF009 -:10657000010107E050464FF00101E5E75846F5E715 -:106580004FF0000104F1A403CDE9000304F5B0725B -:10659000029281F001010CAB2046039AFEF7D4FD74 -:1065A0000028C8D16078800733D4A87898F8021002 -:1065B000C0F38000C1F3800108432AD0297898F8FD -:1065C0000000F94AB9F1020F06D032F81120430059 -:1065D000DA4002F003070AE032F810204B00DA40FC -:1065E00012F0030705D0012F0AD0022F0AD0032F83 -:1065F00006D0039A6AB1012906D0042904D008E024 -:106600000227F6E70127F4E7012801D0042800D18A -:106610000427B07F40F08000B077F17F039860F3EB -:106620000001F1776078800705D50320A0710398F9 -:1066300070B9002029E00220022F18D0012F18D0B5 -:10664000042F2AD00020A071B07F20F08000B07706 -:1066500025213046FCF75EFD05A904F1E0000FF0AE -:1066600003F910B1022800D0FFDF002039E6A07145 -:10667000DFE7A0710D22002104F1200007F007FFE1 -:10668000207840F00200207001208DF8100004AA4C -:1066900031460D9800F098FADAE70120A071D7E7AB -:1066A0002DE9F04387B09046894604460025FCF763 -:1066B000C9FE060006D03078272806D0082007B08B -:1066C000BDE8F08343F20200F9E7B07F00F0030079 -:1066D000022809D05FF0000080F0010120460DF093 -:1066E000E5FB040003D101E00120F5E7FFDFA77916 -:1066F0005FEA090005D0012821D0B9F1020F26D1A7 -:1067000010E0B8F1000F22D1012F05D0022F05D0E3 -:10671000032F05D0FFDF2EE00C252CE001252AE019 -:10672000022528E04046FAF794FDB0B9032F0ED1B8 -:106730001022414604F11D0007F07FFE1BE0012FEF -:1067400002D0022F03D104E0B8F1000F13D00720CC -:10675000B5E74046FAF77DFD08B11020AFE71022FB -:10676000002104F11D0007F092FE0621404607F0CB -:10677000E1FEC4F81D002078252140F002002070C1 -:106780003046FCF7C7FC2078C10713D020F0010089 -:10679000207002208DF8000004F11D0002908DF899 -:1067A00004506946C3300FF05FF8022803D010B1DF -:1067B000FFDF00E02577002081E730B587B00D4688 -:1067C0000446FCF73FFE98B1807F00F003000228EA -:1067D00011D0002080F0010120460DF067FB04007D -:1067E0000ED02846FAF735FD38B1102007B030BD7D -:1067F00043F20200FAE70120ECE72078400701D4D9 -:106800000820F3E7294604F13D002022054607F061 -:1068100014FE207840F01000207001070FD520F002 -:106820000800207007208DF80000694604F1E000A0 -:1068300001950FF019F8022801D000B1FFDF002008 -:10684000D4E770B50D460646FCF7FCFD18B101789B -:10685000272921D102E043F2020070BD807F00F0C1 -:106860000300022808D0002080F0010130460DF01E -:106870001DFB040003D101E00120F5E7FFDFA07953 -:10688000022809D16078C00706D02A462146304642 -:10689000FEF7EBFC10B10FE0082070BDB4F860000B -:1068A0000E280BD204F1620102231022081F0DF002 -:1068B00084F9012101704570002070BD112070BD68 -:1068C00070B5064614460D460846FAF7C2FC18B9DC -:1068D0002046FAF7E4FC08B1102070BDA6F57F4011 -:1068E000FF380ED03046FCF7ADFD38B14178224676 -:1068F0004B08811C1846FCF774FD07E043F20200C8 -:1069000070BD2046FDF7A5FD0028F9D11021E01D3E -:1069100010F0EDFDE21D294604F1170000F08BF99F -:10692000002070BD2DE9F04104468AB01546884626 -:1069300000270846FAF7DAFC18B92846FAF7D6FC19 -:1069400018B110200AB0BDE8F0812046FCF77AFDAE -:10695000060003D0307827281BD102E043F2020062 -:10696000F0E7B07F00F00300022809D05FF00000DC -:1069700080F0010120460DF099FA040003D101E0F6 -:106980000120F5E7FFDF2078400702D56078800717 -:1069900001D40820D6E7B07F00F00300022805D01C -:1069A000A06F05D1A16F04E01C610200606FF8E7E1 -:1069B000616F407800B19DB1487810B1B8F1000F17 -:1069C0000ED0ADB1EA1D06A8E16800F034F910223E -:1069D00006A905F1170007F003FD18B1042707E029 -:1069E0000720AFE71022E91D04F12D0007F025FD77 -:1069F000B8F1000F06D0102208F1070104F11D00C4 -:106A000007F01BFD2078252140F002002070304661 -:106A1000FCF780FB2078C10715D020F00100207022 -:106A200002208DF8000004F11D0002901030039048 -:106A30008DF804706946B3300EF016FF022803D0BB -:106A400010B1FFDF00E0277700207BE7F8B515469F -:106A50000E460746FCF7F6FC040004D020782228F6 -:106A600004D00820F8BD43F20200F8BDA07F00F07A -:106A70000300022802D043F20500F8BD3046FAF7C1 -:106A8000E8FB18B92846FAF7E4FB08B11020F8BD76 -:106A900000953288B31C21463846FEF709FC1128C0 -:106AA00015D00028F3D1297C4A08A17F62F3C711D1 -:106AB000A177297CE27F61F30002E277297C8908D3 -:106AC00084F82010A17F21F04001A177F8BDA17FBB -:106AD0000907FBD4D6F80200C4F83600D6F8060041 -:106AE000C4F83A003088A0861022294604F1240018 -:106AF00007F0A3FC287C4108E07F61F34100E077C8 -:106B0000297C61F38200E077287C800884F82100EA -:106B1000A07F40F00800A0770020D3E770B50D46B5 -:106B200006460BB1072070BDFCF78CFC040007D0B3 -:106B30002078222802D3A07F800604D4082070BDCC -:106B400043F2020070BDADB1294630460CF076F834 -:106B500002F069FB297C4A08A17F62F3C711A17783 -:106B6000297CE27F61F30002E277297C890884F8BE -:106B7000201004E030460CF084F802F054FBA17FB2 -:106B800021F02001A17770BD70B50D46FCF75AFCCD -:106B9000040005D02846FAF782FB20B1102070BD12 -:106BA00043F2020070BD29462046FEF72FFB00206D -:106BB00070BD04E010F8012B0AB100207047491E97 -:106BC00089B2F7D20120704770B51546064602F02B -:106BD0000DFD040000D1FFDF207820F00F00801CA5 -:106BE00020F0F0002030207066802868A060BDE8AA -:106BF000704002F0FEBC10B5134C94F83000002831 -:106C000008D104F12001A1F110000EF06FFE012067 -:106C100084F8300010BD10B190F8B9202AB10A48AC -:106C200090F8350018B1002003E0B83001E00648C4 -:106C300034300860704708B50023009313460A46B5 -:106C40000DF031FB08BD00003002002018B1817842 -:106C5000012938D101E010207047018842F6011265 -:106C6000881A914231D018DC42F60102A1EB0200F1 -:106C700091422AD00CDC41B3B1F5C05F25D06FF44E -:106C8000C050081821D0A0F57060FF381BD11CE05F -:106C900001281AD002280AD117E0B0F5807F14D05D -:106CA00008DC012811D002280FD003280DD0FF28BE -:106CB00009D10AE0B0F5817F07D0A0F580700338D4 -:106CC00003D0012801D0002070470F2070470A2808 -:106CD0001FD008DC0A2818D2DFE800F0191B1F1F9C -:106CE000171F231D1F21102815D008DC0B2812D0D8 -:106CF0000C2810D00D2816D00F2806D10DE0112831 -:106D00000BD084280BD087280FD003207047002099 -:106D1000704705207047072070470F2070470420F8 -:106D20007047062070470C20704743F202007047FE -:106D300038B50C46050041D06946FFF797F90028A1 -:106D400019D19DF80010607861F302006070694607 -:106D5000681CFFF78BF900280DD19DF800106078B2 -:106D600061F3C5006070A978C1F34101012903D026 -:106D7000022905D0072038BD217821F0200102E04A -:106D8000217841F020012170410704D0A978C90879 -:106D900061F386106070607810F0380F07D0A97822 -:106DA000090961F3C710607010F0380F02D16078E4 -:106DB000400603D5207840F040002070002038BD08 -:106DC00070B504460020088015466068FFF7B0FFE4 -:106DD000002816D12089A189884211D8606880785E -:106DE000C0070AD0B1F5007F0AD840F20120B1FBFC -:106DF000F0F200FB1210288007E0B1F5FF7F01D907 -:106E00000C2070BD01F201212980002070BD10B559 -:106E10000478137864F3000313700478640864F34F -:106E2000410313700478A40864F382031370047898 -:106E3000E40864F3C30313700478240964F30413AF -:106E400013700478640964F34513137000788009A3 -:106E500060F38613137031B10878C10701D1800740 -:106E600001D5012000E0002060F3C713137010BDAE -:106E70004278530702D002F0070306E012F0380F01 -:106E800002D0C2F3C20300E001234A7863F3020296 -:106E90004A70407810F0380F02D0C0F3C20005E00D -:106EA000430702D000F0070000E0012060F3C502B4 -:106EB0004A7070472DE9F04F95B00D00824613D00F -:106EC00012220021284607F0E2FA4FF6FF7B05AABE -:106ED0000121584607F0A3F80024264637464FF410 -:106EE00020586FF4205972E0102015B0BDE8F08FE3 -:106EF0009DF81E0001280AD1BDF81C1041450BD099 -:106F000011EB09000AD001280CD002280CD0042C67 -:106F10000ED0052C0FD10DE0012400E00224BDF8B5 -:106F20001A6008E0032406E00424BDF81A7002E0A9 -:106F3000052400E00624BDF81A10514547D12C74F1 -:106F4000BEB34FF0000810AA4FF0070ACDE9028245 -:106F5000CDE900A80DF13C091023CDF81090424670 -:106F60003146584607F02BF908BBBDF83C002A46CD -:106F7000C0B210A90EF045FDC8B9AE81CFB1CDE9C0 -:106F800000A80DF1080C0AAE40468CE8410213231C -:106F900000223946584607F012F940B9BDF83C00C6 -:106FA000F11CC01EC0B22A1D0EF02BFD10B1032033 -:106FB0009BE70AE0BDF82900E881062C05D19DF881 -:106FC0001E00A872BDF81C00288100208DE705A8CE -:106FD00007F031F800288BD0FFF779FE85E72DE91F -:106FE000F0471C46DDE90978DDF8209015460E00D3 -:106FF000824600D1FFDF0CB1208818B1D5B1112035 -:10700000BDE8F087022D01D0012100E0002106F14A -:10701000140005F0CDFEA8F8000002463B462946C4 -:10702000504603F092F9C9F8000008B9A41C3C606E -:107030000020E5E71320E3E7F0B41446DDE904524D -:107040008DB1002314B1022C09D101E0012306E027 -:107050000D7CEE0703D025F0010501230D742146B8 -:10706000F0BC04F050BA1A80F0BC70472DE9FE4F16 -:1070700091461A881C468A468046FAB102AB4946B8 -:1070800003F063F9050019D04046A61C27880DF0CF -:1070900050F83246072629463B4600960CF05FFC26 -:1070A00020882346CDE900504A4651464046FFF726 -:1070B000C3FF002020800120BDE8FE8F0020FBE7F9 -:1070C0002DE9F04786B082460EA8904690E8B000C1 -:1070D000894604AA05A903A88DE807001E462A468A -:1070E00021465046FFF77BFF039901B1012139701A -:1070F000002818D1FA4904F1140204AB086003987F -:1071000005998DE8070042464946504606F003FAC5 -:10711000A8B1092811D2DFE800F005080510100A0F -:107120000C0C0E00002006B06AE71120FBE70720D8 -:10713000F9E70820F7E70D20F5E70320F3E7BDF8AE -:1071400010100398CDE9000133462A4621465046E7 -:10715000FFF772FFE6E72DE9F04389B01646DDE957 -:1071600010870D4681461C461422002103A807F013 -:107170008EF9012002218DF810108DF80C008DF889 -:107180001170ADF8146064B1A278D20709D08DF8FF -:107190001600E088ADF81A00A088ADF81800A068C5 -:1071A000079008A80095CDE90110424603A948467A -:1071B0006B68FFF785FF09B0BDE8F083F0B58BB0D1 -:1071C00000240646069407940727089405A8099406 -:1071D000019400970294CDE903400D461023224606 -:1071E000304606F0ECFF78B90AA806A9019400978A -:1071F0000294CDE90310BDF8143000222946304630 -:1072000006F07BFD002801D0FFF761FD0BB0F0BD5B -:1072100006F00CBC2DE9FC410C468046002602F02D -:10722000E5F9054620780D287ED2DFE800F0BC079E -:1072300013B325BD49496383AF959B00A8480068F7 -:1072400020B1417841F010014170ADE0404602F0BC -:10725000FDF9A9E0042140460CF028FE070000D10A -:10726000FFDF07F11401404605F037FDA5BB1321F0 -:107270004046FDF7CFFB97E0042140460CF016FE98 -:10728000070000D1FFDFE088ADF800000020B881E2 -:107290009DF80000010704D5C00602D5A088B8817A -:1072A00005E09DF8010040067ED5A088F88105B96B -:1072B000FFDF22462946404601F0ACFC022673E07F -:1072C000E188ADF800109DF8011009060FD50728D8 -:1072D00003D006280AD00AE024E0042140460CF03E -:1072E000E5FD060000D1FFDFA088F0810226CDB9C0 -:1072F000FFDF17E0042140460CF0D8FD070000D165 -:10730000FFDF07F1140006F0C8FB90F0010F02D177 -:10731000E079000648D5387C022640F00200387437 -:1073200005B9FFDF224600E03DE02946404601F076 -:1073300071FC39E0042140460CF0B8FD017C002DC1 -:1073400001F00206C1F340016171017C21F00201EC -:107350000174E7D1FFDFE5E702260121404602F094 -:10736000A7F921E0042140460CF0A0FD0546606825 -:1073700000902089ADF8040001226946404602F0E1 -:10738000B8F9287C20F0020028740DE0002DC9D146 -:10739000FFDFC7E7022600214046FBF799F8002DE2 -:1073A000C0D1FFDFBEE7FFDF3046BDE8FC813EB560 -:1073B0000C0009D001466B4601AA002006F084FFAC -:1073C00020B1FFF784FC3EBD10203EBD0020208090 -:1073D000A0709DF8050002A900F00700FEF762FE0C -:1073E00050B99DF8080020709DF8050002A9C0F36F -:1073F000C200FEF757FE08B103203EBD9DF808000D -:1074000060709DF80500C109A07861F30410A070B8 -:107410009DF80510890961F3C300A0709DF8041060 -:10742000890601D5022100E0012161F342009DF8A7 -:10743000001061F30000A07000203EBD70B514463E -:1074400006460D4651EA040005D075B10846F9F725 -:1074500044FF78B901E0072070BD2946304606F0A8 -:107460009AFF10B1BDE8704031E454B12046F9F7FD -:1074700034FF08B1102070BD21463046BDE8704091 -:1074800095E7002070BD2DE9FC5F0C46904605464F -:10749000002701780822007A3E46B2EB111F7DD109 -:1074A00004F10A0100910A31821E4FF0020A04F130 -:1074B000080B0191092A72D2DFE802F0EDE005F530 -:1074C00028287BAACE00688804210CF0EFFC060077 -:1074D00000D1FFDFB08928B152270726C3E00000A2 -:1074E0009402002051271026002C7DD06888A080AF -:1074F0000120A071A88900220099FFF79FFF0028B2 -:1075000073D1A8892081288AE081D1E0B5F8129052 -:10751000072824D1E87B000621D5512709F1140062 -:1075200086B2002CE1D0A88900220099FFF786FFDF -:1075300000285AD16888A08084F806A0A8892081F4 -:107540000120A073288A2082A4F81290A88A0090B3 -:1075500068884B46A969019A01F038FBA8E05027DA -:1075600009F1120086B2002C3ED0A88900225946AB -:10757000FFF764FF002838D16888A080A889E080E0 -:10758000287A072813D002202073288AE081E87B1C -:10759000C0096073A4F81090A88A01E085E082E039 -:1075A000009068884B4604F11202A969D4E70120D3 -:1075B000EAE7B5F81290512709F1140086B2002CC1 -:1075C00066D0688804210CF071FC83466888A0802E -:1075D000A88900220099FFF731FF00286ED184F8B6 -:1075E00006A0A889208101E052E067E00420A07392 -:1075F000288A2082A4F81290A88A009068884B46B6 -:10760000A969019A01F0E2FAA989ABF80E104FE0DE -:107610006888FBF717FF0746688804210CF046FCD2 -:10762000064607B9FFDF06B9FFDF687BC00702D057 -:107630005127142601E0502712264CB36888A080F9 -:10764000502F06D084F806A0287B594601F0CEFAC8 -:107650002EE0287BA11DF9E7FE49A88949898142CE -:1076600005D1542706269CB16888A08020E05327C6 -:107670000BE06888A080A889E08019E06888042170 -:107680000CF014FC00B9FFDF55270826002CF0D1C0 -:10769000A8F8006011E056270726002CF8D068886B -:1076A000A080002013E0FFDF02E0012808D0FFDF08 -:1076B000A8F800600CB1278066800020BDE8FC9F20 -:1076C00057270726002CE3D06888A080687AA0712D -:1076D000EEE7401D20F0030009B14143091D01EB15 -:1076E0004000704713B5DB4A00201071009848B184 -:1076F000002468460CF0F7F9002C02D1D64A009914 -:1077000011601CBD01240020F4E770B50D4614463D -:10771000064686B05C220021284606F0B8FE04B971 -:10772000FFDFA0786874A2782188284601F089FAE2 -:107730000020A881E881228805F11401304605F077 -:10774000B0FA6A460121304606F069FC1AE000BF33 -:107750009DF80300000715D5BDF806103046FFF769 -:107760002DFD9DF80300BDF8061040F010008DF8C7 -:107770000300BDF80300ADF81400FF233046059A5E -:1077800006F0D1FD684606F056FC0028E0D006B0B1 -:1077900070BD10B50C4601F1140005F0BAFA0146AF -:1077A000627C2046BDE8104001F080BA30B5044646 -:1077B000A84891B04FF6FF75C18905AA284606F082 -:1077C0002EFC30E09DF81E00A0422AD001282AD1CC -:1077D000BDF81C00B0F5205F03D042F601018842DD -:1077E00021D1002002AB0AAA0CA9019083E807006E -:1077F00007200090BDF81A1010230022284606F03A -:10780000DEFC38B9BDF828000BAAC0B20CA90EF0F6 -:10781000F8F810B1032011B030BD9DF82E00A04241 -:1078200001D10020F7E705A806F005FC0028C9D023 -:107830000520F0E770B5054604210CF037FB040085 -:1078400000D1FFDF04F114010C46284605F045FA8B -:1078500021462846BDE8704005F046BA70B58AB0AA -:107860000C460646FBF7EEFD050014D028782228CA -:1078700027D30CB1A08890B101208DF80C00032013 -:107880008DF8100000208DF8110054B1A088ADF8DB -:107890001800206807E043F202000AB070BD09201A -:1078A000FBE7ADF818000590042130460CF0FEFA15 -:1078B000040000D1FFDF04F1140005F040FA0007D6 -:1078C00001D40820E9E701F091FE60B108A8022187 -:1078D0000094CDE9011095F8232003A93046636890 -:1078E000FFF7EEFBD9E71120D7E72DE9F04FB2F80B -:1078F00002A0834689B0154689465046FBF7A2FD93 -:107900000746042150460CF0D1FA0026044605969D -:107910004FF002080696ADF81C6007B9FFDF04B906 -:10792000FFDF4146504603F055FF50B907AA06A9AC -:1079300005A88DE807004246214650466368FFF7D8 -:107940004EFB444807AB0660DDE9051204F1140064 -:10795000CDF80090CDE90320CDE9013197F823203F -:10796000594650466B6805F033FA06000AD0022EDD -:1079700004D0032E14D0042E00D0FFDF09B030460F -:10798000BDE8F08FBDF81C000028F7D00599CDE9BF -:1079900000104246214650466368FFF74DFBEDE775 -:1079A000687840F008006870E8E710B50C46FFF70B -:1079B000BFF900280BD1607800F00701012905D13B -:1079C00010F0380F02D02078810601D5072010BDB5 -:1079D00040F0C8002070002010BD2DE9F04F99B094 -:1079E00004464FF000081B48ADF81C80ADF820801D -:1079F000ADF82480A0F80880ADF81480ADF81880A8 -:107A0000ADF82880ADF82C80007916460D46474623 -:107A1000012808D0022806D0032804D0042802D068 -:107A2000082019B0ACE72046F9F713FCF0BB284654 -:107A3000F9F70FFCD0BB6068F9F758FCB0BB606881 -:107A400068B160892189884202D8B1F5007F05D9E3 -:107A50000C20E6E7940200201800002080460EAAC1 -:107A600006A92846FFF7ACF90028DAD168688078C3 -:107A7000C0F34100022808D19DF8190010F0380F1A -:107A800003D02869F9F729FC80B905A92069FFF717 -:107A90004FF90028C5D1206950B1607880079DF862 -:107AA000150000F0380002D5F0B301E011E0D8BBBA -:107AB0009DF8140080060ED59DF8150010F0380FC3 -:107AC00003D06068F9F709FC18B96068F9F70EFC93 -:107AD00008B11020A5E70BA906A8FFF7C9F99DF882 -:107AE0002D000BA920F00700401C8DF82D006069C7 -:107AF000FFF75BFF002894D10AA9A069FFF718F9E6 -:107B000000288ED19DF8280080062BD4A06940B1B2 -:107B10009DF8290000F00701012923D110F0380F4A -:107B200020D0E06828B100E01CE00078D0B11C282B -:107B300018D20FAA611C2046FFF769F901213846C7 -:107B400061F30F2082468DF85210B94642F60300C9 -:107B50000F46ADF850000DF13F0218A928680DF04E -:107B600052FF08B107205CE79DF8600015A9CDF829 -:107B70000090C01CCDE9019100F0FF0B00230BF237 -:107B80000122514614A806F075F9E8BBBDF854006F -:107B90000C90FB482A8929690092CDE901106B8974 -:107BA000BDF838202868069906F064F9010077D1FD -:107BB00020784FF0020AC10601D4800616D58DF850 -:107BC000527042F60210ADF85000CDF80C9008A9A2 -:107BD00003AACDF800A0CDE90121002340F2032241 -:107BE00014A80B9906F046F9010059D1E4484D4616 -:107BF00008380089ADF83D000FA8CDE90290CDF816 -:107C00000490CDF8109000E00CE04FF007095B46BF -:107C10000022CDF80090BDF854104FF6FF7006F02A -:107C20006CF810B1FFF753F8FBE69DF83C00000636 -:107C300024D52946012060F30F218DF852704FF4AE -:107C400024500395ADF8500062789DF80C00002395 -:107C500062F300008DF80C006278CDF800A05208A5 -:107C600062F341008DF80C0003AACDE9012540F232 -:107C7000032214A806F0FEF8010011D1606880B359 -:107C80002069A0B905A906A8FFF7F2F86078800777 -:107C900007D49DF8150020F038008DF8150006E097 -:107CA00077E09DF8140040F040008DF814008DF846 -:107CB000527042F60110ADF85000208940F20121C7 -:107CC000B0FBF1F201FB1202606809ABCDF8008055 -:107CD000CDE90103002314A8059906F0CBF80100B3 -:107CE00057D12078C00728D00395A06950B90AA9B8 -:107CF00006A8FFF7BDF89DF8290020F00700401CFA -:107D00008DF829009DF8280007A940F040008DF863 -:107D100028008DF8527042F60310ADF8500003AA07 -:107D2000CDF800A0CDE90121002340F2032214A8E0 -:107D30000A9906F09FF801002BD1E06868B3294644 -:107D4000012060F30F218DF8527042F60410ADF857 -:107D50005000E068002302788DF8582040788DF8B4 -:107D60005900E06816AA4088ADF85A00E06800792A -:107D70008DF85C00E068C088ADF85D00CDF800903B -:107D8000CDE901254FF4027214A806F073F8010042 -:107D900003D00C9800F0B6FF43E679480321083879 -:107DA000017156B100893080BDF824007080BDF8A3 -:107DB0002000B080BDF81C00F080002031E670B5D6 -:107DC00001258AB016460B46012802D0022816D19A -:107DD00004E08DF80E504FF4205003E08DF80E5063 -:107DE00042F60100ADF80C005BB10024601C60F3AA -:107DF0000F2404AA08A918460DF005FE18B10720A3 -:107E00004BE5102049E504A99DF820205C48CDE908 -:107E10000021801E02900023214603A802F20122C5 -:107E200006F028F810B1FEF752FF36E5544808383E -:107E30000EB1C1883180057100202EE5F0B593B0F8 -:107E4000044601268DF83E6041F601000F46ADF86C -:107E50003C0011AA0FA93046FFF7B1FF002837D127 -:107E60002000474C4FF00005A4F1080432D01C223A -:107E7000002102A806F00BFB9DF808008DF83E607B -:107E800040F020008DF8080042F60520ADF83C00D7 -:107E900004200797ADF82C00ADF8300039480A905F -:107EA0000EA80D900E950FA80990ADF82E506A46B9 -:107EB00009A902A8FFF791FD002809D1BDF800002B -:107EC0006081BDF80400A081401CE0812571002084 -:107ED00013B0F0BD6581A581BDF84400F4E72DE93C -:107EE000F74F2749A0B00024083917940A79A14612 -:107EF000012A04D0022A02D0082023B040E5CA8813 -:107F0000824201D00620F8E721988A46824201D1B8 -:107F10000720F2E70120214660F30F21ADF8480069 -:107F20004FF6FF788DF86E000691ADF84A8042F664 -:107F3000020B8DF872401CA9ADF86CB0ADF8704022 -:107F40001391ADF8508012A806F0A4F800252E4633 -:107F50002F460DAB072212A9404606F09EF898B1B5 -:107F60000A2861D1B5B3AEB3ADF86450ADF8666020 -:107F70009DF85E008DF8144019AC012868D06FE0C0 -:107F80009C020020266102009DF83A001FB30128E0 -:107F900059D1BDF8381059451FD118A809A9019425 -:107FA0000294CDE9031007200090BDF8361010238D -:107FB0000022404606F003F9B0BBBDF8600004287B -:107FC00001D006284AD1BDF82410219881423AD127 -:107FD0000F2092E73AE0012835D1BDF83800B0F51E -:107FE000205F03D042F6010188422CD1BAF8060086 -:107FF000BDF83610884201D1012700E0002705B105 -:108000009EB1219881421ED118A809AA0194029418 -:10801000CDE90320072000900D46102300224046A2 -:1080200006F0CDF800B902E02DE04E460BE0BDF8B9 -:108030006000022801D0102810D1C0B217AA09A9E7 -:108040000DF0DFFC50B9BDF8369082E7052054E70B -:1080500005A917A8221D0DF0D6FC08B103204CE796 -:108060009DF814000023001DC2B28DF81420229840 -:108070000092CDE901401BA8069905F0FBFE10B95E -:1080800002228AF80420FEF722FE36E710B50B46DE -:10809000401E88B084B205AA00211846FEF7B7FE3C -:1080A00000200DF1080C06AA05A901908CE8070034 -:1080B000072000900123002221464FF6FF7005F0B3 -:1080C0001CFE0446BDF81800012800D0FFDF204642 -:1080D000FEF7FDFD08B010BDF0B5FF4F044687B0B8 -:1080E00038790E46032804D0042802D0082007B0AF -:1080F000F0BD04AA03A92046FEF762FE0500F6D1F2 -:1081000060688078C0F3410002280AD19DF80D0014 -:1081100010F0380F05D02069F9F7DFF808B110200A -:10812000E5E7208905AA21698DE807006389BDF884 -:1081300010202068039905F09DFE10B1FEF7C7FDE1 -:10814000D5E716B1BDF814003080042038712846F8 -:10815000CDE7F8B50C0006460BD001464FF6FF758B -:1081600000236A46284606F0AFF820B1FEF7AFFDBF -:10817000F8BD1020F8BD69462046FEF7D9FD00285D -:10818000F8D1A078314600F001032846009A06F0A5 -:10819000CAF8EBE730B587B0144600220DF1080CA1 -:1081A00005AD01928CE82C00072200920A46014698 -:1081B00023884FF6FF7005F0A0FDBDF81410218054 -:1081C000FEF785FD07B030BD70B50D4604210BF0FC -:1081D0006DFE040000D1FFDF294604F11400BDE864 -:1081E000704004F0A5BD70B50D4604210BF05EFE95 -:1081F000040000D1FFDF294604F11400BDE87040FF -:1082000004F0B9BD70B50D4604210BF04FFE04001B -:1082100000D1FFDF294604F11400BDE8704004F0EE -:10822000D1BD70B5054604210BF040FE040000D11D -:10823000FFDF214628462368BDE870400122FEF793 -:1082400015BF70B5064604210BF030FE040000D1C6 -:10825000FFDF04F1140004F05CFD401D20F0030575 -:1082600011E0011D00880022431821463046FEF728 -:10827000FDFE00280BD0607CABB2684382B2A068E0 -:10828000011D0BF0D0FCA06841880029E9D170BD28 -:1082900070B5054604210BF009FE040000D1FFDF94 -:1082A000214628466368BDE870400222FEF7DEBE24 -:1082B00070B50E46054601F099F9040000D1FFDFC4 -:1082C0000120207266726580207820F00F00001D6A -:1082D00020F0F00040302070BDE8704001F089B916 -:1082E00010B50446012900D0FFDF2046BDE810404C -:1082F0000121FAF7EDB82DE9F04F97B04FF0000AE1 -:108300000C008346ADF814A0D04619D0E06830B117 -:10831000A068A8B10188ADF81410A0F800A05846D4 -:10832000FBF790F8070043F2020961D03878222861 -:108330005CD3042158460BF0B9FD050005D103E0DC -:10834000102017B0BDE8F08FFFDF05F1140004F036 -:10835000E0FC401D20F00306A078012803D002288D -:1083600001D00720EDE7218807AA584605F057FEFF -:1083700030BB07A805F05FFE10BB07A805F05BFE49 -:1083800048B99DF82600012805D1BDF82400A0F5C4 -:108390002451023902D04FF45050D2E7E068B0B116 -:1083A000CDE902A00720009005AACDF804A0049210 -:1083B000A2882188BDF81430584605F09EFC10B103 -:1083C000FEF785FCBDE7A168BDF8140008809DF8A4 -:1083D0001F00C00602D543F20140B2E70B9838B146 -:1083E000A1780078012905D080071AD40820A8E7D1 -:1083F0004846A6E7C007F9D002208DF83C00A868DF -:108400004FF00009A0B1697C4288714391420FD9B5 -:108410008AB2B3B2011D0BF0BCFB8046A0F800A0ED -:1084200006E003208DF83C00D5F800804FF00109EC -:108430009DF8200010F0380F00D1FFDF9DF82000DC -:108440002649C0F3C200084497F8231010F8010C25 -:10845000884201D90F2074E72088ADF8400014A9A4 -:108460000095CDE90191434607220FA95846FEF732 -:1084700027FE002891D19DF8500050B9A07801281E -:1084800007D1687CB3B2704382B2A868011D0BF0BB -:1084900094FB002055E770B5064615460C46084685 -:1084A000FEF7D4FB002805D12A4621463046BDE818 -:1084B000704084E470BD12E570B51E4614460D0090 -:1084C0000ED06CB1616859B160B10349C98881426D -:1084D00008D0072070BD000094020020296102002E -:1084E0001020F7E72068FEF7B1FB0028F2D13246F2 -:1084F00021462846BDE87040FFF76FBA70B51546B3 -:108500000C0006D038B1FE490989814203D007200A -:10851000E0E71020DEE72068FEF798FB0028D9D1BD -:1085200029462046BDE87040D6E570B5064686B0BF -:108530000D4614461046F8F7B2FED0BB6068F8F757 -:10854000D5FEB0BBA6F57F40FF3803D03046FAF722 -:1085500079FF80B128466946FEF7ACFC00280CD1B3 -:108560009DF810100F2008293DD2DFE801F0080621 -:108570000606060A0A0843F2020006B0AAE703202C -:10858000FBE79DF80210012908D1BDF80010B1F5F4 -:10859000C05FF2D06FF4C052D142EED09DF8061009 -:1085A00001290DD1BDF80410A1F52851062907D2E3 -:1085B00000E029E0DFE801F0030304030303DCE744 -:1085C0009DF80A1001290FD1BDF80810B1F5245FFC -:1085D000D3D0A1F60211B1F50051CED00129CCD0F3 -:1085E000022901D1C9E7FFDF606878B9002305AA35 -:1085F0002946304605F068FE10B1FEF768FBBCE77F -:108600009DF81400800601D41020B6E76188224648 -:1086100028466368FFF7BEFDAFE72DE9F0438146CA -:1086200087B0884614461046F8F739FE18B1102076 -:1086300007B0BDE8F083002306AA4146484605F08E -:1086400043FE10B1FEF743FBF2E79DF81800C006A9 -:1086500002D543F20140EBE70025072705A8019565 -:1086600000970295CDE9035062884FF6FF734146AB -:10867000484605F0A4FD060013D16068F8F70FFE28 -:1086800060B960680195CDE9025000970495238890 -:1086900062884146484605F092FD0646BDF8140042 -:1086A00020803046CEE739B1954B0A889B899A42A3 -:1086B00002D843F2030070471DE610B586B0904C17 -:1086C0000423ADF81430638943B1A4898C4201D2EC -:1086D000914205D943F2030006B010BD0620FBE726 -:1086E000ADF81010002100910191ADF80030022189 -:1086F0008DF8021005A9029104A90391ADF812208A -:108700006946FFF7F8FDE7E72DE9FC4781460D468E -:108710000846F8F79EFD88BB4846FAF793FE5FEAE5 -:1087200000080AD098F80000222829D304214846DE -:108730000BF0BCFB070005D103E043F20200BDE8EB -:10874000FC87FFDF07F1140004F0F9FA06462878E9 -:10875000012803D0022804D00720F0E7B0070FD586 -:1087600002E016F01C0F0BD0A8792C1DC00709D011 -:10877000E08838B1A068F8F76CFD18B11020DEE78A -:108780000820DCE721882A780720B1F5847F35D0DE -:108790001EDC40F20315A1F20313A94226D00EDC21 -:1087A000B1F5807FCBD003DCF9B1012926D1C6E732 -:1087B000A1F58073013BC2D0012B1FD113E0012B27 -:1087C000BDD0022B1AD0032BB9D0042B16D112E046 -:1087D000A1F20912082A11D2DFE802F00B040410FA -:1087E00010101004ABE7022AA9D007E0012AA6D096 -:1087F00004E0320700E0F206002AA0DACDB200F071 -:10880000F5FE50B198F82300CDE90005FA8923461A -:1088100039464846FEF79FFC91E711208FE72DE986 -:10882000F04F8BB01F4615460C4683460026FAF7DC -:1088300009FE28B10078222805D208200BB081E576 -:1088400043F20200FAE7B80801D00720F6E7032F49 -:1088500000D100274FF6FF79CCB1022D71D320460D -:10886000F8F744FD30B904EB0508A8F10100F8F76A -:108870003DFD08B11020E1E7AD1E38F8028CAAB228 -:108880002146484605F081FE40455AD1ADB21C490B -:10889000B80702D58889401C00E001201FFA80F843 -:1088A000F80701D08F8900E04F4605AA4146584697 -:1088B00005F0B5FB4FF0070A4FF00009FCB1204668 -:1088C00008E0408810283CD8361D304486B2AE42BD -:1088D00037D2A01902884245F3D352E09DF8170021 -:1088E00002074ED57CB304EB0608361DB8F80230FB -:1088F000B6B2102B25D89A19AA4222D802E040E03D -:1089000094020020B8F8002091421AD1C0061BD56D -:10891000CDE900A90DF1080C0AAAA11948468CE876 -:108920000700B8F800100022584605F0E6F910B12B -:10893000FEF7CDF982E7B8F80200BDF828108842AA -:1089400002D00B207AE704E0B8F80200304486B287 -:1089500006E0C00604D55846FEF730FC00288AD150 -:108960009DF81700BDF81A1020F010008DF81700C0 -:10897000BDF81700ADF80000FF235846009A05F037 -:10898000D2FC05A805F057FB18B9BDF81A10B9427A -:10899000A4D9042158460BF089FA040000D1FFDF66 -:1089A000A2895AB1CDE900A94D4600232146584677 -:1089B000FEF7D1FB0028BDD1A5813FE700203DE7B0 -:1089C0002DE9FF4F8BB01E4617000D464FF00004F7 -:1089D00012D0B00802D007200FB0B3E4032E00D1AC -:1089E00000265DB10846F8F778FC28B93888691E7A -:1089F0000844F8F772FC08B11020EDE7C74AB00749 -:108A000001D5D18900E00121F0074FF6FF7802D0AF -:108A1000D089401E00E0404686B206AA0B9805F0B9 -:108A2000FEFA4FF000094FF0070B0DF1140A38E081 -:108A30009DF81B00000734D5CDF80490CDF800B0A8 -:108A4000CDF80890CDE9039A434600220B9805F033 -:108A5000B6FB60BB05B3BDF814103A882144281951 -:108A6000091D8A4230D3BDF81E2020F8022BBDF824 -:108A7000142020F8022BCDE900B9CDE90290CDF801 -:108A800010A0BDF81E10BDF8143000220B9805F0A0 -:108A900096FB08B103209FE7BDF814002044001D99 -:108AA00084B206A805F0C7FA20B10A2806D0FEF75E -:108AB0000EF991E7BDF81E10B142B9D934B17DB1BC -:108AC0003888A11C884203D20C2085E7052083E763 -:108AD00022462946404605F058FD014628190180E6 -:108AE000A41C3C80002077E710B50446F8F7D7FBBC -:108AF00008B1102010BD8948C0892080002010BD19 -:108B0000F0B58BB00D4606461422002103A805F0EF -:108B1000BEFC01208DF80C008DF8100000208DF8AF -:108B20001100ADF814503046FAF78CFC48B10078CB -:108B3000222812D3042130460BF0B8F9040005D1E5 -:108B400003E043F202000BB0F0BDFFDF04F11400BC -:108B5000074604F0F4F8800601D40820F3E7207CEF -:108B6000022140F00100207409A80094CDE9011011 -:108B7000072203A930466368FEF7A2FA20B1217CE0 -:108B800021F001012174DEE729463046F9F791FC16 -:108B900008A9384604F0C2F800B1FFDFBDF8204054 -:108BA000172C01D2172000E02046A84201D92C46FC -:108BB00002E0172C00D2172421463046FFF713FBA2 -:108BC00021463046F9F799F90020BCE7F8B51C4674 -:108BD00015460E46069F0BF09AFA2346FF1DBCB2BF -:108BE00031462A4600940AF086FEF8BD70B50C4660 -:108BF00005460E220021204605F049FC0020208079 -:108C00002DB1012D01D0FFDF64E4062000E0052036 -:108C1000A0715FE410B548800878134620F00F007B -:108C2000001D20F0F00080300C4608701422194618 -:108C300004F1080005F001FC00F0DBFC374804609B -:108C400010BD2DE9F047DFF8D890491D064621F008 -:108C5000030117460C46D9F800000AF062FF050030 -:108C600000D1FFDF4FF000083560A5F800802146F5 -:108C7000D9F800000AF055FF050000D1FFDF75604C -:108C8000A5F800807FB104FB07F1091D0BD0D9F8CE -:108C900000000AF046FF040000D1FFDFB460C4F812 -:108CA0000080BDE8F087C6F80880FAE72DE9F041BA -:108CB0001746491D21F00302194D06460168144666 -:108CC00028680AF059FF2246716828680AF054FFA4 -:108CD0003FB104FB07F2121D03D0B16828680AF007 -:108CE0004BFF04200BF08AF8044604200BF08EF8AA -:108CF000201A012804D12868BDE8F0410AF006BF17 -:108D0000BDE8F08110B50C4605F058F900B1FFDF61 -:108D10002046BDE81040FDF7DABF000094020020B5 -:108D20001800002038B50C468288817B19B1418932 -:108D3000914200D90A462280C188121D90B26A462B -:108D40000AF0B2F8BDF80000032800D30320C1B236 -:108D5000208801F020F838BD38B50C468288817B28 -:108D600019B10189914200D90A462280C188121D99 -:108D700090B26A460AF098F8BDF80000022800D3C5 -:108D80000220C1B2208801F006F8401CC0B238BDF4 -:108D90002DE9FF5F82468B46F74814460BF103022C -:108DA000D0E90110CDE9021022F0030201A84FF42E -:108DB000907101920AF097FEF04E002C02D1F0491A -:108DC000019A8A60019901440191B57F05F101057D -:108DD00004D1E8B20CF098FD00B1FFDF019800EB80 -:108DE0000510C01C20F0030101915CB9707AB27AC1 -:108DF0001044C2B200200870B08C80B204F03DFF75 -:108E000000B1FFDF0198716A08440190214601A872 -:108E100000F084FF80460198C01C20F00300019000 -:108E2000B37AF27A717A04B100200AF052FF019904 -:108E300008440190214601A800F0B8FFCF48002760 -:108E40003D4690F801900CE0284600F04AFF0646A7 -:108E500081788088F9F7E8F871786D1C00FB01775C -:108E6000EDB24D45F0D10198C01C20F003000190F7 -:108E700004B100203946F9F7E2F8019900270844C7 -:108E80000190BE483D4690F801900CE0284600F065 -:108E900028FF0646C1788088FEF71BFC71786D1CA0 -:108EA00000FB0177EDB24D45F0D10198C01C20F0D8 -:108EB0000300019004B100203946FEF713FC01992C -:108EC0004FF0000908440190AC484D4647780EE049 -:108ED000284600F006FF0646807B30B106F1080008 -:108EE00002F09CF9727800FB02996D1CEDB2BD4254 -:108EF000EED10198C01C20F00300019004B10020C5 -:108F00009F494A78494602F08DF901990844019039 -:108F1000214601A800F0B8FE0198C01D20F007000E -:108F20000190DAF80010814204D3A0EB0B01B1F5F7 -:108F3000803F04DB4FF00408CAF8000004E0CAF8E0 -:108F40000000B8F1000F03D0404604B0BDE8F09F28 -:108F500084BB8C490020019A0EF044FEFBF714FA02 -:108F6000864C207F0090607F012825D0002328B305 -:108F70000022824800211030F8F73AFA00B1FFDFF2 -:108F80007E49E07F2031FEF759FF00B1FFDF7B48CB -:108F90004FF4F6720021443005F079FA7748042145 -:108FA000443080F8E91180F8EA11062180F8EB11CD -:108FB000032101710020C8E70123D8E702AAD8E7FE -:108FC00070B56E4C06464434207804EB4015E078CA -:108FD000083598B9A01990F8E80100280FD0A078BA -:108FE0000F2800D3FFDF20220021284605F04FFA8A -:108FF000687866F3020068700120E070284670BD52 -:109000002DE9F04105460C460027007805219046E1 -:109010003E46B1EB101F00D0FFDF287A50B1012887 -:109020000ED0FFDFA8F800600CB12780668000201A -:10903000BDE8F0810127092674B16888A08008E0A6 -:109040000227142644B16888A0802869E060A88AB5 -:109050002082287B2072E5E7A8F80060E7E730B5BA -:10906000464C012000212070617020726072032242 -:10907000A272E07261772177217321740521218327 -:109080001F216183607440A161610A21A177E077AB -:1090900039483B4DB0F801102184C07884F8220093 -:1090A0004FF4B06060626868C11C21F00301814226 -:1090B00000D0FFDF6868606030BD30B5304C1568A7 -:1090C000636810339D4202D20420136030BD2B4BE5 -:1090D0005D785A6802EB0512107051700320D08041 -:1090E000172090800120D0709070002090735878E5 -:1090F000401C5870606810306060002030BD70B552 -:1091000006461E480024457807E0204600F0E9FDA9 -:109110000178B14204D0641CE4B2AC42F5D1002025 -:1091200070BDF7B5074608780C4610B3FFF7E7FFA8 -:109130000546A7F12006202F06D0052E19D2DFE81C -:1091400006F00F383815270000F0D6FD0DB169780C -:1091500000E00021401AA17880B20844FF2808D816 -:10916000A07830B1A088022831D202E060881728A8 -:109170002DD20720FEBD000030610200B0030020A8 -:109180001C000020000000206E52463578000000D0 -:10919000207AE0B161881729EBD3A1881729E8D399 -:1091A000A1790029E5D0E1790029E2D0402804D94D -:1091B000DFE7242F0BD1207A48B161884FF6FB708E -:1091C000814202D8A188814201D90420D2E765B941 -:1091D000207802AA0121FFF770FF0028CAD1207869 -:1091E000FFF78DFF050000D1FFDF052E18D2DFE865 -:1091F00006F0030B0E081100A0786870A088E880C4 -:109200000FE06088A8800CE0A078A87009E0A07842 -:10921000E87006E054F8020FA8606068E86000E0BB -:10922000FFDF0020A6E71A2835D00DDC132832D244 -:10923000DFE800F01B31203131272723252D313184 -:1092400029313131312F0F00302802D003DC1E28A4 -:1092500021D1072070473A3809281CD2DFE800F0F6 -:10926000151B0F1B1B1B1B1B07000020704743F225 -:109270000400704743F202007047042070470D203D -:1092800070470F2070470820704711207047132047 -:109290007047062070470320704710B5007800F033 -:1092A000010009F0F3FDBDE81040BCE710B50078FF -:1092B00000F0010009F0F3FDBDE81040B3E70EB582 -:1092C000017801F001018DF80010417801F00101F1 -:1092D0008DF801100178C1F340018DF8021041783A -:1092E000C1F340018DF80310017889088DF804104E -:1092F000417889088DF8051081788DF80610C178BD -:109300008DF8071000798DF80800684608F0FDFD1B -:10931000FFF789FF0EBD2DE9FC5FDFF8F883FE4CF7 -:1093200000264FF490771FE0012000F082FD01201D -:10933000FFF746FE05463946D8F808000AF0F1FB6B -:10934000686000B9FFDF686808F0AAFCB0B1284681 -:10935000FAF75EFB284600F072FD28B93A466968C4 -:10936000D8F808000AF008FC94F9E9010428DBDACF -:1093700002200AF043FD07460025AAE03A46696844 -:10938000D8F808000AF0F8FBF2E7B8F802104046F7 -:10939000491C89B2A8F80210B94201D300214180CA -:1093A0000221B8F802000AF081FD002866D0B8F862 -:1093B0000200694609F0CFFCFFF735FF00B1FFDF7F -:1093C0009DF80000019078B1B8F802000AF0B1FEF3 -:1093D0005FEA000900D1FFDF48460AF020F918B122 -:1093E000B8F8020002F0E4F9B8F802000AF08FFEC3 -:1093F0005FEA000900D1FFDF48460AF008F9E8BB40 -:109400000321B8F802000AF051FD5FEA000B4BD1CE -:10941000FFDF49E0DBF8100010B10078FF284DD0E5 -:10942000022000F006FD0220FFF7CAFD82464846F2 -:109430000AF0F9F9CAF8040000B9FFDFDAF804000D -:109440000AF0C1FA002100900170B8F802105046ED -:10945000AAF8021002F0B2F848460AF0B6FA00B9CB -:10946000FFDF019800B10126504600F0E8FC18B972 -:109470009AF80100000705D5009800E027E0CBF836 -:10948000100011E0DBF8101039B10878401C10F022 -:10949000FF00087008D1FFDF06E0002211464846B1 -:1094A00000F0F0FB00B9FFDF94F9EA01022805DBC8 -:1094B000B8F8020002F049F80028ABD194F9E901AC -:1094C000042804DB48460AF0E4FA00B101266D1CCA -:1094D000EDB2BD4204D294F9EA010228BFF655AFBD -:1094E000002E7FF41DAFBDE8FC5F032000F0A1BC9F -:1094F00010B5884CE06008682061AFF2E510F9F71C -:10950000E4FC607010BD844800214438017081483B -:10951000017082494160704770B505464FF0805038 -:109520000C46D0F8A410491C05D1D0F8A810C943A6 -:109530000904090C0BD050F8A01F01F0010129709B -:10954000416821608068A080287830B970BD06210C -:1095500020460DF0CCFF01202870607940F0C0005B -:10956000607170BD70B54FF080540D46D4F8801016 -:10957000491C0BD1D4F88410491C07D1D4F88810A9 -:10958000491C03D1D4F88C10491C0CD0D4F880109D -:109590000160D4F884104160D4F888108160D4F858 -:1095A0008C10C16002E010210DF0A1FFD4F89000F2 -:1095B000401C0BD1D4F89400401C07D1D4F898007B -:1095C000401C03D1D4F89C00401C09D054F8900FE3 -:1095D000286060686860A068A860E068E86070BDA6 -:1095E0002846BDE8704010210DF081BF4A4800793F -:1095F000E6E470B5484CE07830B3207804EB4010D6 -:10960000407A00F00700204490F9E801002800DCCF -:10961000FFDF2078002504EB4010407A00F00700BF -:10962000011991F8E801401E81F8E8012078401CFA -:10963000C0B220700F2800D12570A078401CA07007 -:109640000DF0D4FDE57070BDFFDF70BD3EB5054681 -:1096500003210AF02BFC044628460AF058FD054673 -:1096600004B9FFDF206918B10078FF2800D1FFDFBF -:1096700001AA6946284600F005FB60B9FFDF0AE051 -:10968000002202A9284600F0FDFA00B9FFDF9DF88C -:10969000080000B1FFDF9DF80000411E8DF80010AA -:1096A000EED220690199884201D1002020613EBD9F -:1096B00070B50546A0F57F400C46FF3800D1FFDFAE -:1096C000012C01D0FFDF70BDFFF790FF040000D137 -:1096D000FFDF207820F00F00401D20F0F000503018 -:1096E000207065800020207201202073BDE870404A -:1096F0007FE72DE9F04116460D460746FFF776FF56 -:10970000040000D1FFDF207820F00F00401D20F082 -:10971000F00005E01C000020F403002048140020A5 -:109720005030207067800120207228682061A8884E -:10973000A0822673BDE8F0415BE77FB5FFF7DFFC51 -:10974000040000D1FFDF02A92046FFF7EBFA05462F -:1097500003A92046FFF700FB8DF800508DF80100AB -:10976000BDF80800001DADF80200BDF80C00001D9A -:10977000ADF80400E088ADF80600684609F070FB1B -:10978000002800D0FFDF7FBD2DE9F05FFC4E814651 -:10979000307810B10820BDE8F09F4846F7F77FFD0C -:1097A00008B11020F7E7F74C207808B9FFF757FC0D -:1097B000A17A607A4D460844C4B200F09DFAA042F6 -:1097C00007D2201AC1B22A460020FFF776FC0028F3 -:1097D000E1D17168EB48C91C002721F003017160D9 -:1097E000B3463E463D46BA463C4690F801800AE004 -:1097F000204600F076FA4178807B0E4410FB01553C -:10980000641CE4B27F1C4445F2D10AEB870000EBF4 -:10981000C600DC4E00EB85005C46F17A012200EBCD -:109820008100DBF80410451829464846FFF7B0FAD6 -:10983000070012D00020FFF762FC05000BD005F1F5 -:109840001300616820F00300884200D0FFDF7078C9 -:10985000401E7070656038469DE7002229464846E4 -:10986000FFF796FA00B1FFDFD9F8000060604FF60D -:10987000FF7060800120207000208CE72DE9F0410E -:109880000446BF4817460D46007810B10820BDE8D1 -:10989000F0810846F7F7DDFC08B11020F7E7B94E74 -:1098A000307808B9FFF7DBFB601E1E2807D8012CB3 -:1098B00023D12878FE2820D8B0770020E7E7A4F14C -:1098C00020001F2805D8E0B23A462946BDE8F041FD -:1098D00027E4A4F140001F2805D829462046BDE80A -:1098E000F04100F0D4BAA4F1A0001F2805D8294601 -:1098F0002046BDE8F04100F006BB0720C7E72DE990 -:10990000F05F81460F460846F7F7C9FC48B948465C -:10991000F7F7E3FC28B909F1030020F003014945FA -:1099200001D0102037E797484FF0000B4430817882 -:1099300069B14178804600EB411408343E883A46CC -:109940000021204600F089FA050004D027E0A7F89E -:1099500000B005201FE7B9F1000F24D03888B042CD -:1099600001D90C251FE0607800F00700824600F066 -:1099700060FA08EB0A063A4696F8E8014946401CA8 -:1099800086F8E801204600F068FA054696F8E801F6 -:10999000401E86F8E801032000F04BFA2DB10C2D93 -:1099A00001D0A7F800B02846F5E6754F5046BAF149 -:1099B000010F25D002280DD0BAF1030F35D0FFDFFB -:1099C00098F801104046491CC9B288F801100F29C7 -:1099D00037D038E0606828B16078000702D460882A -:1099E000FFF734FE98F8EA014446012802D178785E -:1099F000F9F78AFA94F9EA010428E1DBFFDFDFE7EF -:109A0000616821B14FF49072B8680AF0B5F898F81F -:109A1000E9014446032802D17878F9F775FA94F9F8 -:109A2000E9010428CCDBFFDFCAE76078C00602D575 -:109A30006088FFF70BFE98F9EB010628C0DBFFDF1B -:109A4000BEE780F801B08178491E88F8021096F8C8 -:109A5000E801401C86F8E801A5E770B50C4605460C -:109A6000F7F7F7FB18B92046F7F719FC08B11020F3 -:109A700070BD28460BF07FFF207008B1002070BD3C -:109A8000042070BD70B505460BF08EFFC4B22846A9 -:109A9000F7F723FC08B1102070BD35B128782C7081 -:109AA00018B1A04201D0072070BD2046FDF77EFE10 -:109AB000052805D10BF07BFF012801D0002070BDE7 -:109AC0000F2070BD70B5044615460E460846F7F7E0 -:109AD000C0FB18B92846F7F7E2FB08B1102070BDAB -:109AE000022C03D0102C01D0092070BD2A4631462B -:109AF00020460BF086FF0028F7D0052070BD70B51A -:109B000014460D460646F7F7A4FB38B92846F7F782 -:109B1000C6FB18B92046F7F7E0FB08B1102070BD6E -:109B20002246294630460BF06EFF0028F7D007206A -:109B300070BD3EB50446F7F7B2FB08B110203EBD3C -:109B4000684608F053F9FFF76EFB0028F7D19DF83F -:109B500006002070BDF808006080BDF80A00A080F3 -:109B600000203EBD70B505460C460846F7F7B5FB2C -:109B700020B95CB12068F7F792FB28B1102070BDC6 -:109B80001C000020B0030020A08828B121462846F0 -:109B9000BDE87040FDF762BE0920F0E770B50546EC -:109BA0000C460846F7F755FBA0BB681E1E280ED8CA -:109BB000032D01D90720E2E705B9FFDFFE4800EBDE -:109BC000850050F8041C2046BDE870400847A5F108 -:109BD00020001F2805D821462846BDE87040FAF726 -:109BE00042BBA5F160001F2805D821462846BDE8E4 -:109BF0007040F8F7DABCF02D0DD0F12D15D0BF2D47 -:109C0000D8D1A078218800F0010001F08DFB98B137 -:109C10000020B4E703E0A068F7F71BFB08B11020B1 -:109C2000ADE7204609F081F902E0207809F0A0F9BB -:109C3000BDE87040FFF7F7BA0820A0E770B504460A -:109C40000D460846F7F72BFB30B9601E1E280FD8CB -:109C50002846F7F7FEFA08B1102090E7012C03D050 -:109C6000022C01D0032C01D1062088E7072086E7CB -:109C7000A4F120001F28F9D829462046BDE87040ED -:109C8000FAF762BB09F092BC38B50446CB48007BBA -:109C900000F00105F9B904F01DFC0DB1226800E0E7 -:109CA0000022C7484178C06807F06DFDC4481030F5 -:109CB000C0788DF8000010B1012802D004E0012026 -:109CC00000E000208DF80000684608F0FFF8BA4870 -:109CD000243808F0B5FE002D02D02068283020601E -:109CE00038BD30B5B54D04466878A04200D8FFDFD6 -:109CF000686800EB041030BD70B5B04800252C46F4 -:109D0000467807E02046FFF7ECFF4078641C2844C3 -:109D1000C5B2E4B2B442F5D1284630E72DE9F041AE -:109D20000C4607464FF0000800F01FF90646FF28D2 -:109D300001D94FF013083868C01C20F003023A60C4 -:109D400054EA080421D19D48F3B2072128300DF0D0 -:109D5000DBFD09E0072C10D2DFE804F00604080858 -:109D60000A040600974804E0974802E0974800E09C -:109D700097480DF0E9FD054600E0FFDFA54200D061 -:109D8000FFDF641CE4B2072CE4D3386800EB061054 -:109D9000386040467BE5021D5143452900D24521EC -:109DA0000844C01CB0FBF2F0C0B270472DE9FC5F64 -:109DB000064682484FF000088B464746444690F8D6 -:109DC000019022E02046FFF78CFF050000D1FFDF65 -:109DD000687869463844C7B22846FEF7A3FF824632 -:109DE00001A92846FEF7B8FF0346BDF80400524615 -:109DF000001D81B2BDF80000001D80B20AF0D4F849 -:109E00006A78641C00FB0288E4B24C45DAD1306801 -:109E1000C01C20F003003060BBF1000F00D0002018 -:109E2000424639460AF0CEF8316808443060BDE851 -:109E3000FC9F6249443108710020C87070475F4937 -:109E40004431CA782AB10A7801EB421108318142C3 -:109E500001D001207047002070472DE9F0410646EF -:109E60000078154600F00F0400201080601E0F4699 -:109E7000052800D3FFDF50482A46183800EB84003D -:109E8000394650F8043C3046BDE8F04118472DE90A -:109E9000F0414A4E0C46402806D0412823D04228A3 -:109EA0002BD0432806D123E0A07861780D18E17803 -:109EB000814201D90720EAE42078012801D9132042 -:109EC000E5E4FF2D08D80BF009FF07460DF046F931 -:109ED000381A801EA84201DA1220D8E42068B06047 -:109EE000207930730DE0BDE8F041084600F078B805 -:109EF00008780228DED8307703E008780228D9D81D -:109F000070770020C3E4F8B500242C4DA02805D0BC -:109F1000A12815D0A22806D00720F8BD087800F0A7 -:109F20000100E8771FE00E4669463046FDF73DFD2B -:109F30000028F2D130882884B07885F8220012E019 -:109F400008680921F82801D3820701D00846F8BD26 -:109F50006A7C02F00302012A04D16A8BD73293B2E1 -:109F60008342F3D868622046F8BD2DE9F047DFF858 -:109F70004C900026344699F8090099F80A2099F87F -:109F800001700244D5B299F80B20104400F0FF088C -:109F900008E02046FFF7A5FE817B407811FB0066B4 -:109FA000641CE4B2BC42F4D199F8091099F80A0093 -:109FB0002944294441440DE054610200B0030020CB -:109FC0001C0000206741000045B30000DD2F0000A9 -:109FD000FB56010000B1012008443044BDE8F08781 -:109FE00038B50446407800F00300012803D0022869 -:109FF0000BD0072038BD606858B1F7F777F9D0B9B2 -:10A000006068F7F76AF920B915E06068F7F721F999 -:10A0100088B969462046FCF729F80028EAD160781B -:10A0200000F00300022808D19DF8000028B1606804 -:10A03000F7F753F908B1102038BD6189F8290DD818 -:10A04000208988420AD8607800F003020A48012A71 -:10A0500006D1D731426A89B28A4201D2092038BD7D -:10A0600094E80E0000F1100585E80E000AB9002101 -:10A070000183002038BD0000B00300202DE9F0412D -:10A08000074614468846084601F08AFD064608EB56 -:10A0900088001C22796802EBC0000D18688C58B14A -:10A0A0004146384601F08BFD014678680078C200D1 -:10A0B000082305F120000CE0E88CA8B141463846A1 -:10A0C00001F084FD0146786808234078C20005F15C -:10A0D000240009F0A8FD38B1062121726681D0E97B -:10A0E0000010C4E9031009E0287809280BD00520E6 -:10A0F000207266816868E060002028702046BDE814 -:10A10000F04101F02EBD072020726681F4E72DE9B1 -:10A11000F04116460D460746406801EB85011C22BA -:10A1200002EBC1014418204601F072FD40B100214C -:10A13000708865F30F2160F31F4106200DF0BEFC0F -:10A1400009202070324629463846BDE8F04195E79F -:10A150002DE9F0410E46074600241C21F07816E058 -:10A1600004EB8403726801EBC303D25C6AB1FFF7AE -:10A170003DFA050000D1FFDF6F802A4621463046B8 -:10A18000FFF7C5FF0120BDE8F081641CE4B2A042E6 -:10A19000E6D80020F7E770B5064600241C21C078F9 -:10A1A0000AE000BF04EB8403726801EBC303D51817 -:10A1B0002A782AB1641CE4B2A042F3D8402070BDD2 -:10A1C00028220021284604F062F9706880892881DD -:10A1D000204670BD70B5034600201C25DC780CE0DD -:10A1E00000EB80065A6805EBC6063244167816B1B5 -:10A1F000128A8A4204D0401CC0B28442F0D8402067 -:10A2000070BDF0B5044600201C26E5780EE000BFC6 -:10A2100000EB8007636806EBC7073B441F788F425B -:10A2200002D15B78934204D0401CC0B28542EFD883 -:10A230004020F0BD0078032801D0002070470120A5 -:10A2400070470078022801D0002070470120704735 -:10A250000078072801D000207047012070472DE9C1 -:10A26000F041064688461078F1781546884200D3BA -:10A27000FFDF2C781C27641CF078E4B2A04201D8E0 -:10A28000201AC4B204EB8401706807EBC1010844D2 -:10A29000017821B14146884708B12C7073E72878CE -:10A2A000A042E8D1402028706DE770B514460B88B5 -:10A2B0000122A240134207D113430B8001230A223B -:10A2C000011D09F07AFC047070BD2DE9FF4F81B0CB -:10A2D0000878DDE90E7B9A4691460E4640072CD45D -:10A2E000019809F026FF040000D1FFDF07F1040800 -:10A2F00020461FFA88F109F065F8050000D1FFDF5C -:10A30000204629466A4609F0B0FA0098A0F8037082 -:10A31000A0F805A0284609F056FB017869F306016C -:10A320006BF3C711017020461FFA88F109F08DF810 -:10A3300000B9FFDF019807F094F906EB0900017FEF -:10A34000491C017705B0BDE8F08F2DE9F84F0E46A6 -:10A350009A4691460746032109F0A8FD0446008D60 -:10A36000DFF8B885002518B198F80000B0421ED17A -:10A37000384609F0DEFE070000D1FFDF09F10401D5 -:10A38000384689B209F01EF8050010D03846294633 -:10A390006A4609F06AFA009800210A460180817035 -:10A3A00007F01CFA0098C01DCAF8000021E098F8D8 -:10A3B0000000B04216D104F1260734F8341F012002 -:10A3C00000FA06F911EA090F00D0FFDF2088012307 -:10A3D00040EA090020800A22391D384609F008FCAD -:10A3E000067006E0324604F1340104F12600FFF75E -:10A3F0005CFF0A2188F800102846BDE8F88FFEB5FA -:10A4000015460C46064602AB0C220621FFF79DFFBF -:10A41000002827D00299607812220A70801C4870A8 -:10A4200008224A80A07002982988052381806988C3 -:10A43000C180A9880181E988418100250C20CDE9EE -:10A440000005062221463046FFF73FFF294600223D -:10A4500066F31F41F02310460DF086FA6078801CE9 -:10A4600060700120FEBDFEB514460D46062206466C -:10A4700002AB1146FFF769FF002812D0029B1320A0 -:10A4800000211870A8785870022058809C800620FF -:10A49000CDE900010246052329463046FFF715FFA6 -:10A4A0000120FEBD2DE9FE430C46804644E002AB90 -:10A4B0000E2207214046FFF748FF002841D0606880 -:10A4C0001C2267788678BF1C06EB860102EBC1016F -:10A4D000451802981421017047700A214180698A49 -:10A4E0000181E98A4181A9888180A98981813046D9 -:10A4F00001F056FB029905230722C8806F700420E3 -:10A50000287000250E20CDE9000521464046FFF7C2 -:10A51000DCFE294666F30F2168F31F41F023002279 -:10A5200006200DF021FA6078FD49801C6070626899 -:10A530002046921CFFF793FE606880784028B6D1D1 -:10A540000120BDE8FE83FEB50D46064638E002ABAD -:10A550000E2207213046FFF7F8FE002835D0686844 -:10A560001C23C17801EB810203EBC202841802981C -:10A5700015220270627842700A224280A2894281CA -:10A58000A2888281084601F00BFB01460298818077 -:10A59000618AC180E18A0181A088B8B10020207061 -:10A5A00000210E20CDE9000105230722294630466F -:10A5B000FFF78BFE6A68DB492846D21CFFF74FFE87 -:10A5C0006868C0784028C2D10120FEBD0620E6E7B9 -:10A5D0002DE9FE430C46814644E0204601F002FB93 -:10A5E000D0B302AB082207214846FFF7AEFE002891 -:10A5F000A7D060681C2265780679AD1C06EB860141 -:10A6000002EBC10147180298B7F8108006210170CB -:10A61000457004214180304601F0C2FA014602989B -:10A6200005230722C180A0F804807D7008203870BF -:10A630000025CDE9000521464846FFF746FE29469C -:10A6400066F30F2169F31F41F023002206200DF06D -:10A650008BF96078801C60706268B3492046121DD7 -:10A66000FFF7FDFD606801794029B6D1012068E758 -:10A670002DE9F34F83B00D4691E0284601F0B2FA80 -:10A6800000287DD068681C2290F806A00AEB8A0199 -:10A6900002EBC10144185146284601F097FAA1780F -:10A6A000CB0069684978CA00014604F1240009F02A -:10A6B000D6FA07468188E08B4FF00009091A8EB25E -:10A6C00008B1C84607E04FF00108504601F053FAC0 -:10A6D00008B9B61CB6B2208BB04200D80646B346C5 -:10A6E00002AB324607210398FFF72FFE060007D082 -:10A6F000B8F1000F0BD0504601F03DFA10B106E062 -:10A7000000201FE60299B8884FF0020908800196E0 -:10A71000E28B3968ABEB09001FFA80F80A44039812 -:10A720004E46009209F005FDDDE90021F61D434685 -:10A73000009609F014F9E08B404480B2E083B988B8 -:10A74000884201D1012600E00026CDE900B6238A27 -:10A75000072229460398FFF7B8FD504601F00BFA8F -:10A7600010B9E089401EE08156B1A078401CA0706D -:10A770006868E978427811FB02F1CAB2012300E06F -:10A7800007E081690E3009F018FA80F800A0002077 -:10A79000E0836A6865492846921DFFF760FD686896 -:10A7A000817940297FF469AF0120CBE570B5064679 -:10A7B00048680D4614468179402910D104EB840184 -:10A7C0001C2202EBC101084401F043FA002806D024 -:10A7D0006868294684713046BDE8704048E770BD1E -:10A7E000FEB50C460746002645E0204601F0FAF982 -:10A7F000D8B360681C22417901EB810102EBC101F1 -:10A800004518688900B9FFDF02AB082207213846E6 -:10A81000FFF79BFD002833D00299607816220A705A -:10A82000801C4870042048806068407901F0B8F9C5 -:10A83000014602980523072281806989C18008208A -:10A84000CDE9000621463846FFF73FFD6078801CC1 -:10A850006070A88969890844B0F5803F00D3FFDFA4 -:10A86000A88969890844A8816E81626830492046B8 -:10A87000521DFFF7F4FC606841794029B5D10120F1 -:10A88000FEBD30B5438C458BC3F3C704002345B1EF -:10A89000838B641EED1AC38A6D1E1D4495FBF3F372 -:10A8A000E4B22CB1008918B1A04200D8204603447C -:10A8B0004FF6FF70834200D3034613800C7030BD07 -:10A8C0002DE9FC41074616460D46486802EB860115 -:10A8D0001C2202EBC10144186A4601A92046FFF779 -:10A8E000D0FFA089618901448AB2BDF8001091426D -:10A8F00012D0081A00D5002060816868407940288D -:10A900000AD1204601F09BF9002805D06868294645 -:10A9100046713846FFF764FFBDE8FC813000002037 -:10A9200035A2000043A2000051A2000053BC000069 -:10A930003FBC00002DE9FE4F0F468146154650886A -:10A94000032109F0B3FA0190B9F8020001F01BF9F4 -:10A9500082460146019801F045F9002824D001986B -:10A960001C2241680AEB8A0002EBC0000C1820464A -:10A9700001F04EF9002817D1B9F80000E18A8842A9 -:10A980000ED8A18961B1B8420ED100265146019876 -:10A9900001F015F9218C01EB0008608B30B114E057 -:10A9A000504601F0E8F8A0B3BDE8FE8F504601F034 -:10A9B000E2F808B1678308E0022FF5D3B9F8040084 -:10A9C0006083618A884224D80226B81B87B2B8F80F -:10A9D0000400A28B801A002814DD874200DA384672 -:10A9E0001FFA80FB688869680291D8F800100A4451 -:10A9F000009209F08CFBF61D009A5B4602990096C6 -:10AA000008F079FFA08B384480B2A083618B884224 -:10AA100007D96888019903B05246BDE8F04F01F0AC -:10AA200035B91FD14FF009002872B9F802006881CA -:10AA3000D8E90010C5E90410608BA881284601F010 -:10AA400090F85146019801F0BAF8014601980823A0 -:10AA500040680078C20004F1200009F0E4F800200A -:10AA6000A0836083504601F086F810B9A089401E8B -:10AA7000A0816888019903B00AF0FF02BDE8F04F99 -:10AA80001EE72DE9F041064615460F461C461846BE -:10AA9000F6F7DFFB18B92068F6F701FC10B11020BB -:10AAA000BDE8F0817168688C0978B0EBC10F01D303 -:10AAB0001320F5E73946304601F081F80146706809 -:10AAC00008230078C20005F1200009F076F8D4E9E7 -:10AAD0000012C0E900120020E2E710B5044603218D -:10AAE00009F0E4F90146007800F00300022805D0DF -:10AAF0002046BDE8104001F1140280E48A8A204615 -:10AB0000BDE81040AFE470B50446032109F0CEF96A -:10AB1000054601462046FFF75BFD002816D0294672 -:10AB20002046FFF75DFE002810D029462046FFF79B -:10AB30000AFD00280AD029462046FFF7B3FC00286A -:10AB400004D029462046BDE8704091E570BD2DE94E -:10AB5000F0410C4680461EE0E178427811FB02F19C -:10AB6000CAB2816901230E3009F05DF80778606888 -:10AB70001C22C179491EC17107EB8701606802EB95 -:10AB8000C10146183946204601F02CF818B130466C -:10AB900001F037F820B16068C1790029DCD17FE786 -:10ABA000FEF724FD050000D1FFDF0A202872384699 -:10ABB00000F0F6FF68813946204601F007F80146AB -:10ABC000606808234078C20006F1240009F02BF8E1 -:10ABD000D0E90010C5E90310A5F80280284600F06E -:10ABE000C0FFB07800B9FFDFB078401EB07057E703 -:10ABF00070B50C460546032109F058F90146406836 -:10AC0000C2792244C2712846BDE870409FE72DE911 -:10AC1000FE4F8246507814460F464FF00008002839 -:10AC20004FD0012807D0022822D0FFDF2068B8606B -:10AC30006068F860B8E602AB0E2208215046FFF7C4 -:10AC400084FB0028F2D00298152105230170217899 -:10AC500041700A214180C0F80480C0F80880A0F843 -:10AC60000C80628882810E20CDE90008082221E054 -:10AC7000A678304600F094FF054606EB86012C22AC -:10AC8000786802EBC1010822465A02AB11465046D1 -:10AC9000FFF75BFB0028C9D00298072101702178DB -:10ACA00041700421418008218580C680CDE90018CB -:10ACB00005230A4639465046FFF707FB87F8088008 -:10ACC00072E6A678022516B1022E13D0FFDF2A1DE8 -:10ACD000914602AB08215046FFF737FB0028A5D06C -:10ACE00002980121022E01702178417045808680F2 -:10ACF00002D005E00625EAE7A188C180E18801814C -:10AD0000CDE900980523082239465046D4E710B50E -:10AD10000446032109F0CAF8014600F10802204662 -:10AD2000BDE8104073E72DE9F04F0F4605468DB0A2 -:10AD300014465088032109F0B9F84FF000088DF847 -:10AD400014800646ADF81680042F7BD36A78002A5B -:10AD500078D028784FF6FF794FF01C0A132834D0AA -:10AD600008DC012871D006284AD007286ED01228A6 -:10AD70000ED106E014286AD0152869D0162807D10C -:10AD8000AAE10C2F04D1307800F00301022907D08A -:10AD9000CDF80880CDF80C8068788DF808004CE07C -:10ADA00040F0080030706878B07001208DF8140011 -:10ADB000A888ADF81800E888ADF81A002889ADF821 -:10ADC0001C006889ADF81E0011E1B078904239D1BD -:10ADD0003078010736D5062F34D120F008003070C6 -:10ADE0006088414660F31F4100200CF067FE02209E -:10ADF0008DF81400ADF81890A888ADF81A00F6E0A8 -:10AE0000082F1FD1A888EF88814600F0BCFE80463D -:10AE10000146304600F0E6FE18B1404600F0ABFEB9 -:10AE2000B8B1FC48D0E90010CDE902106878ADF85F -:10AE30000C908DF80800ADF80E70608802AA3146BB -:10AE4000FFF7E5FE0DB0BDE8F08FB6E01EE041E093 -:10AE5000ECE0716808EB88002C2202EBC000085A75 -:10AE6000B842EFD1EB4802AAD0E90210CDE90210B6 -:10AE700068788DF8080008F0FF058DF80A506088A2 -:10AE80003146FFF7C4FE224629461FE0082FD9D1DC -:10AE9000B5F80480E88800F076FE074601463046A3 -:10AEA00000F0A0FE0028CDD007EB870271680AEB06 -:10AEB000C2000844028A4245C4D101780829C1D1A0 -:10AEC000407869788842BDD1F9B222463046FFF712 -:10AED0001EF9B7E70E2F7FF45BAFE9886F898B46C9 -:10AEE000B5F808903046FFF775F9ABF140014029FD -:10AEF00001D309204AE0B9F1170F01D3172F01D26E -:10AF00000B2043E040280ED000EB800271680AEB72 -:10AF1000C20008440178012903D140786978884249 -:10AF200090D00A2032E03046FFF735F9014640283C -:10AF30002BD001EB810372680AEBC30002EB00081F -:10AF4000012288F800206A7888F801207068AA88B1 -:10AF50004089B84200D93846AD8903232372A282C2 -:10AF6000E7812082A4F80C906582084600F018FE64 -:10AF70006081A8F81490A8F81870A8F80E50A8F8E6 -:10AF800010B0204600F0EDFD5CE7042005212172A1 -:10AF9000A4F80A80E081012121739E49D1E90421AE -:10AFA000CDE9022169788DF80810ADF80A006088B3 -:10AFB00002AA3146FFF72BFEE3E7062F89D3B078CC -:10AFC00090421AD13078010717D520F00800307070 -:10AFD0006088414660F31F4100200CF06FFD0220A5 -:10AFE0008DF81400A888ADF81800ADF81A906088A4 -:10AFF000224605A9F9F7E3F824E704213046FFF7D4 -:10B0000000F905464028BFD0022083030090224665 -:10B010002946304600F003FE4146608865F30F2163 -:10B0200060F31F4106200CF049FD0BE70E2FABD15A -:10B0300004213046FFF7E5F881464028A4D0414678 -:10B04000608869F30F2160F31F4106200CF036FD84 -:10B05000A8890B906889099070682F894089B84247 -:10B0600000D938468346B5F80680A8880A90484635 -:10B0700000F096FD60810B9818B1022000900B9BA8 -:10B0800024E0B8F1170F1ED3172F1CD30420207211 -:10B0900009986082E781A4F810B0A4F80C8009EB4D -:10B0A000890271680AEBC2000D18DDE90913A5F8E1 -:10B0B0001480A5F818B0E9812B82204600F051FDDC -:10B0C00006202870BEE601200B2300902246494648 -:10B0D000304600F0A4FDB5E6082F8DD1A988304692 -:10B0E000FFF778F80746402886D000F044FD002896 -:10B0F0009BD107EB870271680AEBC20008448046C7 -:10B1000000F086FD002890D1ED88B8F80E002844A4 -:10B11000B0F5803F05D360883A46314600F0B6FD71 -:10B1200090E6002DCED0A8F80E0060883A46314651 -:10B13000FFF73CFB08202072384600F031FD6081AB -:10B14000A5811EE72DE9F05F0C4601281FD09579F7 -:10B1500092F8048092F8056005EB85011F2202EB4E -:10B16000C10121F0030B08EB060111FB05F14FF6BD -:10B17000FF7202EAC10909F1030115FB0611264F0E -:10B1800021F0031ABB6840B101283ED125E0616877 -:10B19000E57891F800804E78DEE75946184608F0C9 -:10B1A000C0FC606000B9FFDF5A460021606803F010 -:10B1B0006EF9E5705146B86808F0B3FC6168486103 -:10B1C00000B9FFDF6068426902EB090181616068D4 -:10B1D00080F800806068467017E0606852464169F8 -:10B1E000184608F0C9FC5A466168B86808F0C4FC03 -:10B1F000032008F003FE0446032008F007FE201A8F -:10B20000012802D1B86808F081FC0BEB0A00BDE808 -:10B21000F09F000060610200300000200246002123 -:10B2200002208FE7F7B5FF4C0A20164620700098E1 -:10B2300060B100254FEA0D0008F055FC0021A17017 -:10B240006670002D01D10099A160FEBD012500208E -:10B25000F2E770B50C46154638220021204603F06F -:10B2600016F9012666700A22002104F11C0003F081 -:10B270000EF905B9FFDF297A207861F3010020700B -:10B28000A87900282DD02A4621460020FFF75AFF32 -:10B2900061684020E34A88706168C870616808711D -:10B2A000616848716168887161682888088161688F -:10B2B00068884881606886819078002811D061682C -:10B2C0000620087761682888C885616828884886CC -:10B2D00060680685606869889288018681864685EF -:10B2E000828570BDC878002802D00022012029E79D -:10B2F000704770B50546002165F31F4100200CF032 -:10B30000DDFB0321284608F0D1FD040000D1FFDF5A -:10B3100021462846FEF71CFF002804D0207840F084 -:10B3200010002070012070BD70B505460C4603204A -:10B3300008F056FD08B1002070BDBA4885708480C1 -:10B34000012070BD2DE9FF4180460E460F0CFEF72F -:10B350004DF9050007D06F800321384608F0A6FD9F -:10B36000040008D106E004B03846BDE8F0411321DE -:10B37000F9F750BBFFDF5FEA080005D0B8F1060F10 -:10B3800018D0FFDFBDE8FF8120782A4620F00800B2 -:10B3900020700020ADF8020002208DF800004FF66A -:10B3A000FF70ADF80400ADF8060069463846F8F7BE -:10B3B00006FFE7E7C6F3072101EB81021C23606863 -:10B3C00003EBC202805C042803D008280AD0FFDF08 -:10B3D000D8E7012000904FF440432A46204600F071 -:10B3E0001EFCCFE704B02A462046BDE8F041FEF738 -:10B3F0008EBE2DE9F05F05464089002790460C4639 -:10B400003E46824600F0BFFB8146287AC01E0828CF -:10B410006BD2DFE800F00D04192058363C47722744 -:10B420001026002C6CD0D5E90301C4E902015CE0D0 -:10B4300070271226002C63D00A2205F10C0104F1BA -:10B44000080002F0FAFF50E071270C26002C57D0BC -:10B45000E868A06049E0742710269CB3D5E9030191 -:10B46000C4E902016888032108F020FD8346FEF745 -:10B47000BDF802466888508049465846FEF7FEFDF2 -:10B4800033E075270A26ECB1A88920812DE07627C4 -:10B490001426BCB105F10C0004F1080307C883E8C9 -:10B4A000070022E07727102664B1D5E90301C4E93B -:10B4B00002016888032108F0F9FC01466888FFF75B -:10B4C00046FB12E01CE073270826CCB168880321F4 -:10B4D00008F0ECFC01460078C00606D56888FEF747 -:10B4E00037FE10B96888F8F777FAA8F800602CB131 -:10B4F0002780A4F806A066806888A080002086E6E1 -:10B50000A8F80060FAE72DE9FC410C461E461746F4 -:10B510008046032108F0CAFC05460A2C0AD2DFE85F -:10B5200004F005050505050509090907042303E0DD -:10B53000062301E0FFDF0023CDE9007622462946FD -:10B540004046FEF7C2FEBDE8FC81F8B50546A0F511 -:10B550007F40FF382BD0284608F0D9FD040000D1E9 -:10B56000FFDF204608F05FF9002821D001466A4637 -:10B57000204608F07AF900980321B0F805602846C3 -:10B5800008F094FC0446052E13D0304600F0FBFA78 -:10B5900005460146204600F025FB40B1606805EBFA -:10B5A00085013E2202EBC101405A002800D0012053 -:10B5B000F8BD007A0028FAD00020F8BDF8B504469E -:10B5C000408808F0A4FD050000D1FFDF6A46284648 -:10B5D000616800F0C4FA01460098091F8BB230F888 -:10B5E000032F0280428842800188994205D1042AB3 -:10B5F00008D0052A20D0062A16D022461946FFF781 -:10B6000099F9F8BD001D0E46054601462246304612 -:10B61000F6F739FF0828F4D1224629463046FCF7D0 -:10B6200064F9F8BD30000020636864880A46011D93 -:10B630002046FAF789F9F4E72246001DFFF773FB6D -:10B64000EFE770B50D460646032108F02FFC040015 -:10B6500004D02078000704D5112070BD43F2020009 -:10B6600070BD2A4621463046FEF7C9FE18B9286843 -:10B6700060616868A061207840F0080020700020B8 -:10B6800070BD70B50D460646032108F00FFC04009E -:10B6900004D02078000704D4082070BD43F20200D3 -:10B6A00070BD2A4621463046FEF7DDFE00B9A58270 -:10B6B000207820F008002070002070BD2DE9F04FA8 -:10B6C0000E4691B08046032108F0F0FB0446404648 -:10B6D00008F02FFD07460020079008900990ADF86C -:10B6E00030000A9002900390049004B9FFDF0DF13E -:10B6F0000809FFB9FFDF1DE038460BA9002207F05B -:10B7000055FF9DF82C0000F07F050A2D00D3FFDFC8 -:10B710006019017F491E01779DF82C00000609D5AC -:10B720002A460CA907A8FEF7C0FD19F80510491C08 -:10B7300009F80510761EF6B2DED204F13400F84D99 -:10B7400004F1260BDFF8DCA304F12A07069010E0D1 -:10B750005846069900F08CFA064628700A2800D34D -:10B76000FFDF5AF8261040468847E08CC05DB042A3 -:10B7700002D0208D0028EBD10A202870E94D4E46DA -:10B7800028350EE00CA907A800F072FA0446375DD0 -:10B7900055F8240000B9FFDF55F82420394640460B -:10B7A0009047BDF81E000028ECD111B0BDE8F08F25 -:10B7B00010B5032108F07AFB040000D1FFDF0A2254 -:10B7C000002104F11C0002F062FE207840F0040029 -:10B7D000207010BD10B50C46032108F067FB204413 -:10B7E000007F002800D0012010BD2DE9F84F8946C8 -:10B7F00015468246032108F059FB070004D028466D -:10B80000F5F727FD40B903E043F20200BDE8F88FE9 -:10B810004846F5F744FD08B11020F7E7786828B1ED -:10B8200069880089814201D90920EFE7B9F8000051 -:10B830001C2488B100F0A7F980460146384600F084 -:10B84000D1F988B108EB8800796804EBC000085C86 -:10B8500001280BD00820D9E73846FEF79CFC80462B -:10B86000402807D11320D1E70520CFE7FDF7BEFE22 -:10B8700006000BD008EB8800796804EBC0000C18B8 -:10B88000B9F8000020B1E88910B113E01120BDE73C -:10B890002888172802D36888172801D20720B5E71F -:10B8A000686838B12B1D224641463846FFF7E9F853 -:10B8B0000028ABD104F10C0269462046FEF7E1FFF7 -:10B8C000288860826888E082B9F8000030B10220E0 -:10B8D0002070E889A080E889A0B12BE003202070C7 -:10B8E000A889A08078688178402905D180F80280F5 -:10B8F00039465046FEF7D6FD404600F051F9A9F80A -:10B90000000021E07868218B4089884200D90846F0 -:10B910002083A6F802A004203072B9F800007081DC -:10B92000E0897082F181208B3082A08AB08130461C -:10B9300000F017F97868C178402905D180F80380B4 -:10B9400039465046FEF7FFFD00205FE770B50D4613 -:10B950000646032108F0AAFA04000ED0284600F09B -:10B9600012F905460146204600F03CF918B1284678 -:10B9700000F001F920B1052070BD43F2020070BD56 -:10B9800005EB85011C22606802EBC101084400F050 -:10B990003FF908B1082070BD2A462146304600F024 -:10B9A00075F9002070BD2DE9F0410C461746804620 -:10B9B000032108F07BFA0546204600F0E4F804462F -:10B9C00095B10146284600F00DF980B104EB8401E1 -:10B9D0001C22686802EBC1014618304600F018F9D5 -:10B9E00038B10820BDE8F08143F20200FAE70520F3 -:10B9F000F8E73B46324621462846FFF742F8002842 -:10BA0000F0D1E2B229464046FEF75AFF708C083862 -:10BA1000082803D242484078F7F776FA0020E1E799 -:10BA20002DE9F0410D4617468046032108F03EFA05 -:10BA30000446284600F0A7F8064624B13846F5F734 -:10BA400008FC38B902E043F20200CBE73868F5F7AA -:10BA500000FC08B11020C5E73146204600F0C2F8CE -:10BA600060B106EB86011C22606802EBC10145183B -:10BA7000284600F0CDF818B10820B3E70520B1E75B -:10BA8000B888A98A884201D90C20ABE76168E88CA4 -:10BA90004978B0EBC10F01D31320A3E7314620460C -:10BAA00000F094F80146606808234078C20005F170 -:10BAB000240008F082F8D7E90012C0E90012F2B2BF -:10BAC00021464046FEF772FE00208BE72DE9F04745 -:10BAD0000D461F4690468146032108F0E7F90446CB -:10BAE000284600F050F806463CB14DB13846F5F70F -:10BAF000F4FB50B11020BDE8F08743F20200FAE7F2 -:10BB0000606858B1A0F80C8027E03146204600F06C -:10BB100069F818B1304600F02EF828B10520EAE7A0 -:10BB2000300000207861020006EB86011C2260686C -:10BB300002EBC1014518284600F06AF808B1082058 -:10BB4000D9E7A5F80880F2B221464846FEF7B8FECC -:10BB50001FB1A8896989084438800020CBE707F025 -:10BB600084BE017821F00F01491C21F0F001103151 -:10BB70000170FDF73EBD20B94E48807808B1012024 -:10BB80007047002070474B498988884201D10020C6 -:10BB90007047402801D2402000E0403880B2704712 -:10BBA00010B50446402800D9FFDF2046FFF7E3FF29 -:10BBB00010B14048808810BD4034A0B210BD40682C -:10BBC00042690078484302EBC0007047C278406881 -:10BBD000037812FB03F24378406901FB032100EB79 -:10BBE000C1007047C2788A4209D9406801EB8101DF -:10BBF0001C2202EBC101405C08B10120704700200B -:10BC000070470078062801D901207047002070474E -:10BC10000078062801D00120704700207047F0B45A -:10BC200001EB81061C27446807EBC6063444049DDB -:10BC300005262670E3802571F0BCFEF71FBA10B50B -:10BC4000418911B1FFF7DDFF08B1002010BD0120CF -:10BC500010BD10B5C18C8278B1EBC20F04D9C18977 -:10BC600011B1FFF7CEFF08B1002010BD012010BDBB -:10BC700010B50C4601230A22011D07F0D4FF0078FD -:10BC80002188012282409143218010BDF0B402EB53 -:10BC900082051C264C6806EBC505072363554B68D7 -:10BCA0001C79402C03D11A71F0BCFEF791BCF0BC9A -:10BCB000704700003000002010B5EFF3108000F056 -:10BCC000010472B6FC484178491C41704078012853 -:10BCD00001D10BF0B3FA002C00D162B610BD70B5E3 -:10BCE000F54CA07848B90125A570FFF7E5FF0BF0EA -:10BCF000B6FA20B100200BF080FA002070BD4FF0A2 -:10BD00008040E570C0F80453F7E770B5EFF310809A -:10BD100000F0010572B6E84C607800B9FFDF60788A -:10BD2000401E6070607808B90BF08CFA002D00D1CD -:10BD300062B670BDE04810B5817821B10021C170B4 -:10BD40008170FFF7E2FF002010BD10B504460BF034 -:10BD500086FAD9498978084000D001202060002067 -:10BD600010BD10B5FFF7A8FF0BF079FA02220123EE -:10BD7000D149540728B1D1480260236103200872D9 -:10BD800002E00A72C4F804330020887110BD2DE966 -:10BD9000F84FDFF824934278817889F80420002650 -:10BDA00089F80510074689F806600078DFF810B3B7 -:10BDB000354620B1012811D0022811D0FFDF0BF049 -:10BDC00060FA4FF0804498B10BF062FAB0420FD1A4 -:10BDD00030460BF061FA0028FAD042E00126EEE787 -:10BDE000FFF76AFF58460168C907FCD00226E6E75C -:10BDF0000120E060C4F80451B2490E600107D1F897 -:10BE00004412B04AC1F3423124321160AD49343199 -:10BE100008604FF0020AC4F804A3A060AA480168B1 -:10BE2000C94341F3001101F10108016841F010011B -:10BE3000016001E019F0A8FFD4F804010028F9D04E -:10BE400030460BF029FA0028FAD0B8F1000F04D1DF -:10BE50009D48016821F010010160C4F808A3C4F8EE -:10BE6000045199F805004E4680B1387870B90BF04E -:10BE7000F6F980460BF006FC6FF00042B8F1000FB7 -:10BE800002D0C6E9032001E0C6E90302DBF80000A6 -:10BE9000C00701D00BF0DFF9387810B13572BDE87A -:10BEA000F88F4FF01808C4F808830127A7614FF4F2 -:10BEB0002070ADF8000000BFBDF80000411EADF8D5 -:10BEC0000010F9D2C4F80C51C4F810517A48C01DC2 -:10BED0000BF06CFA3570FFF744FF676179493079F0 -:10BEE00020310860C4F80483D9E770B5050000D19B -:10BEF000FFDF4FF080424FF0FF30C2F8080300210F -:10BF0000C2F80011C2F80411C2F80C11C2F81011E5 -:10BF1000694C61700BF0AFF910B10120A070607036 -:10BF200067480068C00701D00BF095F92846BDE8C6 -:10BF300070402CE76048007A002800D0012070474C -:10BF40002DE9F04F61484FF0000A85B0D0F800B0FD -:10BF5000D14657465D4A5E49083211608406D4F8DE -:10BF6000080110B14FF0010801E04FF000080BF09C -:10BF7000F0F978B1D4F8240100B101208246D4F858 -:10BF80001C0100B101208146D4F8200108B101272D -:10BF900000E00027D4F8000100B101200490D4F89B -:10BFA000040100B101200390D4F80C0100B101207C -:10BFB0000290D4F8100100B101203F4D0190287883 -:10BFC00000260090B8F1000F04D0C4F808610120E9 -:10BFD0000BF013F9BAF1000F04D0C4F82461092062 -:10BFE0000BF00BF9B9F1000F04D0C4F81C610A2062 -:10BFF0000BF003F927B1C4F820610B200BF0FDF81A -:10C000002D48C01D0BF0DAF900B1FFDFDFF8AC807E -:10C010000498012780B1C4F80873E87818B1EE706D -:10C0200000200BF0EAF8287A022805D103202872B4 -:10C030000221C8F800102761039808B1C4F8046110 -:10C04000029850B1C4F80C61287A032800D0FFDFB1 -:10C05000C8F800602F72FFF758FE019838B1C4F895 -:10C060001061287A012801D100F05CF8676100981E -:10C0700038B12E70287A012801D1FFF772FEFFF740 -:10C0800044FE0D48C01D0BF0AFF91049091DC1F861 -:10C0900000B005B0BDE8F08F074810B5C01D0BF02B -:10C0A0008DF90549B0B1012008704FF0E021C1F8C9 -:10C0B0000002BDE81040FFE544000020340C0040C1 -:10C0C0000C0400401805004010ED00E0100502408F -:10C0D00001000001087A012801D1FFF742FEBDE806 -:10C0E000104024480BF080B970B5224CE41FA078B2 -:10C0F00008B90BF0A7F801208507A861207A00266F -:10C10000032809D1D5F80C0120B900200BF0C4F8A0 -:10C110000028F7D1C5F80C6126724FF0FF30C5F842 -:10C12000080370BD70B5134CE41F6079F0B10128AD -:10C1300003D0A179401E814218DA0BF090F8054631 -:10C140000BF0A0FA6179012902D9A179491CA171EA -:10C150000DB1216900E0E168411A022902DA11F10A -:10C16000020F06DC0DB1206100E0E060BDE8704028 -:10C17000F7E570BD4B0000200F4A12680D498A4256 -:10C180000CD118470C4A12680A4B9A4206D101B5E5 -:10C190000BF04AFA0BF01DFDBDE8014007490968A4 -:10C1A0000958084706480749054A064B70470000EA -:10C1B00000000000BEBAFECA5C000020040000209F -:10C1C000C8130020C8130020F8B51D46DDE9064756 -:10C1D0000E000AD007F0ADFF2346FF1DBCB231466A -:10C1E0002A46009407F0BBFBF8BDD0192246194639 -:10C1F00002F023F92046F8BD70B50D460446102222 -:10C20000002102F044F9258117206081A07B40F0D5 -:10C210000A00A07370BD4FF6FF720A80014602202B -:10C220000BF04CBC704700897047827BD30701D16B -:10C23000920703D48089088000207047052070474A -:10C24000827B920700D581817047014600200988D2 -:10C2500041F6FE52114200D00120704700B503465E -:10C26000807BC00701D0052000BD59811846FFF72B -:10C27000ECFFC00703D0987B40F004009873987BD4 -:10C2800040F001009873002000BD827B520700D56A -:10C2900009B14089704717207047827B61F3C30260 -:10C2A000827370472DE9FC5F0E460446017896467E -:10C2B000012000FA01F14DF6FF5201EA020962681D -:10C2C0004FF6FF7B1188594502D10920BDE8FC9F3C -:10C2D000B9F1000F05D041F6FE55294201D00120E9 -:10C2E000F4E741EA090111801D0014D000232B70EE -:10C2F00094F800C0052103221F464FF0020ABCF14A -:10C300000E0F76D2DFE80CF0F909252F47646B7722 -:10C31000479193B4D1D80420D8E7616820898B7BFA -:10C320009B0767D517284AD30B89834247D389894E -:10C33000172901D3814242D185F800A0A5F8010058 -:10C340003280616888816068817B21F0020181739D -:10C35000C6E0042028702089A5F801006089A5F8AE -:10C3600003003180BCE0208A3188C01D1FFA80F8AC -:10C37000414524D3062028702089A5F80100608952 -:10C38000A5F80300A089A5F805000721208ACDE9BA -:10C390000001636941E00CF0FF00082810D008207C -:10C3A00028702089A5F801006089A5F80300318074 -:10C3B0006A1D694604F10C0009F025FB10B15EE02E -:10C3C0001020EDE730889DF800100844308087E0A9 -:10C3D0000A2028702089A5F80100328044E00C2052 -:10C3E00028702089A5F801006089A5F80300318034 -:10C3F0003AE082E064E02189338800EB41021FFAD1 -:10C4000082F843453BD3B8F1050F38D30E222A708A -:10C410000BEA4101CDE90010E36860882A467146C5 -:10C42000FFF7D2FEA6F800805AE04020287060890D -:10C430003188C01C1FFA80F8414520D32878714606 -:10C4400020F03F00123028702089A5F80100608993 -:10C45000CDE9000260882A46E368FFF7B5FEA6F83A -:10C460000080287840063BD461682089888037E0C6 -:10C47000A0893288401D1FFA80F8424501D2042766 -:10C480003DE0162028702089A5F801006089A5F8F4 -:10C490000300A089CDE9000160882A46714623691E -:10C4A000FFF792FEA6F80080DEE718202870207AB9 -:10C4B0006870A6F800A013E061680A88920401D4AD -:10C4C00005271CE0C9882289914201D0062716E081 -:10C4D0001E21297030806068018821F4005101809C -:10C4E000B9F1000F0BD061887823002202200BF0F5 -:10C4F0003BFA61682078887006E033800327606823 -:10C50000018821EA090101803846DFE62DE9FF4F65 -:10C5100085B01746129C0D001E461CD03078C1070E -:10C5200003D000F03F00192801D9012100E00021CB -:10C530002046FFF7AAFEA8420DD32088A0F57F4130 -:10C54000FF3908D03078410601D4000605D508200F -:10C5500009B0BDE8F08F0720FAE700208DF8000051 -:10C560008DF8010030786B1E00F03F0C0121A81EF1 -:10C570004FF0050A4FF002094FF0030B9AB2BCF1DD -:10C58000200F75D2DFE80CF08B10745E7468748C29 -:10C59000749C74B574BA74C874D474E1747474F10E -:10C5A00074EF74EE74ED748B052D78D18DF80090D6 -:10C5B000A0788DF804007088ADF8060030798DF809 -:10C5C0000100707800F03F000C2829D00ADCA0F1AF -:10C5D0000200092863D2DFE800F0126215621A62D5 -:10C5E0001D622000122824D004DC0E281BD0102845 -:10C5F000DBD11BE016281FD01828D6D11FE02078E9 -:10C60000800701E020784007002848DAEEE0207833 -:10C610000007F9E72078C006F6E720788006F3E700 -:10C6200020784006F0E720780006EDE72088C00576 -:10C63000EAE720884005E7E720880005E4E720884E -:10C64000C004E1E72078800729D5032D27D18DF894 -:10C6500000B0B6F8010081E0217849071FD5062D0A -:10C660001DD381B27078012803D0022817D102E0CF -:10C67000C9E0022000E0102004228DF8002072782A -:10C680008DF80420801CB1FBF0F2ADF8062092B2C8 -:10C6900042438A4203D10397ADF80890A6E079E0BF -:10C6A0002078000776D598B282088DF800A0ADF802 -:10C6B0000420B0EB820F6DD10297ADF8061095E023 -:10C6C0002178C90666D5022D64D381B206208DF883 -:10C6D0000000707802285DD3B1FBF0F28DF8040001 -:10C6E000ADF8062092B242438A4253D1ADF8089089 -:10C6F0007BE0207880064DD5072003E020784006B7 -:10C700007FD508208DF80000A088ADF80400ADF8B2 -:10C710000620ADF8081068E02078000671D50920E1 -:10C72000ADF804208DF80000ADF8061002975DE02A -:10C730002188C90565D5022D63D381B20A208DF801 -:10C740000000707804285CD3C6E72088400558D5DF -:10C75000012D56D10B208DF80000A088ADF8040003 -:10C7600044E021E026E016E0FFE72088000548D5F8 -:10C77000052D46D30C208DF80000A088ADF80400EC -:10C78000B6F803006D1FADF80850ADF80600ADF81F -:10C790000AA02AE035E02088C00432D5012D30D12E -:10C7A0000D208DF8000021E02088800429D4B6F8FF -:10C7B0000100E080A07B000723D5032D21D3307832 -:10C7C00000F03F001B2818D00F208DF800002088B3 -:10C7D00040F40050A4F80000B6F80100ADF80400E1 -:10C7E000ED1EADF80650ADF808B003976946059800 -:10C7F000F5F792FB050008D016E00E208DF800003A -:10C80000EAE7072510E008250EE0307800F03F0049 -:10C810001B2809D01D2807D0022005990BF04EF9DE -:10C82000208800F400502080A07B400708D52046D7 -:10C83000FFF70BFDC00703D1A07B20F00400A0731D -:10C84000284685E61FB5022806D101208DF8000094 -:10C8500088B26946F5F760FB1FBD0000F8B51D46BC -:10C86000DDE906470E000AD007F063FC2346FF1DF2 -:10C87000BCB231462A46009407F071F8F8BDD019D1 -:10C880002246194601F0D9FD2046F8BD2DE9FF4F9B -:10C890008DB09B46DDE91B57DDF87CA00C46082BCC -:10C8A00005D0E06901F0FEF850B11020D2E02888F0 -:10C8B000092140F0100028808AF80010022617E0B5 -:10C8C000E16901208871E2694FF420519180E169AA -:10C8D0008872E06942F601010181E06900218173FB -:10C8E0002888112140F0200028808AF800100426B2 -:10C8F00038780A900A2038704FF0020904F11800C5 -:10C900004D460C9001F0C6FBB04681E0BBF1100F24 -:10C910000ED1022D0CD0A9EB0800801C80B20221A0 -:10C92000CDE9001005AB52461E990D98FFF796FF12 -:10C93000BDF816101A98814203D9F74800790F9074 -:10C9400004E003D10A9808B138702FE04FF00201DB -:10C95000CDE900190DF1160352461E990D98FFF707 -:10C960007DFF1D980088401B801B83B2C6F1FF002D -:10C97000984200D203461E990BA8D9B15FF000027D -:10C98000DDF878C0CDE9032009EB060189B2CDE9D5 -:10C9900001C10F980090BDF8161000220D9801F00B -:10C9A0000EFC387070B1C0B2832807D0BDF81600F5 -:10C9B00020833AE00AEB09018A19E1E7022011B06D -:10C9C000BDE8F08FBDF82C00811901F0FF08022DA1 -:10C9D0000DD09AF80120424506D1BDF820108142C1 -:10C9E00007D0B8F1FF0F04D09AF801801FE08AF851 -:10C9F0000180C94800680178052902D1BDF81610E8 -:10CA0000818009EB08001FFA80F905EB080085B268 -:10CA1000DDE90C1005AB0F9A01F03FFB28B91D981A -:10CA20000088411B4145BFF671AF022D13D0BBF109 -:10CA3000100F0CD1A9EB0800801C81B20220CDE9B7 -:10CA4000000105AB52461E990D98FFF707FF1D9890 -:10CA50000580002038700020B1E72DE9F8439C469E -:10CA6000089E13460027B26B9AB3491F8CB2F18F10 -:10CA7000A1F57F45FF3D05D05518AD882944891D96 -:10CA80008DB200E000252919B6F83C8008314145F7 -:10CA900020D82A44BCF8011022F8021BBCF803106D -:10CAA00022F8021B984622F8024B914607F02FFB12 -:10CAB0004FF00C0C41464A462346CDF800C006F024 -:10CAC0001AFFF587B16B00202944A41D214408807A -:10CAD00003E001E0092700E083273846BDE8F8833A -:10CAE00010B50B88848F9C420CD9846BE0180488A5 -:10CAF00044B1848824F40044A41D23440B801060B6 -:10CB0000002010BD0A2010BD2DE9F0478AB0002595 -:10CB1000904689468246ADF8185007274BE00598A5 -:10CB200006888088000446D4A8F8006007A801950C -:10CB300000970295CDE903504FF40073002231466F -:10CB4000504601F03CFB04003CD1BDF81800ADF8A4 -:10CB50002000059804888188B44216D10A0414D4B0 -:10CB600001950295039521F400410097049541F445 -:10CB7000804342882146504601F0BFF804000BD1A3 -:10CB80000598818841F40041818005AA08A948469A -:10CB9000FFF7A6FF0400DCD00097059802950195E9 -:10CBA000039504950188BDF81C300022504601F021 -:10CBB000A4F80A2C06D105AA06A94846FFF790FF5B -:10CBC0000400ACD0ADF8185004E00598818821F439 -:10CBD0000041818005AA06A94846FFF781FF002889 -:10CBE000F3D00A2C03D020460AB0BDE8F08700201D -:10CBF000FAE710B50C46896B86B051B10C218DF85F -:10CC00000010A18FADF80810A16B01916946FAF7E9 -:10CC100001FB00204FF6FF71A063E187A08706B0FB -:10CC200010BD2DE9F0410D460746896B0020069E98 -:10CC30001446002911D0012B0FD13246294638461F -:10CC4000FFF762FF002808D1002C06D032462946A3 -:10CC50003846BDE8F04100F034BFBDE8F0812DE971 -:10CC6000FC411446DDE9087C0E46DDE90A15521D3B -:10CC7000BCF800E092B2964502D20720BDE8FC81E4 -:10CC8000ACF8002017222A70A5F80160A5F803303F -:10CC90000522CDE900423B462A46FFF7DFFD002092 -:10CCA000ECE770B50C46154648220021204601F0FD -:10CCB000EEFB04F1080044F81C0F00204FF6FF7152 -:10CCC000E06161842084A5841720E08494F82A0020 -:10CCD00040F00A0084F82A0070BD4FF6FF720A8007 -:10CCE000014603200AF0EABE30B585B00C46054681 -:10CCF000FFF77FFFA18E284629B101218DF8001092 -:10CD00006946FAF787FA0020E0622063606305B0A5 -:10CD100030BDB0F8400070476000002090F8462019 -:10CD2000920703D4408808800020F4E70620F2E749 -:10CD300090F846209207EED5A0F84410EBE70146A4 -:10CD4000002009880A0700D5012011F0F00F01D05A -:10CD500040F00200CA0501D540F004008A0501D563 -:10CD600040F008004A0501D540F010000905D2D571 -:10CD700040F02000CFE700B5034690F84600C0071A -:10CD800001D0062000BDA3F842101846FFF7D7FFD8 -:10CD900010F03E0F05D093F8460040F0040083F8F1 -:10CDA000460013F8460F40F001001870002000BD47 -:10CDB00090F84620520700D511B1B0F84200AAE71A -:10CDC0001720A8E710F8462F61F3C3020270A2E70C -:10CDD0002DE9FF4F9BB00E00DDE92B34DDE929780A -:10CDE000289D24D02878C10703D000F03F001928DF -:10CDF00001D9012100E000212046FFF7D9FFB04210 -:10CE000015D32878410600F03F010CD41E290CD020 -:10CE1000218811F47F6F0AD13A8842B1A1F57F428F -:10CE2000FF3A04D001E0122901D1000602D5042006 -:10CE30001FB0C5E5FA491D984FF0000A08718DF83A -:10CE400018A08DF83CA00FAA0A60ADF81CA0ADF8A0 -:10CE500050A02978994601F03F02701F5B1C04F135 -:10CE6000180C4FF0060E4FF0040BCDF858C01F2AD7 -:10CE70007ED2DFE802F07D7D107D267DAC7DF47DE5 -:10CE8000F37DF27DF17DF47DF07D7D7DEF7DEE7DA6 -:10CE90007D7D7D7DED0094F84610B5F80100890791 -:10CEA00001D5032E02D08DF818B01EE34FF40061B7 -:10CEB000ADF85010608003218DF83C10ADF84000B3 -:10CEC000D4E2052EEFD1B5F801002083ADF81C00A7 -:10CED000B5F80310618308B1884201D9012079E1D6 -:10CEE0000020A07220814FF6FF702084169801F078 -:10CEF000D1F8052089F800000220029083460AAB91 -:10CF00001D9A16991B9801F0C8F890BB9DF82E0049 -:10CF1000012804D0022089F80100102003E001203C -:10CF200089F8010002200590002203A90BA808F04F -:10CF30006AFDE8BB9DF80C00059981423DD1398816 -:10CF4000801CA1EB0B01814237DB02990220CDE965 -:10CF500000010DF12A034A4641461B98FFF77EFC6B -:10CF600002980BF1020B801C81B217AA029101E01A -:10CF70009CE228E003A90BA808F045FD02999DF862 -:10CF80000C00CDE9000117AB4A4641461B98FFF75C -:10CF900065FC9DF80C000AAB0BEB00011FFA81FB4E -:10CFA00002991D9A084480B2029016991B9800E0DD -:10CFB00003E001F072F80028B6D0BBF1020F02D0F6 -:10CFC000A7F800B04FE20A208DF818004BE20021CC -:10CFD0000391072EFFF467AFB5F801002083ADF889 -:10CFE0001C00B5F80320628300283FF477AF90421D -:10CFF0003FF674AF0120A072B5F805002081002033 -:10D00000A073E06900F04EFD78B9E16901208871F4 -:10D01000E2694FF420519180E1698872E16942F63A -:10D0200001000881E06900218173F01F20841E98AF -:10D03000606207206084169801F02CF8072089F8B8 -:10D0400000000120049002900020ADF82A0028E0A2 -:10D0500019E29FE135E1E5E012E2A8E080E043E07B -:10D060000298012814D0E0698079012803D1BDF825 -:10D070002800ADF80E00049803ABCDE900B04A4695 -:10D0800041461B98FFF7EAFB0498001D80B204900C -:10D09000BDF82A00ADF80C00ADF80E00059880B27E -:10D0A00002900AAB1D9A16991B9800F0F6FF28B95A -:10D0B00002983988001D05908142D1D2029801283A -:10D0C00081D0E0698079012803D1BDF82800ADF84E -:10D0D0000E00049803ABCDE900B04A4641461B98C8 -:10D0E000FFF7BCFB0298BDE1072E02D0152E7FF49E -:10D0F000DAAEB5F801102183ADF81C10B5F80320A5 -:10D10000628300293FF4EAAE91423FF6E7AE012187 -:10D11000A1724FF0000BA4F808B084F80EB0052EF1 -:10D1200007D0C0B2691DE26908F06BFC00287FF4EB -:10D130004AAF4FF6FF70208401A906AA14A8CDF8C3 -:10D1400000B081E885032878214600F03F031D9A4E -:10D150001B98FFF79BFB8246208BADF81C0082E1F9 -:10D160000120032EC3D14021ADF85010B5F80110B5 -:10D170002183ADF81C100AAAB8F1000F00D00023DB -:10D18000CDE9020304921D98CDF804800090388800 -:10D190000022401E83B21B9801F011F88DF8180090 -:10D1A00090BB0B2089F80000BDF8280035E04FF057 -:10D1B000010C052E9BD18020ADF85000B5F8011070 -:10D1C0002183B5F803002084ADF81C10B0F5007F72 -:10D1D00003D907208DF8180087E140F47C422284AF -:10D1E0000CA8B8F1000F00D00023CDE90330CDE941 -:10D1F000018C1D9800903888401E83B21B9800F067 -:10D20000DEFF8DF8180018B18328A8D10220BFE0F6 -:10D210000D2189F80010BDF83000401C22E100000B -:10D2200060000020032E04D248067FF53CAE0020AB -:10D2300018E1B5F80110ADF81C102878400602D5A9 -:10D240008DF83CE002E007208DF83C004FF000082C -:10D250000320CDE902081E9BCDF810801D98019394 -:10D26000A6F1030B00901FFA8BF342461B9800F0C7 -:10D2700044FD8DF818008DF83C80297849060DD5BD -:10D280002088C00506D5208BBDF81C10884201D12E -:10D29000C4F8248040468DF81880E3E0832801D14B -:10D2A0004FF0020A4FF48070ADF85000BDF81C003A -:10D2B0002083A4F820B01E986062032060841321AC -:10D2C000CDE0052EFFF4EFADB5F80110ADF81C1060 -:10D2D000A28F6AB3A2F57F43FE3B29D008228DF8C6 -:10D2E0003C2000BF4FF0000B0523CDE9023BDDF8E9 -:10D2F00078C0CDF810B01D9A80B2CDF804C040F4CB -:10D3000000430092B5F803201B9800F0F6FC8DF85E -:10D310003CB04FF400718DF81800ADF85010832820 -:10D3200010D0F8B1A18FA1F57F40FE3807D0DCE026 -:10D330000B228DF83C204FF6FE72A287D2E7A4F8AC -:10D340003CB0D2E000942B4631461E9A1B98FFF762 -:10D3500084FB8DF8180008B183284BD1BDF81C0060 -:10D36000208353E700942B4631461E9A1B98FFF703 -:10D3700074FB8DF81800E8BBE18FA06B0844831D97 -:10D380008DE888034388828801881B98FFF767FC33 -:10D39000824668E095F80180022E70D15FEA0800AD -:10D3A00002D0B8F1010F6AD109208DF83C0007A81E -:10D3B00000908DF840804346002221461B98FFF7DD -:10D3C00030FC8DF842004FF0000B8DF843B050B99F -:10D3D000B8F1010F12D0B8F1000F04D1A18FA1F55F -:10D3E0007F40FF380AD0A08F40B18DF83CB04FF499 -:10D3F000806000E037E0ADF850000DE00FA91B9809 -:10D40000F9F708FF82468DF83CB04FF48060ADF824 -:10D410005000BAF1020F06D0FC480068C07928B16C -:10D420008DF8180027E0A4F8188044E0BAF1000F46 -:10D4300003D081208DF818003DE007A800904346F6 -:10D44000012221461B98FFF7ECFB8DF818002146BE -:10D450001B98FFF7CEFB9DF8180020B9192189F819 -:10D460000010012038809DF83C0020B10FA91B98C6 -:10D47000F9F7D0FE8246BAF1000F33D01BE018E076 -:10D480008DF818E031E02078000712D5012E10D178 -:10D490000A208DF83C00E088ADF8400003201B997D -:10D4A0000AF00CFB0820ADF85000C0E648067FF5F6 -:10D4B000FAAC4FF0040A2088BDF8501008432080D1 -:10D4C000BDF8500080050BD5A18FA1F57F40FE3837 -:10D4D00006D11E98E06228982063A6864FF0030AC2 -:10D4E0005046A5E49DF8180078B1012089F80000A5 -:10D4F000297889F80110BDF81C10A9F802109DF8D0 -:10D50000181089F80410052038802088BDF85010C4 -:10D5100088432080E4E72DE9FF4F8846087895B0DE -:10D52000012181404FF20900249C0140ADF82010F8 -:10D530002088DDF88890A0F57F424FF0000AFF3A7E -:10D5400006D039B1000705D5012019B0BDE8F08F2C -:10D550000820FAE7239E4FF0000B0EA886F800B0D3 -:10D5600018995D460988ADF83410A8498DF81CB0AB -:10D57000179A0A718DF838B0086098F800000128F1 -:10D580003BD0022809D003286FD1307820F03F002B -:10D590001D303070B8F80400E08098F800100320C7 -:10D5A000022904D1317821F03F011B31317094F808 -:10D5B0004610090759D505ABB9F1000F13D000216A -:10D5C00002AA82E80B000720CDE90009BDF834006B -:10D5D000B8F80410C01E83B20022159800F0EFFDC9 -:10D5E0000028D1D101E0F11CEAE7B8F80400A6F860 -:10D5F0000100BDF81400C01C04E198F805108DF876 -:10D600001C1098F80400012806D04FF4007A022874 -:10D610002CD00328B8D16CE12188B8F8080011F4A7 -:10D620000061ADF8201020D017281CD3B4F84010AA -:10D63000814218D3B4F84410172901D3814212D182 -:10D64000317821F03F01C91C3170A6F80100032197 -:10D65000ADF83410A4F8440094F8460020F002001D -:10D6600084F8460065E105257EE177E1208808F130 -:10D67000080700F4FE60ADF8200010F0F00F1BD09A -:10D6800010F0C00F03D03888228B9042EBD199B9AB -:10D69000B878C00710D0B9680720CDE902B1CDF83D -:10D6A00004B00090CDF810B0FB88BA88398815987E -:10D6B00000F023FB0028D6D12398BDF82010401C91 -:10D6C00080294ED006DC10290DD020290BD040290E -:10D6D00087D124E0B1F5807F6ED051457ED0B1F581 -:10D6E000806F97D1DEE0C80601D5082000E0102049 -:10D6F00082460DA907AA0520CDE902218DF8380040 -:10D70000ADF83CB0CDE9049608A93888CDE9000110 -:10D710005346072221461598FFF7B8F8A8E09DF870 -:10D720001C2001214FF00A0A002A9BD105ABB9F158 -:10D73000000F00D00020CDE902100720CDE900093C -:10D74000BDF834000493401E83B2218B002215984B -:10D7500000F035FD8DF81C000B203070BDF8140072 -:10D7600020E09DF81C2001214FF00C0A002A22D154 -:10D7700013ABB9F1000F00D00020CDE90210072053 -:10D78000CDE900090493BDF83400228C401E83B219 -:10D79000218B159800F013FD8DF81C000D203070C2 -:10D7A000BDF84C00401CADF8340005208DF8380061 -:10D7B000208BADF83C00BCE03888218B88427FF498 -:10D7C00052AF9DF81C004FF0120A00281CD1606A6D -:10D7D000A8B1B878C0073FF446AF00E018E0BA68D7 -:10D7E0000720CDE902B2CDF804B00090CDF810B01A -:10D7F000FB88BA88159800F080FA8DF81C00132079 -:10D8000030700120ADF8340093E00000600000208B -:10D810003988208B8142D2D19DF81C004FF0160A26 -:10D820000028A06B08D0E0B34FF6FF7000215F46E0 -:10D83000ADF808B0019027E068B1B978C907BED14A -:10D84000E18F0DAB0844821D03968DE80C024388DE -:10D850008288018809E0B878C007BCD0BA680DABEF -:10D8600003968DE80C02BB88FA881598FFF7F7F944 -:10D8700005005ED0072D72D076E0019005AA02A9BE -:10D880002046FFF72DF90146E28FBDF808008242DD -:10D8900001D00029F1D0E08FA16B084407800198E6 -:10D8A000E08746E09DF81C004FF0180A40B1208B3D -:10D8B000C8B13888208321461598FFF79AF938E0D7 -:10D8C00004F118000090237E012221461598FFF7ED -:10D8D000A8F98DF81C000028EDD119203070012026 -:10D8E000ADF83400E7E7052521461598FFF781F9E3 -:10D8F0003AE0208800F40070ADF8200050452DD1AA -:10D90000A08FA0F57F41FE3901D006252CE0D8F884 -:10D9100008004FF0160A48B1A063B8F80C10A187B0 -:10D920004FF6FF71E187A0F800B002E04FF6FF70FC -:10D93000A087BDF8200030F47F611AD07823002240 -:10D94000032015990AF010F898F80000207120883B -:10D95000BDF82010084320800EE000E00725208855 -:10D96000BDF8201088432080208810F47F6F1CD0E1 -:10D970003AE02188814321809DF8380020B10EA92A -:10D980001598F9F747FC05469DF81C000028EBD0D8 -:10D9900086F801A001203070208B70809DF81C005B -:10D9A00030710520ADF83400DEE7A18EE1B11898A2 -:10D9B0000DAB0088ADF834002398CDE90304CDE920 -:10D9C0000139206B0090E36A179A1598FFF700FA67 -:10D9D000054601208DF838000EA91598F9F71AFCB4 -:10D9E00000B10546A4F834B094F8460040070AD5C3 -:10D9F0002046FFF7A4F910F03E0F04D114F8460FAB -:10DA000020F0040020701898BDF8341001802846DA -:10DA10009BE500B585B0032806D102208DF80000F3 -:10DA200088B26946F9F7F6FB05B000BD10B5384C71 -:10DA30000B782268012B02D0022B2AD111E0137837 -:10DA40000BB1052B01D10423137023688A889A80B7 -:10DA50002268CB88D38022680B8913814989518140 -:10DA60000DE08B8893802268CB88D38022680B8955 -:10DA700013814B8953818B899381096911612168D5 -:10DA8000F9F7C8FB226800210228117003D0002892 -:10DA900000D0812010BD832010BD806B002800D0F5 -:10DAA000012070478178012909D10088B0F5205FF5 -:10DAB00003D042F60101884201D1002070470720BF -:10DAC0007047F0B587B0002415460E460746ADF8FE -:10DAD000184011E005980088288005980194811D60 -:10DAE000CDE902410721049400918388428801888E -:10DAF000384600F002F930B905AA06A93046FEF70B -:10DB0000EFFF0028E6D00A2800D1002007B0F0BDC2 -:10DB10006000002010B58B7883B102789A4205D15D -:10DB20000B885BB102E08B79091D4BB18B789A426F -:10DB3000F9D1B0F801300C88A342F4D1002010BD17 -:10DB4000812010BD072826D012B1012A27D103E079 -:10DB5000497801F0070102E04978C1F3C2010529C3 -:10DB60001DD2DFE801F00318080C12000AB10320EF -:10DB700070470220704704280DD250B10DE00528EF -:10DB800009D2801E022808D303E0062803D0032808 -:10DB900003D005207047002070470F207047812078 -:10DBA0007047C0B282060BD4000607D5FA48807AC7 -:10DBB0004143C01D01EBD00080B27047084670475A -:10DBC0000020704770B513880B800B781C0625D594 -:10DBD000F14CA47A844204D843F01000087000206D -:10DBE00070BD956800F0070605EBD0052D78F5406F -:10DBF00065F304130B701378D17803F0030341EA43 -:10DC0000032140F20123B1FBF3F503FB15119268E8 -:10DC1000E41D00FB012000EBD40070BD906870BDD6 -:10DC200037B51446BDF804101180117841F0040195 -:10DC300011709DF804100A061ED5D74AA368C1F3D7 -:10DC40000011927A824208D8FE2811D1D21DD20842 -:10DC50004942184600F01BFC0AE003EBD00200F03A -:10DC60000703012510789D40A84399400843107090 -:10DC7000207820F0100020703EBD2DE9F0410746CD -:10DC8000C81C0E4620F00300B04202D08620BDE83A -:10DC9000F081C14D002034462E60AF802881AA72E9 -:10DCA000E8801AE0E988491CE980810614D4E1780B -:10DCB00000F0030041EA002040F20121B0FBF1F244 -:10DCC00001FB12012068FFF76CFF2989084480B22C -:10DCD0002881381A3044A0600C3420784107E1D400 -:10DCE0000020D4E7AC4801220189C08800EB400045 -:10DCF00002EB8000084480B270472DE9FF4F89B0E5 -:10DD00001646DDE9168A0F46994623F44045084633 -:10DD100000F054FB040002D02078400703D4012017 -:10DD20000DB0BDE8F08F099806F086F802902078D3 -:10DD3000000606D59848817A0298814201D887204A -:10DD4000EEE7224601A90298FFF73CFF8346002038 -:10DD50008DF80C004046B8F1070F1AD00122214679 -:10DD6000FFF7F0FE0028DBD12078400611D5022015 -:10DD70008DF80C00ADF81070BDF80400ADF812007D -:10DD8000ADF814601898ADF81650CDF81CA0ADF899 -:10DD900018005FEA094004D500252E46A846012751 -:10DDA0000CE02178E07801F0030140EA012040F224 -:10DDB0000121B0FBF1F2804601FB12875FEA494086 -:10DDC00009D5B84507D1A178207901F0030140EACF -:10DDD0000120B04201D3BE4201D90720A0E7A81913 -:10DDE0001FFA80F9B94501D90D2099E79DF80C007B -:10DDF00028B103A90998F9F70BFA002890D1B84582 -:10DE000007D1A0784FEA192161F30100A07084F8CE -:10DE100004901A9800B10580199850EA0A0027D09A -:10DE2000199830B10BEB06002A46199900F005FB52 -:10DE30000EE00BEB06085746189E099806F067F9A6 -:10DE40002B46F61DB5B239464246009505F053FD06 -:10DE5000224601A90298FFF7B5FE9DF8040022466C -:10DE600020F010008DF80400DDE90110FFF7D8FE66 -:10DE7000002055E72DE9FF4FDFF81C91824685B061 -:10DE8000B9F80610D9F8000001EB410100EB81045C -:10DE900040F20120B2FBF0F1174600FB1175DDE9FD -:10DEA000138B4E4629460698FFF77BFE0346FFF785 -:10DEB00019FF1844B1880C30884202D9842009B077 -:10DEC0002FE70698C6B2300603D5B00601D5062066 -:10DED000F5E7B9F80620521C92B2A9F80620BBF16A -:10DEE000000F01D0ABF80020B00602D5C4F80880BE -:10DEF0000AE0B9F808201A4492B2A9F80820D9F823 -:10DF00000000891A0844A0602246FE200699FFF707 -:10DF100087FEE77025712078390A61F301002A0A2B -:10DF2000A17840F0040062F30101A17020709AF81A -:10DF300002006071BAF80000E08000252573300609 -:10DF400002D599F80A7000E00127B00601D54FF01C -:10DF500000084E4600244FF007090FE0CDE90258B3 -:10DF60000195CDF800900495F1882046129B089AFF -:10DF7000FFF7C3FE0028A2D1641CE4B2BC42EDD37B -:10DF800000209CE700B5FFF7ADFE03490C308A88FE -:10DF9000904203D9842000BD00060020CA8808688A -:10DFA00002EB420300EB8300521C037823F00403CE -:10DFB0000370CA80002101730846ECE72DE9F047A1 -:10DFC000804600F0FBF9070005D000264446F74DD7 -:10DFD00040F2012916E00120BDE8F087204600F05C -:10DFE000EDF90278C17802F0030241EA0222B2FBA5 -:10DFF000F9F309FB13210068FFF7D3FD3044641CDB -:10E0000086B2A4B2E988601E8142E7DCA8F1010073 -:10E01000E8802889801B288100203870DCE710B553 -:10E02000144631B1491E218005F006FFA070002082 -:10E0300010BD012010BD70B50446DC48C1880368DE -:10E0400001E0401C20802088884207D200EB40027B -:10E0500013EB820202D015786D07F2D580B28842A8 -:10E0600016D2AAB15079A072D08820819178107907 -:10E0700001F0030140EA0120A081A078E11CFFF734 -:10E08000A1FD20612088401C2080E080002070BD20 -:10E090000A2070BD0121018270472DE9FF4F85B034 -:10E0A0004FF6FF798246A3F8009048681E460D4659 -:10E0B00080788DF8060048680088ADF804000020DC -:10E0C0008DF80A00088A0C88A04200D304462C82EE -:10E0D00051E03878400708D4641C288AA4B2401C58 -:10E0E000288208F10100C0B246E0288A401C28823C -:10E0F000781D6968FFF70EFDD8BB3188494501D10D -:10E10000601E30803188A1EB080030806888A04212 -:10E1100038D3B878397900F0030041EA002801A922 -:10E12000781DFFF7F7FC20BB298949452ED0002236 -:10E1300039460798FFF706FDD8B92989414518D116 -:10E14000E9680391B5F80AC0D7F808B05046CDF891 -:10E1500000C005F0DCFFDDF800C05A460CF1070CEA -:10E160001FFA8CFC43460399CDF800C005F08DFBE7 -:10E1700060B1641CA4B200208046204600F01EF965 -:10E180000700A6D1641E2C820A2098E67480787954 -:10E19000B071F888B0803978F87801F0030140EA6E -:10E1A00001207081A6F80C80504605F045FE3A46E5 -:10E1B00006F10801FFF706FD306100207FE62DE93A -:10E1C000FF4F87B081461C469246DDF860B0DDF80F -:10E1D0005480089800F0F2F8050002D02878400733 -:10E1E00002D401200BB09CE5484605F025FE2978B5 -:10E1F000090605D56D49897A814201D88720F1E762 -:10E20000CAF309062A4601A9FFF7DCFC0746149861 -:10E2100007281CD000222946FFF794FC0028E1D1F2 -:10E220002878400613D501208DF808000898ADF82D -:10E230000C00BDF80400ADF80E00ADF81060ADF8AC -:10E24000124002A94846F8F7E3FF0028CAD129780E -:10E25000E87801F0030140EA0121AA78287902F068 -:10E26000030240EA0220564507D0B1F5007F04D9E9 -:10E27000611E814201DD0B20B4E7864201D90720EF -:10E28000B0E7801B85B2A54200D92546BBF1000F3F -:10E2900001D0ABF80050179818B1B9192A4600F010 -:10E2A000CCF8B8F1000F0DD03E4448464446169FC6 -:10E2B00005F03FFF2146FF1DBCB232462B460094BD -:10E2C00005F04DFB00208DE72DE9F04107461D4686 -:10E2D0001646084600F072F8040002D02078400785 -:10E2E00001D40120D3E4384605F0A6FD21780906C3 -:10E2F00005D52E49897A814201D88720C7E4224674 -:10E300003146FFF75FFC65B12178E07801F0030149 -:10E3100040EA0120B0F5007F01D8012000E0002094 -:10E3200028700020B3E42DE9F04107461D4616464B -:10E33000084600F043F8040002D02078400701D4DA -:10E340000120A4E4384605F077FD2178090605D5BB -:10E350001649897A814201D8872098E422463146BD -:10E36000FFF75EFCFF2D14D02178E07801F0030266 -:10E3700040EA022040F20122B0FBF2F302FB13005C -:10E3800015B900F2012080B2E070000A60F30101CB -:10E39000217000207BE410B50C4600F00FF810B19E -:10E3A0000178490704D4012010BD000000060020B8 -:10E3B000C18821804079A0700020F5E70749CA880C -:10E3C000824209D340B1096800EB40006FF00B02B4 -:10E3D00002EB8000084470470020704700060020D0 -:10E3E00070B504460D4621462B460AB9002070BD83 -:10E3F00001E0491C5B1C501E021E03D008781E78E9 -:10E40000B042F6D008781E78801BF0E730B50C4695 -:10E4100001462346051B954206D202E0521E9D5C32 -:10E420008D54002AFAD107E004E01D780D70491CD4 -:10E430005B1C521E002AF8D130BDF0B50E460146D5 -:10E44000334680EA030404F00304B4B906E002B9D9 -:10E45000F0BD13F8017B01F8017B521E01F00307A8 -:10E46000002FF4D10C461D4602E080CD80C4121F5F -:10E47000042AFAD221462B4600BF04E013F8014BD0 -:10E4800001F8014B521E002AF8D100BFE0E7F0B5B9 -:10E490000C460146E6B204E002B9F0BD01F8016B9A -:10E4A000521E01F00307002FF6D10B46E5B245EAF4 -:10E4B000052545EA054501E020C3121F042AFBD2C9 -:10E4C000194602E001F8016B521E002AFAD100BF82 -:10E4D000E3E7000010B509F0A0FDF4F7F9F909F041 -:10E4E000E7FBBDE8104009F0AFBC302834BF012085 -:10E4F00000207047202834BF4FF0A0420C4A01236F -:10E5000000F01F0003FA00F0002914BFC2F80C0548 -:10E51000C2F808057047202834BF4FF0A0410449D5 -:10E5200000F01F00012202FA00F0C1F81805704740 -:10E530000003005070B50346002002466FF02F051F -:10E540000EE09C5CA4F130060A2E02D34FF0FF309F -:10E5500070BD00EB800005EB4000521C2044D2B29D -:10E560008A42EED370BD30B50A230BE0B0FBF3F462 -:10E5700003FB1404B0FBF3F08D183034521E05F881 -:10E58000014CD2B2002AF1D130BD30B500234FF694 -:10E59000FF7510E0040A44EA002084B2C85C6040C1 -:10E5A000C0F30314604005EA00344440E0B25B1C51 -:10E5B00084EA40109BB29342ECD330BD2DE9F04188 -:10E5C000FE4B0026012793F864501C7893F868C02E -:10E5D000B8B183F89140A3F8921083F8902083F8A3 -:10E5E0008E70BCF1000F0CBF83F8946083F89450D8 -:10E5F000F3488068008805F08AFDBDE8F04105F029 -:10E6000021BA4FF6FF7083F89140A3F8920083F887 -:10E61000902083F88E70BCF1000F14BF83F89450E3 -:10E6200083F89460BDE8F0812DE9F041E44D29685C -:10E6300091F89C200024012A23D091F89620012AE9 -:10E6400030D091F86C301422DC4E0127012B32D0EF -:10E6500091F88E30012B4FD091F8A620012A1CBFD3 -:10E660000020BDE8F08144701F2200F8042B222214 -:10E67000A731FFF7E2FE286880F8A6400120BDE838 -:10E68000F08144701B220270D1F89D204260D1F8C5 -:10E69000A120826091F8A520027381F89C4001209E -:10E6A000BDE8F081447007220270D1F898204260E2 -:10E6B00081F89640E2E78046447000F8042B20225F -:10E6C0006E31FFF7BAFE88F80870286880F86C4051 -:10E6D00090F86E000028D1D1B6F87000A6F8980026 -:10E6E000A868417B86F89A1086F89670008805F035 -:10E6F0000EFD05F0B6F9C1E791F86C30012B0BD097 -:10E70000447017220270D1F890204260B1F8942032 -:10E71000028181F88E40B1E78046447000F8042BF6 -:10E7200020226E31FFF789FE88F80870286880F88B -:10E730006C4090F86E000028A0D1CDE7A04800689A -:10E7400090F86C10002914BFB0F870004FF6FF70FD -:10E75000704770B59A4C06462068002808BFFFDF56 -:10E760000025206845706660002808BFFFDF20682C -:10E77000417800291CBFFFDF70BDCC220021FFF7CC -:10E7800086FE2068FF2101707F2180F83810132158 -:10E790004184282180F86910012180F85C1080F8FC -:10E7A00061500AF0C1F9BDE8704009F0AEBA844981 -:10E7B0000968097881420CBF012000207047804819 -:10E7C000006890F82200C0F3400070477C48006861 -:10E7D00090F8220000F0010070477948006890F836 -:10E7E0002200C0F3001070472DE9F0437448002464 -:10E7F000036893F82400B3F822C0C0F38001C0F38B -:10E800004002114400F001000844CCF3001121B390 -:10E81000BCF1100F02BF6B4931F81000BDE8F08366 -:10E82000BCF1120F18BFBCF1130F0ED0BCF1150FC5 -:10E830001EBFFFDF2046BDE8F0830021624A32F8A8 -:10E84000102010FB0120BDE8F083604A002132F85F -:10E85000102010FB0120BDE8F08393F85E2093F8B0 -:10E860005F102E264FF47A774FF014084FF04009CE -:10E87000022A04BF4AF2D745B5FBF7F510D0012AAA -:10E8800004BF4AF22F75B5FBF7F510D04AF62315F1 -:10E89000B5FBF7F5082A08BF4E4613D0042A18D056 -:10E8A0002646082A0ED0042A13D0022A49D004F1A1 -:10E8B0002806042A0FD0082A1CBF4FF01908082286 -:10E8C00004D00AE04FF0140806F5A8764FF0400295 -:10E8D00003E006F5A8764FF0100218FB026212FB67 -:10E8E0000052C0EB00103A4D00EB800005EB8000B9 -:10E8F00010441CF0010F4FF4C8724FF4BF7504BFF1 -:10E90000CCF34006002E65D0CCF3400600F5A57090 -:10E91000EEB1082904BF174640260CD0042904BFD5 -:10E920002F46102607D0022907BF04F11807042636 -:10E9300004F12807082606EB860808EB86163E44F5 -:10E940001BE004F118064FF019080422C5E7082956 -:10E9500004BF164640270CD0042904BF2E461027BA -:10E9600007D0022907BF04F11806042704F128067E -:10E97000082707EB871706EB8706304400F19C0653 -:10E9800093F8690001F00C07002F08BF0020304405 -:10E9900018BF00F5416027D1082904BF164640275B -:10E9A0001BD0042904BF2E46102716D0022906BF0B -:10E9B00004F11806042704F128060CE00C060020D8 -:10E9C00068000020DC610200E4610200D461020002 -:10E9D000D4FEFFFF64E018BF0827C7EBC70707EBAB -:10E9E000470706EB4706304498301CF0010F17D05C -:10E9F000082908BF40210CD0042904BF2A46102151 -:10EA000007D0022907BF04F11802042104F12802EB -:10EA1000082101EB410303EB0111114408443BE0E1 -:10EA2000082904BF944640260CD0042904BFAC46F4 -:10EA3000102607D0022907BF04F1180C042604F1A0 -:10EA4000280C082606EB8616B3F840300CEB860C33 -:10EA50006044EB2B20D944F2552C0B3303FB0CF311 -:10EA60009B0D082907D0042902D0022905D008E00F -:10EA70002A46102108E0402106E004F11802042192 -:10EA800002E004F12802082101EB811102EB81016F -:10EA900001F5A57103FB010000F5B470BDE8F0833A -:10EAA00000F5A570082904BF944640260CD004291F -:10EAB00004BFAC46102607D0022907BF04F1180C8A -:10EAC000042604F1280C082606EB8616B3F8483015 -:10EAD0000CEB860C6044EB2BDED944F2552C0B3347 -:10EAE00003FB0CF39B0D0829C5D00429C0D00229D3 -:10EAF000C7D1C2E7FE4840F271210068806A4843EE -:10EB00007047FB48006890F83700002818BF0120C4 -:10EB1000704710B5F74C207B022818BF032808D196 -:10EB2000207D04F115010EF0E6FE08281CBF01202F -:10EB300010BD207B002816BF022800200120BDE860 -:10EB400010400AF021BDEB4908737047E849096895 -:10EB500081F8300070472DE9F047E54C2168087BCB -:10EB6000002816BF022800200120487301F10E0181 -:10EB70000AF0F4FC2168087B022816BF0328012252 -:10EB8000002281F82F204FF0080081F82D00487BEB -:10EB900001F10E034FF001064FF00007012804BFFA -:10EBA0005B7913F0C00F0AD001F10E03012804D1E4 -:10EBB000587900F0C000402801D0002000E001207A -:10EBC00081F82E00002A04BF91F8220010F0040FF3 -:10EBD00007D0087D01F115010EF08DFE216881F846 -:10EBE0002D002068476007F0BFFA2168C14D4FF043 -:10EBF0000009886095F82D000EF089FE804695F892 -:10EC00002F00002818BFB8F1000F04D095F82D0090 -:10EC10000EF0B1FC68B195F8300000281CBF95F8E3 -:10EC20002E0000281DD0697B05F10E0001290ED0B1 -:10EC300012E06E734A4605F10E0140460AF0E4FC0C -:10EC400095F82D1005F10E000EF063FF09E04079F4 -:10EC500000F0C000402831D0394605F10E000AF01E -:10EC60000BFD2068C77690F8220010F0040F08BF53 -:10EC7000BDE8F087002795F82D000EF017FD050080 -:10EC800008BFBDE8F087102102F0C2F8002818BFC5 -:10EC9000BDE8F08720683A4600F11C01C676284698 -:10ECA0000AF0B2FC206800F11C0160680FF08EF8D9 -:10ECB0006068BDE8F04701210FF0A3B80EF066FFD1 -:10ECC0004A4605F10E010AF09FFCCAE7884A12681D -:10ECD000137B0370D2F80E000860508A888070475A -:10ECE00078B584490446824E407B087332682078A8 -:10ECF00010706088ADF8000080B200F00101C0F330 -:10ED0000400341EA4301C0F3800341EA8301C0F3B9 -:10ED1000C00341EAC301C0F3001341EA0311C0F389 -:10ED2000401341EA4311C0F3801041EA801050843F -:10ED3000E07D012808BF012507D0022808BF022571 -:10ED400003D0032814BFFFDF0825306880F85E5029 -:10ED5000607E012808BF012507D0022808BF0225D0 -:10ED600003D0032814BFFFDF0825316881F85F5006 -:10ED700091F83500012829D0207B81F82400488CA7 -:10ED80001D280CBF002060688862607D81F8370014 -:10ED9000A07B002816BF0228002001200875D4F8A7 -:10EDA0000F00C1F81500B4F81300A1F81900A07EF7 -:10EDB00091F86B2060F3071281F86B20E07E012848 -:10EDC00018BF002081F83400002078BD91F85E2043 -:10EDD0000420082A08BF81F85E00082D08BF81F8CA -:10EDE0005F00C9E742480068408CC0F3001131B1B0 -:10EDF000C0F38000002804BF1F20704702E0C0F36A -:10EE0000400109B10020704710F0010F14BFEE203F -:10EE1000FF20704736480068408CC0F3001119B1DC -:10EE2000C0F3800028B102E0C0F3400008B1002028 -:10EE30007047012070472E49002209684A664B8CB2 -:10EE40001D2B0CBF81F8682081F8680070470023F3 -:10EE5000274A126882F85D30D164A2F85000012080 -:10EE600082F85D007047224A0023126882F85C3005 -:10EE7000A2F858000120516582F85C0070471C49D7 -:10EE8000096881F8360070471949096881F86100FE -:10EE900070471748006890F961007047144800688F -:10EEA00090F82200C0F3401070471148006890F8B5 -:10EEB0002200C0F3C0007047012070470C48006872 -:10EEC00090F85F00704770B509F018FE09F0F7FD83 -:10EED00009F0C0FC09F06CFD054C2068416E491C2E -:10EEE000416690F83300002558B109F01DFE03E09B -:10EEF000680000200C06002008F007FF206880F85A -:10EF000033502068457090F8391021B1BDE8704049 -:10EF100004200AF0AEBF90F86810D9B1406E81426B -:10EF200018D804200AF0A5FF206890F8220010F0FD -:10EF3000010F07D0A06843220188BDE8704001207E -:10EF4000FFF73CBBBDE8704043224FF6FF71002045 -:10EF5000FFF734BBBDE8704000200AF08ABF2DE9FE -:10EF6000F04782B00F468146FE4E4FF000083068F1 -:10EF7000458C15F0030F10D015F0010F05F00200BD -:10EF800005D0002808BF4FF0010806D004E0002893 -:10EF900018BF4FF0020800D1FFDF4FF0000A5446BF -:10EFA00015F0010F05F002000DD080B915F0040F27 -:10EFB0000DD04AF00800002F1CBF40F0010040F0C7 -:10EFC00002044DD09EE010B115F0040F0DD015F0E5 -:10EFD000070F10D015F0010F05F0020043D00028F4 -:10EFE00008BF15F0040F34D04AE0002F18BF4AF0D4 -:10EFF000090444D141E037B14AF00800044615F055 -:10F00000200F1BD07EE0316805F02002B1F84800E7 -:10F01000104308BF4AF0010474D04AF018000446B7 -:10F0200015F0200F6ED191F85E1011F00C0118BF91 -:10F030000121C94361F30000044663E0316891F89F -:10F040005E1011F00C0118BF012161F300000446AD -:10F0500058E04AF00800002F18BF40F0010451D1D9 -:10F0600040F010044EE0002818BF15F0040F07D040 -:10F07000002F18BF4AF00B0444D14AF0180441E0B5 -:10F0800015F0030F3DD115F0040F3AD077B1306879 -:10F090004AF0080490F85E0010F00C0118BF01213E -:10F0A00061F3410415F0200F24D02BE0306805F007 -:10F0B0002002B0F84810114308BF4AF0030421D0E1 -:10F0C0004AF0180415F0200F0AD000BF90F85E0037 -:10F0D00010F00C0018BF0120C04360F3410411E0A0 -:10F0E00090F85E1011F00C0118BF0121C94361F3C3 -:10F0F0000004EBE710F00C0018BF012060F30004DF -:10F1000000E0FFDF15F0400F1CD0CFB93168B1F837 -:10F110004800002804BF488C10F0010F0BD110F0FC -:10F12000020F08BF10F0200F05D115F0010F08BF26 -:10F1300015F0020F04D091F85E0010F00C0F01D111 -:10F1400044F040047068A0F800A0017821F020018C -:10F1500001704FF007010EF005FE414670680EF099 -:10F16000F8FF214670680FF000F814F0010F0CD082 -:10F170004FF006034FF000027B4970680EF0CFFF9E -:10F180003068417B70680EF02FFE14F0020F18D02B -:10F19000D6E90010B9F1000F4FF006034FF001025D -:10F1A00007D01C310EF0BBFF012170680EF029FE64 -:10F1B00007E015310EF0B3FF3068017D70680EF086 -:10F1C00020FE14F0040F18BFFFDF14F0080F19D051 -:10F1D000CDF800A03068BDF800200223B0F86A1016 -:10F1E00061F30B02ADF8002090F86B0003220109D7 -:10F1F0009DF8010061F307108DF801006946706801 -:10F200000EF08DFF012F62D13068B0F84810E1B3E5 -:10F2100090F82200C0F34000B8BB70680EF095FF74 -:10F22000401CC7B23068C7F1FF05B0F84820B0F8FD -:10F230005A10511AA942B8BF0D46AA423BD990F8BC -:10F24000220010F0010F36D144F0100421467068FE -:10F250000EF08BFFF81CC0B2ED1E284482B230685D -:10F26000B0F86A10436EC1F30B0151FA83F190F8C4 -:10F2700060303E4F1944BC460023E1FB07C31B0925 -:10F280006FF0240C03FB0C1100E020E080F860100C -:10F2900090F85F00012101F01FF90090BDF8000017 -:10F2A0009DF80210032340EA01400190042201A9C5 -:10F2B00070680EF034FF3068AAB2416C70680EF0CE -:10F2C00082FF3068B0F85A102944A0F85A1014F0A0 -:10F2D000400F06D0D6E900100123062261310EF05E -:10F2E0001EFF14F0200F18BFFFDF0020002818BFFA -:10F2F000FFDF02B0BDE8F0872DE9F043194C89B07B -:10F300002068002808BFFFDF20684178002944D129 -:10F310000178FF2941D0002680F83160A0F85A60BA -:10F32000867080F83960304609F062FB104802AD03 -:10F3300000F1240191E80E1085E80E10D0E90D10BF -:10F34000CDE9061002A809F041FB08F0BCFF2068D7 -:10F3500090F9610009F090F8064809F093F8064822 -:10F360000CE00000680000201A06002053E4B36E91 -:10F37000C8610200D0610200CD61020009F012FBF9 -:10F38000606809F038FB206890F8240010F0010F45 -:10F3900007D0252009F07EF80AE009B00C20BDE86E -:10F3A000F08310F0020F18BF262069D009F072F820 -:10F3B000206890F85E10252008F043FF206880F850 -:10F3C0002C6009F00FFB206890F85E10002009F017 -:10F3D00028F90F21052008F0F8FF206890F82E107A -:10F3E000002901BF90F82F10002990F8220010F09A -:10F3F000040F74D006F0B8FE0546206829468068E0 -:10F4000007F0AAFBDFF82884074690FBF8F008FB1A -:10F4100010704142284606F08EFB2168886097FBF9 -:10F42000F8F04A68104448600EF062FA014620681D -:10F43000426891426ED8C0E90165FE4D4FF0010867 -:10F4400095F82D000EF063FA814695F82F000127FC -:10F45000002818BFB9F1000F04D095F82D000EF068 -:10F460008AF8A0B195F8300000281CBF95F82E004E -:10F47000002824D0687B05F10E01012815D019E081 -:10F4800010F0040F14BF2720FFDF8FD190E73A461A -:10F490006F7305F10E0148460AF0B6F895F82D1085 -:10F4A00005F10E000EF035FB09E0487900F0C000D0 -:10F4B000402815D0414605F10E000AF0DDF820681D -:10F4C00090F8220010F0040F24D095F82D000EF0D3 -:10F4D000EDF805001ED0102101F09AFC40B119E0B2 -:10F4E0000EF054FB3A4605F10E010AF08DF8E6E7FE -:10F4F00020683A4600F11C01C77628460AF084F8D5 -:10F50000206800F11C0160680EF060FC0121606859 -:10F510000EF077FC2068417B0E3008F038FF206841 -:10F5200090F85C1061B3B0F85810A0F84810416D25 -:10F53000416490F82210C1F30011F1B9B0F86A00EB -:10F540000221C0F30B05ADF80050684607F0B0FF8C -:10F5500028B1BDF80000C0F30B00A84204D1BDF8EB -:10F560000000401CADF800002168BDF80000B1F8B3 -:10F570006A2060F30B02A1F86A20206880F85C60C2 -:10F58000206890F85D1039B1B0F85010A0F8401024 -:10F59000C16CC16380F85D60B0F86A10426EC1F35F -:10F5A0000B0151FA82F190F86020DFF88CC211440F -:10F5B00063460022E1FB0C3212096FF0240302FBC8 -:10F5C000031180F860100EF00CFA032160680EF051 -:10F5D00090FA216881F8330009B00020BDE8F0837B -:10F5E0009649886070472DE9F043944C83B02268B7 -:10F5F00092F831303BB1508C1D2808BFFFDF03B0BB -:10F60000BDE8F0435FE401260027F1B1054692F81A -:10F61000600008F03FFF206890F85F10FF2008F0BE -:10F6200010FE20684FF4A57190F85F20002009F0CB -:10F63000D4F8206890F8221011F0030F00F02C810C -:10F64000002D00F0238100F027B992F822108046A7 -:10F65000D07EC1F30011002956D0054660680780AE -:10F66000017821F020010170518C132937D01FDC63 -:10F67000102908BF022144D0122908BF062140D01A -:10F68000FFDF6C4D606805F10E010EF091FB697BA8 -:10F6900060680EF0A9FB2068418C1D2918BF152950 -:10F6A00063D0B0F84820416C60680EF0B6FB5CE0B7 -:10F6B000152918BF1D29E3D14FF001010EF052FBAF -:10F6C0006068017841F020010170216885B11C312A -:10F6D0000EF07CFB012160680EF093FBD1E7002166 -:10F6E0000EF040FB6068017841F020010170C8E72E -:10F6F00015310EF06BFB2068017D60680EF081FB18 -:10F70000BFE70EF02FFBBCE70021FFF728FC606885 -:10F71000C17811F03F0F28D0017911F0100F24D0DB -:10F720000EF01EFB2368024693F82410C1F38000FC -:10F73000C1F3400C604401F00101084493F82C101F -:10F74000C1F3800CC1F34005AC4401F001016144F8 -:10F75000401AC1B293F85E0000F0BEFE0090032391 -:10F760000422694660680EF0DAFC2068002590F8F3 -:10F77000241090F82C0021EA000212F0010F18BFAB -:10F7800001250ED111F0020F04D010F0020F08BFB6 -:10F79000022506D011F0040F03D010F0040F08BFAB -:10F7A0000425B8F1000F2BD0012D1BD0022D08BF6E -:10F7B00026201BD0042D14BFFFDF272016D0206881 -:10F7C00090F85E10252008F03CFD206890F822108B -:10F7D000C1F3001169B101224FF49671002008F0C5 -:10F7E000FCFF0DE0252008F055FEE8E708F052FE8A -:10F7F000E5E790F85E204FF49671002008F0EDFFE9 -:10F80000206890F82C10294380F82C1090F82420C0 -:10F8100032EA01011CD04670418C13292BD026DC22 -:10F82000102904BF03B0BDE8F083122923D007E0FC -:10F8300040420F000C06002053E4B36E6800002025 -:10F84000C1F30010002818BFFFDF03B0BDE8F0834C -:10F85000418C1D2908BF80F82C70DCD0C1F3001149 -:10F86000002914BF80F8316080F83170D3E7152982 -:10F8700018BF1D29DBD190F85E2003B04FF00101C5 -:10F88000BDE8F043084609F094B900BF90F85F2046 -:10F890000121084609F08DF92168002DC87E7CD031 -:10F8A0004A8C3D46C2F34000002808BF47F00805D7 -:10F8B00012F0400F18BF45F04005002819BFD1F8DD -:10F8C0003C90B1F84080D1F84490B1F8488060682D -:10F8D000072107800EF046FA002160680EF039FC1F -:10F8E000294660680EF041FC15F0080F17D020681B -:10F8F000BDF800100223B0F86A2062F30B01ADF8E6 -:10F90000001090F86B00032201099DF8010061F3DB -:10F9100007108DF80100694660680EF000FC606811 -:10F920000EF0DCFA2168C0F1FE00B1F85A20A8EB15 -:10F9300002018142A8BF0146CFB2D019404544D24E -:10F9400045F0100160680EF010FC60680EF0C6FA19 -:10F950002168C0F1FE00B1F85A10A8EB0101814204 -:10F96000A8BF0146CFB260680EF0EFFB3844421CDE -:10F970002068B0F86A10436EC1F30B0151FA83F1AD -:10F9800090F86030FE4D1944AC460023E1FB05C3FE -:10F990004FEA131C6FF0240300E03CE00CFB031162 -:10F9A00080F8601090F85F00012100F095FD009054 -:10F9B000BDF800009DF80210032340EA01400190C9 -:10F9C000042201A960680EF0AAFB216891F82200C8 -:10F9D00010F0400F05D001230622613160680EF05F -:10F9E0009EFB20683A46B0F85A0000EB09016068B7 -:10F9F0000EF0E9FB2068B0F85A103944A0F85A100C -:10FA000009F0BFFC002818BFFFDF20684670867031 -:10FA100003B0BDE8F0830121FFF7A1FAF0E7D94870 -:10FA200010B50068417841B90078FF2805D0002161 -:10FA30000846FFF7D8FD002010BD09F05FF809F077 -:10FA40003EF808F007FF08F0B3FF0C2010BD2DE9C9 -:10FA5000F041CC4D0446174628680E4690F86C00DD -:10FA6000002818BFFFDF2868002F80F86E7018BFCD -:10FA7000BDE8F0812188A0F870106188A0F8861098 -:10FA8000A188A0F88810E188A0F88A1094F888115D -:10FA900080F88C1090F82F10002749B1427B00F1BC -:10FAA0000E01012A04D1497901F0C001402935D065 -:10FAB00090F8301041B1427B00F10E01012A04BFE1 -:10FAC000497911F0C00F29D000F17A00F3F794FAC8 -:10FAD0006868FF2E0178C1F380116176D0F80310B9 -:10FAE000C4F81A10B0F80700E08328681ED0C0F8E8 -:10FAF0008010E18BA0F8841000F17402511E304692 -:10FB00000DF014FF002808BFFFDF286890F873107D -:10FB100041F0020180F87310BDE8F081D0F80E10BA -:10FB2000C0F87A10418AA0F87E10D1E7C0F8807042 -:10FB3000A0F88470617E80F87310D4F81A104167C1 -:10FB4000E18BA0F87810BDE8F08170B58D4C0125EF -:10FB5000206890F82200C0F3C00038B13C22FF2199 -:10FB6000A068FFF774FF206880F86C50206890F858 -:10FB7000220010F0010F1CBFA06801884FF03C026A -:10FB800012BF01204FF6FF710020FEF717FD20681D -:10FB900080F8395070BD7B49096881F832007047A0 -:10FBA0002DE9F041774C0026206841780127354641 -:10FBB000012906D0022901D003297DD0FFDFBDE84D -:10FBC000F081817802250029418C46D0C1F34002A2 -:10FBD000002A08BF11F0010F6FD090F85F204FF09E -:10FBE00001014FF0000008F0E4FF216891F82200C5 -:10FBF000C0F34000002814BF0C20222091F85F10B1 -:10FC000008F01FFB2068457090F8330058B108F0E9 -:10FC100068F8206890F85F0010F00C0F0CBF4020CF -:10FC2000452008F077FF206890F83400002818BFBE -:10FC300008F08FFF216891F85F0091F8691010F0CB -:10FC40000C0F08BF0021962008F0F6FE09F090FB8B -:10FC5000002818BFFFDFBDE8F081C1F3001282B1B8 -:10FC600010293FD090F8330020B108F03AF8402036 -:10FC700008F050FF206890F8221011F0040F36D0E1 -:10FC800043E090F8242090F82C309A422AD1B0F822 -:10FC90004800002808BF11F0010F05D111F0020F34 -:10FCA00008BF11F0200F6FD04FF001014FF000009E -:10FCB000FFF799FC206801E041E035E0418C11F04C -:10FCC000010F04BFC1F34001002907D1B0F85A1059 -:10FCD000B0F84820914218BFBDE8F08180F831703B -:10FCE000BDE8F081BDE8F041002101207BE490F8FF -:10FCF0003710012914BF0329102646F00E0190F891 -:10FD00005E204FF0000008F054FF206890F83400A7 -:10FD1000002818BF08F01DFF0021962008F08CFE77 -:10FD200020684570BDE8F081B0F85A10B0F848007E -:10FD3000814242D0BDE8F0410121084653E4817878 -:10FD4000D9B1418C11F0010F22D080F86C7090F87D -:10FD50006E20B0F870100120FEF730FC206845706E -:10FD600008F0CCFE08F0ABFE08F074FD08F020FEB1 -:10FD7000BDE8F04103200AF07CB88178012004E05E -:10FD800053E4B36E6800002017E0BDE8F0412AE4B8 -:10FD900011F0020F04BFFFDFBDE8F081B0F85A1088 -:10FDA000B0F84000814208D001210846FFF71BFC53 -:10FDB000216803204870BDE8F081BDE8F041FFF7FD -:10FDC00082B8FFF780B810B5FE4C206890F8341068 -:10FDD00049B1383008F0CCFE18B921687F2081F88D -:10FDE000380008F0ACFE206890F8330018B108F035 -:10FDF0009BFE07F08AFF0AF02EFCA8B1206890F85D -:10FE00002210C1F3001179B14078022818BFFFDF3A -:10FE100000210120FFF7E7FB2068417800291EBF81 -:10FE200040780128FFDF10BDBDE81040FFF74BB858 -:10FE30002DE9F047E34C0F4680462168B8F1030FE7 -:10FE4000488C08BFC0F3400508D000F0010591F8C8 -:10FE50003200002818BF4FF0010901D14FF000090E -:10FE600008F00CFB0646B8F1030F0CBF4FF0020878 -:10FE70004FF0010835EA090008BFBDE8F0872068A7 -:10FE800090F8330068B10DF08FFD38700146FF28FF -:10FE900007D06068C01C0DF060FD38780DF091FD52 -:10FEA000064360680178C1F3801221680B7D9A4295 -:10FEB00008D10622C01C1531FEF792FA002808BFAF -:10FEC000012000D000203978FF2906D0C8B9206869 -:10FED00090F82D00884216D113E0A0B1616811F8A6 -:10FEE000030BC0F380100DF006FD05460DF061FE1A -:10FEF00038B128460DF0DAFB18B1102100F088FF68 -:10FF000008B1012000E00020216891F8221011F0D2 -:10FF1000040F01D0F0B11AE0CEB9AB4890F8370029 -:10FF2000002818BF404515D1616811F8030BC0F3D4 -:10FF300080100DF0E0FC04460DF03BFE38B1204689 -:10FF40000DF0B4FB18B1102100F062FF10B10120D8 -:10FF5000BDE8F0870020BDE8F0872DE9F04F994D0E -:10FF6000044683B0286800264078022818BFFFDFC7 -:10FF700028684FF07F0B90F8341049B1383008F002 -:10FF8000F7FD002804BF286880F838B008F0D7FDD6 -:10FF900068680DF009FF8046002C00F0458208F0EB -:10FFA00010FA002800F04082012400274FF0FF09DA -:10FFB000B8F1050F1ED1686890F8240000F01F000A -:10FFC000102817D9286890F8360098B18DF800905D -:10FFD00069460520FFF72CFF002800F025822868DD -:10FFE00080F8A64069682222A730C91CFEF725FACE -:10FFF00000F01ABA68680EF062F8002800F0148267 -:020000040001F9 -:100000004046DFF8C4814FF0030A062880F02182C1 -:10001000DFE800F0FCFCFC03FCFB8DF80090694677 -:100020000320FFF705FF002800F0F180296891F810 -:10003000340010B191F89C00D8B12868817801296A -:100040004DD06868042107800DF08CFE08F10E0188 -:1000500068680DF0ADFE98F80D1068680DF0C4FEEC -:100060002868B0F84020C16B68680DF0FAFE00F017 -:1000700063B99DF8000081F89C400A7881F89D20C2 -:10008000FF280FD001F19F029E310DF04FFC002898 -:1000900008BFFFDF286890F89E1041F0020180F849 -:1000A0009E100DE068680278C2F3801281F89E20ED -:1000B000D0F80320C1F89F20B0F80700A1F8A300F2 -:1000C000286800F1A50490F838007F2808BFFFDFFA -:1000D000286890F83810217080F838B0ADE790F8B3 -:1000E00022000721C0F3801938480479686869F351 -:1000F000861407800DF036FE002168680EF029F89E -:10010000214668680EF031F80623002208F10E013E -:1001100068680EF004F82868417B68680DF064FE9A -:1001200068680DF0DBFE2968B1F84020C0F1FE01DF -:100130008A42B8BF1146CFB2BA423CD9F81EC7B204 -:1001400044F0100B594668680EF00FF868680DF01F -:10015000FCFF384400F101082868B0F86A10426ECC -:10016000C1F30B0151FA82F190F86020184C0A4457 -:10017000A4460023E2FB04C319096FF0240301FB2A -:10018000032180F8601090F85F004246012100F0E2 -:10019000A3F90190BDF804009DF80610032340EA7E -:1001A00001400290042202A968680DF0B8FF594688 -:1001B00068680DF0DAFFB9F1000F0FD0D5E9001033 -:1001C000012307E0680000200C060020C86102003F -:1001D00053E4B36E062261310DF0A1FF28683A4660 -:1001E000C16B68680DF0EFFF2868A0F85A70B0F88E -:1001F00040108F420CBF0121002180F8311009F01E -:10020000C0F8002818BFFFDF96E007E021E128686A -:100210008078002840F00A8100F006B98DF800903F -:1002200068680178C1F38019D0F803100191B0F823 -:100230000700ADF8080069460520FFF7F9FD002822 -:1002400028687DD0817800297CD090F85FB0D5E90E -:100250000104D0F80F10C4F80E10B0F8131061822A -:10026000417D2175817D6175B0F81710E182B0F88C -:1002700019106180B0F81B10A180B0F81D10E1804A -:1002800000F11F0104F1080015F085FE686890F880 -:10029000241001F01F01217690F82400400984F811 -:1002A000880184F864B084F865B01BF00C0F0CBFB3 -:1002B0000021012104F130000EF0ABF92868002282 -:1002C00090F8691084F8661090F8610084F867006F -:1002D0009DF80010A868FFF7BAFB022009F0C9FDDD -:1002E000B2480DF1040B08210468686807800DF01E -:1002F00039FD002168680DF02CFF214668680DF07B -:1003000034FF0623002208F10E0168680DF007FF94 -:100310002868417B68680DF067FD494668680DF004 -:1003200070FD06230122594668680DF0F8FE09F0B9 -:1003300028F8002818BFFFDF286880F801A077E0C0 -:100340006DE0FFE76868D5F808804FF00109027892 -:1003500098F80D10C2F34012114088F80D10D0F833 -:100360000F10C8F80E10B0F81310A8F81210417D45 -:1003700088F81410817D88F81510B0F81710A8F8C7 -:100380001610B0F81910A8F80210B0F81B10A8F851 -:100390000410B0F81D10A8F8061000F11F0108F1B4 -:1003A000080015F0F8FD686890F8241001F01F01AE -:1003B00088F8181090F824000021400988F8880176 -:1003C00088F8649088F8659008F130000EF021F903 -:1003D0002868002290F8691088F8661090F861008B -:1003E00088F867009DF80010A868FFF730FB2868C0 -:1003F00080F86C4090F86E20B0F870100120FEF785 -:10040000DDF82868477008F079FB08F058FB08F021 -:1004100021FA08F0CDFA012009F02BFD08E090F850 -:100420002200C0F3001008B1012601E0FEF74BFDE9 -:10043000286890F8330018B108F076FB07F065FCE7 -:1004400096B10AF008F960B100210120FFF7CBF85E -:1004500013E0286890F82200C0F300100028E5D0CF -:10046000E2E7FEF730FD08E028688178012904D131 -:1004700090F85F10FF2007F0E4FE2868417800291B -:1004800019BF4178012903B0BDE8F08F40780328F7 -:1004900018BFFFDF03B0BDE8F08F70B5444C0646CF -:1004A0000D462068807858B107F0F2FD21680346B8 -:1004B000304691F85F202946BDE870400AF085BAC1 -:1004C00007F0E6FD21680346304691F85E20294694 -:1004D000BDE870400AF079BA78B50C460021009169 -:1004E000082804BF4FF4C87040210DD0042804BF71 -:1004F0004FF4BF70102107D0022807BF01F1180088 -:10050000042101F128000821521D02FB01062848A0 -:100510009DF80010006890F8602062F3050141F03A -:1005200040058DF8005090F85F00012829D002287E -:100530002ED004281CBF0828FFDF2FD025F0800014 -:100540008DF80000C4EB041000EB80004FF01E019A -:1005500001EB800006FB04041648844228BFFFDF3D -:100560001548A0FB0410BDF80110000960F30C0150 -:10057000ADF80110BDF800009DF8021040EA0140FE -:1005800078BD9DF8020020F0E0008DF80200D5E76C -:100590009DF8020020F0E000203004E09DF8020009 -:1005A00020F0E00040308DF80200C7E7C86102008B -:1005B00068000020C4BF0300898888880023C383A3 -:1005C000428401EBC202521EB2FBF1F1018470477A -:1005D0002DE9F04104460026D9B3552333224FF4C8 -:1005E000FA4501297DD0022900F01481032918BFA2 -:1005F000BDE8F08104F17001207B00F01F00207342 -:1006000084F889605FF0000004EB000C9CF808C0DF -:1006100003EA5C05ACEB050C0CF0FF0C0CF03305A9 -:1006200002EA9C0CAC440D180CEB1C1C0CF00F0CDB -:1006300085F814C04D7E401CAC44C0B281F819C08E -:100640000528E1D30CF0FF00252898BFBDE8F08114 -:10065000DCE0FFE704F17005802200212846FDF769 -:1006600016FFAE71EE712E736E73EE732E746E7193 -:10067000AE76EE76212085F84000492085F84100CD -:10068000FE2085F874002588702200212046FDF7A1 -:10069000FEFE2580012584F8645084F865502820EA -:1006A00084F86600002104F130000DF0B2FF1B2237 -:1006B000A4F84E20A4F85020A4F85220A4F8542006 -:1006C0004FF4A470A4F85600A4F8580065734FF4D2 -:1006D00048606080A4F8F060A4F8F260A4F8F460C8 -:1006E00000E023E0A4F8F660A4F8F86084F8FA606B -:1006F00084F8FD60A4F8066184F80461A4F8186128 -:10070000A4F81A6184F8B66184F8B76184F8C0610E -:1007100084F8C16184F88C6184F88F6184F8A861E1 -:10072000C4F8A061C4F8A461BDE8F081A4F8066132 -:1007300084F8FB606088FE490144B1FBF0F1A4F845 -:1007400090104BF68031A4F89210B4F806C0A4F8CB -:100750009860B4F89C704FEACC0C4743BCFBF0FCAB -:1007600097FBF0F70CF1010CA4F89C701FFA8CFCBD -:100770000CFB00F704F17001A4F89AC0B7F5C84F5C -:10078000C4BFACF1010CA1F82AC0B5FBF0FC0CF120 -:10079000010CA1F830C000F5802C0CF5EE3CACF15A -:1007A0000105B5FBF0FCA1F820C0CD8B05FB00FCDA -:1007B000BCFBF0F0C8830846217B01F01F012173C8 -:1007C0004676002104EB010C9CF808C003EA5C05A6 -:1007D000ACEB050C0CF0FF0C0CF0330502EA9C0CA2 -:1007E000AC4445180CEB1C1C0CF00F0C85F814C025 -:1007F000457E491CAC44C9B280F819C00529E1D333 -:100800000CF0FF00252898BFBDE8F081FFDFBDE8B0 -:10081000F08100BFB4F8B011B4F8B4316288A4F824 -:100820009860B4F89CC0DB000CFB02FCB3FBF1F356 -:100830009CFBF1FC5B1CA4F89CC09BB203FB01FC7D -:1008400004F17000A4F89A30BCF5C84FC4BF5B1E19 -:100850004385B5FBF1F35B1C0386438C01EBC303BB -:100860005B1EB3FBF1F30384C38B5A43B2FBF1F17C -:10087000C183BDE8F0812DE9F04104460025A1B314 -:1008800055234FF4FA464FF0330C01297DD002294D -:1008900000F0E080032918BFBDE8F08104F170008A -:1008A000217B01F01F01217384F889500021621817 -:1008B000127A03EA5205521BD2B202F033050CEA57 -:1008C00092022A44451802EB121202F00F022A7516 -:1008D000457E491C2A44C9B242760529E7D3D0B2E5 -:1008E000252898BFBDE8F081B1E0FFE704F170066C -:1008F000802200213046FDF7CAFDB571F5713573D0 -:100900007573F57335747571B576F576212086F8B3 -:100910004000492086F84100FE2086F874002688B1 -:10092000702200212046FDF7B2FD2680012684F8C2 -:10093000646084F86560282084F86600002104F172 -:1009400030000DF066FE1B22A4F84E20A4F85020C3 -:10095000A4F85220A4F854204FF4A470A4F8560030 -:10096000A4F858006673A4F8F850202084F8FA0020 -:1009700084F8F050C4F8F45084F8245184F82551D8 -:1009800084F82E5184F82F5100E005E084F81451CA -:1009900084F82051BDE8F081618865480844B0FBC7 -:1009A000F1F0A4F890004BF68030A4F89200E288B1 -:1009B000A4F89850B4F89C70D2004F43B2FBF1F207 -:1009C00097FBF1F7521CA4F89C7092B202FB01F75E -:1009D00004F17000A4F89A20B7F5C84FC4BF521EA6 -:1009E0004285B6FBF1F2521C028601F5802202F527 -:1009F000EE32561EB6FBF1F20284C68B06FB01F204 -:100A0000B2FBF1F1C1830146207B00F01F0020738F -:100A10004D7600202218127A03EA5205521BD2B2F8 -:100A200002F033050CEA92022A440D1802EB12126E -:100A300002F00F022A754D7E401C2A44C0B24A764D -:100A40000528E7D3D0B2252898BFBDE8F081FFDFA5 -:100A5000BDE8F081D0F81811628804F1700348896C -:100A6000C989A4F89850B4F89CC0C9000CFB02FCDA -:100A7000B1FBF0F19CFBF0FC491CA4F89CC089B2CE -:100A800001FB00FCA4F89A10BCF5C84FC4BF491E76 -:100A90005985B6FBF0F1491C1986598C00EBC10150 -:100AA000491EB1FBF0F11984D98B5143B1FBF0F031 -:100AB000D883BDE8F0812DE9F003447E0CB1252CEC -:100AC00003D9BDE8F00312207047002A02BF0020BE -:100AD000BDE8F003704791F80DC01F260123154DA6 -:100AE0004FF00008BCF1000F7AD0BCF1010F1EBF1F -:100AF0001F20BDE8F0037047B0F800C00A7C8F7B70 -:100B000091F80F907A404F7C87EA090742EA072262 -:100B100082EA0C0C5FF000070CF0FF0999FAA9F9C2 -:100B20004FEA1C2C4FEA19699CFAACFC04E0000067 -:100B3000FFDB050053E4B36E4FEA1C6C49EA0C2C52 -:100B40000CEB0C1C7F1C9444FFB21FFA8CFC032F8F -:100B5000E2D38CEA020CFB4F0022ECFB0572120977 -:100B60006FF0240502FB05C2D2B201EBD2078276F8 -:100B700002F007053F7A03FA05F52F4218BFC27647 -:100B80007ED104FB0CF2120C521CD2B25FF00004B6 -:100B900000EB040C9CF814C094453CBFA2EB0C0283 -:100BA000D2B212D30D194FF0000C2D7A03FA0CF7C4 -:100BB0003D421CBF521ED2B2002A69D00CF1010C7A -:100BC0000CF0FF0CBCF1080FF0D304F1010C0CF099 -:100BD000FF04052CDCD33046BDE8F0037047FFE787 -:100BE00090F81AC00C7E474604FB02C2D54C4FF069 -:100BF000000CE2FB054C4FEA1C1C6FF024040CFBBC -:100C00000422D2B201EBD204827602F0070C247ADD -:100C100003FA0CFC14EA0C0F1FBFC2764046BDE875 -:100C2000F003704790F819C0B2FBFCF40CFB1422DF -:100C3000521CD2B25FF0000400EB040C9CF814C00C -:100C400094453CBFA2EB0C02D2B212D30D194FF067 -:100C5000000C2D7A03FA0CF815EA080F1CBF521E7F -:100C6000D2B272B10CF1010C0CF0FF0CBCF1080F08 -:100C7000F0D304F1010C0CF0FF04052CDCD3AAE73F -:100C800009E00CEBC401C1763846BDE8F0037047BB -:100C90000CEBC401C1764046BDE8F0037047AA4A98 -:100CA000016812681140A94A126811430160704737 -:100CB00030B4A749A44B00244FF0010C0A78521C11 -:100CC000D2B20A70202A08BF0C700D781A680CFA8C -:100CD00005F52A42F2D0097802680CFA01F1514078 -:100CE000016030BC704770B46FF01F02010C02EA63 -:100CF00090251F23A1F5AA4054381CBFA1F5AA4096 -:100D0000B0F1550009D0A1F52850AA381EBFA1F5B1 -:100D10002A40B0F1AA00012000D100204FF0000CC1 -:100D2000624601248CEA0106F6431643B6F1FF3F02 -:100D300011D005F001064FEA5C0C4CEAC63C03F00A -:100D4000010652086D085B08641C42EAC632162C84 -:100D5000E8DD70BC704770BC0020704790F804C09C -:100D60003CF01F011CBF0020704730B401785522B1 -:100D700002EA5103C91AC9B201F03304332303EA6A -:100D800091012144447801EB111102EA5405641BDE -:100D9000E4B204F0330503EA94042C4404EB141485 -:100DA00001F00F0104F00F040C448178C07802EACE -:100DB0005105491BC9B201F0330503EA91012944E9 -:100DC00001EB111101F00F01214402EA5004001B54 -:100DD000C0B200F0330403EA9000204400EB10108E -:100DE00000F00F00014402EA5C00ACEB0000C0B26E -:100DF00000F0330203EA9000104400EB101000F002 -:100E00000F00084401288CBF0120002030BC70472F -:100E10000A000ED00123012A0BDB491EC9B210F8CB -:100E200001C0BCF1000F01D0002070475B1C934251 -:100E3000F3DD01207047002A08BF70471144401EAF -:100E400012F0010F03D011F8013D00F8013F5208E4 -:100E500008BF704711F8013C437011F8023D00F8DB -:100E6000023F521EF6D1704770B58CB000F11004ED -:100E70001D4616460DF1FF3C5FF0080014F8012CEA -:100E80008CF8012014F8022D0CF8022F401EF5D129 -:100E900001F1100C6C460DF10F0108201CF8012C1B -:100EA0004A701CF8022D01F8022F401EF6D1204690 -:100EB00013F01CFB7EB16A1E04F130005FF00801E4 -:100EC00010F8013C537010F8023D02F8023F491E31 -:100ED000F6D10CB070BD08982860099868600A982F -:100EE000A8600B98E8600CB070BD38B505460C469C -:100EF000684607F03DFE002808BF38BD9DF9002078 -:100F00002272E07E607294F90A100020511A48BFE4 -:100F1000494295F82D308B42C8BF38BDFF2B08BF22 -:100F200038BDE17A491CC9B2E17295F82E30994278 -:100F300003D8A17A7F2918BF38BDA2720020E072C1 -:100F4000012038BD53E4B36E04620200086202005F -:100F5000740000200C2818BF0B2810D00D2818BFD3 -:100F60001F280CD0202818BF212808D0222818BFFD -:100F7000232804D024281EBF2628002070474FF0C5 -:100F8000010070470C2963D2DFE801F006090E1357 -:100F9000161B323C415C484E002A5BD058E0072AC1 -:100FA00018BF082A56D053E00C2A18BF0B2A51D07C -:100FB0004EE00D2A4ED04BE0A2F10F000C2849D98B -:100FC00046E023B1A2F110000B2843D940E0122AD9 -:100FD00018BF112A3ED090F8380020B1122A37D31A -:100FE0001A2A37D934E0162A32D31A2A32D92FE0F6 -:100FF000A2F10F0103292DD990F8380008B31B2A5C -:1010000028D925E0002B08BF042A21D122E013B102 -:10101000062A1FD01CE0012A1AD11BE01C2A1CBF83 -:101020001D2A1E2A16D013E01F2A18BF202A11D00D -:10103000212A18BF222A0DD0232A1CBF242A262A9F -:1010400008D005E013B10E2A04D001E0052A01D032 -:1010500000207047012070472DE9F0410D460446FD -:10106000866805F02FFA58B905F07EF840F236711F -:1010700004F061FDA060204605F024FA0028F3D0BA -:1010800095B13046A16805F067FD00280CDD2844C5 -:10109000401EB0FBF5F707FB05F1304604F04BFDB1 -:1010A000A0603846BDE8F0810020BDE8F08170B551 -:1010B0000446904228BF70BD101B64280BD325182E -:1010C0008D4206D8042105F07AFD00281CBF284671 -:1010D00070BD204670BD6420F1E711F00C0F13D0F5 -:1010E00001F0040100290DBF4022102296214FF487 -:1010F000167101F5BC71A0EB010388428CBF93FB14 -:10110000F2F0002080B27047022919BF6FF00D0184 -:1011100001EBD0006FF00E0101EB9000F2E7084404 -:1011200018449830002A14BF042100210844704755 -:1011300010B4002A14BF4FF429624FF4A472002B9C -:1011400019BF4FF429634FF0080C4FF4A4734FF00C -:10115000010C00280CBF0124002491F866001CF04B -:101160000C0F08BF0020D11808449830002C14BF81 -:1011700004210021084410BC704700280CBF012343 -:10118000002391F86600002BA0F6482000F50050DF -:1011900018BF04231844496A81422CBF0120002053 -:1011A00012F00C0118BF012131EA000014BF002029 -:1011B0000120704710B413680B66137813F00C030A -:1011C00018BF0123527812F00C0218BF012253EA13 -:1011D000020C04BF10BC7047002B0CBF4FF4A4736B -:1011E0004FF42963002A19BF4FF429624FF0080C0D -:1011F0004FF4A4724FF0010C00280CBF012400240E -:1012000091F866001CF00C0F08BF00201A4410442F -:101210009830002C14BF0422002210444A6A8242F3 -:1012200024BF10BC704791F860004FF0030230F00B -:101230000C0381F8603091F8610020F00C0081F817 -:10124000610008BF81F86020002808BF81F8612094 -:1012500010BC704710F0010F1CBF0120704710F048 -:10126000020F1CBF0220704710F0040018BF0820B6 -:1012700070472DE9F0470446174689464FF00108AC -:1012800008460DF0FAF8054648460DF0FAF810F059 -:10129000010F18BF012624D015F0010F18BF01233C -:1012A0002AD000BF56EA030108BF4FF0000810F033 -:1012B000070F08BF002615F0070F08BF002394F89A -:1012C0006400B0420CBF00203046387094F86510BE -:1012D000994208BF00237B70002808BF002B25D14E -:1012E00015E010F0020F18BF0226D5D110F0040F40 -:1012F00014BF08260026CFE715F0020F18BF0223FF -:10130000D0D115F0040F14BF08230023CAE74846C4 -:101310000DF0BDF8B4F87010401A00B247F6FE7137 -:10132000884201DC002801DC4FF0000816B1082ECD -:101330000CD018E094F86400012818BF022812D0DD -:1013400004281EBF0828FFDF032D0CD194F8C0012C -:1013500048B1B4F8C401012894F8640006D0082804 -:1013600001D0082038704046BDE8F087042818BF37 -:101370000420F7D1F5E7012814BF0228704710F0C8 -:101380000C0018BF0420704738B4CBB2C1F3072C4F -:10139000C1B2C0F30724012B07D0022B09D0042BC4 -:1013A00008BFBCF1040F2DD006E0BCF1010F03D142 -:1013B00028E0BCF1020F25D0012906D0022907D070 -:1013C000042908BF042C1DD004E0012C02D119E02F -:1013D000022C17D001EA0C0161F3070204EA0301B1 -:1013E00061F30F22D1B211F0020F18BF022310D007 -:1013F000C2F307218DF8003011F0020F18BF02214F -:101400001BD111E0214003EA0C03194061F30702EC -:10141000E6E711F0010F18BF0123E9D111F0040F25 -:1014200014BF08230023E3E711F0010F18BF0121C7 -:1014300003D111F0040118BF08218DF80110082B09 -:1014400001BF000C012804208DF80000BDF8000049 -:1014500038BC70474FF0000C082902D0042909D08D -:1014600011E001280FD10420907082F803C013808E -:1014700001207047012806D00820907082F803C030 -:1014800013800120704700207047162A10D12A22AD -:101490000C2818BF0D280FD04FF0230C1F280DD09B -:1014A00031B10878012818BF002805D0162805D0CA -:1014B00000207047012070471A70FBE783F800C0D6 -:1014C000F8E7012908D002290BD0042912BF082906 -:1014D00040F6A660704707E0002804BF40F2E240F3 -:1014E000704740F6C410704700B5FFDF40F2E2409D -:1014F00000BD00000178406829B190F82C1190F8E7 -:101500008C0038B901E001F0BDBD19B1042901D04A -:10151000012070470020704770B50C460546062133 -:1015200002F0C4FC606008B1002006E007212846F4 -:1015300002F0BCFC606018B101202070002070BD7A -:10154000022070BD2DE9FC470C4606466946FFF7B0 -:10155000E3FF00287DD19DF8000050B1FDF7EEF8C3 -:10156000B0427CD0214630460AF008FC002873D1F6 -:101570002DE00DF097F9B04271D02146304612F0BF -:10158000B6FA002868D1019D95F8F00022E001200C -:1015900000E00020804695F839004FF0010A4FF036 -:1015A0000009F0B195F83A0080071AD584F8019047 -:1015B00084F800A084F80490E68095F83B1021722E -:1015C000A98F6181E98FA18185F8399044E0019D5F -:1015D00095F82C0170350028DBD1287F0028D8D061 -:1015E000D5E7304602F0A5FD070000D1FFDF384601 -:1015F00001F0B5FF40B184F801900F212170E68021 -:10160000208184F804A027E0304602F080FD070026 -:1016100000D1FFDFB8F1000F21D0384601F0F7FF0D -:10162000B8B19DF8000038B90198D0F81801418888 -:10163000B14201D180F80090304607F00DFF84F8E8 -:1016400001900C21217084F80490E680697F21725A -:1016500000E004E085F81C900120BDE8FC87002034 -:10166000FBE71CB56946FFF757FF00B1FFDF68468F -:1016700001F014FDFE4900208968A1F8F2001CBDAC -:101680002DE9FC4104460E46062002F0B7FB054654 -:10169000072002F0B3FB2844C7B20025A8463E4409 -:1016A00017E02088401C80B22080B04202D3404620 -:1016B000A4F8008080B2B84204D3B04202D2002025 -:1016C000BDE8FC816946FFF727FF0028F8D06D1CB4 -:1016D000EDB2AE42E5D84FF6FF7020801220EFE762 -:1016E00038B54FF6FF70ADF800000DE00621BDF8EB -:1016F000000002F0EDFB04460721BDF8000002F0F7 -:10170000E7FB0CB100B1FFDF00216846FFF7B8FF2F -:101710000028EBD038BD70B507F00CFF0BF034FF9C -:10172000D44C4FF6FF76002526836683D2A0257021 -:1017300001680079A4F14002657042F8421FA11CC3 -:101740001071601C12F0EFFA1B2020814FF4A4717D -:101750006181A081E18107212177617703212174D3 -:10176000042262746082A082A4F13E00E1820570CE -:101770004680BF480C300570A4F11000057046800B -:1017800084F8205070BD70B5B94C16460D466060A7 -:10179000217007F047FEFFF7A3FFFFF7BCFF20789B -:1017A0000FF0BDFFB6480DF0D0F92178606812F057 -:1017B0005FFA20780BF0DCF8284608F0AFFEB0485E -:1017C000FCF7C7FF217860680AF0B2FB3146207849 -:1017D00012F024FDBDE870400BF0D6BE10B5012418 -:1017E0000AB1002010BD21B1012903D000242046F8 -:1017F00010BD02210CF024FDF9E710B50378044672 -:10180000002B406813460A46014609D05FF00100EC -:10181000FFF78EFC6168496A884203D9012010BD38 -:101820000020F5E7002010BD2DE9F04117468A7829 -:101830001E46804642B11546C87838B1044669074D -:1018400006D52AB1012104E00725F5E70724F6E7CC -:101850000021620702D508B1012000E0002001420A -:1018600006D0012211464046FFF7C7FF98B93DE078 -:1018700051B1002201214046FFF7BFFF58B9600770 -:1018800034D50122114620E060B1012200214046FA -:10189000FFF7B3FF10B10920BDE8F081680725D537 -:1018A000012206E068074FEA44700AD5002814DBDD -:1018B000002201214046FFF7A0FFB8B125F0040542 -:1018C00014E0002812DA012200214046FFF795FFBC -:1018D00060B100BF24F0040408E001221146404634 -:1018E000FFF78BFF10B125F00405F3E73D7034706E -:1018F0000020D1E770B58AB0044600886946FFF73A -:101900000BFE002806D1A08830B1012804D002289F -:1019100002D012200AB070BD04AB03AA214668466B -:10192000FFF782FF0500F5D19DF800100120002689 -:101930000029019906D081F8C101019991F80C1292 -:10194000B1BB2DE081F82F01019991F8561139B9F9 -:10195000019991F82E1119B9019991F8971009B1CF -:101960003A2519E00199059681F82E01019A9DF812 -:101970000C0082F83001019B9DF8102083F8312182 -:10198000A388019CA4F832318DF814008DF815203D -:1019900005AA0020FFF70EFC019880F82F6126E0D1 -:1019A000019991F8C01119B9019991F8971009B1ED -:1019B0003A2519E00199059681F8C00101989DF832 -:1019C0000C2080F8C221019B9DF8100083F8C30110 -:1019D000A388019CA4F8C4318DF814208DF815005B -:1019E00005AA0120FFF7E6FB019880F8C1612846AF -:1019F00090E710B504460020A17801B90120E278F3 -:101A00000AB940F0020001F058FB002803D120463B -:101A1000BDE810406EE710BD70B5044691F8650052 -:101A200091F866300D4610F00C0F00D1002321898B -:101A3000A088FFF774FB696A814229D2401A401CD2 -:101A4000A1884008091A8AB2A2802189081A208137 -:101A5000668895F864101046FFF73FFB864200D277 -:101A600030466080E68895F8651020890AE000001D -:101A70007800002018080020FFFFFFFF1F00000073 -:101A8000D8060020FFF729FB864200D23046E080CE -:101A900070BDF0B585B00D46064603A9FFF73CFDC5 -:101AA00000282DD19DF80C0060B300220499FB2082 -:101AB000B1F84E30FB2B00D30346B1F85040FB2069 -:101AC000FB2C00D30446DFF85CC59CE88110009035 -:101AD0000197CDF808C0ADF80230ADF80640684671 -:101AE000FFF79AFF6E80BDF80400E880BDF808009B -:101AF0006881BDF80200A880BDF80600288100209A -:101B000005B0F0BD0122D1E72DE9F04186B00446D1 -:101B100000886946FFF700FD002876D12189E0881A -:101B200001F0E4FA002870D1A188608801F0DEFAA3 -:101B300000286AD12189E08801F0CFFA002864D119 -:101B4000A188608801F0C9FA07005ED1208802A947 -:101B5000FFF79FFF00B1FFDFBDF81010628809207A -:101B6000914252D3BDF80C10E28891424DD3BDF89A -:101B70001210BDF80E2023891144A2881A44914204 -:101B800043D39DF80010019D4FF00008012640F658 -:101B9000480041B185F8B761019991F8F81105F550 -:101BA000DB7541B91AE085F82561019991F84A1170 -:101BB00005F5927509B13A2724E0E18869806188CA -:101BC000E9802189814200D30146A980A188814210 -:101BD00000D208462881012201990FE0E18869803E -:101BE0006188E9802189814200D30146A980A188CA -:101BF000814200D208462881019900222846FFF739 -:101C00000BFF2E7085F80180384606B044E67BE76E -:101C100070B504460CF0FCFDB0B12078182811D145 -:101C2000207901280ED1E088062102F03FF9040056 -:101C300008D0208807F010FC2088062102F048F91F -:101C400000B1FFDF012070BDF74D28780028FAD0E1 -:101C5000002666701420207020223146201DFCF7DB -:101C600016FC022020712E70ECE710B50446FCF73C -:101C7000DBFC002813D0207817280FD1207968B119 -:101C8000E088072102F012F940B1008807F0E4FB78 -:101C9000E088072102F01CF900B1FFDF012010BD30 -:101CA0002DE9F0475FEA000800D1FFDFDE4802219E -:101CB0001A308146FFF7E4FC00B1FFDFDA4C062062 -:101CC000678B02F09BF80546072002F097F828443E -:101CD000C5B2681CC6B2608BB04203D14046FFF764 -:101CE000C4FF58B9608BA84203D14046FFF790FF6C -:101CF00020B9608B4146FFF725FC38B1404601F022 -:101D000003FA0028E7D10120BDE8F0870221484608 -:101D1000FFF7B6FC10B9608BB842DCD14046BDE895 -:101D2000F04712F0C1BA10B501F053F908B10C2018 -:101D300010BD0BF07DFC002010BD10B504460078EE -:101D400018B1012801D0122010BD01F053F920B1C3 -:101D50000BF0C0FD08B10C2010BD207801F013F984 -:101D6000E21D04F11703611CBDE810400BF0DABC62 -:101D700010B5044601F02DF908B10C2010BD2078F3 -:101D800028B1012803D0FF280BD0122010BD01F08C -:101D9000FAF8611C0BF00CFC08B1002010BD072004 -:101DA00010BD01200BF03EFCF7E710B50BF095FDE0 -:101DB00008B1002010BD302010BD10B5044601F060 -:101DC00019F908B10C2010BD20460BF080FD002051 -:101DD00010BD10B501F00EF920B10BF07BFD08B17C -:101DE0000C2010BD0BF0F6FC002010BDFF2181700F -:101DF0004FF6FF7181808D4949680A7882718A881F -:101E000002814988418101214170002070477CB5E1 -:101E10000025022A19D015DC12F10C0F15D009DCAF -:101E200012F1280F11D012F1140F0ED012F1100F71 -:101E300011D10AE012F1080F07D012F1040F04D0FB -:101E40004AB902E0D31E052B05D8012806D0022886 -:101E500008D003280AD0122528467CBD1046FDF77D -:101E600013F8F9E710460CF06BFEF5E70846144648 -:101E70006946FFF751FB08B10225EDE79DF8000028 -:101E80000198002580F86740E6E710B51346012267 -:101E9000FEF7EAFF002010BD10B5044610F02FFA3F -:101EA000052804D020460FF029FC002010BD0C208E -:101EB00010BD10B5044601F09DF808B10C2010BD0E -:101EC0002146002007F037FB002010BD10B5044666 -:101ED0000FF0A3FC50B108F0A6FD38B1207808F04F -:101EE00029FB20780DF04DF9002010BD0C2010BD0D -:101EF00010B5044601F07EF808B10C2010BD214653 -:101F0000012007F018FB002010BD38B504464FF63D -:101F1000FF70ADF80000A079E179884216D02079F1 -:101F2000FCF7E3FA90B16079FCF7DFFA70B10022B8 -:101F3000A079114612F0A0FD40B90022E0791146C7 -:101F400012F09AFD10B9207A072801D9122038BD65 -:101F500008F076FD60B910F0D2F948B90021684662 -:101F6000FFF78EFB20B1204606F044F9002038BD73 -:101F70000C2038BD2DE9FC41817805461A2925D071 -:101F80000EDC16292ED2DFE801F02D2D2D2D2D216E -:101F90002D2D2D2D2D2D2D2D2D2D2D2D2D21212195 -:101FA0002A291FD00BDCA1F11E010C291AD2DFE86F -:101FB00001F019191919191919191919190D3A399D -:101FC00004290FD2DFE801F00E020E022888B0F5D6 -:101FD000706F07D201276946FFF79EFA20B10220F1 -:101FE000BDE8FC811220FBE79DF8000000F0D2FF65 -:101FF000019C10B104F58A7401E004F5C6749DF8E3 -:10200000000000F0C7FF019E10B106F2151601E0B6 -:1020100006F28D166846FFF76DFA08B1207838B1E0 -:102020000C20DDE70C620200180800207800002078 -:102030002770A8783070684601F030F80020CFE7AC -:102040007CB50D466946FFF767FA002618B12E6089 -:102050002E7102207CBD9DF8000000F09BFF019CCA -:102060009DF80000703400F095FF019884F84260FC -:1020700081682960017B297194F842100029F5D10B -:1020800000207CBD10B5044600F0B4FF20B10BF079 -:1020900021FC08B10C2010BD207800F074FFE2791B -:1020A000611C0BF093FD08B1002010BD022010BD93 -:1020B00010B5886E60B1002241F8682F0120CA7106 -:1020C0008979884012F0CCFC002800D01F2010BD78 -:1020D0000C2010BD1CB50C466946FFF71DFA002800 -:1020E00009D19DF8000000280198B0F8700000D0D8 -:1020F000401C208000201CBD1CB504460088694699 -:10210000FFF70AFA08B102201CBD606828B1DDE9BA -:102110000001224601F04CF81CBDDDE90001FFF78B -:10212000C7FF1CBD70B51C460D4618B1012801D073 -:10213000122070BD1946104601F078F830B12146E2 -:10214000284601F07DF808B1002070BD302070BD38 -:1021500070B5044600780E46012804D018B1022854 -:1021600001D0032840D1607828B1012803D002288B -:1021700001D0032838D1E07B10B9A078012833D1F1 -:10218000A07830F005012FD110F0050F2CD0628916 -:10219000E188E0783346FFF7C5FF002825D1A07815 -:1021A00005281DD16589A289218920793346FFF749 -:1021B000B9FF002819D1012004EB40014A891544D8 -:1021C0002218D378927893420ED1CA8889888A429D -:1021D0000AD1401CC0B20228EED3E088A84203D343 -:1021E000A07B08B1072801D9122070BD002070BD66 -:1021F00010B586B0044600F0E1FE10B10C2006B028 -:1022000010BD022104F10A0001F02FF8A0788DF82A -:102210000800A0788DF8000060788DF80400207820 -:102220008DF80300A07B8DF80500E07B00B1012054 -:102230008DF80600A078C10717D0E07801F00CF8FF -:102240008DF80100E088ADF80A006089ADF80C0057 -:10225000A078400716D5207900F0FEFF8DF8020027 -:102260002089ADF80E00A0890AE040070AD5E07881 -:1022700000F0F2FF8DF80200E088ADF80E006089F2 -:10228000ADF8100002A80FF0D4FA0028B7D16846C4 -:102290000CF07CFFB3E710B504460121FFF758FFAF -:1022A000002803D12046BDE81040A1E710BD027808 -:1022B000012A01D0BAB118E042783AB1012A05D01A -:1022C000022A12D189B1818879B100E059B14188DF -:1022D00049B1808838B101EB8101490000EB8000F1 -:1022E000B1EB002F01D2002070471220704770B56B -:1022F000044600780D46012809D010F000F80528A2 -:1023000003D00FF0A6F9002800D00C2070BD0CF00F -:102310000AFE88B10CF01CFE0CF018FF0028F5D165 -:1023200025B160780CF0ACFE0028EFD1A188608860 -:10233000BDE870400FF0A3BA122070BD10B504467E -:102340000121FFF7B4FF002804D12046BDE810406A -:102350000121CCE710BDF0B5871FDDE9056540F62A -:102360007B44A74213D28F1FA74210D288420ED8B7 -:10237000B2F5FA7F0BD2A3F10A00241FA04206D2C5 -:10238000521C4A43B2EB830F01DAAE4201D900205E -:10239000F0BD0120F0BD2DE9FC47477A894604468F -:1023A00017F0050F7ED0F8087CD194F83A0008B9F0 -:1023B000012F77D10025A8462E46F90789F0010A9A -:1023C00019D0208A514600F031FFE8B360895146A8 -:1023D00000F036FFC0B3208A6189884262D8A18E9E -:1023E000E08DCDE90001238D628CA18BE08AFFF79F -:1023F000B2FF48B30125B8070ED504EB4500828E25 -:10240000C18DCDE90012038D428C818BC08AFFF70C -:10241000A2FFC8B1A8466D1C78071ED504EB45067F -:102420005146308A00F002FF70B17089514600F0C9 -:1024300007FF48B1308A7189884253D8B18EF08D38 -:10244000CDE90001338D00E00BE0728CB18BF08A96 -:10245000FFF781FF28B12E466D1CB9F1000F03D0A4 -:1024600030E03020BDE8FC87F80707D0780705D5B5 -:1024700004EB460160894989884233D1228A0121CF -:102480001BE0414503D004EB4100008A024404EB09 -:102490004100C38A868AB34224D1838B468BB342E0 -:1024A00020D100E01EE0438C068CB3421AD1038D8C -:1024B000C08C834216D1491CC9B2A942E1D36089BC -:1024C00090420FD3207810B101280BD102E0A07800 -:1024D0000028F9D1607838B1012805D0022803D04E -:1024E000032801D01220BDE70020BBE7002152E7FE -:1024F0000178C90702D0406811F0A9BE11F076BE7C -:1025000010B50078012800D00020FCF7B8FC0020AE -:1025100010BD2DE9F0478EB00D46AFF6A422D2E9EA -:102520000092014690462846FFF735FF06000CD181 -:1025300000F044FD40B9FE4F387828B90CF0B2F9EC -:10254000A0F57F41FF3903D00C200EB0BDE8F08725 -:10255000032105F1100000F088FEF54809AA3E3875 -:102560000990F4480A90F248062110380B900CA804 -:1025700001F06AFC040037D00021FEF77CF904F179 -:1025800030017B8ABA8ACB830A84797C0091BA466F -:102590003B7CBA8A798A208801F044FD00B1FFDFD4 -:1025A000208806F058FF218804F10E0000F02CFD71 -:1025B000E1A004F1120700680590032105A804F0CA -:1025C0006DFF002005A90A5C3A54401CC0B20328E4 -:1025D000F9D3A88B6080688CA080288DE080687A11 -:1025E000410703D508270AE00920AEE7C10701D05B -:1025F000012704E0800701D5022700E000273A46C2 -:10260000BAF8160011460FF0CFF90146A062204635 -:102610000FF0D8F93A4621460020FEF7AEFD00B98A -:102620000926C34A21461C320020FEF7C3FD0027BD -:1026300084F8767084F87770A87800F0A4FC60764F -:10264000D5F80300C4F81A00B5F80700E083C4F811 -:10265000089084F80C80012084F8200101468DF850 -:102660000070684604F01AFF9DF8000000F00701B2 -:10267000C0F3C1021144C0F3401008448DF80000BB -:10268000401D2076092801D20830207601212046FD -:10269000FEF7F1F868780CF051FCEEBBA9782878C9 -:1026A000EA1C0CF01EFC48B10CF052FCA97828780A -:1026B000EA1C0CF0BFFC060002D052E0122650E0EB -:1026C000687A00F005010020CA0700D001208A07BF -:1026D00001D540F00200490701D540F008000CF098 -:1026E000E9FB06003DD1214603200CF0CDFC06009D -:1026F00037D10CF0D2FC060033D1697A01F0050124 -:102700008DF80810697AC90708D06889ADF80A0001 -:10271000288AADF80C0000E023E00120697A8A07DE -:1027200000D5401C490707D505EB40004189ADF8AD -:102730000E10008AADF8100002A80FF07AF80646D5 -:1027400095F83A0000B101200CF0C6FB4EB90CF030 -:10275000FDFC060005D1A98F20460FF00BF80600FE -:1027600008D0208806F078FE2088062101F0B0FB12 -:1027700000B1FFDF3046E8E601460020C9E638B583 -:102780006B48007878B90FF0BAFD052805D00CF039 -:1027900089F8A0F57F41FF3905D068460FF0B3F8FE -:1027A000040002D00CE00C2038BD0098008806F030 -:1027B00053FE00980621008801F08AFB00B1FFDF7C -:1027C000204638BD1CB582894189CDE900120389B4 -:1027D000C28881884088FFF7BEFD08B100201CBD7B -:1027E00030201CBD70B50546FFF7ECFF00280ED168 -:1027F0002888062101F05AFB040007D000F042FCB3 -:1028000020B1D4F81801017831B901E0022070BD7F -:10281000D4F86411097809B13A2070BD052181719D -:10282000D4F8181100200881D4F81811A88848811C -:10283000D4F81811E8888881D4F818112889C8813B -:10284000D4F81801028941898A4204D88279082A79 -:1028500001D88A4201D3122070BD29884180D4F862 -:10286000181102200870002070BD3EB50446FEF726 -:1028700075FAB0B12E480125A0F1400245702368D9 -:1028800042F8423F237900211371417069460620C6 -:1028900001F095FA00B1FFDF684601F06EFA10B161 -:1028A0000EE012203EBDBDF80440029880F8205191 -:1028B000684601F062FA18B9BDF80400A042F4D1EC -:1028C00000203EBD70B505460088062101F0EEFAF5 -:1028D000040007D000F0D6FB20B1D4F81811087816 -:1028E00030B901E0022070BDD4F86401007808B16D -:1028F0003A2070BDB020005D10F0010F22D0D5F855 -:1029000002004860D5F806008860D4F8180169898B -:1029100010228181D4F8180105F10C010E3004F564 -:102920008C74FBF78AFD216803200870288805E075 -:1029300018080020840000201122330021684880FC -:10294000002070BD0C2070BD38B504460078EF281B -:102950004DD86088ADF80000009800F097FC88B36F -:102960006188080708D4D4E9012082423FD8202A90 -:102970003DD3B0F5804F3AD8207B18B3072836D81E -:10298000607B28B1012803D0022801D003282ED172 -:102990004A0703D4022801D0032805D1A07B08B13F -:1029A000012824D1480707D4607D28B1012803D02D -:1029B000022801D003281AD1C806E07D03D50128DA -:1029C00015D110E013E0012801D003280FD1C8066B -:1029D00009D4607E012803D0022801D0032806D143 -:1029E000A07E0F2803D8E07E18B1012801D0122064 -:1029F00038BD002038BDF8B514460D46064608F02F -:102A00001FF808B10C20F8BD3046FFF79DFF0028E5 -:102A1000F9D1FCF73EFA2870B07554B9FF208DF853 -:102A2000000069460020FCF71EFA69460020FCF70A -:102A30000EFA3046BDE8F840FCF752B90022DAE75A -:102A40000078C10801D012207047FA4981F82000AF -:102A50000020704710B504460078C00704D1608894 -:102A600010B1FCF7D7F980B12078618800F001023D -:102A7000607800F02FFC002806D1FCF7B3F901467E -:102A80006088884203D9072010BD122010BD6168FC -:102A9000FCF7E9F9002010BD10B504460078C00726 -:102AA00004D1608810B1FBF78AFE70B1207861888C -:102AB00000F00102607800F00DFC002804D160886D -:102AC0006168FCF7C4F9002010BD122010BD7CB570 -:102AD000044640784225012808D8A078FBF767FE15 -:102AE00020B120781225012802D090B128467CBD63 -:102AF000FCF7DBF920B1A0880028F7D08028F5D8B2 -:102B0000FCF7DAF960B160780028EFD0207801286E -:102B100008D006F0C3FD044607F05DFC00287FD016 -:102B20000C207CBDFBF7F5FF10B9FCF7B7F990B3AB -:102B300007F086FF0028F3D1FBF700FEA0F57F41E8 -:102B4000FF39EDD1FCF707F8A68842F21070464332 -:102B5000A079FCF770F9FBF739FEF8B100220721E4 -:102B600001A801F071F9040058D0B3480021846035 -:102B70002046FDF72DFD2046FCF732FDAD4D04F15A -:102B800030006A8AA98AC2830184FBF726FE60B1FD -:102B9000E88A01210DE0FFE712207CBD31460020CC -:102BA00007F0CBFC88B3FFDF44E0FCF787F9014670 -:102BB000E88A07F091FD0146A0620022204606F057 -:102BC00070FDFBF70AFE38B9FCF778F9024621469A -:102BD0000120FEF7D2FAD0B1964A21461C320120DC -:102BE000FEF7E8FA687C00902B7CAA8A698A208824 -:102BF00001F018FA00B1FFDF208806F02CFC314606 -:102C0000204607F09AFC00B1FFDF13E008E007213F -:102C1000BDF8040001F05CF900B1FFDF09207CBDC4 -:102C200044B1208806F018FC2088072101F050F9F3 -:102C300000B1FFDF00207CBD002148E770B50D46E4 -:102C4000072101F033F9040003D094F88F0110B18B -:102C50000AE0022070BD94F87D00142801D01528E8 -:102C600002D194F8DC0108B10C2070BD1022294675 -:102C700004F5C870FBF7E1FB012084F88F01002008 -:102C800070BD10B5072101F011F918B190F88F113E -:102C900011B107E0022010BD90F87D10142903D077 -:102CA000152901D00C2010BD022180F88F110020C1 -:102CB00010BD2DE9FC410C464BF6803212219442A6 -:102CC0001DD8E4B16946FEF727FC002815D19DF810 -:102CD000000000F05FF9019E9DF80000703600F0E2 -:102CE00059F9019DAD1C2F88224639463046FDF723 -:102CF00065FC2888B842F6D10020BDE8FC81084672 -:102D0000FBE77CB5044600886946FEF705FC002811 -:102D100010D19DF8000000F03DF9019D9DF80000E4 -:102D2000703500F037F90198A27890F82C10914294 -:102D300001D10C207CBD7F212972A9720021E9728A -:102D4000E17880F82D10217980F82E10A17880F894 -:102D50002C1000207CBD1CB50C466946FEF7DCFB40 -:102D600000280AD19DF8000000F014F9019890F8AD -:102D70008C0000B10120207000201CBD7CB50D46E8 -:102D800014466946FEF7C8FB002809D19DF80000EB -:102D900000F000F9019890F82C00012801D00C20D7 -:102DA0007CBD9DF8000000F0F5F8019890F87810CF -:102DB000297090F87900207000207CBD70B50D4618 -:102DC0001646072101F072F818B381880124C388E0 -:102DD000428804EB4104AC4217D842F210746343BA -:102DE000A4106243B3FBF2F2521E94B24FF4FA7293 -:102DF000944200D91446A54200D22C46491C641CBA -:102E0000B4FBF1F24A43521E91B290F8C8211AB9AC -:102E100001E0022070BD01843180002070BD10B53A -:102E20000C46072101F042F840B1022C08D91220CB -:102E300010BD000018080020780000200220F7E7ED -:102E400014F0010180F8FD10C4F3400280F8FC206A -:102E500004D090F8FA1009B107F054FC0020E7E71D -:102E6000017889B1417879B141881B290CD38188D7 -:102E70001B2909D3C188022906D3F64902680A65CD -:102E800040684865002070471220704710B504461E -:102E90000EF086FD204607F0D8FB0020C8E710B5ED -:102EA00007F0D6FB0020C3E72DE9F04115460F4699 -:102EB00006460122114638460EF076FD04460121F1 -:102EC000384607F009FC844200D20446012130460E -:102ED00000F065F806460121002000F060F8311886 -:102EE000012096318C4206D901F19600611AB1FB9E -:102EF000F0F0401C80B228800020BDE8F08110B5C1 -:102F0000044600F077F808B10C2091E7601C0AF045 -:102F100038FE207800F00100FBF718FE207800F062 -:102F200001000CF010F8002082E710B504460720DD -:102F300000F056FF08B10C207AE72078C00711D0C6 -:102F400000226078114611F097FD08B112206FE75A -:102F5000A06809F01DFB6078D4F8041009F021FB8B -:102F6000002065E7002009F013FB00210846F5E783 -:102F700010B505F036FE00205AE710B5006805F0E0 -:102F800084F8002054E718B1022801D001207047CE -:102F90000020704708B1002070470120704710B52D -:102FA000012904D0022905D0FFDF204640E7C000F8 -:102FB000503001E080002C3084B2F6E710B50FF0FD -:102FC0009EF9042803D0052801D0002030E7012015 -:102FD0002EE710B5FFF7F2FF10B10CF07BF828B91F -:102FE00007F02EFD20B1FBF78CFD08B101201FE793 -:102FF00000201DE710B5FFF7E1FF18B907F020FD2D -:10300000002800D0012013E72DE9FE4300250F46DC -:1030100080460A260421404604F069FA4046FDF73E -:103020003EFE062000F0EAFE044616E06946062051 -:1030300000F0C5FE0BE000BFBDF80400B84206D0AA -:103040000298042241460E30FBF7CAF950B1684697 -:1030500000F093FE0500EFD0641E002C06DD002D6D -:10306000E4D005E04046FDF723FEF5E705B9FFDFB4 -:10307000D8F80000FDF737FE761E01D00028C9D031 -:10308000BDE8FE8390F8F01090F88C0020B919B1DB -:10309000042901D0012070470020704701780029E1 -:1030A0000AD0416891F8FA20002A05D0002281F860 -:1030B000FA20406807F026BB704770B514460546F5 -:1030C000012200F01BF9002806D121462846BDE860 -:1030D0007040002200F012B970BDFB2802D8B1F593 -:1030E000296F01D911207047002070471B38E12853 -:1030F00006D2B1F5A47F03D344F29020814201D9D6 -:1031000012207047002070471FB55249403191F896 -:103110002010CA0702D102781D2A0AD08A0702D4D9 -:1031200002781C2A28D049073DD40178152937D0C8 -:1031300039E08088ADF8000002A9FEF7EDF900B192 -:10314000FFDF9DF80800FFF725FF039810F8601FC8 -:103150008DF8021040788DF803000020ADF80400CF -:1031600001B9FFDF9DF8030000B9FFDF6846FEF7F5 -:1031700040FCD8B1FFDF19E08088ADF800004FF4C3 -:103180002961FB20ADF80410ADF80200ADF806008F -:10319000ADF808106846FEF73AFD38B1FFDF05E0EC -:1031A000807BC00702D0002004B041E60120FBE78D -:1031B000F8B50746508915460C4640B1B0F5004FAA -:1031C00005D20022A878114611F056FC08B1122051 -:1031D000F8BDA06E04F1700630B1A97894F86E00C5 -:1031E000814201D00C20F8BD012184F86F10A9782C -:1031F00084F86E106968A1666989A4F86C10288942 -:10320000B084002184F86F1028886946FEF762FFB9 -:10321000B08CBDF80010081A00B2002804DD214669 -:103220003846FEF745FFDDE70020F8BD042803D34C -:1032300021B9B0F5804F01D90020704701207047B7 -:10324000042803D321B9B0F5804F01D9002070477D -:1032500001207047D8070020012802D018B10020B3 -:103260007047022070470120704710B500224FF4CC -:10327000C84408E030F81230A34200D9234620F8B1 -:103280001230521CD2B28A42F4D3D1E580B2C106C8 -:103290000BD401071CD481064FEAC07101D5B9B91E -:1032A00000E099B1800713D410E0410610D48106E4 -:1032B0000ED4C1074FEA807104D0002902DB400719 -:1032C00004D405E0010703D4400701D4012070476E -:1032D0000020704770B50C460546FF2904D8FBF75F -:1032E0007CFA18B11F2C01D9122070BD2846FBF7BB -:1032F0005EFA08B1002070BD422070BD0AB1012203 -:1033000000E00222024202D1C80802D109B1002025 -:10331000704711207047000030B5058825F400443F -:1033200021448CB24FF4004194420AD2121B92B253 -:103330001B339A4201D2A94307E005F4004121431F -:1033400003E0A21A92B2A9431143018030BD0844A0 -:10335000083050434A31084480B2704770B51D466A -:1033600016460B46044629463046049AFFF7EFFFFF -:103370000646B34200D2FFDF282200212046FBF799 -:1033800086F84FF6FF70A082283EB0B26577608065 -:10339000B0F5004F00D9FFDF618805F13C008142A4 -:1033A00000D2FFDF60880835401B343880B22080AF -:1033B0001B2800D21B2020800020A07770BD8161D7 -:1033C000886170472DE9F05F0D46C188044600F121 -:1033D0002809008921F4004620F4004800F063FB2E -:1033E00010B10020BDE8F09F4FF0000A4FF0010B34 -:1033F000B0450CD9617FA8EB0600401A0838854219 -:1034000019DC09EB06000021058041801AE0608884 -:10341000617F801B471A083F0DD41B2F00DAFFDFA6 -:10342000BD4201DC294600E0B9B2681A0204120C60 -:1034300004D0424502DD84F817A0D2E709EB06006C -:103440000180428084F817B0CCE770B5044600F1E3 -:103450002802C088E37D20F400402BB1104402888C -:10346000438813448B4201D2002070BD00258A425C -:1034700002D30180458008E0891A0904090C4180C3 -:1034800003D0A01D00F01FFB08E0637F0088083315 -:10349000184481B26288A01DFFF73EFFE575012048 -:1034A00070BD70B5034600F12804C588808820F4FB -:1034B00000462644A84202D10020188270BD988997 -:1034C0003588A84206D3401B75882D1A2044ADB21A -:1034D000C01E05E02C1AA5B25C7F20443044401D7C -:1034E0000C88AC4200D90D809C8924B10024147052 -:1034F0000988198270BD0124F9E770B5044600F10E -:103500002801808820F400404518208A002825D012 -:10351000A189084480B2A08129886A881144814227 -:1035200000D2FFDF2888698800260844A1898842E4 -:1035300012D1A069807F2871698819B1201D00F01F -:10354000C2FA08E0637F28880833184481B2628891 -:10355000201DFFF7E1FEA6812682012070BD2DE926 -:10356000F041418987880026044600F12805B942C8 -:1035700019D004F10A0800BF21F400402844418812 -:1035800019B1404600F09FFA08E0637F00880833D5 -:10359000184481B262884046FFF7BEFE761C6189FE -:1035A000B6B2B942E8D13046BDE8F0812DE9F0412C -:1035B00004460B4627892830A68827F40041B4F832 -:1035C0000A8001440D46B74201D10020ECE70AB160 -:1035D000481D106023B1627F691D1846FAF72DFF60 -:1035E0002E88698804F1080021B18A1996B200F08A -:1035F0006AFA06E0637F62880833991989B2FFF797 -:103600008BFE474501D1208960813046CCE7818817 -:10361000C088814201D10120704700207047018994 -:103620008088814201D1012070470020704770B529 -:103630008588C38800F1280425F4004223F4004162 -:1036400014449D421AD08389058A5E1925886388AF -:10365000EC18A64214D313B18B4211D30EE0437F72 -:1036600008325C192244408892B2801A80B2233317 -:10367000984201D211B103E08A4201D1002070BD0D -:10368000012070BD2DE9F0478846C18804460089B5 -:1036900021F4004604F1280720F4004507EB060951 -:1036A00000F001FA002178BBB54204D9627FA81B63 -:1036B000801A002503E06088627F801B801A08382A -:1036C00023D4E28962B1B9F80020B9F802303BB1E5 -:1036D000E81A2177404518DBE0893844801A09E070 -:1036E000801A217740450ADB607FE1890830304449 -:1036F00039440844C01EA4F81280BDE8F08745454F -:1037000003DB01202077E7E7FFE761820020F4E791 -:103710002DE9F74F044600F12805C088884620F4BB -:10372000004A608A05EB0A0608B1404502D2002033 -:10373000BDE8FE8FE08978B13788B6F8029007EBD4 -:103740000901884200D0FFDF207F4FF0000B50EAD4 -:10375000090106D088B33BE00027A07FB94630714D -:10376000F2E7E18959B1607F2944083050440844A8 -:10377000B4F81F1020F8031D94F821108170E2891D -:1037800007EB080002EB0801E1813080A6F802B0E7 -:1037900002985F4650B1637F30880833184481B285 -:1037A0006288A01DFFF7B8FDE78121E0607FE18915 -:1037B00008305044294408442DE0FFE7E089B4F87C -:1037C0001F102844C01B20F8031D94F8211081709D -:1037D00009EB0800E28981B202EB0800E081378042 -:1037E00071800298A0B1A01D00F06DF9A4F80EB090 -:1037F000A07F401CA077A07D08B1E088A08284F85B -:1038000016B000BFA4F812B084F817B001208FE7FB -:10381000E0892844C01B30F8031DA4F81F108078ED -:1038200084F82100EEE710B5818800F1280321F427 -:1038300000442344848AC288A14212D0914210D00D -:10384000818971B9826972B11046FFF7E8FE50B9FB -:103850001089283220F400401044197900798842F8 -:1038600001D1002010BD184610BD00F12803407F93 -:1038700008300844C01E1060088808B9DB1E1360B9 -:1038800008884988084480B270472DE9F04100F16A -:103890002806407F1C4608309046431808884D880B -:1038A000069ADB1EA0B1C01C80B2904214D9801AC7 -:1038B000A04200DB204687B298183A464146FAF704 -:1038C0008FFD002816D1E01B84B2B844002005E02B -:1038D000ED1CADB2F61EE8E7101A80B20119A9423C -:1038E00006D8304422464146BDE8F041FAF778BD9B -:1038F0004FF0FF3058E62DE9F04100F12804407FF9 -:103900001E46083090464318002508884F88069ABE -:10391000DB1E90B1C01C80B2904212D9801AB04216 -:1039200000DB304685B299182A464046FAF785FDF5 -:10393000701B86B2A844002005E0FF1CBFB2E41E45 -:10394000EAE7101A80B28119B94206D82118324626 -:103950004046FAF772FDA81985B2284624E62DE9FB -:10396000F04100F12804407F1E460830904643187D -:10397000002508884F88069ADB1E90B1C01C80B2D3 -:10398000904212D9801AB04200DB304685B29818B6 -:103990002A464146FAF751FD701B86B2A844002022 -:1039A00005E0FF1CBFB2E41EEAE7101A80B28119DD -:1039B000B94206D8204432464146FAF73EFDA819DE -:1039C00085B22846F0E5401D704710B5044600F169 -:1039D0002801C288808820F400431944904206D010 -:1039E000A28922B9228A12B9A28A904201D100206A -:1039F00010BD0888498831B1201D00F064F800200E -:103A00002082012010BD637F62880833184481B290 -:103A1000201DFFF781FCF2E70021C181017741827F -:103A2000C1758175704703881380C28942B1C2880D -:103A300022F4004300F128021A440A60C08970474A -:103A40000020704710B50446808AA0F57F41FF39F9 -:103A500000D0FFDFE088A082E08900B10120A075DE -:103A600010BD4FF6FF71818200218175704710B53E -:103A70000446808AA0F57F41FF3900D1FFDFA07D99 -:103A800028B9A088A18A884201D1002010BD012058 -:103A900010BD8188828A914201D1807D08B10020C9 -:103AA00070470120704720F4004221F400439A42FD -:103AB00007D100F4004001F40041884201D0012008 -:103AC00070470020704730B5044600880D4620F44A -:103AD0000040A84200D2FFDF21884FF40040884315 -:103AE0002843208030BD70B50C00054609D0082C55 -:103AF00000D2FFDF1DB1A1B2286800F044F8201DFC -:103B000070BD0DB100202860002070BD002102684A -:103B100003E093881268194489B2002AF9D100F0B1 -:103B200032B870B500260D460446082900D2FFDFE2 -:103B3000206808B91EE0044620688188A94202D0A6 -:103B400001680029F7D181880646A94201D10068A1 -:103B50000DE005F1080293B20022994209D32844EE -:103B6000491B026081802168096821600160206032 -:103B700000E00026304670BD00230B608A8002689A -:103B80000A600160704700234360021D01810260EA -:103B90007047F0B50F460188408815460C181E4640 -:103BA000AC4200D3641B3044A84200D9FFDFA01907 -:103BB000A84200D9FFDF3819F0BD2DE9F041884651 -:103BC00006460188408815460C181F46AC4200D3B3 -:103BD000641B3844A84200D9FFDFE019A84200D98D -:103BE000FFDF70883844708008EB0400BDE8F08186 -:103BF0002DE9F041054600881E461746841B88467D -:103C0000BC4200D33C442C8068883044B84200D980 -:103C1000FFDFA019B84200D9FFDF68883044688010 -:103C200008EB0400E2E72DE9F04106881D46044652 -:103C3000701980B2174688462080B84201D3C01B55 -:103C400020806088A84200D2FFDF7019B84200D9F6 -:103C5000FFDF6088401B608008EB0600C6E730B5D8 -:103C60000D460188CC18944200D3A41A408898428B -:103C700000D8FFDF281930BD2DE9F041C84D0446BA -:103C80009046A8780E46A04200D8FFDF05EB8607D5 -:103C9000B86A50F8240000B1FFDFB868002816D0D9 -:103CA000304600F044F90146B868FFF73AFF0500D6 -:103CB0000CD0B86A082E40F8245000D3FFDFB94872 -:103CC0004246294650F82630204698472846BDE807 -:103CD000F0812DE9F8431E468C1991460F460546A2 -:103CE000FF2C00D9FFDFB14500D9FFDFE4B200951A -:103CF0004DB300208046E81C20F00300A84200D00D -:103D0000FFDF4946DFF89892684689F8001089F885 -:103D1000017089F8024089F8034089F8044089F865 -:103D2000054089F8066089F80770414600F008F9F7 -:103D3000002142460F464B460098C01C20F003006D -:103D4000009012B10EE00120D4E703EB8106B062CF -:103D5000002005E0D6F828C04CF82070401CC0B206 -:103D6000A042F7D30098491C00EB8400C9B2009030 -:103D70000829E1D3401BBDE8F88310B50446EDF7F0 -:103D80008EFA08B1102010BD2078854A618802EBB8 -:103D9000800092780EE0836A53F8213043B14A1CC8 -:103DA0006280A180806A50F82100A060002010BDD0 -:103DB000491C89B28A42EED86180052010BD70B5D9 -:103DC00005460C460846EDF76AFA08B1102070BDAA -:103DD000082D01D3072070BD25700020608070BDC4 -:103DE0000EB56946FFF7EBFF00B1FFDF6846FFF74E -:103DF000C4FF08B100200EBD01200EBD10B5044661 -:103E0000082800D3FFDF6648005D10BD3EB50546BB -:103E100000246946FFF7D3FF18B1FFDF01E0641CFF -:103E2000E4B26846FFF7A9FF0028F8D02846FFF75C -:103E3000E5FF001BC0B23EBD59498978814201D9D6 -:103E4000C0B27047FF2070472DE9F041544B06295E -:103E500003D007291CD19D7900E0002500244FF6EE -:103E6000FF7603EB810713F801C00AE06319D7F866 -:103E700028E09BB25EF823E0BEF1000F04D0641C82 -:103E8000A4B2A445F2D8334603801846B34201D108 -:103E900000201CE7BDE8F041EEE6A0F57F43FF3BC4 -:103EA00001D0082901D300207047E5E6A0F57F4244 -:103EB000FF3A0BD0082909D2394A9378834205D9B1 -:103EC00002EB8101896A51F8200070470020704799 -:103ED0002DE9F04104460D46A4F57F4143F202006E -:103EE000FF3902D0082D01D30720F0E62C494FF00E -:103EF00000088A78A242F8D901EB8506B26A52F826 -:103F00002470002FF1D027483946203050F8252062 -:103F100020469047B16A284641F8248000F007F80F -:103F200002463946B068FFF727FE0020CFE61D495C -:103F3000403131F810004FF6FC71C01C084070474A -:103F40002DE9F843164E8846054600242868C01C13 -:103F500020F0030028602046FFF7E9FF315D484369 -:103F6000B8F1000F01D0002200E02A68014600925B -:103F700032B100274FEA0D00FFF7B5FD1FB106E093 -:103F800001270020F8E706EB8401009A8A6029687F -:103F9000641C0844E4B22860082CD7D3EBE6000088 -:103FA0003C0800201862020070B50E461D461146FE -:103FB00000F0D3F804462946304600F0D7F82044F4 -:103FC000001D70BD2DE9F04190460D4604004FF0F4 -:103FD000000610D00027E01C20F00300A04200D013 -:103FE000FFDFE5B141460020FFF77DFD0C3000EB1F -:103FF000850617B113E00127EDE7614F04F10C00CE -:10400000AA003C602572606000EB85002060002102 -:104010006068FAF73CFA41463868FFF764FD3046BD -:10402000BDE8F0812DE9FF4F554C804681B02068F6 -:104030009A46934600B9FFDF2068027A424503D9C9 -:10404000416851F8280020B143F2020005B0BDE8F4 -:10405000F08F5146029800F080F886B258460E99CB -:1040600000F084F885B27019001D87B22068A1465F -:1040700039460068FFF755FD04001FD06780258092 -:104080002946201D0E9D07465A4601230095FFF73D -:1040900065F92088314638440123029ACDF800A002 -:1040A000FFF75CF92088C1193846FFF788F9D9F87D -:1040B00000004168002041F82840C7E70420C5E718 -:1040C00070B52F4C0546206800B9FFDF2068017AE3 -:1040D000A9420DD9426852F8251049B1002342F88F -:1040E00025304A880068FFF747FD2168087A06E016 -:1040F00043F2020070BD4A6852F820202AB9401EDF -:10410000C0B2F8D20868FFF701FD002070BD70B59D -:104110001B4E05460024306800B9FFDF3068017A85 -:10412000A94204D9406850F8250000B1041D20467A -:1041300070BD70B5124E05460024306800B9FFDF2F -:104140003068017AA94206D9406850F8251011B1AB -:1041500031F8040B4418204670BD10B50A46012101 -:10416000FFF7F5F8C01C20F0030010BD10B50A469B -:104170000121FFF7ECF8C01C20F0030010BD000087 -:104180008C00002070B50446C2F110052819FAF71A -:1041900054F915F0FF0109D0491ECAB28020A0547D -:1041A0002046BDE870400021FAF771B970BD30B506 -:1041B00005E05B1EDBB2CC5CD55C6C40C454002BCC -:1041C000F7D130BD10B5002409E00B78521E44EA47 -:1041D000430300F8013B11F8013BD2B2DC09002A8D -:1041E000F3D110BD2DE9F04389B01E46DDE9107909 -:1041F00090460D00044622D002460846F949FDF7D4 -:1042000044FE102221463846FFF7DCFFE07B000623 -:1042100006D5F44A3946102310320846FFF7C7FF87 -:10422000102239464846FFF7CDFFF87B000606D539 -:10423000EC4A4946102310320846FFF7B8FF102217 -:1042400000212046FAF723F90DE0103EB6B208EB44 -:104250000601102322466846FFF7A9FF224628469A -:104260006946FDF712FE102EEFD818D0F2B2414683 -:104270006846FFF787FF10234A46694604A8FFF700 -:1042800096FF1023224604A96846FFF790FF2246B6 -:1042900028466946FDF7F9FD09B0BDE8F083102313 -:1042A0003A464146EAE770B59CB01E4605461346BD -:1042B00020980C468DF80800202219460DF10900BF -:1042C000FAF7BBF8202221460DF12900FAF7B5F8DC -:1042D00017A913A8CDE90001412302AA31462846B7 -:1042E000FFF780FF1CB070BD2DE9FF4F9FB014AEEB -:1042F000DDE92D5410AFBB49CDE9007620232031F4 -:104300001AA8FFF76FFF4FF000088DF808804FF0F4 -:1043100001098DF8099054F8010FCDF80A00A08822 -:10432000ADF80E0014F8010C1022C0F340008DF817 -:10433000100055F8010FCDF81100A888ADF8150050 -:1043400015F8010C2C99C0F340008DF8170006A851 -:104350008246FAF772F80AA8834610222299FAF7E1 -:104360006CF8A0483523083802AA40688DF83C80D4 -:10437000CDE900760E901AA91F98FFF733FF8DF84C -:1043800008808DF809902068CDF80A00A088ADF863 -:104390000E0014F8010C1022C0F340008DF810003C -:1043A0002868CDF81100A888ADF8150015F8010CA3 -:1043B0002C99C0F340008DF817005046FAF73DF8ED -:1043C000584610222299FAF738F8864835230838DB -:1043D00002AA40688DF83C90CDE900760E901AA9AB -:1043E0002098FFF7FFFE23B0BDE8F08FF0B59BB03B -:1043F0000C460546DDE922101E461746DDE920324F -:10440000D0F801C0CDF808C0B0F805C0ADF80CC0B8 -:104410000078C0F340008DF80E00D1F80100CDF80F -:104420000F00B1F80500ADF8130008781946C0F385 -:1044300040008DF815001088ADF8160090788DF8C2 -:1044400018000DF119001022F9F7F7FF0DF12900FE -:1044500010223146F9F7F1FF0DF1390010223946EB -:10446000F9F7EBFF17A913A8CDE90001412302AA30 -:1044700021462846FFF7B6FE1BB0F0BDF0B5A3B04D -:1044800017460D4604461E46102202A82899F9F741 -:10449000D4FF06A820223946F9F7CFFF0EA8202224 -:1044A0002946F9F7CAFF1EA91AA8CDE90001502331 -:1044B00002AA314616A8FFF795FE1698206023B091 -:1044C000F0BDF0B589B00446DDE90E070D46397838 -:1044D000109EC1F340018DF8001031789446C1F36D -:1044E00040018DF801101968CDF802109988ADF8D7 -:1044F000061099798DF808100168CDF809108188A7 -:10450000ADF80D1080798DF80F0010236A466146D2 -:1045100004A8FFF74CFE2246284604A9FDF7B5FC87 -:10452000D6F801000090B6F80500ADF80400D7F801 -:104530000100CDF80600B7F80500ADF80A0000202C -:10454000039010236A46214604A8FFF730FE224656 -:10455000284604A9FDF799FC09B0F0BD1FB51C68F9 -:1045600000945B68019313680293526803920246B9 -:1045700008466946FDF789FC1FBD10B588B00446A2 -:104580001068049050680590002006900790084637 -:104590006A4604A9FDF779FCBDF80000208008B048 -:1045A00010BD1FB51288ADF800201A88ADF80220A2 -:1045B0000022019202920392024608466946FDF7E4 -:1045C00064FC1FBD7FB5074B14460546083B9A1C8B -:1045D0006846FFF7E6FF224669462846FFF7CDFF0B -:1045E0007FBD00007062020070B5044600780E4680 -:1045F000012813D0052802D0092813D10EE0A068A5 -:1046000061690578042003F059FA052D0AD0782352 -:1046100000220420616903F0A7F903E00420616926 -:1046200003F04CFA31462046BDE8704001F08AB8EC -:1046300010B500F12D03C2799C78411D144064F33C -:104640000102C271D2070DD04A795C7922404A71C9 -:104650000A791B791A400A718278C9788A4200D98E -:10466000817010BD00224A71F5E74178012900D020 -:104670000C21017070472DE9F04F93B04FF0000B03 -:104680000C690D468DF820B0097801260C201746DC -:104690004FF00D084FF0110A4FF008091B2975D291 -:1046A000DFE811F01B00C40207031F035E03710360 -:1046B000A303B803F9031A0462049504A204EF04E7 -:1046C0002D05370555056005F305360639066806DC -:1046D0008406FE062207EB06F00614B120781D289A -:1046E0002AD0D5F808805FEA08004FD001208DF865 -:1046F0002000686A02220D908DF824200A208DF88F -:104700002500A8690A90A8880028EED098F8001023 -:1047100091B10F2910D27DD2DFE801F07C1349DE80 -:10472000FCFBFAF9F8F738089CF6F50002282DD1C1 -:1047300024B120780C2801D00026F0E38DF8202049 -:10474000CBE10420696A03F0B9F9A8880728EED103 -:10475000204600F0F2FF022809D0204600F0EDFFCD -:10476000032807D9204600F0E8FF072802D20120DD -:10477000207004E0002CB8D020780128D7D198F818 -:104780000400C11F0A2902D30A2061E0C4E1A0701D -:10479000D8F80010E162B8F80410218698F80600F5 -:1047A00084F83200012028700320207044E007289C -:1047B000BDD1002C99D020780D28B8D198F80310DD -:1047C00094F82F20C1F3C000C2F3C002104201D000 -:1047D000062000E00720890707D198F8051001425C -:1047E000D2D198F806100142CED194F8312098F831 -:1047F000051020EA02021142C6D194F8322098F83E -:10480000061090430142BFD198F80400C11F0A2945 -:10481000BAD200E008E2617D81427CD8D8F800106D -:104820006160B8F80410218198F80600A072012098 -:1048300028700E20207003208DF82000686A0D90EB -:1048400004F12D000990601D0A900F300B9022E1B9 -:104850002875FCE3412891D1204600F06EFF042822 -:1048600002D1E078C00704D1204600F066FF0F288F -:1048700084D1A88CD5F80C8080B24FF0400BE6694B -:10488000FFF745FC324641465B464E46CDF8009068 -:10489000FFF731F80B208DF82000686A0D90E06971 -:1048A0000990002108A8FFF79FFE2078042806D071 -:1048B000A07D58B1012809D003280AD04AE3052079 -:1048C0002070032028708DF82060CEE184F800A0CD -:1048D00032E712202070EAE11128BCD1204600F016 -:1048E0002CFF042802D1E078C00719D0204600F040 -:1048F00024FF062805D1E078C00711D1A07D022849 -:104900000ED0204608E0CCE084E072E151E124E1E1 -:1049100003E1E9E019E0B0E100F00FFF11289AD1BE -:10492000102208F1010104F13C00F9F786FD6078DE -:1049300001286ED012202070E078C00760D0A07DE2 -:104940000028C8D00128C6D05AE0112890D12046AE -:1049500000F0F3FE082804D0204600F0EEFE1328F5 -:1049600086D104F16C00102208F101010646F9F726 -:1049700064FD207808280DD014202070E178C80745 -:104980000DD0A07D02280AD06278022A04D0032824 -:10499000A1D035E00920F0E708B1012837D1C807D8 -:1049A00013D0A07D02281DD000200090D4E906215C -:1049B00033460EA8FFF777FC10220EA904F13C0045 -:1049C000F9F70EFDC8B1042042E7D4E90912201D11 -:1049D0008DE8070004F12C0332460EA8616BFFF747 -:1049E00070FDE9E7606BC1F34401491E0068C840EF -:1049F00000F0010040F08000D7E72078092806D1B8 -:104A000085F800908DF8209036E32870EFE30920B8 -:104A1000FBE79EE1112899D1204600F08EFE0A287E -:104A200002D1E078C00704D1204600F086FE1528A8 -:104A30008CD104F13C00102208F101010646F9F77F -:104A4000FCFC20780A2816D016202070D4E9093200 -:104A5000606B611D8DE80F0004F15C0304F16C02D2 -:104A600047310EA8FFF7C2FC10220EA93046F9F715 -:104A7000B7FC18B1F9E20B20207073E22046FFF773 -:104A8000D7FDA078216AC0F110020B18002118464A -:104A9000F9F7FDFC26E3394608A8FFF7A5FD064611 -:104AA0003CE20228B7D1204600F047FE042804D398 -:104AB000204600F042FE082809D3204600F03DFEC3 -:104AC0000E2829D3204600F038FE122824D2A07DDB -:104AD0000228A0D10E208DF82000686A0D9098F869 -:104AE00001008DF82400F5E3022894D1204600F05F -:104AF00024FE002810D0204600F01FFE0128F9D027 -:104B0000204600F01AFE0C28F4D004208DF8240072 -:104B100098F801008DF8250060E21128FCD1002CE6 -:104B2000FAD020781728F7D16178606A022912D06C -:104B30005FF0000101EB4101182606EBC1011022D4 -:104B4000405808F10101F9F778FC0420696A00F087 -:104B5000E7FD2670F0E50121ECE70B28DCD1002C05 -:104B6000DAD020781828D7D16078616A02281CD062 -:104B70005FF0000000EB4002102000EBC20009587B -:104B8000B8F8010008806078616A02280FD0002020 -:104B900000EB4002142000EBC2000958404650F8D8 -:104BA000032F0A604068486039E00120E2E70120F5 -:104BB000EEE71128B0D1002CAED020781928ABD167 -:104BC0006178606A022912D05FF0000101EB4101B7 -:104BD0001C2202EBC1011022405808F10101F9F733 -:104BE0002CFC0420696A00F09BFD1A20B6E001212C -:104BF000ECE7082890D1002C8ED020781A288BD191 -:104C0000606A98F80120017862F347010170616AD7 -:104C1000D8F8022041F8012FB8F806008880042057 -:104C2000696A00F07DFD90E2072011E638780128DE -:104C300094D1182204F114007968F9F7FEFBE079A9 -:104C4000C10894F82F0001EAD001E07861F3000078 -:104C5000E070217D002974D12178032909D0C00793 -:104C600025D0032028708DF82090686A0D9041208F -:104C700008E3607DA178884201D90620E8E5022694 -:104C80002671E179204621F0E001E171617A21F09D -:104C9000F0016172A17A21F0F001A172FFF7C8FC66 -:104CA0002E708DF82090686A0D900720EAE20420AB -:104CB000ABE6387805289DD18DF82000686A0D9004 -:104CC000B8680A900720ADF824000A988DF830B033 -:104CD0006168016021898180A17A8171042020703E -:104CE000F8E23978052985D18DF82010696A0D918F -:104CF000391D09AE0EC986E80E004121ADF8241019 -:104D00008DF830B01070A88CD7F80C8080B2402697 -:104D1000A769FFF70EFA41463A463346C846CDF832 -:104D20000090FEF71CFE002108A8FFF75DFCE0786C -:104D300020F03E00801CE0702078052802D00F2073 -:104D40000CE04AE1A07D20B1012802D0032802D066 -:104D500002E10720BEE584F80080EDE42070EBE47A -:104D6000102104F15C0002F0C2FB606BB0BBA07DBF -:104D700018B1012801D00520FDE006202870F84870 -:104D80006063A063C2E23878022894D1387908B110 -:104D90002875B7E3A07D022802D0032805D022E0C1 -:104DA000B8680028F5D060631CE06078012806D060 -:104DB000A07994F82E10012805D0E94806E0A179E1 -:104DC00094F82E00F7E7B8680028E2D06063E07836 -:104DD000C00701D0012902D0E14803E003E0F868F0 -:104DE0000028D6D0A06306200FE68DF82090696ACF -:104DF0000D91E1784846C90709D06178022903D1AD -:104E0000A17D29B1012903D0A17D032900D007206C -:104E1000287033E138780528BBD1207807281ED0C8 -:104E200084F800A005208DF82000686A0D90B8680D -:104E30000A90ADF824A08DF830B003210170E1781C -:104E4000CA070FD0A27D022A1AD000210091D4E90E -:104E5000061204F15C03401CFFF725FA6BE384F8AB -:104E60000090DFE7D4E90923211D8DE80E0004F14D -:104E70002C0304F15C02401C616BFFF722FB5AE338 -:104E8000626BC1F34401491E1268CA4002F001017D -:104E900041F08001DAE738780528BDD18DF820008F -:104EA000686A0D90B8680A90ADF824A08DF830B00B -:104EB000042100F8011B102204F15C01F9F7BDFA8E -:104EC000002108A8FFF790FB2078092801D01320C3 -:104ED00044E70A2020709AE5E078C10742D0A17D1E -:104EE000012902D0022927D038E0617808A80129D9 -:104EF00016D004F16C010091D4E9061204F15C03B0 -:104F0000001DFFF7BBFA0A20287003268DF82080C9 -:104F1000686A0D90002108A8FFF766FBE1E2C7E28E -:104F200004F15C010091D4E9062104F16C03001D39 -:104F3000FFF7A4FA0026E9E7C0F3440114290DD2D3 -:104F40004FF0006101EBB0104FEAB060E0706078A4 -:104F5000012801D01020BDE40620FFE6607801287A -:104F60003FF4B6AC0A2050E5E178C90708D0A17D2E -:104F7000012903D10B202870042030E028702EE096 -:104F80000E2028706078616B012818D004F15C0352 -:104F900004F16C020EA8FFF7E1FA2046FFF748FB88 -:104FA000A0780EAEC0F1100230440021F9F76FFA7C -:104FB00006208DF82000686A09960D909BE004F1A8 -:104FC0006C0304F15C020EA8FFF7C8FAE8E7397831 -:104FD000022903D139790029D0D0297592E28DF8C0 -:104FE0002000686A0D9056E538780728F6D1D4E994 -:104FF00009216078012808D004F16C00CDE9000295 -:10500000029105D104F16C0304E004F15C00F5E7C2 -:1050100004F15C0304F14C007A680646216AFFF74C -:1050200063F96078012822D1A078216AC0F11002CA -:105030000B1800211846F9F72AFAD4E90923606B06 -:1050400004F12D018DE80F0004F15C0300E05BE248 -:1050500004F16C0231460EA8FFF7C8F910220EA920 -:1050600004F13C00F9F7BCF908B10B20ACE485F879 -:10507000008000BF8DF82090686A0D908DF824A004 -:1050800009E538780528A9D18DF82000686A0D90C7 -:10509000B8680A90ADF824A08DF830B080F8008090 -:1050A000617801291AD0D4E9092104F12D03A66BF6 -:1050B00003910096CDE9013204F16C0304F15C0226 -:1050C00004F14C01401CFFF791F9002108A8FFF7FB -:1050D0008BFA6078012805D015203FE6D4E9091243 -:1050E000631DE4E70E20287006208DF82000686A12 -:1050F000CDF824B00D90A0788DF82800CBE4387856 -:105100000328C0D1E079C00770D00F202870072095 -:1051100065E7387804286BD11422391D04F1140096 -:10512000F9F78BF9616A208CA1F80900616AA0780F -:10513000C871E179626A01F003011172616A627AF1 -:105140000A73616AA07A81F8240016205DE485F86C -:1051500000A08DF82090696A50460D9192E0000001 -:10516000706202003878052842D1B868A861617879 -:10517000606A022901D0012100E0002101EB410118 -:10518000142606EBC1014058082102F0B0F96178FD -:10519000606A022901D0012100E0002101EB4101F8 -:1051A00006EBC101425802A8E169FFF70BFA6078EB -:1051B000626A022801D0012000E0002000EB4001DB -:1051C000102000EBC1000223105802A90932FEF79B -:1051D000EEFF626AFD4B0EA80932A169FFF7E1F903 -:1051E0006178606A022904D0012103E044E18DE086 -:1051F000BFE0002101EB4101182606EBC101A278B6 -:1052000040580EA9F9F719F96178606A022901D0AE -:10521000012100E0002101EB410106EBC1014158F1 -:10522000A0780B18C0F1100200211846F9F72FF9E9 -:1052300005208DF82000686A0D90A8690A90ADF8E5 -:1052400024A08DF830B0062101706278616A022ACC -:1052500001D0012200E0002202EB420206EBC20272 -:10526000401C89581022F9F7E8F8002108A8FFF738 -:10527000BBF91220C5F818B028708DF82090686A24 -:105280000D900B208DF8240005E43878052870D1A6 -:105290008DF82000686A0D90B8680A900B20ADF870 -:1052A00024000A98072101706178626A022901D0FE -:1052B000012100E0002101EB4103102101EBC301BA -:1052C00051580988A0F801106178626A022902D059 -:1052D000012101E02FE1002101EB4103142101EB49 -:1052E000C30151580A6840F8032F4968416059E0EA -:1052F0001920287001208DF8300074E616202870DF -:105300008DF830B0002108A8FFF76EF9032617E1E9 -:1053100014202870AEE6387805282AD18DF82000B0 -:10532000686A0D90B8680A90ADF824A08DF830B086 -:1053300080F800906278616A4E46022A01D001220C -:1053400000E0002202EB42021C2303EBC202401CDD -:1053500089581022F9F771F8002108A8FFF744F9DD -:10536000152028708DF82060686A0D908DF82460F3 -:1053700039E680E0387805287DD18DF82000686A0C -:105380000D90B8680A90ADF8249009210170616908 -:10539000097849084170616951F8012FC0F802206D -:1053A0008988C18020781C28A8D1A1E7E078C007AF -:1053B00002D04FF0060C01E04FF0070C6078022895 -:1053C0000AD000BF4FF0000000EB040101F1090119 -:1053D00005D04FF0010004E04FF00100F4E74FF07A -:1053E00000000B78204413EA0C030B7010F8092F0F -:1053F00002EA0C02027004D14FF01B0C84F800C0CA -:10540000D2B394F801C0BCF1010F00D09BB990F861 -:1054100000C0E0465FEACC7C04D028F001060670AC -:10542000102606E05FEA887C05D528F002060670A3 -:1054300013262E70032694F801C0BCF1020F00D091 -:1054400092B991F800C05FEACC7804D02CF0010644 -:105450000E70172106E05FEA8C7805D52CF0020665 -:105460000E701921217000260078D0BBCAB3C3BBCF -:105470001C20207035E012E002E03878062841D187 -:105480001A2015E4207801283CD00C283AD0204678 -:10549000FFF7EBF809208DF82000686A0D9031E0E5 -:1054A0003878052805D00620387003261820287083 -:1054B00046E005208DF82000696A0D91B9680A91CF -:1054C0000221ADF8241001218DF830100A990870DE -:1054D000287D4870394608A8FFF786F80646182048 -:1054E0002870012E0ED02BE001208DF82000686A74 -:1054F0000D9003208DF82400287D8DF8250085F877 -:1055000014B012E0287D80B11D2020701720287073 -:105510008DF82090686A0D9002208DF8240039469D -:1055200008A8FFF761F806460AE00CB1FE202070DB -:105530009DF8200020B1002108A8FFF755F80CE4E1 -:1055400013B03046BDE8F08F2DE9F04387B00C462C -:105550004E6900218DF804100120257803460227AA -:105560004FF007094FF0050C85B1012D53D0022DE6 -:1055700039D1FE2030708DF80030606A059003202C -:105580008DF80400207E8DF8050063E02179012963 -:1055900025D002292DD0032928D0042923D1B17D7B -:1055A000022920D131780D1F042D04D30A3D032D8B -:1055B00001D31D2917D12189022914D38DF8047034 -:1055C000237020899DF80410884201E0686202007F -:1055D00018D208208DF80000606A059057E07078B6 -:1055E0000128EBD0052007B0BDE8F0831D20307006 -:1055F000E4E771780229F5D131780C29F3D18DF8DF -:105600000490DDE7083402F804CB94E80B0082E84C -:105610000B000320E7E71578052DE4D18DF800C0D5 -:10562000656A0595956802958DF8101094F80480C8 -:10563000B8F1010F13D0B8F1020F2DD0B8F1030F5C -:105640001CD0B8F1040FCED1ADF804700E20287034 -:10565000207E687000216846FEF7C6FF0CE0ADF8BA -:1056600004700B202870207E002100F01F0068705D -:105670006846FEF7B9FF37700020B4E7ADF8047054 -:105680008DF8103085F800C0207E687027701146B4 -:105690006846FEF7A9FFA6E7ADF804902B70207FBF -:1056A0006870607F00F00100A870A07F00F01F000C -:1056B000E870E27F2A71C0071CD094F8200000F047 -:1056C0000700687194F8210000F00700A87100211C -:1056D0006846FEF789FF2868F062A8883086A879B6 -:1056E00086F83200A069407870752879B0700D2076 -:1056F0003070C1E7A9716971E9E700B587B0042886 -:105700000CD101208DF800008DF8040000200591D7 -:105710008DF8050001466846FEF766FF07B000BD3C -:1057200070B50C46054602F0C9F921462846BDE889 -:1057300070407823002202F017B908B10078704752 -:105740000C20704770B50C0005784FF000010CD0AC -:1057500021702146EFF7D1FD69482178405D8842EC -:1057600001D1032070BD022070BDEFF7C6FD0020FF -:1057700070BD0279012A05D000220A704B78012BF6 -:1057800002D003E0042070470A758A610279930011 -:10579000521C0271C15003207047F0B587B00F460C -:1057A00005460124287905EB800050F8046C7078D8 -:1057B000411E02290AD252493A46083901EB8000BB -:1057C000314650F8043C2846984704460CB1012C59 -:1057D00011D12879401E10F0FF00287101D0032458 -:1057E000E0E70A208DF80000706A0590002101961C -:1057F0006846FFF7A7FF032CD4D007B02046F0BDC2 -:1058000070B515460A46044629461046FFF7C5FFFF -:10581000064674B12078FE280BD1207C30B10020E0 -:105820002870294604F10C00FFF7B7FF2046FEF769 -:105830001CFF304670BD704770B50E4604467C2292 -:105840000021F8F724FE0225012E03D0022E04D0F9 -:10585000052070BD0120607000E065702046FEF7F5 -:1058600004FFA575002070BD28B1027C1AB10A465C -:1058700000F10C01C4E70120704710B5044686B062 -:10588000042002F01BF92078FE2806D000208DF8B5 -:10589000000069462046FFF7E7FF06B010BD7CB563 -:1058A0000E4600218DF804104178012903D0022909 -:1058B00003D0002405E0046900E044690CB1217CB8 -:1058C00089B16D4601462846FFF753FF032809D1E9 -:1058D000324629462046FFF793FF9DF80410002921 -:1058E00000D004207CBD04F10C05EBE730B40C467D -:1058F0000146034A204630BC024B0C3AFEF751BE2B -:10590000AC6202006862020070B50D46040011D05E -:1059100085B1220100212846F8F7B9FD102250492F -:105920002846F8F78AFD4F48012101704470456010 -:10593000002070BD012070BD70B505460024494EA1 -:1059400011E07068AA7B00EB0410817B914208D1C2 -:10595000C17BEA7B914204D10C222946F8F740FD35 -:1059600030B1641CE4B230788442EAD3002070BDC8 -:10597000641CE0B270BD70B50546FFF7DDFF00287E -:1059800005D1384C20786178884201D3002070BD61 -:105990006168102201EB00102946F8F74EFD2078CF -:1059A000401CC0B2207070BD2E48007870472D4951 -:1059B0000878012802D0401E08700020704770B59A -:1059C0000D460021917014461180022802D0102843 -:1059D00015D105E0288890B10121A17010800CE05C -:1059E000284613B1FFF7C7FF01E0FFF7A5FFA0703E -:1059F00010F0FF0F03D0A8892080002070BD012087 -:105A000070BD0023DBE770B5054614460E0009D0D3 -:105A100000203070A878012806D003D911490A78EF -:105A200090420AD9012070BD24B1287820702888BE -:105A3000000A5070022008700FE064B1496810221B -:105A400001EB001120461039F8F7F7FC2878207395 -:105A50002888000A607310203070002070BD00009C -:105A6000BB620200900000202DE9F04190460C46F8 -:105A700007460025FE48072F00EB881607D2DFE80F -:105A800007F00707070704040400012500E0FFDF13 -:105A900006F81470002D13D0F548803000EB880113 -:105AA00091F82700202803D006EB4000447001E065 -:105AB00081F8264006EB44022020507081F82740F0 -:105AC000BDE8F081F0B51F4614460E460546202A73 -:105AD00000D1FFDFE649E648803100EB871C0CEB84 -:105AE000440001EB8702202E07D00CEB46014078E2 -:105AF0004B784870184620210AE092F8253040780B -:105B000082F82500F6E701460CEB4100057040786D -:105B1000A142F8D192F82740202C03D00CEB44048A -:105B2000637001E082F826300CEB4104202363709F -:105B300082F82710F0BD30B50D46CE4B4419002237 -:105B4000181A72EB020100D2FFDFCB48854200DD5C -:105B5000FFDFC9484042854200DAFFDFC548401CEC -:105B6000844207DA002C01DB204630BDC148401CCE -:105B7000201830BDBF48C043FAE710B5044601689D -:105B8000407ABE4A52F82020114450B10220084405 -:105B900020F07F40EDF763F894F90810BDE810405D -:105BA000C9E70420F3E72DE9F047B14E803696F8B7 -:105BB0002D50DFF8BC9206EB850090F8264034E0CB -:105BC00009EB85174FF0070817F81400012806D0D5 -:105BD00004282ED005282ED0062800D0FFDF01F0A3 -:105BE00025F9014607EB4400427806EB850080F872 -:105BF000262090F82720A24202D1202280F82720D8 -:105C0000084601F01EF92A4621460120FFF72CFF25 -:105C10009B48414600EB041002682046904796F8E6 -:105C20002D5006EB850090F82640202CC8D1BDE809 -:105C3000F087022000E003208046D0E710B58C4CAE -:105C40002021803484F8251084F8261084F8271049 -:105C5000002084F8280084F82D0084F82E10411EBE -:105C6000A16044F8100B2074607420736073A073FB -:105C70008449E07720750870487000217C4A103C08 -:105C800002F81100491CC9B22029F9D30120ECF710 -:105C9000D6FE0020ECF7D3FE012084F82200EDF7B9 -:105CA000FFF87948EDF711F9764CA41E207077487B -:105CB000EDF70BF96070BDE81040ECF74DBE10B584 -:105CC000ECF76FFE6F4CA41E2078EDF717F96078A3 -:105CD000EDF714F9BDE8104001F0E0B8202070475E -:105CE0000020ECF785BE70B5054601240E46AC4099 -:105CF0005AB1FFF7F5FF0146654800EBC500C0F853 -:105D00001015C0F81465634801E06248001D046086 -:105D100070BD2DE9F34F564C0025803404EB810A09 -:105D200089B09AF82500202821D0691E0291544993 -:105D3000009501EB0017391D03AB07C983E8070085 -:105D4000A18BADF81C10A07F8DF81E009DF81500EA -:105D5000A046C8B10226494951F820400399A2192A -:105D6000114421F07F41019184B102210FE0012013 -:105D7000ECF765FE0020ECF762FEECF730FE01F078 -:105D80008DF884F82F50A9E00426E4E700218DF86F -:105D90001810022801D0012820D103980119099870 -:105DA000081A801C9DF81C1020F07F4001B10221D0 -:105DB000353181420BD203208DF815000398C4F1D0 -:105DC0003201401A20F07F40322403900CE098F812 -:105DD000240018B901F043FA002863D0322C03D212 -:105DE00014B101F04FF801E001F058F8254A10789D -:105DF00018B393465278039B121B00219DF818405C -:105E0000994601281AD0032818D000208DF81E00CA -:105E1000002A04DD981A039001208DF818009DF8DF -:105E20001C0000B1022103981B4A20F07F40039020 -:105E300003AB099801F03EF810B110E00120E5E74E -:105E40009DF81D0018B99BF80000032829D08DF893 -:105E50001C50CDF80C908DF818408DF81E509DF810 -:105E6000180010B30398012381190022184615E089 -:105E7000840A0020FF7F841E0020A107CC6202005C -:105E8000840800209A00002017780100A75B010019 -:105E900000F0014004F50140FFFF3F00ECF722FE57 -:105EA00006E000200BB0BDE8F08F0120ECF7C7FD45 -:105EB00097F90C20012300200199ECF713FEF87BE1 -:105EC000C00701D0ECF7F7FE012188F82F108AF8FF -:105ED000285020226946FE48F8F7AFFA0120E1E792 -:105EE0002DE9F05FDFF8E883064608EB860090F8BE -:105EF0002550202D1FD0A8F180002C4600EB8617DE -:105F0000A0F50079DFF8CCB305E0A24607EB4A0024 -:105F10004478202C0AD0ECF730FE09EB04135A46E3 -:105F200001211B1D00F0C6FF0028EED0AC4202D0BC -:105F3000334652461EE0E84808B1AFF30080ECF764 -:105F40001CFE98F82F206AB1D8F80C20411C891A41 -:105F50000902CA1701EB12610912002902DD0020B3 -:105F6000BDE8F09F3146FFF7D4FE08B10120F7E706 -:105F700033462A4620210420FFF7A4FDEFE72DE950 -:105F8000F041D34C2569ECF7F8FD401B0002C11726 -:105F900000EB1160001200D4FFDF94F8220000B182 -:105FA000FFDF012784F8227094F82E00202800D10A -:105FB000FFDF94F82E60202084F82E00002584F85E -:105FC0002F5084F8205084F82150C4482560007870 -:105FD000022833D0032831D000202077A068401C4D -:105FE00005D04FF0FF30A0600120ECF728FD002025 -:105FF000ECF725FDECF721FEECF719FEECF7EFFCD2 -:106000000EF0D6FDB648056005604FF0E0214FF474 -:106010000040B846C1F88002ECF7BBFE94F82D7042 -:106020003846FFF75DFF0028FAD0A948803800EB1A -:10603000871010F81600022802D006E00120CCE7F5 -:106040003A4631460620FFF70FFD84F8238004EB23 -:10605000870090F82600202804D0A048801E4078B1 -:10606000ECF752FF207F002803D0ECF7D6FD257710 -:10607000657725E5964910B591F82D2000248039E3 -:1060800001EB821111F814302BB1641CE4B2202C06 -:10609000F8D3202010BD934901EB041108600020C3 -:1060A000C87321460120FFF7DFFC204610BD10B564 -:1060B000012801D0032800D171B3854A92F82D3010 -:1060C000834C0022803C04EB831300BF13F8124082 -:1060D0000CB1082010BD521CD2B2202AF6D37F4A40 -:1060E00048B1022807D0072916D2DFE801F01506CB -:1060F000080A0C0E100000210AE01B2108E03A21DA -:1061000006E0582104E0772102E0962100E0B52165 -:1061100051701070002010BD072010BD6F4810B5E1 -:106120004078ECF79CFD80B210BD10B5202811D24C -:10613000674991F82D30A1F1800202EB831414F825 -:1061400010303BB191F82D3002EB831212F8102081 -:10615000012A01D0002010BD91F82D200146002019 -:10616000FFF782FC012010BD10B5ECF706FDBDE87D -:106170001040ECF774BD2DE9F0410E46544F017804 -:106180002025803F0C4607EB831303E0254603EBF5 -:1061900045046478944202D0202CF7D108E0202CEA -:1061A00006D0A14206D103EB41014978017007E016 -:1061B000002085E403EB440003EB45014078487080 -:1061C000494F7EB127B1002140F22D40AFF300804E -:1061D0003078A04206D127B100214FF48660AFF39A -:1061E0000080357027B1002140F23540AFF30080C8 -:1061F000012065E410B542680B689A1A1202D417A0 -:1062000002EB1462121216D4497A91B1427A82B921 -:10621000364A006852F82110126819441044001DD3 -:10622000891C081A0002C11700EB11600012322805 -:1062300001DB012010BD002010BD2DE9F047294EE3 -:10624000814606F500709846144600EB811712E06F -:1062500006EB0415291D4846FFF7CCFF68B988F8FE -:106260000040A97B99F80A00814201D80020DEE4B1 -:1062700007EB44004478202CEAD10120D7E42DE933 -:10628000F047824612480E4600EB8600DFF8548045 -:1062900090F825402020107008F5007099461546AA -:1062A00000EB86170BE000BF08EB04105146001D01 -:1062B000FFF7A0FF28B107EB44002C704478202C96 -:1062C000F2D1297889F800104B46224631460FE07A -:1062D000040B0020FFFF3F00000000009A00002098 -:1062E00000F500408408002000000000CC6202009D -:1062F0005046BDE8F047A0E72DE9FC410F460446B3 -:106300000025FE4E10E000BF9DF80000256806EB5A -:1063100000108168204600F0E1FD2068A84202D10B -:106320000020BDE8FC8101256B4601AA39462046C4 -:10633000FFF7A5FF0028E7D02846F2E770B504462E -:10634000EF480125A54300EB841100EB85104022A6 -:10635000F8F773F8EB4E26B1002140F29D40AFF301 -:106360000080E748803000EB850100EB8400D0F826 -:106370002500C1F8250026B1002140F2A140AFF36D -:106380000080284670BD8A4203D003460520FFF7EF -:1063900099BB202906D0DA4A02EB801000EB4100BD -:1063A00040787047D649803101EB800090F8250095 -:1063B0007047D24901EB0010001DFFF7DEBB7CB532 -:1063C0001D46134604460E4600F1080221461846B3 -:1063D000ECF752FC94F908000F2804DD1F382072F6 -:1063E0002068401C206096B10220C74951F8261051 -:1063F000461820686946801B20F07F40206094F991 -:1064000008002844C01C1F2803DA012009E00420EA -:10641000EBE701AAECF730FC9DF8040010B10098FE -:10642000401C00900099206831440844C01C20F0B2 -:106430007F4060607CBDFEB50C46064609786079F9 -:10644000907220791F461546507279B12179002249 -:106450002846A368FFF7B3FFA9492846803191F881 -:106460002E20202A0AD00969491D0DE0D4E9022313 -:10647000217903B02846BDE8F040A0E7A349497858 -:10648000052900D20521314421F07F4100F026FD8D -:1064900039462846FFF730FFD4E9023221796846B1 -:1064A000FFF78DFF2B4600213046019A00F002FDD8 -:1064B000002806D103B031462846BDE8F04000F080 -:1064C0000DBDFEBD2DE9F14F84B000F0C3FCF0B16D -:1064D00000270498007800284FF000006DD1884D07 -:1064E000884C82468346803524B1002140F2045016 -:1064F000AFF3008095F82D8085F823B0002624B1F5 -:10650000002140F20950AFF3008017B105E00127E8 -:10651000DFE74046FFF712FF804624B1002140F23A -:106520001150AFF30080ECF728FB814643466A46E2 -:106530000499FFF780FF24B1002140F21750AFF318 -:10654000008095F82E0020280CD029690098401A68 -:106550000002C21700EB1260001203D5684600F07B -:10656000BDFC01264CB1002140F22150AFF3008068 -:10657000002140F22650AFF300806B46644A0021B0 -:10658000484600F097FC98B127B941466846FFF7A6 -:10659000B3FE064326B16846FFF7EFFA0499886018 -:1065A0004FF0010A24B1002140F23A50AFF30080CD -:1065B00095F82300002897D1504605B073E42DE9E3 -:1065C000F04F89B08B46824600F044FC4C4C80343E -:1065D00030B39BF80000002710B1012800D0FFDF86 -:1065E000484D25B1002140F2F950AFF300804349F6 -:1065F000012001EB0A18A946CDF81C005FEA090644 -:1066000004D0002140F20160AFF30080079800F051 -:1066100018FC94F82D50002084F8230067B119E08D -:1066200094F82E000127202800D1FFDF9BF80000FE -:106630000028D5D0FFDFD3E72846FFF77FFE0546C9 -:1066400026B1002140F20B60AFF3008094F82300E4 -:106650000028D3D126B1002140F21560AFF30080AD -:10666000ECF78BFA2B4602AA59460790FFF7E3FE98 -:1066700098F80F005FEA060900F001008DF813009A -:1066800004D0002140F21F60AFF300803B462A4651 -:1066900002A9CDF800A0079800F02BFC064604EBF9 -:1066A000850090F828000090B9F1000F04D0002177 -:1066B00040F22660AFF3008000F0B8FB0790B9F11C -:1066C000000F04D0002140F22C60AFF3008094F85A -:1066D0002300002892D1B9F1000F04D0002140F22C -:1066E0003460AFF300800DF1080C9CE80E00C8E99F -:1066F0000112C8F80C30BEB30CE000008408002082 -:10670000840A002000000000CC6202009A000020F1 -:10671000FFFF3F005FEA090604D0002140F241601C -:10672000AFF300800098B84312D094F82E002028D0 -:106730000ED126B1002140F24660AFF3008028461A -:10674000FFF7CEFB20B99BF80000D8B3012849D051 -:10675000B9F1000F04D0002140F26360AFF3008074 -:10676000284600F05CFB01265FEA090504D0002101 -:1067700040F26C60AFF30080079800F062FB25B137 -:1067800000214FF4CE60AFF300808EB194F82D005D -:1067900004EB800090F82600202809D025B10021C4 -:1067A00040F27760AFF30080F7484078ECF7ACFB3D -:1067B00025B1002140F27C60AFF3008009B0304683 -:1067C000BDE8F08FFFE7B9F1000F04D0002140F2DF -:1067D0004E60AFF3008094F82D2051460420FFF75F -:1067E00043F9C0E7002E3FF409AF002140F25960A1 -:1067F000AFF3008002E72DE9F84FE44D814695F8AC -:106800002D004FF00008E24C4FF0010B474624B139 -:10681000002140F28A60AFF30080584600F011FB7F -:1068200085F8237024B1002140F28F60AFF300801F -:1068300095F82D00FFF782FD064695F8230028B154 -:10684000002CE4D0002140F295604BE024B10021FF -:1068500040F29960AFF30080CC48803800EB86119D -:1068600011F81900032856D1334605EB830A4A462E -:106870009AF82500904201D1012000E0002000900C -:106880000AF125000021FFF776FC0146009801423D -:1068900003D001228AF82820AF77E1B324B1002188 -:1068A00040F29E60AFF30080324649460120FFF778 -:1068B000DBF89AF828A024B1002140F2A960AFF3D8 -:1068C000008000F0B3FA834624B1002140F2AE60AC -:1068D000AFF3008095F8230038B1002C97D0002149 -:1068E00040F2B260AFF3008091E7BAF1000F07D039 -:1068F00095F82E00202803D13046FFF7F1FAE0B1D9 -:1069000024B1002140F2C660AFF30080304600F0B1 -:1069100086FA4FF0010824B1002140F2CF60AFF3B6 -:106920000080584600F08DFA24B1002140F2D36077 -:10693000AFF300804046BDE8F88F002CF1D0002175 -:1069400040F2C160AFF30080E6E70120ECF750B8F9 -:106950008D48007870472DE9F0418C4C94F82E005A -:1069600020281FD194F82D6004EB860797F8255056 -:10697000202D00D1FFDF8549803901EB861000EB27 -:106980004500407807F8250F0120F87084F82300AF -:10699000294684F82E50324602202234FFF764F84C -:1069A0000020207005E42DE9F0417A4E774C012556 -:1069B00038B1012821D0022879D003287DD0FFDF0B -:1069C00017E400F05FFAFFF7C6FF207E00B1FFDF9B -:1069D00084F821500020ECF732F8A168481C04D05C -:1069E000012300221846ECF77DF814F82E0F2178C9 -:1069F00006EB01110A68012154E0FFF7ACFF01200A -:106A0000ECF71DF894F8210050B1A068401C07D0A5 -:106A100014F82E0F217806EB01110A68062141E0D7 -:106A2000207EDFF86481002708F10208012803D0E6 -:106A300002281ED0FFDFB5E7A777ECF7EEF898F84D -:106A40000000032801D165772577607D524951F810 -:106A5000200094F8201051B948B161680123091A47 -:106A600000221846ECF73EF8022020769AE72776B7 -:106A700098E784F8205000F005FAA07F50B198F80C -:106A8000010061680123091A00221846ECF72AF870 -:106A9000257600E0277614F82E0F217806EB0111F9 -:106AA0000A680021BDE8F041104700E005E03648E3 -:106AB0000078BDE8F041ECF727BAFFF74CFF14F877 -:106AC0002E0F217806EB01110A680521EAE710B5BF -:106AD0002E4C94F82E00202800D1FFDF14F82E0F42 -:106AE00021782C4A02EB01110A68BDE8104004210C -:106AF00010477CB5254C054694F82E00202800D17F -:106B0000FFDFA068401C00D0FFDF94F82E00214971 -:106B100001AA01EB0010694690F90C002844ECF73B -:106B2000ABF89DF904000F2801DD012000E00020F2 -:106B3000009908446168084420F07F41A16094F8FE -:106B40002100002807D002B00123BDE870400022D8 -:106B50001846EBF7C7BF7CBD30B5104A0B1A541C62 -:106B6000B3EB940F1ED3451AB5EB940F1AD393428F -:106B700003D9101A43185B1C14E0954210D9511A1E -:106B80000844401C43420DE098000020040B002004 -:106B90000000000084080020CC620200FF7F841EF9 -:106BA000FFDF0023184630BD0123002201460220EA -:106BB000EBF798BF0220EBF742BFEBF7DEBF2DE902 -:106BC000FE4FEE4C05468A4694F82E00202800D150 -:106BD000FFDFEA4E94F82E10A0462046A6F520725C -:106BE00002EB011420218DF8001090F82D10376968 -:106BF00000EB8101D8F8000091F82590284402AA02 -:106C000001A90C36ECF738F89DF90800002802DDE0 -:106C10000198401C0190A0680199642D084452D34A -:106C2000D74B00225B1B72EB02014CD36168411A07 -:106C300021F07F41B1F5800F45D220F07F40706098 -:106C400086F80AA098F82D1044466B464A4630460E -:106C5000FFF7F3FAB0B3A068401C10D0EBF78DFF3C -:106C6000A168081A0002C11700EB11600012022887 -:106C70002BDD0120EBF7E3FE4FF0FF30A06094F82E -:106C80002D009DF8002020210F34FFF77CFBA17F11 -:106C9000BA4A803A02EB8111E27F01EB420148706F -:106CA00054F80F0C284444F80F0C012020759DF86F -:106CB0000000202803D0B3484078ECF725F90120E4 -:106CC000BDE8FE8F01E00020FAE77760FBE72DE9E1 -:106CD000F047AA4C074694F82D00A4F1800606EB75 -:106CE000801010F8170000B9FFDF94F82D50A0466F -:106CF000A54C24B1002140F6EA00AFF3008040F635 -:106D0000F60940F6FF0A06EB851600BF16F81700D5 -:106D1000012819D0042811D005280FD006280DD03D -:106D20001CB100214846AFF300800FF02DF8002C75 -:106D3000ECD000215046AFF30080E7E72A46394601 -:106D40000120FEF791FEF2E74FF0010A4FF0000933 -:106D5000454624B1002140F60610AFF300805046AE -:106D600000F06FF885F8239024B1002140F60B1055 -:106D7000AFF3008095F82D00FFF7E0FA064695F88E -:106D8000230028B1002CE4D0002140F611101FE0B0 -:106D900024B1002140F61510AFF3008005EB86000A -:106DA00000F1270133463A462630FFF7E4F924B1D3 -:106DB000002140F61910AFF3008000F037F882464A -:106DC00095F8230038B1002CC3D0002140F61F10E5 -:106DD000AFF30080BDE785F82D60012085F8230022 -:106DE000504600F02EF8002C04D0002140F62C1064 -:106DF000AFF30080BDE8F08730B504465F480D462C -:106E000090F82D005D49803901EB801010F81400D6 -:106E100000B9FFDF5D4800EB0410C57330BD574972 -:106E200081F82D00012081F82300704710B55848E3 -:106E300008B1AFF30080EFF3108000F0010072B6EC -:106E400010BD10B5002804D1524808B1AFF300803E -:106E500062B610BD50480068C005C00D10D0103893 -:106E600040B2002804DB00F1E02090F8000405E0C7 -:106E700000F00F0000F1E02090F8140D4009704779 -:106E80000820704710B53D4C94F82400002804D128 -:106E9000F4F712FF012084F8240010BD10B5374C20 -:106EA00094F82400002804D0F4F72FFF002084F881 -:106EB000240010BD10B51C685B68241A181A24F051 -:106EC0007F4420F07F40A14206D8B4F5800F03D262 -:106ED000904201D8012010BD002010BDD0E9003241 -:106EE000D21A21F07F43114421F07F41C0E90031E3 -:106EF00070472DE9FC418446204815468038089C9F -:106F000000EB85160F4616F81400012804D002285D -:106F100002D00020BDE8FC810B46204A01216046DA -:106F2000FFF7C8FFF0B101AB6A4629463846FFF7C4 -:106F3000A6F9B8B19DF804209DF800102846FFF787 -:106F400022FA06EB440148709DF8000020280DD07D -:106F500006EB400044702A4621460320FEF784FDDC -:106F60000120D7E72A4621460420F7E703480121FC -:106F700000EB850000F8254FC170ECE7040B002002 -:106F8000FF1FA107980000200000000084080020D7 -:106F9000000000000000000004ED00E0FFFF3F00E3 -:106FA0002DE9F041044680074FF000054FF001063F -:106FB0000CD56B480560066000F0E8F920B169481F -:106FC000016841F48061016024F00204E0044FF0A4 -:106FD000FF3705D564484660C0F8087324F4805430 -:106FE000600003D56148056024F08044E0050FD5BA -:106FF0005F48C0F80052C0F808735E490D60091D73 -:107000000D605C4A04210C321160066124F4807426 -:10701000A00409D558484660C0F80052C0F808736B -:107020005648056024F40054C4F38030C4F3C031E2 -:10703000884200D0FFDF14F4404F14D0504846601F -:10704000C0F808734F488660C0F80052C0F8087353 -:107050004D490D600A1D16608660C0F808730D600A -:10706000166024F4404420050AD5484846608660EE -:10707000C0F80873C0F848734548056024F40064FC -:107080000DF070FD4348044200D0FFDFBDE8F08101 -:10709000F0B50022202501234FEA020420FA02F174 -:1070A000C9072DD051B2002910DB00BF4FEA51179C -:1070B0004FEA870701F01F0607F1E02703FA06F6FB -:1070C000C7F88061BFF34F8FBFF36F8F0CDB00BF3A -:1070D0004FEA51174FEA870701F01F0607F1E02733 -:1070E00003FA06F6C7F8806204DB01F1E02181F8BB -:1070F000004405E001F00F0101F1E02181F8144D99 -:1071000002F10102AA42C9D3F0BD10B5224C2060A1 -:107110000846F4F7EAFE2068FFF742FF2068FFF711 -:10712000B7FF0DF045F900F092F90DF01BFD0DF0E1 -:1071300058FCEBF7B5FEBDE810400DF0EDB910B509 -:10714000154C2068FFF72CFF2068FFF7A1FF0DF01A -:1071500009FDF4F7C9FF0020206010BD0A20704728 -:10716000FC1F00403C17004000C0004004E5014007 -:10717000008000400485004000D0004004D500405D -:1071800000E0004000F0004000F5004000B000408A -:1071900008B50040FEFF0FFD9C00002070B5264999 -:1071A0000A680AB30022154601244B685B1C4B6039 -:1071B0000C2B00D34D600E7904FA06F30E681E42C4 -:1071C0000FD0EFF3108212F0010272B600D001224C -:1071D0000C689C430C6002B962B6496801600020EB -:1071E00070BD521C0C2AE0D3052070BD4FF0E02189 -:1071F0004FF48000C1F800027047EFF3108111F0E6 -:10720000010F72B64FF0010202FA00F20A48036859 -:1072100042EA0302026000D162B6E7E706480021B5 -:1072200001604160704701218140034800680840C7 -:1072300000D0012070470000A0000020012081073D -:10724000086070470121880741600021C0F80011E3 -:1072500018480170704717490120087070474FF0B7 -:107260008040D0F80001012803D01248007800289F -:1072700000D00120704710480068C00700D00120EE -:1072800070470D480C300068C00700D001207047DF -:107290000948143000687047074910310A68D20362 -:1072A00006D5096801F00301814201D10120704730 -:1072B00000207047A8000020080400404FF08050D4 -:1072C000D0F830010A2801D0002070470120704713 -:1072D00000B5FFF7F3FF20B14FF08050D0F8340134 -:1072E00008B1002000BD012000BD4FF08050D0F853 -:1072F00030010E2801D000207047012070474FF068 -:107300008050D0F83001062803D0401C01D0002066 -:107310007047012070474FF08050D0F830010D28A1 -:1073200001D000207047012070474FF08050D0F806 -:107330003001082801D000207047012070474FF02D -:107340008050D0F83001102801D000207047012073 -:10735000704700B5FFF7F3FF30B9FFF7DCFF18B94E -:10736000FFF7E3FF002800D0012000BD00B5FFF7C4 -:10737000C6FF38B14FF08050D0F83401062803D34F -:10738000401C01D0002000BD012000BD00B5FFF76A -:10739000B6FF48B14FF08050D0F83401062803D32F -:1073A000401C01D0012000BD002000BD0021017063 -:1073B000084670470146002008707047EFF31081BF -:1073C00001F0010172B60278012A01D0012200E029 -:1073D00000220123037001B962B60AB10020704790 -:1073E0004FF400507047E9E7EFF3108111F0010FFF -:1073F00072B64FF00002027000D162B600207047F2 -:10740000F2E700002DE9F04115460E46044600273C -:1074100000F0EBF8A84215D3002341200FE000BF95 -:1074200094F84220A25CF25494F84210491CB1FB3B -:10743000F0F200FB12115B1C84F84210DBB2AB428D -:10744000EED3012700F0DDF83846BDE8F08172493F -:1074500010B5802081F800047049002081F84200B6 -:1074600081F84100433181F8420081F84100433105 -:1074700081F8420081F841006948FFF797FF6848AA -:10748000401CFFF793FFEBF793FCBDE8104000F0C2 -:10749000B8B840207047614800F0A7B80A460146D6 -:1074A0005E48AFE7402070475C48433000F09DB82D -:1074B0000A46014659484330A4E7402101700020A4 -:1074C000704710B504465548863000F08EF820709D -:1074D000002010BD0A460146504810B58630FFF71F -:1074E00091FF08B1002010BD42F2070010BD70B539 -:1074F0000C460646412900D9FFDF4A48006810388B -:1075000040B200F054F8C5B20D2000F050F8C0B2FF -:10751000854201D3012504E0002502E00DB1EBF71F -:107520008AFC224631463D48FFF76CFF0028F5D023 -:1075300070BD2DE9F0413A4F0025064617F10407CA -:1075400057F82540204600F041F810B36D1CEDB20D -:10755000032DF5D33148433000F038F8002825D00A -:107560002E4800F033F8002820D02C48863000F058 -:107570002DF800281AD0EBF734FC2948FFF71EFF3E -:10758000B0F5005F00D0FFDFBDE8F0412448FFF711 -:107590002BBF94F841004121265414F8410F401CA0 -:1075A000B0FBF1F201FB12002070D3E74DE7002899 -:1075B00004DB00F1E02090F8000405E000F00F008B -:1075C00000F1E02090F8140D4009704710F8411FB9 -:1075D0004122491CB1FBF2F302FB131140788142B6 -:1075E00001D1012070470020704710F8411F4078FA -:1075F000814201D3081A02E0C0F141000844C0B240 -:10760000704710B50648FFF7D9FE002803D1BDE842 -:107610001040EBF7D1BB10BD0DE000E0340B0020B3 -:10762000AC00002004ED00E070B5154D2878401C3A -:10763000C4B26878844202D000F0DBFA2C7070BDCE -:107640002DE9F0410E4C4FF0E02600BF00F0C6FAE5 -:107650000EF09AFB40BF20BF677820786070D6F8A4 -:107660000052E9F798FE854305D1D6F8040210B917 -:107670002078B842EAD000F0ACFA0020BDE8F081F2 -:10768000BC0000202DE9F04101264FF0E02231033B -:107690004FF000084046C2F88011BFF34F8FBFF390 -:1076A0006F8F204CC4F800010C2000F02EF81E4D06 -:1076B0002868C04340F30017286840F01000286095 -:1076C000C4F8046326607F1C02E000BF0EF05CFB80 -:1076D000D4F800010028F9D01FB9286820F0100064 -:1076E0002860124805686660C4F80863C4F8008121 -:1076F0000C2000F00AF82846BDE8F08110B50446D9 -:10770000FFF7C0FF2060002010BD002809DB00F05B -:107710001F02012191404009800000F1E020C0F8E3 -:107720008012704700C0004010ED00E008C5004026 -:107730002DE9F047FF4C0646FF21A06800EB06123A -:1077400011702178FF2910D04FF0080909EB0111C1 -:1077500009EB06174158C05900F0F4F9002807DD7D -:10776000A168207801EB061108702670BDE8F0874B -:1077700094F8008045460DE0A06809EB05114158DA -:10778000C05900F0DFF9002806DCA068A84600EB2D -:1077900008100578FF2DEFD1A06800EB061100EB73 -:1077A00008100D700670E1E7F0B5E24B04460020CA -:1077B00001259A680C269B780CE000BF05EB0017AA -:1077C000D75DA74204D106EB0017D7598F4204D0EA -:1077D000401CC0B28342F1D8FF20F0BD70B5FFF766 -:1077E000ECF9D44C08252278A16805EB02128958DF -:1077F00000F0A8F9012808DD2178A06805EB011147 -:107800004058BDE87040FFF7CFB9FFF7A1F8BDE8D9 -:107810007040EBF779BB2DE9F041C64C2578FFF7B6 -:10782000CCF9FF2D6ED04FF00808A26808EB0516C2 -:10783000915900F087F90228A06801DD80595DE0C8 -:1078400000EB051109782170022101EB0511425C62 -:107850005AB1521E4254815901F5800121F07F41F5 -:1078600081512846FFF764FF34E00423012203EB33 -:10787000051302EB051250F803C0875CBCF1000F42 -:1078800010D0BCF5007F10D9CCF3080250F806C028 -:107890000CEB423C2CF07F4C40F806C0C3589A1ABF -:1078A000520A09E0FF2181540AE0825902EB4C326E -:1078B00022F07F428251002242542846FFF738FFCF -:1078C0000C21A06801EB05114158E06850F8272011 -:1078D000384690472078FF2814D0FFF76EF92278B9 -:1078E000A16808EB02124546895800F02BF90128DF -:1078F00093DD2178A06805EB01114058BDE8F04107 -:10790000FFF752B9BDE8F081F0B51D4614460E46AA -:107910000746FF2B00D3FFDFA00700D0FFDF85481D -:10792000FF210022C0E90247C57006710170427054 -:1079300082701046012204E002EB0013401CE15467 -:10794000C0B2A842F8D3F0BD70B57A4C064665784F -:107950002079854200D3FFDFE06840F82560607839 -:10796000401C6070284670BD2DE9FF5F1D468B46A8 -:107970000746FF24FFF721F9DFF8B891064699F88A -:107980000100B84200D8FFDF00214FF001084FF09E -:107990000C0A99F80220D9F808000EE008EB011350 -:1079A000C35CFF2B0ED0BB4205D10AEB011350F88C -:1079B00003C0DC450CD0491CC9B28A42EED8FF2C6A -:1079C00002D00DE00C46F6E799F803108A4203D185 -:1079D000FF2004B0BDE8F09F1446521C89F8022035 -:1079E00008EB04110AEB0412475440F802B00421DA -:1079F000029B0022012B01EB04110CD040F8012066 -:107A00004FF4007808234FF0020C454513D9E905DF -:107A1000C90D02D002E04550F2E7414606EB413283 -:107A200003EB041322F07F42C250691A0CEB0412DC -:107A3000490A81540BE005B9012506EB453103EBFA -:107A4000041321F07F41C1500CEB0411425499F80A -:107A500000502046FFF76CFE99F80000A84201D0C4 -:107A6000FFF7BCFE3846B4E770B50C460546FFF795 -:107A7000A4F8064621462846FFF796FE0446FF284E -:107A80001AD02C4D082101EB0411A868415830464A -:107A900000F058F800F58050C11700EBD1404013BA -:107AA0000221AA6801EB0411515C09B100EB4120ED -:107AB000002800DC012070BD002070BD2DE9F047DA -:107AC00088468146FFF770FE0746FF281BD0194DF8 -:107AD0002E78A8683146344605E0BC4206D02646DA -:107AE00000EB06121478FF2CF7D10CE0FF2C0AD023 -:107AF000A6420CD100EB011000782870FF2804D0BA -:107B0000FFF76CFE03E0002030E6FFF753F8414634 -:107B10004846FFF7A9FF0123A968024603EB0413B7 -:107B2000FF20C854A878401EB84200D1A87001EBCD -:107B3000041001E0000C002001EB06110078087031 -:107B4000104613E6081A0002C11700EB116000127C -:107B50007047000010B5202000F07FF8202000F0D2 -:107B60008DF84D49202081F80004E9F712FC4B49BB -:107B700008604B48D0F8041341F00101C0F8041329 -:107B8000D0F8041341F08071C0F804134249012079 -:107B90001C39C1F8000110BD10B5202000F05DF8BF -:107BA0003E480021C8380160001D01603D4A481E62 -:107BB00010603B4AC2F80803384B1960C2F8000154 -:107BC000C2F8600138490860BDE81040202000F08C -:107BD00055B834493548091F086070473149334862 -:107BE000086070472D48C8380160001D521E0260B1 -:107BF00070472C4901200860BFF34F8F70472DE973 -:107C0000F0412849D0F8188028480860244CD4F85E -:107C100000010025244E6F1E28B14046E9F712FBF3 -:107C200040B9002111E0D4F8600198B14046E9F76D -:107C300009FB48B1C4F80051C4F860513760BDE891 -:107C4000F041202000F01AB831684046BDE8F0410C -:107C50000EF0A4B8FFDFBDE8F08100280DDB00F0D6 -:107C60001F02012191404009800000F1E020C0F88E -:107C70008011BFF34F8FBFF36F8F7047002809DB70 -:107C800000F01F02012191404009800000F1E02036 -:107C9000C0F880127047000020E000E0C8060240F3 -:107CA00000000240180502400004024001000001EB -:107CB0005E4800210170417010218170704770B5DD -:107CC000054616460C460220EAF714FE57490120E5 -:107CD00008705749F01E086056480560001F046090 -:107CE00070BD10B50220EAF705FE5049012008706A -:107CF00051480021C0F80011C0F80411C0F8081163 -:107D00004E494FF40000086010BD48480178D9B1D1 -:107D10004B4A4FF4000111604749D1F8003100226D -:107D2000002B1CBFD1F80431002B02D0D1F8081170 -:107D300019B142704FF0100104E04FF001014170A1 -:107D400040490968817002704FF00000EAF7D2BD27 -:107D500010B50220EAF7CEFD34480122002102705E -:107D60003548C0F80011C0F80411C0F808110260CD -:107D700010BD2E480178002904BF407870472E4876 -:107D8000D0F80011002904BF02207047D0F800117C -:107D900000291CBFD0F80411002905D0D0F8080133 -:107DA000002804BF01207047002070471F4800B51D -:107DB0000278214B4078C821491EC9B282B1D3F85C -:107DC00000C1BCF1000F10D0D3F8000100281CBF87 -:107DD000D3F8040100280BD0D3F8080150B107E014 -:107DE000022802D0012805D002E00029E4D1FFDFFB -:107DF000002000BD012000BD0C480178002904BF0F -:107E0000807870470C48D0F8001100291CBFD0F8CA -:107E10000411002902D0D0F8080110B14FF0100071 -:107E2000704708480068C0B270470000BE000020DC -:107E300010F5004008F5004000F0004004F5014056 -:107E400008F5014000F400405748002101704170DE -:107E5000704770B5064614460D460120EAF74AFD04 -:107E600052480660001D0460001D05605049002056 -:107E7000C1F850014F490320086050494E4808603E -:107E8000091D4F48086070BD2DE9F0410546464880 -:107E90000C46012606704B4945EA024040F08070CE -:107EA0000860FFF72CFA002804BF47480460002749 -:107EB000464CC4F80471474945480860002D02BF8C -:107EC000C4F800622660BDE8F081012D18BFFFDF15 -:107ED000C4F80072266041493F480860BDE8F0815F -:107EE0003148017871B13B4A394911603749D1F8BD -:107EF00004210021002A08BF417002D0384A1268CC -:107F0000427001700020EAF7F5BC2748017800298B -:107F100004BF407870472D48D0F80401002808BFFE -:107F200070472F480068C0B27047002808BF7047EC -:107F30002DE9F0471C480078002808BFFFDF234CDC -:107F4000D4F80401002818BFBDE8F0874FF00209FB -:107F5000C4F80493234F3868C0F30018386840F021 -:107F600010003860D4F80401002804BF4FF4004525 -:107F70004FF0E02608D100BFC6F880520DF004FF94 -:107F8000D4F804010028F7D0B8F1000F03D1386805 -:107F900020F010003860C4F80893BDE8F0870B4962 -:107FA0000120886070470000C100002008F50040F3 -:107FB000001000401CF500405011004098F50140B1 -:107FC0000CF0004004F5004018F5004000F00040BF -:107FD0000000020308F501400000020204F5014020 -:107FE00000F4004010ED00E0012804BF41F6A47049 -:107FF0007047022804BF41F288307047042804BF4C -:1080000046F218007047082804BF47F2A0307047B6 -:1080100000B5FFDF41F6A47000BD10B5FE48002496 -:1080200001214470047044728472C17280F825404A -:10803000C462846380F83C4080F83D40FF2180F8B2 -:108040003E105F2180F83F1018300DF09FFFF3497C -:10805000601E0860091D0860091D0C60091D08608C -:10806000091D0C60091D0860091D0860091D0860D4 -:10807000091D0860091D0860091D0860091D0860C8 -:10808000091D0860091D086010BDE549486070477A -:10809000E448016801F00F01032904BF0120704783 -:1080A000016801F00F01042904BF02207047016834 -:1080B00001F00F01052904D0006800F00F00062828 -:1080C00007D1D948006810F0060F0CBF0820042023 -:1080D000704700B5FFDF012000BD012812BF022854 -:1080E00000207047042812BF08284FF4C87070475A -:1080F00000B5FFDF002000BD012804BF2820704725 -:10810000022804BF18207047042812BF08284FF423 -:10811000A870704700B5FFDF282000BD70B5C148CA -:10812000016801F00F01032908BF012414D0016880 -:1081300001F00F01042904BF022418210DD00168A9 -:1081400001F00F0105294BD0006800F00F00062850 -:108150001CBFFFDF012443D02821AF48C26A806AD8 -:10816000101A0E18082C04BF4EF6981547F2A030CE -:108170002DD02046042C08BF4EF628350BD0012800 -:1081800008BF41F6A47506D0022C1ABFFFDF41F6E6 -:10819000A47541F28835012C08BF41F6A47016D0B1 -:1081A000022C08BF002005D0042C1ABFFFDF0020DE -:1081B0004FF4C8702D1A022C08BF41F2883006D047 -:1081C000042C1ABFFFDF41F6A47046F21800281AEB -:1081D0004FF47A7100F2E730B0FBF1F0304470BD3B -:1081E0009148006810F0060F0CBF082404244FF4D7 -:1081F000A871B2E710B58D49026801F118040A634D -:1082000042684A63007A81F83800207E48B1207FB6 -:10821000F6F781F9A07E011C18BF0121207FF6F737 -:1082200069F9607E002808BF10BD607FF6F773F91A -:10823000E07E011C18BF0121607FBDE81040F6F709 -:1082400059B930B50024054601290AD0022908BFD2 -:108250004FF0807405D0042916BF08294FF0C74499 -:10826000FFDF44F4847040F480107149086045F4E5 -:10827000403001F1040140F00070086030BD30B5BD -:108280000024054601290AD0022908BF4FF0807456 -:1082900005D0042916BF08294FF0C744FFDF44F476 -:1082A000847040F480106249086045F4403001F168 -:1082B000040140F0007008605E48D0F8000100281A -:1082C00018BFFFDF30BD2DE9F04102274FF0E02855 -:1082D00001250024C8F88071BFF34F8FBFF36F8F63 -:1082E000554804600560FFF751F8544E18B13068E6 -:1082F00040F480603060FFF702F838B1306820F059 -:10830000690040F0960040F0004030604D494C4814 -:1083100008604FF01020806CB0F1FF3F04D04A4954 -:108320000A6860F317420A60484940F25B600860DF -:10833000091F40F203100860081F05603949032037 -:10834000086043480560444A42491160444A434931 -:108350001160121F43491160016821F440710160EE -:10836000016841F480710160C8F8807231491020C1 -:10837000C1F80403284880F83140C46228484068A6 -:10838000002808BFBDE8F081BDE8F0410047274A5A -:108390000368C2F81A308088D08302F11800017295 -:1083A00070471D4B10B51A7A8A4208D10146062241 -:1083B000981CF6F715F8002804BF012010BD002016 -:1083C00010BD154890F825007047134A5170107081 -:1083D0007047F0B50546800000F1804000F5805000 -:1083E0008B88C0F820360B78D1F8011043EA0121C0 -:1083F000C0F8001605F10800012707FA00F61A4C2C -:10840000002A04BF2068B04304D0012A18BFFFDF50 -:1084100020683043206029E0280C0020000E004036 -:10842000C40000201015004014140040100C00205F -:108430001415004000100040FC1F00403C17004095 -:108440002C000089781700408C150040381500403A -:108450005016004000000E0408F501404080004026 -:10846000A4F501401011004040160040206807FAB2 -:1084700005F108432060F0BD0CF0C4BCFE4890F844 -:1084800032007047FD4AC17811600068FC49000263 -:1084900008607047252808BF02210ED0262808BF93 -:1084A0001A210AD0272808BF502106D00A2894BFD5 -:1084B0000422062202EB4001C9B2F24A1160F249DD -:1084C000086070472DE9F047EB4CA17A012956D09E -:1084D000022918BFBDE8F087627E002A08BFBDE808 -:1084E000F087012950D0E17E667F0D1C18BF012561 -:1084F0005FF02401DFF894934FF00108C9F84C8035 -:10850000DFF88CA34718DAF80000B84228BFFFDF75 -:108510000020C9F84C01CAF80070300285F0010152 -:1085200040EA015040F0031194F82000820002F16B -:10853000804202F5C042C2F81015D64901EB800115 -:10854000A07FC20002F1804202F5F832C2F8141591 -:10855000D14BC2F81035E27FD30003F1804303F51D -:10856000F833C3F81415CD49C3F8101508FA00F014 -:1085700008FA02F10843CA490860BDE8F087227E84 -:10858000002AAED1BDE8F087A17E267F002914BF66 -:10859000012500251121ADE72DE9F041C14E8046AE -:1085A00003200D46C6F80002BD49BF4808602846B2 -:1085B0000CF02CFCB04F0124B8F1000F04BFBC72CA -:1085C000346026D0B8F1010F23D1B848006860B9F3 -:1085D00015F00C0F09D0C6F80443012000F0DAFEB4 -:1085E000F463346487F83C4002E0002000F0D2FEDF -:1085F00028460CF0F3FC0220B872FEF7B7FE38B93B -:10860000FEF7C4FE20B9AA48016841F4C021016008 -:1086100074609E48C4649E4800682946BDE8F041E5 -:1086200050E72DE9F0479F4E814603200D46C6F8DE -:108630000002DFF86C829C48C8F8000008460CF085 -:10864000E5FB28460CF0CAFC01248B4FB9F1000F62 -:1086500003D0B9F1010F0AD031E0BC72B86B40F41D -:108660008010B8634FF48010C8F8000027E00220A3 -:10867000B872B86B40F40010B8634FF40010C8F83B -:1086800000008A48006860B915F00C0F09D0C6F8E0 -:108690000443012000F07EFEF463346487F83C401C -:1086A00002E0002000F076FEFEF760FE38B9FEF72B -:1086B0006DFE20B97E48016841F4C0210160EAF7EF -:1086C000F7FA2946BDE8F047FCE62DE9F84F754C6E -:1086D0008246032088461746C4F80002DFF8C0919E -:1086E0007148C9F8000010460CF090FBDFF8C4B1E7 -:1086F000614E0125BAF1000F04BFCBF80040B572FE -:1087000004D0BAF1010F18BFFFDF2FD06A48C0F8BC -:1087100000806B4969480860B06B40F40020B0638A -:10872000D4F800321021C4F808130020C4F8000265 -:10873000DFF890C18A03CCF80020C4F80001C4F827 -:108740000C01C4F81001C4F80401C4F81401C4F801 -:1087500018015D4800680090C4F80032C9F8002094 -:10876000C4F80413BAF1010F14D026E038460CF017 -:1087700035FCFEF7FBFD38B9FEF708FE20B94C4882 -:10878000016841F4C02101605048CBF8000002208C -:10879000B072BBE74548006860B917F00C0F09D00C -:1087A000C4F80453012000F0F5FDE563256486F864 -:1087B0003C5002E0002000F0EDFD4FF40020C9F82D -:1087C00000003248C56432480068404528BFFFDFDA -:1087D00039464046BDE8F84F74E62DE9F041264C95 -:1087E0000646002594F8310017468846002808BF41 -:1087F000FFDF16B1012E16D021E094F831000128D8 -:1088000008D094F83020394640460CF014FBE16A59 -:10881000451814E094F830103A4640460CF049FBF5 -:10882000E16A45180BE094F8310094F83010012803 -:108830003A46404609D00CF064FBE16A45183A46D6 -:1088400029463046BDE8F0413FE70CF014FBE16AF1 -:108850004518F4E72DE9F84F124CD4F8000220F047 -:108860000309D4F804034FF0100AC0F30018C4F849 -:1088700008A300262CE00000280C0020241500404E -:108880001C150040081500405415004000800040B1 -:108890004C850040006000404C81004010110040B9 -:1088A00004F5014000100040000004048817004057 -:1088B00068150040ACF50140488500404881004003 -:1088C000A8F5014008F501401811004004100040CF -:1088D000C4F80062FC48FB490160FC4D0127A97AFD -:1088E000012902D0022903D015E0297E11B912E036 -:1088F000697E81B1A97FEA7F07FA01F107FA02F2E6 -:108900001143016095F82000800000F1804000F5DF -:10891000C040C0F81065FF208DF80000C4F8106159 -:10892000276104E09DF80000401E8DF800009DF8CE -:10893000000018B1D4F810010028F3D09DF8000011 -:10894000002808BFFFDFC4F81061002000F022FDFE -:108950006E72AE72EF72C4F80092B8F1000F18BFD9 -:10896000C4F804A3BDE8F88FFF2008B58DF8000017 -:10897000D7480021C0F810110121016105E000BFB6 -:108980009DF80010491E8DF800109DF8001019B1D7 -:10899000D0F810110029F3D09DF80000002808BF7E -:1089A000FFDF08BD0068CB4920F07F4008607047BA -:1089B0004FF0E0200221C0F8801100F5C070BFF335 -:1089C0004F8FBFF36F8FC0F80011704710B490E85D -:1089D0001C10C14981E81C10D0E90420C1E9042021 -:1089E00010BC70474FF0E0210220C1F80001704731 -:1089F000BA4908707047BA490860704770B50546B3 -:108A0000EAF756F9B14C2844E16A884298BFFFDF83 -:108A100001202074EAF74CF9B24A28440021606131 -:108A2000C2F84411B0490860A06BB04940F480001E -:108A3000A063D001086070BD70B5A44C0546AC4A77 -:108A40000220207410680E4600F00F00032808BFB3 -:108A5000012213D0106800F00F00042808BF022282 -:108A60000CD0106800F00F0005281BD0106800F033 -:108A70000F0006281CBFFFDF012213D094F831003D -:108A800094F83010012815D028460CF081FA954949 -:108A900060610020C1F844016169E06A08449249BC -:108AA000086070BD9348006810F0060F0CBF0822E4 -:108AB0000422E3E7334628460CF038FAE7E7824918 -:108AC0004FF4800008608148816B21F4800181634C -:108AD000002101747047C20002F1804202F5F832B1 -:108AE000854BC2F81035C2F81415012181407F482A -:108AF00001607648826B1143816370477948012198 -:108B00004160C1600021C0F84411774801606F489E -:108B1000C1627047794908606D48D0F8001241F091 -:108B20004001C0F8001270476948D0F8001221F0E7 -:108B30004001C0F800127149002008607047644885 -:108B4000D0F8001221F01001C0F80012012181615B -:108B500070475E49FF2081F83E005D480021C0F863 -:108B60001C11D0F8001241F01001C0F8001270473B -:108B7000574981B0D1F81C21012A0DD0534991F8F1 -:108B80003E10FF290DBF00204942017001B008BF0F -:108B90007047012001B07047594A126802F07F0205 -:108BA000524202700020C1F81C0156480068009033 -:108BB000EFE7F0B517460C00064608BFFFDF434D50 -:108BC00014F0010F2F731CBF012CFFDF002E0CBF10 -:108BD000012002206872EC7201281CBF0228FFDF0E -:108BE000F0BD3A4981F83F007047384A136C036082 -:108BF000506C086070472DE9F84F38480078042819 -:108C000028BFFFDF314CDFF8C080314D94F83C00C5 -:108C100000260127E0B1D5F8040110F1000918BFC2 -:108C20004FF00109D5F81001002818BF012050EAC3 -:108C300009014FF4002B17D08021C5F80813C8F89C -:108C400000B084F83C6090F0010F18BFBDE8F88FC9 -:108C5000DFF89090D9F84C01002871D0A07A012853 -:108C60006FD002286ED0D1E0D5F80001DFF890A0D7 -:108C700030B3C5F800616F61FF20009002E0401E34 -:108C8000009005D0D5F81C0100280098F7D000B955 -:108C9000FFDFDAF8000000F07F0A94F83F0050454B -:108CA0003CBF002000F076FB84F83EA0C5F81C61B4 -:108CB000C5F808731348006800902F64AF6326E07E -:108CC00022E0000000000E0408F50140280C0020FE -:108CD000001000403C150040100C0020C400002093 -:108CE00004150040008000404485004004F5014028 -:108CF000101500401414004004110040601500409D -:108D0000481500401C110040B9F1000F03D0B9F123 -:108D1000000F2ED05CE0DAF8000000F07F0084F84D -:108D20003E00C5F81C6194F83D1061B194F83F1005 -:108D300081421BD2002000F02DFB2F64AF6315E0B1 -:108D400064E04CE04EE0FE49096894F83F308AB296 -:108D5000090C984203D30F2A06D9022904D2012014 -:108D600000F018FB2F6401E02F64AF63F548006842 -:108D700000908022C5F80423F3498F64F348036808 -:108D8000A0F1040CDCF800C043F698273B4463458F -:108D900015D2026842F210731A440260C1F84861A9 -:108DA000EC49EB480860091FEB480860EB48C0F845 -:108DB00000B0A06B40F40020A063BDE8F88F06600F -:108DC000C1F84861C5F80823C8F800B0C1F8486187 -:108DD0008020C5F80803C8F800B0BDE8F88F207EF1 -:108DE00010B913E0607E88B1A07FE17F07FA00F040 -:108DF00007FA01F10843C8F8000094F82000800049 -:108E000000F1804000F5C040C0F81065C9F84C7012 -:108E1000D34800682064D34800686064D248A16BDE -:108E20000160A663217C002019B1D9F84411012901 -:108E300000D00021A27A012A6ED0022A74D000BF8D -:108E4000D5F8101101290CBF1021002141EA0008BA -:108E5000C648016811F0FF0F03D0D5F8141101299D -:108E600000D0002184F83210006810F0FF0F03D00A -:108E7000D5F81801012800D0002084F83300BC4840 -:108E8000006884F83400FEF774FF012818BF002042 -:108E900084F83500C5F80061C5F80C61C5F81061AB -:108EA000C5F80461C5F81461C5F81861B1480068D7 -:108EB0000090A548C0F84461AF480068DFF8BC9254 -:108EC0000090D9F80000A062A9F104000068E062F7 -:108ED000AB48016801F00F01032908BF012013D03E -:108EE000016801F00F01042908BF02200CD00168BD -:108EF00001F00F01052926D0006800F00F000628B8 -:108F00001CBFFFDF01201ED084F83000A07A84F857 -:108F1000310002282CD11EE0D5F80C01012814BF25 -:108F2000002008208CE7FFE7D5F80C01012814BFCA -:108F300000200220934A1268012A14BF0422002252 -:108F4000104308437CE79048006810F0060F0CBF00 -:108F500008200420D8E7607850B18C490968097866 -:108F60000840217831EA000008BF84F8247001D05D -:108F700084F82460DFF818A218F0020F06D0E9F791 -:108F800097FEA16A081ADAF81010884718F0010F46 -:108F900018BF4FF0000B0DD0E9F78AFEE16ADAF84E -:108FA0001420081A594690477A48007810F0010FAB -:108FB0002FD10CE018F0020F18BF4FF0010BEBD1CE -:108FC00018F0080F18BF4FF0020BE5D1ECE7DFF8FF -:108FD000BCB1DBF80000007800F00F00072828BFC4 -:108FE00084F8256015D2DBF80000062200F10901A3 -:108FF000A01CF5F7F5F940B9207ADBF800100978E4 -:10900000B0EBD11F08BF012001D04FF0000084F861 -:109010002500E17A4FF0000011F0020F1CBF18F09C -:10902000020F18F0040F19D111F0100F1CBF94F8A3 -:109030003320002A02D094F835207AB111F0080FBD -:109040001CBF94F82420002A08D111F0040F02D08C -:1090500094F8251011B118F0010F01D04FF0010064 -:10906000617A19B168B1FFF7F5FB10E03E484A4953 -:109070000160D5F8000220F00300C5F80002E77295 -:1090800005E001290AD0022918BFFFDF0DD018F032 -:10909000010F14D0DAF80000804745E06672E772ED -:1090A000A7729621227B002006E06672E7720220FA -:1090B000A072227B96210120FFF78FFBE7E718F0D3 -:1090C000020F2AD018F0040F21D1FEF74FF9F0B9A2 -:1090D000FEF75CF9D8B931480168001F0068C0F399 -:1090E000006CC0F3425500F00F03C0F30312C0F34D -:1090F0000320BCF1000F0AD0002B1CBF002A00285F -:1091000005D1002918BF032D38BF48F0040827EA0D -:109110009800DAF80410884706E018F0080F18BF26 -:10912000DAF8080056D08047A07A022818BFBDE8B8 -:10913000F88F207C002808BFBDE8F88F02492FE097 -:10914000741500401C11004000800040488500401C -:1091500014100040ACF501404881004004F5014086 -:1091600004B500404C85004008F501404016004021 -:109170001014004018110040448100404485004014 -:109180001015004000140040141400400415004065 -:10919000100C0020C40000200000040454140040FF -:1091A000C1F8446102281DD0012818BFFFDFE16A21 -:1091B0006069884298BFFFDFD4F81400C9F8000046 -:1091C000A06B4FF4800140F48000A06382480160EE -:1091D000BDE8F88F18F0100F14BFDAF80C00FFDFAD -:1091E000A1D1A1E76169E06A0844E7E738B57B49A6 -:1091F00004460220887201212046FFF763F9784A6D -:1092000004F13D001060774B0020C3F8440176491B -:10921000C1F80001C1F80C01C1F81001C1F8040146 -:10922000C1F81401C1F818017048006800900120CD -:109230009864101D00681168884228BFFFDF38BDA0 -:109240002DE9F843654A88460024917A0125684F44 -:10925000012902D0022903D015E0117E11B912E0D4 -:10926000517E81B1917FD37F05FA01F105FA03F3B5 -:109270001943396092F82010890001F1804101F50D -:10928000C041C1F8104506460220907201213046C7 -:10929000FFF718F9524906F13D000860514AC2F83B -:1092A00044415148C0F80041C0F80C41C0F8104199 -:1092B000C0F80441C0F81441C0F818414B48006898 -:1092C00000909564081D00680968884228BFFFDF88 -:1092D000B8F1000F1CBF4FF400303860BDE8F883D0 -:1092E000022810B50DD0012804BF42F6CE3010BDC3 -:1092F000042817BF082843F6A440FFDF41F66A00A0 -:1093000010BDFDF7E5FF30B9FDF7F9FF002808BFF4 -:1093100041F6583001D041F2643041F29A010844DC -:1093200010BD314910B50020C1F800023049314864 -:109330000860324930480860091D31480860091D3D -:1093400030480860091D30480860091D2F48086032 -:10935000091D2F48086001200BF058FD1E494FF4ED -:109360003810086010BD22494FF43810086070476B -:109370002848016803291BBF00680228012000203B -:109380007047244801680B291BBF00680A28012088 -:109390000020704720490968C9B9204A204913684C -:1093A00070B123F0820343F07D0343F00043136068 -:1093B0000A6822F0100242F0600242F0004205E02A -:1093C00023F0004313600A6822F000420A60034958 -:1093D00081F83D007047000004F50140280C002092 -:1093E00044850040008000400010004018110040FB -:1093F00008F50140000004041011004098F50140F8 -:109400000410004044810040141000401C11004032 -:109410001010004050150040881700403C170040D5 -:109420007C17004010B5404822220021F5F72FF8A4 -:109430003D480024017821F010010170012104F061 -:10944000FFFE3A494FF6FF7081F822408884384980 -:109450000880488010BD704734498A8C824218BF0A -:109460007047002081F822004FF6FF708884704713 -:109470002D49016070472E49088070472B498A8C1E -:10948000A2F57F43FF3B03D00021016008467047EF -:1094900091F822202549012A1ABF016001200020ED -:1094A0007047224901F1220091F82220012A04BFCD -:1094B00000207047012202701D48008888841046F1 -:1094C00070471B49488070471849194B8A8C5B8844 -:1094D0009A4206D191F82220002A1EBF0160012085 -:1094E0007047002070471148114A818C5288914280 -:1094F00009D14FF6FF71818410F8221F19B10021A4 -:10950000017001207047002070470848084A818C8C -:109510005288914205D190F8220000281CBF0020FB -:109520007047012070470000960C0020700C00204E -:10953000CC0000207047584A012340B1012818BFD1 -:1095400070471370086890608888908170475370E6 -:109550000868C2F802008888D08070474E4A10B16F -:10956000012807D00EE0507860B1D2F80200086000 -:10957000D08804E0107828B19068086090898880CD -:109580000120704700207047434910B1012803D0E3 -:1095900006E0487810B903E0087808B10120704768 -:1095A0000020704730B58DB00C4605460D220021D5 -:1095B00004A8F4F76CFFE0788DF81F0020798DF88F -:1095C0001E0060798DF81D00286800906868019081 -:1095D000A8680290E868039068460AF087FF207840 -:1095E0009DF82F1088420CD160789DF82E1088428B -:1095F00007D1A0789DF82D10884202BF01200DB040 -:1096000030BD00200DB030BD30B50C4605468DB0E4 -:109610004FF0030104F1030012B1FDF749FF01E02F -:10962000FDF765FF60790D2220F0C00040F040009A -:109630006071002104A8F4F72AFFE0788DF81F007C -:1096400020798DF81E0060798DF81D002868009043 -:1096500068680190A8680290E868039068460AF07C -:1096600045FF9DF82F0020709DF82E0060709DF83A -:109670002D00A0700DB030BD10B5002904464FF08C -:10968000060102D0FDF714FF01E0FDF730FF60791D -:1096900020F0C000607110BDD0000020FE4840687E -:1096A00070472DE9F0410F46064601461446012059 -:1096B00005F06FF8054696F86500FEF795FC4AF24E -:1096C000B12108444FF47A71B0FBF1F0718840F297 -:1096D00071225143C0EB4100001BA0F55A7402F007 -:1096E0005AFF002818BF1E3CAF4234BF28463846F8 -:1096F000A04203D2AF422CBF3C462C467462BDE868 -:10970000F0812DE9FF4F8BB0044690F86500884644 -:109710000390DDE90D1008430A90E0480027057822 -:109720000C2D28BFFFDFDE4E36F8159094F88851D7 -:109730000C2D28BFFFDFDA4830F81500484480B20E -:10974000009094F87D000D280CBF012000200790A8 -:109750000D98002804BF94F82C0103282BD10798FA -:1097600048B3B4F8AA01404525D1D4F83401C4F86F -:109770002001608840F2E2414843C4F82401B4F873 -:109780007A01B4F806110844C4F82801204602F012 -:109790000CFFB4F8AE01E08294F8AC016075B4F847 -:1097A000B0016080B4F8B201A080B4F8B401E080E8 -:1097B000022084F82C01D4F884010990D4F88001A7 -:1097C0000690B4F80661B4F87801D4F874110191E8 -:1097D0000D9921B194F8401151B100F0D6B804F5BB -:1097E000807104917431059104F5B075091D07E08D -:1097F00004F5AA710491091D059104F5A275091DCE -:109800000891B4F87010A8EB0000A8EB01010FFA62 -:1098100080F90FFA81FBB9F1000F05DAD4F8700175 -:1098200001900120D9460A909C484FF0000A007927 -:10983000A8B3F2F77FFB90B3B4F8180102282ED337 -:1098400094F82C0102282AD094F8430138BB94F8EC -:10985000880100900C2828BFFFDF9148009930F85C -:10986000110000F5C86080B2009094F82C01012826 -:109870007ED0608840F2E2414843009901F0E6F86A -:10988000D4F8342180B206EB0B01A1EB0901821A56 -:1098900001FB02AAC4F83401012084F8430194F8C2 -:1098A0002C01002865D0012800F01482022800F065 -:1098B0007181032818BFFFDF00F04782A7EB0A0180 -:1098C0000198FCF738F90599012640F271220860E9 -:1098D0000898A0F80080002028702E710598006874 -:1098E000A8606188D4F834015143C0EB41006B4952 -:1098F000A0F54E70C8618969814287BF04990860EC -:10990000049801600498616A0068084400F5D47006 -:10991000E86002F040FE10B1E8681E30E8606E7149 -:10992000B4F8F000A0EB080000B20028C4BF032088 -:109930006871079800280E9800F06982E0B100BFB6 -:10994000B4F8181100290CBF0020B4F81A01A4F8CB -:109950001A0194F81C21401C504388420CD26879AB -:10996000401E002808DD6E71B4F81A01401C01E0A9 -:109970000FE05AE0A4F81A010D98002800F06A825E -:1099800094F84001002800F061820FB00220BDE889 -:10999000F08F94F8800003283DD03F4894F865107C -:1099A00090F82C00F7F78DFDE18A40F271225143C7 -:1099B00000EB4100CDF80800D4F82401009901F033 -:1099C00045F8D4F82021D4F82811821A01FB02AA04 -:1099D000C4F820010099029801F038F8D4F8301149 -:1099E000C4F83001411A8A44608840F2E241484399 -:1099F000009901F02BF806EB0B01D4F82821A1EB1C -:109A00000901891AD4F83421C4F83401821A491E94 -:109A100001FB02AA40E7E18A40F27122D4F8240156 -:109A2000514300EB41000290C6E70698002808BFAA -:109A3000FFDF94F86510184890F82C00F7F741FD07 -:109A40000990E08A40F271214143099800EB4100FE -:109A5000009900F0FBFFC4F83001608840F2E24159 -:109A60004843009900F0F2FFC4F8340103A902A8AA -:109A7000FFF7BBF8DDE90160039FE9F7F0F8014665 -:109A80003046FDF769F800F10F06E9F711F9381AC9 -:109A9000801B009006E00000B80C0020E0000020D1 -:109AA000E4620200B4F83401214686B20120D4F801 -:109AB000289004F06EFE074694F86500FEF794FACD -:109AC0004AF2B12108444FF47A7BB0FBFBF0618885 -:109AD00040F271225143C0EB4100801BA0F55A7641 -:109AE00002F059FD002818BF1E3EB94534BF384664 -:109AF0004846B04203D2B9452CBF4E463E46666248 -:109B000094F86500FEF7E9FA00F2E140B0FBFBF1E2 -:109B100006980F1894F86500FEF7DFFA064694F8E9 -:109B20006500FEF761FA30444AF2AB310844B0FBFD -:109B3000FBF1E08A40F2712242430998D4F8306187 -:109B400000EB4200401A801B384400993138471A14 -:109B5000607D40F2E24110FB01F994F8650000904D -:109B600010F00C0F0ABF00984EF62830FEF73CFAB2 -:109B70004AF2B1210844B0FBFBF000EB460000EBD9 -:109B800009060098FEF7B8FA304400F18401FE4857 -:109B9000816193E6E18A40F27122D4F824015143B5 -:109BA00000EB4100009900F051FFC4F830016188DA -:109BB00040F2E2404843009900F048FFC4F8340105 -:109BC00087B221460120D4F828B004F0E2FD814696 -:109BD00094F86500FEF708FA4AF2B12101444FF407 -:109BE0007A70B1FBF0F0618840F271225143C0EB12 -:109BF0004100C01BA0F55A7702F0CDFC002818BF29 -:109C00001E3FCB4534BF48465846B84203D2CB45E9 -:109C10002CBF5F464F4667621EBB0E9808B394F890 -:109C200065603046FEF7E0F94AF2B12101444FF495 -:109C30007A70B1FBF0F0D4F83011E28A084440F2B7 -:109C40007123D4F824115A4301EB42010F1A304614 -:109C5000FEF752FA01460998401A3844A0F120074D -:109C60000AE0E18A40F27122D4F82401514300EB6A -:109C70004100D4F83011471AD4F82821D4F8201123 -:109C8000D4F8300101FB0209607D40F2E24110FB93 -:109C900001FB94F8656016F00C0F0ABF30464EF6D3 -:109CA0002830FEF7A1F94AF2B12101444FF47A704D -:109CB000B1FBF0F000EB490000EB0B093046FEF77A -:109CC0001BFA484400F16001AF488161012084F82B -:109CD0002C01F3E5618840F271225143D4F834013C -:109CE000D4F82821C0EB410101FB09F706EB0B0179 -:109CF000891AD4F820C1D4F83031491E0CFB023245 -:109D000001FB0029607D40F2E24110FB01FB94F869 -:109D1000656016F00C0F0ABF30464EF62830FEF78D -:109D200063F94AF2B12101444FF47A70B1FBF0F0CB -:109D300000EB490000EB0B093046FEF7DDF9484423 -:109D400000F1600190488161B8E5618840F27122BC -:109D5000D4F834015143C0EB410000FB09F794F8FB -:109D60007C0024281CBF94F87D0024280BD1B4F873 -:109D7000AA01A8EB000000B2002804DB94F8AD01B2 -:109D8000002818BF03900A9800B3FEB9099800286C -:109D90001ABF06980028FFDF94F8650010F00C0F3A -:109DA00014BF4EF62830FEF71FF94AF2B1210144E4 -:109DB0004FF47A70B1FBF0F03F1A94F86500FEF7AB -:109DC0009BF90999081A3844A0F12007D4F83411F6 -:109DD00006EB0B0000FB01F6039810F00C0F0ABF16 -:109DE00003984EF62830FEF7FFF84AF2B1210144FD -:109DF0004FF47A70B1FBF0F000EB46060398FEF7E3 -:109E00007BF9304400F160015F48816156E500282C -:109E10007FF496AD94F82C0100283FF4ADAD618835 -:109E200040F27122D4F834015143C0EB410128467D -:109E3000F7F712F90004000C3FF49EAD18990029C1 -:109E400018BF088001200FB0BDE8F08F94F87C01A6 -:109E5000FCF7D1FC94F87C012946FCF7B0FB20B15B -:109E60000D9880F0010084F841010FB00020BDE89A -:109E7000F08F2DE9F843454C0246434F00266168B8 -:109E8000606A052A60D2DFE802F003464B4F5600B5 -:109E9000A07A002560B101216846FDF709FB9DF815 -:109EA000000042F210710002B0FBF1F201FB12055A -:109EB000F4F720FE4119A069FBF73DFEA06126746E -:109EC000032060754FF0010884F81480607AD0B9DF -:109ED000A06A80B1F4F70EFE0544F4F785FC411941 -:109EE000A06A884224BF401BA06204D2C4F8288024 -:109EF000F5F72BFE07E0207B04F11001FCF75FFB78 -:109F0000002808BFFFDF2684FCF739F87879BDE820 -:109F1000F843E8F7F9BFBDE8F843002100F0B3BD0E -:109F2000C1F88001BDE8F883D1F88001BDE8F843AD -:109F3000012100F0A8BD84F83060FCF720F87879A2 -:109F4000BDE8F843E8F7E0BFFFDFBDE8F8832DE99F -:109F5000F04F0E4C824683B020788B4601270025B7 -:109F6000094E4FF00209032804BF207B50457DD1E4 -:109F7000606870612078032818BFFFDF4FF0030886 -:109F8000BBF1080F73D203E0E0000020B80C002002 -:109F9000DFE80BF0040F32322D9999926562F5F7E4 -:109FA000ABF9002818BFFFDF86F8028003B0BDE8D8 -:109FB000F08FF4F77AFF68B9F4F716FC0546E0690C -:109FC000A84228BFE56105D2281A0421FCF7F7FD55 -:109FD000E56138B1F5F723FD002818BFFFDF03B0B6 -:109FE000BDE8F08F03B00020BDE8F04F41E703B0BB -:109FF000BDE8F04FFEF7FFBD2775257494F83000DB -:10A000004FF0010A58B14FF47A71A069FBF793FD44 -:10A01000A061002104F11000F7F71EF80EE0F4F73C -:10A0200069FD82465146A069FBF785FDA061514656 -:10A0300004F11000F7F710F800F1010A208C411C20 -:10A040000A293CBF50442084606830B1208C401CF9 -:10A050000A2828BF84F8159001D284F81580607A08 -:10A06000A8B9A06AE8B1F4F745FD01E02FE02AE0C5 -:10A070008046F4F7B9FB00EB0801A06A884224BFD0 -:10A08000A0EB0800A0620CD2A762F5F75EFD207B72 -:10A09000FCF74BF82570707903B0BDE8F04FE8F796 -:10A0A00033BF207B04F11001FCF789FA002808BFB8 -:10A0B000FFDF03B0BDE8F08F207BFCF736F825709A -:10A0C00003B0BDE8F08FFFDF03B0BDE8F08FBAF159 -:10A0D000200F28BFFFDFDFF8E886072138F81A00D5 -:10A0E000F9F7E4FE040008BFFFDFBAF1200F28BF34 -:10A0F000FFDF38F81A002188884218BFFFDF4FF0D1 -:10A10000200A7461BBF1080F80F06181DFE80BF079 -:10A110000496A0A099FEFDFCC4F88051F580C4F817 -:10A12000845194F8410138B9FCF71EF8D4F84C1169 -:10A13000FCF712FD00281BDCB4F83E11B4F87000E7 -:10A14000814206D1B4F8F410081AA4F8F6002046AB -:10A1500005E0081AA4F8F600B4F83E112046A4F869 -:10A160007010D4F86811C4F84C11C0F870111DE0DB -:10A17000B4F83C11B4F87000081AA4F8F600B4F86A -:10A180003C112046A4F87010D4F84C11C4F86811A2 -:10A19000C4F87011D4F85411C4F80011D4F858114F -:10A1A000C4F87411B4F85C11A4F8781102F008F93D -:10A1B000FBF7B4FF804694F86500FDF715FF4AF2FF -:10A1C000B12108444FF47A71B0FBF1F0D4F83411A6 -:10A1D00040F27122084461885143C0EB4100A0F174 -:10A1E000300AB8F1B70F98BF4FF0B70821460120E9 -:10A1F00004F0CFFA4044AAEB0000A0F21D38A246BA -:10A200002146012004F0C5FADAF824109C3081427E -:10A2100088BF0D1AC6F80C80454528BF4546B56075 -:10A22000D4F86C01A0F5D4703061FCF762FC84F8BE -:10A23000407186F8029003B0BDE8F08F02F0A6F9F5 -:10A2400001E0FEF7D8FC84F8407103B0BDE8F08F60 -:10A25000FBF78AFFD4F8702101461046FCF77CFC1E -:10A2600048B1628840F27123D4F834115A43C1EBEB -:10A270004201B0FBF1F094F87D100D290FD0B4F835 -:10A280007010B4F83E210B189A42AEBF501C401C0F -:10A290000844A4F83E0194F8420178B905E0B4F806 -:10A2A0003E01401CA4F83E0108E0B4F83E01B4F8B9 -:10A2B000F410884204BF401CA4F83E01B4F87A01AF -:10A2C0000DF1040B401CA4F87A01B4F89A00B4F81C -:10A2D0009810401AB4F87010401E08441FFA80F914 -:10A2E0000BE000231A462046CDF800B0FFF709FA2C -:10A2F00068B3012818BFFFDF48D0B4F83E11A9EBBE -:10A30000010000B2002802E053E047E05FE0E8DA35 -:10A31000082084F88D0084F88C70204601F012FE2D -:10A3200084F82C5194F87C514FF6FF77202D00D300 -:10A33000FFDF28F8157094F87C01FBF7F6FE84F82F -:10A340007CA1707903B0BDE8F04FE8F7DDBDA06EE9 -:10A35000002804BF03B0BDE8F08FB4F83E01B4F8A4 -:10A360009420801A01B20029DCBF03B0BDE8F08F51 -:10A37000B4F86C000144491E91FBF0F189B201FB75 -:10A380000020A4F8940003B0BDE8F08FB4F83E01BB -:10A39000BDF804100844A4F83E01AEE7FEF7E4FA65 -:10A3A000FEF729FC4FF0E020C0F8809203B0BDE832 -:10A3B000F08F94F82C01042818BFFFDF84F82C518B -:10A3C00094F87C514FF6FF77202DB2D3B0E7FFDF32 -:10A3D00003B0BDE8F08F10B5FA4C207850B10120E1 -:10A3E0006072F5F7D8FB2078032805D0207A002882 -:10A3F00008BF10BD0C2010BD207BFCF7FCF9207BB2 -:10A40000FCF765FC207BFBF790FE002808BFFFDF10 -:10A410000020207010BD2DE9F04FEA4F83B038784E -:10A4200001244FF0000840B17C720120F5F7B3FB26 -:10A430003878032818BF387A0DD0DFF88C9389F864 -:10A44000034069460720F9F7BAFC002818BFFFDF70 -:10A450004FF6FF7440E0387BFCF7CDF9387BFCF712 -:10A4600036FC387BFBF761FE002808BFFFDF87F86A -:10A470000080E2E7029800281CBF90F82C11002908 -:10A480002AD00088A0421CBFDFF834A34FF0200B75 -:10A490003AD00721F9F70AFD040008BFFFDF94F85E -:10A4A0007C01FCF714FC84F82C8194F87C514FF665 -:10A4B000FF76202D28BFFFDF2AF8156094F87C0175 -:10A4C000FBF733FE84F87CB169460720F9F777FC87 -:10A4D000002818BFFFDF12E06846F9F74EFC00289D -:10A4E000C8D011E0029800281CBF90F82C11002958 -:10A4F00005D00088A0F57F41FF39CAD104E0684645 -:10A50000F9F73BFC0028EDD089F8038087F830800C -:10A5100087F80B8003B00020BDE8F08FAA4948718E -:10A520000020887001220A7048700A71C870A5491D -:10A53000087070E7A449087070472DE9F84FA14CE6 -:10A5400006460F462078002862D1A048FBF792FD0E -:10A55000207320285CD04FF00308666084F80080E8 -:10A56000002565722572AEB1012106F58E70FCF7EB -:10A57000BEFF0620F9F742FC81460720F9F73EFCB2 -:10A5800096F81C114844B1FBF0F200FB1210401C7D -:10A5900086F81C01FBF7C2FD40F2F651884238BF35 -:10A5A00040F2F65000F5A0701FFA80F9F4F7A2FA15 -:10A5B000012680B3A672F4F717F9E061FBF7D4FD2A -:10A5C000824601216846FCF769FF9DF8000042F2CF -:10A5D00010710002B0FBF1F201FB120000EB090167 -:10A5E0005046FBF7A8FAA762A061267584F815808B -:10A5F0002574207B04F11001FBF7E1FF002808BF60 -:10A60000FFDF25840020F5F7C6FA0020BDE8F88FAB -:10A610000C20BDE8F88FFFE7E761FBF7A5FD494691 -:10A62000FBF789FAA061A57284F830600120FDF77C -:10A6300054FD4FF47A7100F2E140B0FBF1F0381AAA -:10A64000A0F5AB60A5626063CFE75F4948707047D3 -:10A650005D49087170475B4810B5417A00291CBFFD -:10A66000002010BD816A51B990F8301039B1416AAB -:10A67000406B814203D9F5F768FA002010BD012034 -:10A6800010BD2DE9F041504C0646E088401CE080AA -:10A69000D4E902516078D6F8807120B13A46284654 -:10A6A000F6F705FD0546A068854205D02169281A00 -:10A6B00008442061FCF71DFAA560AF4209D896F85E -:10A6C0002C01012805D0E078002804BF0120BDE856 -:10A6D000F0810020BDE8F08110B504460846FDF782 -:10A6E00083FC4AF2B12108444FF47A71B0FBF1F0D7 -:10A6F00040F2E241614300F54E7081428CBF081A7E -:10A70000002010BD70B5044682B0002084F84001DE -:10A7100094F8FB00002807BF94F82C01032802B02E -:10A7200070BDFBF721FDD4F8702101461046FCF7FF -:10A7300013FA0028DCBF02B070BD628840F27123BA -:10A74000D4F834115A43C1EB4201B0FBF1F0B4F834 -:10A750007010401C0844A4F83C01B4F8F400B4F8AC -:10A760003C21801A00B20028DCBF02B070BD01207D -:10A7700084F84201B4F89A00B4F8982001AE801A27 -:10A78000401E084485B212E00096B4F83C11002344 -:10A7900001222046FEF7B5FF002804BF02B070BDBD -:10A7A000012815D0022812BFFFDF02B070BDB4F837 -:10A7B0003C01281A00B20028BCBF02B070BDE3E71C -:10A7C000F00C0020B80C0020E00000204F9F01009A -:10A7D000B4F83C01BDF804100844A4F83C01E6E7D5 -:10A7E000F8B50422002506295BD2DFE801F0072630 -:10A7F0000319192A044680F82C2107E00446C948A9 -:10A80000C078002818BF84F82C210AD0FBF7B7FBCA -:10A81000A4F87A51B4F87000A4F83E0184F84251CB -:10A82000F8BD0095B4F8F410012300222046FEF78D -:10A8300068FF002818BFFFDFE8E7032180F82C112C -:10A84000F8BD0646876AB0F83401314685B201206A -:10A8500003F09FFF044696F86500FDF7C5FB4AF23A -:10A86000B12108444FF47A71B0FBF1F0718840F2E5 -:10A8700071225143C0EB4100401BA0F55A7501F015 -:10A880008AFE002818BF1E3DA74234BF2046384626 -:10A89000A84228BF2C4602D2A74228BF3C46746279 -:10A8A000F8BDFFDFF8BD2DE9F05F9E4EB1780229BB -:10A8B00006BFF1880029BDE8F09F7469C4F88401DF -:10A8C00094F86500FDF718FCD4F88411081AB168F3 -:10A8D0000144B160F1680844F060746994F8430180 -:10A8E000002808BFBDE8F09F94F82C01032818BF8A -:10A8F000BDE8F09F94F8655037780C2F28BFFFDF34 -:10A90000894E36F8178094F888710C2F28BFFFDF26 -:10A9100036F81700404494F8888187B2B8F10C0FDC -:10A9200028BFFFDF36F8180000F5C8601FFA80F86E -:10A930002846FDF7E1FBD4F884114FF0000A0E1A07 -:10A9400015F00C0F0ABF28464EF62830FDF74CFBD9 -:10A950004FF47A7900F2E730B0FBF9F0361A284666 -:10A96000FDF7CAFBD4F8001115F00C0FA1EB000B9A -:10A970000ABF28464EF62830FDF736FB4AF2B121D1 -:10A980000844B0FBF9F0ABEB0000A0F160017943A3 -:10A99000B1FBF8F1292202EB50006031A0EB51022B -:10A9A00000EB5100B24201D8B04201D8F1F774FB7C -:10A9B000608840F2E2414843394600F047F8C4F865 -:10A9C000340184F843A1BDE8F09F70B505465548B1 -:10A9D00090F802C0BCF1020F07BF406900F5C074D7 -:10A9E000524800F12404002904BF256070BD4FF4D3 -:10A9F0007A7601290DD002291CBFFFDF70BD1046F9 -:10AA0000FEF76EFC00F2E140B0FBF6F0281A206081 -:10AA100070BD1846FDF761FB00F2E140B0FBF6F0B7 -:10AA2000281A206070BD4148007800281CBF002013 -:10AA3000704710B50720F9F7D3F980F0010010BD79 -:10AA40003A480078002818BF0120704730B5024608 -:10AA50000020002908BF30BDA2FB0110490A41EACD -:10AA6000C051400A4C1C40F100000022D4F1FF31DB -:10AA700040F2A17572EB000038BFFFDF04F5F4600F -:10AA8000B0FBF5F030BD2DE9F843284C0025814698 -:10AA900084F83050D4F8188084F82C10E5722570B2 -:10AAA0000127277239466068F5F792FD6168C1F8A1 -:10AAB0007081267B81F87C61C1F88091C1F8748136 -:10AAC000B1F80080202E28BFFFDF194820F816803B -:10AAD000646884F82C510023A4F878511A4619466A -:10AAE00020460095FEF70DFE002818BFFFDFC4F8D2 -:10AAF0002851C4F8205184F82C71A4F83E51A4F8D0 -:10AB00003C5184F84251B4F87000401EA4F8700023 -:10AB1000A4F87A51FBF733FA02484079BDE8F843CC -:10AB2000E8F7F2B9E0000020E4620200B80C00206F -:10AB3000F00C0020012804D0022805D0032808D1F9 -:10AB400005E0012907D004E0022904D001E004292E -:10AB500001D000207047012070472DE9F0410E46DA -:10AB6000044603F08AFC0546204603F08AFC0446AE -:10AB7000F6F770FBFB4F010015D0386990F86420A0 -:10AB80008A4210D090F8C0311BB190F8C2312342F4 -:10AB90001FD02EB990F85D30234201D18A4218D8D7 -:10ABA00090F8C001A8B12846F6F754FB70B1396996 -:10ABB00091F86520824209D091F8C00118B191F84E -:10ABC000C301284205D091F8C00110B10120BDE8B1 -:10ABD000F0810020FBE730B5E24C85B0E069002849 -:10ABE0005FD0142200216846F3F751FC206990F8E9 -:10ABF0006500FDF7F9F94FF47A7100F5FA70B0FBD2 -:10AC0000F1F5206990F86500FDF776FA2844ADF873 -:10AC1000060020690188ADF80010B0F87010ADF89A -:10AC200004104188ADF8021090F8A20130B1A0697B -:10AC3000C11C039103F002FB8DF81000206990F80D -:10AC4000A1018DF80800E169684688472069002164 -:10AC500080F8A21180F8A1110399002921D090F861 -:10AC6000A01100291DD190F87C10272919D09DF83A -:10AC70001010039A002914D013780124FF2B12D04E -:10AC8000072B0ED102290CD15178FF2909D100BF21 -:10AC900080F8A0410399C0F8A4119DF8101080F825 -:10ACA000A31105B030BD1B29F2D9FAE770B5AD4C40 -:10ACB000206990F87D001B2800D0FFDF2069002567 -:10ACC00080F8A75090F8D40100B1FFDF206990F818 -:10ACD000A81041B180F8A8500188A0F8D81180F8D8 -:10ACE000D6510E2108E00188A0F8D81180F8D6517D -:10ACF000012180F8DA110D2180F8D4110088F9F7CC -:10AD000006FAF8F79FFE2079E8F7FEF8206980F848 -:10AD10007D5070BD70B5934CA07980072CD5A0787C -:10AD2000002829D162692046D37801690D2B01F1F1 -:10AD300070005FD00DDCA3F102034FF001050B2B77 -:10AD400019D2DFE803F01A1844506127182C183A7A -:10AD50006400152B6FD008DC112B4BD0122B5AD06E -:10AD6000132B62D0142B06D166E0162B71D0172B53 -:10AD700070D0FF2B6FD0FFDF70BD91F87F200123D3 -:10AD80001946F6F7FFF80028F6D12169082081F866 -:10AD90007F0070BD1079BDE8704001F090BC91F863 -:10ADA0007E00C00700D1FFDF01F048FC206910F8E9 -:10ADB0007E1F21F00101017070BD91F87D00102807 -:10ADC00000D0FFDF2069112180F8A75008E091F83A -:10ADD0007D00142800D0FFDF2069152180F8A750DE -:10ADE00080F87D1070BD91F87D00152800D0FFDF40 -:10ADF000172005E091F87D00152800D0FFDF19200D -:10AE0000216981F87D0070BDBDE870404EE7BDE866 -:10AE1000704001F028BC91F87C2001230021F6F756 -:10AE2000B1F800B9FFDF0E200FE011F87E0F20F01F -:10AE3000040008701DE00FE091F87C200123002140 -:10AE4000F6F7A0F800B9FFDF1C20216981F87C002B -:10AE500070BD12E01BE022E091F87E00C0F301100B -:10AE6000012800D0FFDF206910F87E1F21F01001BB -:10AE70000170BDE8704001F0E1BB91F87C20012336 -:10AE80000021F6F77FF800B9FFDF1F20DDE791F81A -:10AE90007D00212801D000B1FFDF2220B0E7BDE80E -:10AEA000704001F0D7BB2F48016991F87E2013074D -:10AEB00002D501218170704742F0080281F87E209E -:10AEC0008069C07881F8E10001F0AFBB10B5254C76 -:10AED00021690A88A1F8162281F8140291F8640009 -:10AEE00001F091FB216981F8180291F8650001F0E9 -:10AEF0008AFB216981F81902012081F812020020E1 -:10AF000081F8C0012079BDE81040E7F7FDBF10B51A -:10AF1000144C05212069FFF763FC206990F85A1052 -:10AF2000012908D000F5F57103F001FC2079BDE896 -:10AF30001040E7F7E9BF022180F85A1010BD10B5A4 -:10AF4000084C01230921206990F87C207030F6F725 -:10AF500019F848B12169002001F8960F087301F82B -:10AF60001A0C10BD000100200120A070F9E770B597 -:10AF7000F74D012329462869896990F87C200979D1 -:10AF80000E2A01D1122903D000241C2A03D004E088 -:10AF9000BDE87040D3E7142902D0202A07D008E08A -:10AFA00080F87C4080F8A240BDE87040AFE71629E9 -:10AFB00006D0262A01D1162902D0172909D00CE083 -:10AFC00000F87C4F80F82640407821280CD01A20C9 -:10AFD00017E090F87D20222A07D0EA69002A03D0E2 -:10AFE000FF2901D180F8A23132E780F87D4001F0DD -:10AFF00025FB286980F8974090F8C0010028F3D01D -:10B000000020BDE8704061E710B5D14C216991F88E -:10B010007C10202902D0262902D0A2E7FFF756FF94 -:10B020002169002081F87C0081F8A20099E72DE9D0 -:10B03000F843C74C206990F87C10202908D00027DD -:10B0400090F87D10222905D07FB300F17C0503E044 -:10B050000127F5E700F17D0510F8B01F41F004016C -:10B060000170A06903F015FA4FF00108002608B33B -:10B070003946A069FFF771FDE0B16A46A169206910 -:10B08000F6F7F7F890B3A06903F001FA2169A1F887 -:10B09000AA01B1F8701001F0AAFA40B32069282182 -:10B0A00080F88D1080F88C8058E0FFE70220A070B7 -:10B0B000BDE8F883206990F8C00110B11E20FFF7A9 -:10B0C00005FFAFB1A0692169C07881F8E20008FAF4 -:10B0D00000F1C1F3006000B9FFDF20690A2180F8A8 -:10B0E0007C1090F8A20040B9FFDF06E009E02AE0FA -:10B0F0002E7001F0A3FAFFF7D6FE206980F8976062 -:10B10000D6E7226992F8C00170B1B2F8703092F8B7 -:10B110006410B2F8C40102F5D572F6F79BF968B174 -:10B120002169252081F87C00206900F17D0180F8EB -:10B1300097608D4212D180F87D600FE00020FFF70C -:10B14000C5FE2E70F0E720699DF8001080F8AC1164 -:10B150009DF8011080F8AD1124202870206900F1BD -:10B160007D018D4203D1BDE8F84301F067BA80F854 -:10B17000A2609DE770B5764C01230B21206990F801 -:10B180007D207030F5F7FEFE202650BB206901239C -:10B19000002190F87D207030F5F7F4FE0125F0B124 -:10B1A000206990F87C0024281BD0A06903F04FF997 -:10B1B000C8B1206990F8B01041F0040180F8B010D7 -:10B1C000A1694A7902F0070280F85D20097901F04F -:10B1D000070180F85C1090F8C1311BBB06E0A57038 -:10B1E00036E6A67034E6BDE870405CE690F8C03103 -:10B1F000C3B900F164035E788E4205D1197891429B -:10B2000002D180F897500DE000F503710D700288AF -:10B210004A8090F85C200A7190F85D0048712079AE -:10B22000E7F772FE2169212081F87D00BDE87040BA -:10B2300001F0FBB9F8B5464C206990F87E0010F09B -:10B24000300F04D0A07840F00100A070F8BDA069D4 -:10B2500003F0E2F850B3A06903F0D8F80746A069FC -:10B2600003F0D8F80646A06903F0CEF80546A069B9 -:10B2700003F0CEF801460097206933462A46303065 -:10B2800003F0BFF9A079800703D56069C07814285E -:10B290000FD0216991F87C001C280AD091F85A003F -:10B2A00001280ED091F8B70158B907E0BDE8F84081 -:10B2B000F9E52169012081F85A0002E091F8B60110 -:10B2C00030B1206910F87E1F41F0100101700EE0CE -:10B2D00091F87E0001F5FC7240F0200081F87E00BC -:10B2E00031F8300B03F017FA2079E7F70DFEBDE8CF -:10B2F000F84001F09AB970B5154C206990F87E10AD -:10B30000890707D590F87C20012308217030F5F7D4 -:10B3100039FEF8B1206990F8AA00800712D4A0691C -:10B3200003F056F8216981F8AB00A06930F8052FC9 -:10B33000A1F8AC204088A1F8AE0011F8AA0F40F0A7 -:10B3400002000870206990F8AA10C90705D011E022 -:10B35000000100200120A0707AE590F87E008007AF -:10B3600000D5FFDF206910F87E1F41F00201017057 -:10B3700001F05BF92069002590F87C10062906D1C0 -:10B3800080F87C5080F8A2502079E7F7BDFD206955 -:10B3900090F8A8110429DFD180F8A8512079E7F7A7 -:10B3A000B3FD206990F87C100029D5D180F8A25017 -:10B3B0004EE570B5FB4C01230021206990F87D20FB -:10B3C0007030F5F7DFFD012578B9206990F87D2010 -:10B3D000122A0AD0012305217030F5F7D3FD10B1F0 -:10B3E0000820A07034E5A57032E5206990F8A80027 -:10B3F00008B901F01AF92169A06901F5847102F018 -:10B40000C8FF2169A069D83102F0CEFF206990F809 -:10B41000DC0100B1FFDF21690888A1F8DE0101F538 -:10B42000F071A06902F0A3FF2169A06901F5F47130 -:10B4300002F0A5FF206980F8DC51142180F87D100E -:10B440002079BDE87040E7F75FBD70B5D54C0123AA -:10B450000021206990F87D207030F5F793FD0125DB -:10B46000A8B1A06902F04FFF98B1A0692169B0F8B6 -:10B470000D00A1F8AA01B1F8701001F0B8F858B1A8 -:10B480002069282180F88D1080F88C50E0E4A570A8 -:10B49000DEE4BDE8704006E5A0692169027981F823 -:10B4A000AC21B0F80520A1F8AE2102F01FFF216900 -:10B4B000A1F8B001A06902F01CFF2169A1F8B20156 -:10B4C000A06902F01DFF2169A1F8B4010D2081F8E7 -:10B4D0007D00BDE47CB5B34CA079C00738D0A0692D -:10B4E00001230521C578206990F87D207030F5F79B -:10B4F00049FD68B1AD1E0A2D06D2DFE805F0090945 -:10B500000505090905050909A07840F00800A070A3 -:10B51000A07800281CD1A06902F0BEFE00286ED0E1 -:10B52000A0690226C5781DB1012D01D0162D18D1B4 -:10B53000206990F87C00F5F70DFD90B1216991F834 -:10B540007C001F280DD0202803D0162D16D0A67001 -:10B550007CBD262081F87C00162D02D02A20FFF722 -:10B56000B5FC0C2D5BD00CDC0C2D48D2DFE805F0CF -:10B5700036331F48BEBE4BB55ABE393C2020A070A2 -:10B580007CBD0120142D6ED008DC0D2D6CD0112D4A -:10B590006BD0122D6ED0132D31D168E0152D7FD0D8 -:10B5A000162D6FD0182D6ED0FF2D28D198E0206970 -:10B5B0000123194690F87F207030F5F7E3FC00284E -:10B5C00008D1A06902F0CCFE216981F88E01072024 -:10B5D00081F87F008CE001F0EDF889E0FFF735FF9E -:10B5E00086E001F0C7F883E0206990F87D1011290A -:10B5F00001D0A6707CE0122180F87D1078E075E023 -:10B60000FFF7D7FE74E0206990F87D001728F0D18D -:10B6100001F014F821691B2081F87D0068E0FFF734 -:10B620006AFE65E0206990F87E00C00703D0A0782C -:10B6300040F0010023E06946A06902F0D0FE9DF8C9 -:10B64000000000F02501206900F8B01F9DF80110EE -:10B6500001F04901417000F0E8FF206910F87E1FF9 -:10B6600041F0010117E018E023E025E002E0FFF7D8 -:10B6700066FC3DE0216991F87E10490704D5A07071 -:10B6800036E00DE00FE011E000F0CFFF206910F888 -:10B690007E1F41F0040101702AE0FFF7CBFD27E097 -:10B6A00001F030F824E0FFF765FD21E0FFF7BFFC73 -:10B6B0001EE0A06900790DE0206910F8B01F41F08C -:10B6C00004010170A06902F0F7FE162810D1A069EC -:10B6D00002F0F6FEFFF798FC0AE0FFF748FC07E0EF -:10B6E000E16919B1216981F8A20101E0FFF7DBFBF3 -:10B6F0002169F1E93002401C42F10002C1E9000277 -:10B700007CBD70B5274CA07900074AD5A0780028E9 -:10B7100047D1206990F8E400FE2800D1FFDF2069BE -:10B72000FE21002580F8E41090F87D10192906D13B -:10B7300080F8A75000F082FF206980F87D502069D2 -:10B7400090F87C101F2902D0272921D119E090F808 -:10B750007D00F5F7FFFB78B120692621012380F8F1 -:10B760007C1090F87D200B217030F5F70BFC78B938 -:10B770002A20FFF7ABFB0BE02169202081F87C0039 -:10B7800006E0012180F8A11180F87C5080F8A250D9 -:10B79000206990F87F10082903D10221217080F8D8 -:10B7A000E41021E40001002010B5FD4C216991F85E -:10B7B000AC210AB991F8642081F8642091F8AD2198 -:10B7C0000AB991F8652081F8652010B10020FFF7D3 -:10B7D0007DFB206902F041FF002806D02069BDE80A -:10B7E000104000F5F57102F0A2BF16E470B5EC4C04 -:10B7F00006460D46206990F8E400FE2800D0FFDFE1 -:10B800002269002082F8E46015B1A2F8A400E7E400 -:10B8100022F89E0F01201071E2E470B5E04C012384 -:10B820000021206990F87C207030F5F7ABFB0028F0 -:10B830007BD0206990F8B61111B190F8B71139B1E9 -:10B8400090F8C01100296FD090F8C11119B36BE0C6 -:10B8500090F87D1024291CD090F87C10242918D051 -:10B860005FF0000300F5D67200F5DB7102F096FE82 -:10B870002169002081F8B60101461420FFF7B6FFC8 -:10B88000216901F13000C28A21F8E62F408B4880FF -:10B8900050E00123E6E790F87D2001230B21703072 -:10B8A000F5F770FB68BB206990F8640000F0ABFE10 -:10B8B0000646206990F8650000F0A5FE054620695F -:10B8C00090F8C2113046FFF735F9D8B1206990F8E9 -:10B8D000C3112846FFF72EF9A0B12269B2F87030E3 -:10B8E00092F86410B2F8C40102F5D572F5F7B2FD12 -:10B8F00020B12169252081F87C001BE00020FFF7A2 -:10B90000E5FA11E020690123032190F87D207030D1 -:10B91000F5F738FB40B920690123022190F87D201A -:10B920007030F5F72FFB08B1002059E400211620F4 -:10B93000FFF75CFF012053E410B5E8BB984C206989 -:10B9400090F87E10CA0702D00121092052E08A0730 -:10B950000AD501210C20FFF749FF206910F8AA1F22 -:10B9600041F00101017047E04A0702D5012113208F -:10B9700040E00A0705D510F8E11F417101210720B9 -:10B9800038E011F0300F3BD090F8B711A1B990F822 -:10B99000B611E1B190F87D1024292FD090F87C10D9 -:10B9A00024292BD05FF0000300F5D67200F5DB717F -:10B9B00002F0F4FD216900E022E011F87E0F20F092 -:10B9C000200040F010000870002081F83801206944 -:10B9D00090F87E10C90613D502F03FFEFFF797FAE4 -:10B9E000216901F13000C28A21F8E62F408B48809E -:10B9F00001211520FFF7FAFE0120F6E60123D3E727 -:10BA00000020F2E670B5664C206990F8E410FE293B -:10BA100078D1A178002975D190F87F2001231946AB -:10BA20007030F5F7AFFA00286CD1206990F88C11CE -:10BA300049B10021A0F89C1090F88D1180F8E61013 -:10BA4000002102205BE090F87D200123042170306A -:10BA5000F5F798FA0546FFF76FFF002852D1284600 -:10BA600000F00CFF00284DD120690123002190F83F -:10BA70007C207030F5F786FA78B120690123042123 -:10BA800090F87D207030F5F77DFA30B9206990F894 -:10BA9000960010B10021122031E0206990F87C203E -:10BAA0000A2A0DD0002D2DD1012300217030F5F789 -:10BAB00069FA78B1206990F8A81104290AD105E043 -:10BAC00010F8E21F01710021072018E090F8AA0089 -:10BAD000800718D0FFF7A1FE002813D120690123A9 -:10BAE000002190F87C207030F5F74CFA002809D03E -:10BAF000206990F8A001002804D00021FF20BDE8B3 -:10BB0000704073E609E000210C20FFF76FFE20690A -:10BB100010F8AA1F41F0010101701DE43EB5054671 -:10BB20006846FDF7ABFC00B9FFDF22220021009838 -:10BB3000F2F7ADFC0321009802F096FB0098017823 -:10BB400021F010010170294602F0B3FB144C0D2DB9 -:10BB500043D00BDCA5F102050B2D19D2DFE805F06F -:10BB600022184B191922185718192700152D5FD0C4 -:10BB700008DC112D28D0122D0BD0132D09D0142D37 -:10BB800006D155E0162D2CD0172D6AD0FF2D74D07C -:10BB9000FFDFFDF786FC002800D1FFDF3EBD00007F -:10BBA000000100202169009891F8E61017E0E26892 -:10BBB00000981178017191884171090A8171518849 -:10BBC000C171090A0172E4E70321009802F072FCD6 -:10BBD0000621009802F072FCDBE700980621017153 -:10BBE000D7E70098D4F8101091F8C221027191F8AB -:10BBF000C3114171CDE72169009801F5887102F008 -:10BC0000D7FB21690098DC3102F0DCFBC1E7FA497F -:10BC1000D1E90001CDE90101206901A990F8B00046 -:10BC200000F025008DF80400009802F006FCB0E753 -:10BC30002069B0F84810009802F0D6FB2069B0F8EF -:10BC4000E810009802F0D4FB2069B0F84410009886 -:10BC500002F0D2FB2069B0F8E610009802F0D0FBA9 -:10BC600097E7216991F8C00100280098BCD111F82C -:10BC7000642F02714978BCE7FFE7206990F8A3219F -:10BC8000D0F8A411009802F022FB82E7DB4810B53F -:10BC9000006990F8821041B990F87D2001230621B7 -:10BCA0007030F5F76FF9002800D001209DE570B5E0 -:10BCB000D24D286990F8801039B1012905D00229A8 -:10BCC00006D0032904D0FFDF03E4B0F8F41037E016 -:10BCD00090F87F10082936D0B0F89810B0F89A2064 -:10BCE00000248B1C9A4206D3511A891E0C04240C82 -:10BCF00001D0641EA4B290F8961039B190F87C205F -:10BD0000012309217030F5F73DF940B3FFF7BEFF7D -:10BD100078B129690020B1F89020B1F88E108B1C01 -:10BD20009A4203D3501A801E00D0401EA04200D277 -:10BD300084B20CB1641EA4B22869B0F8F410214496 -:10BD4000A0F8F0102DE5B0F898100329BDD330F815 -:10BD5000701F428D1144491CA0F8801021E5002479 -:10BD6000EAE770B50C4605464FF4087200212046FC -:10BD7000F2F78DFB258014E5F8F7A2B92DE9F04123 -:10BD80000D4607460721F8F791F8041E3CD094F8B9 -:10BD9000C8010026A8B16E70092028700BE0268427 -:10BDA00084F8C861D4F8CA016860D4F8CE01A860EC -:10BDB000B4F8D201A88194F8C8010028EFD12E71FF -:10BDC000AEE094F8D40190B394F8D4010D2813D0C8 -:10BDD0000E2801D0FFDFA3E02088F8F798F9074686 -:10BDE000F7F745FE78B96E700E20287094F8D601EA -:10BDF00028712088E88014E02088F8F788F9074641 -:10BE0000F7F735FE10B10020BDE8F0816E700D200F -:10BE1000287094F8D60128712088E88094F8DA0117 -:10BE2000287284F8D4613846F7F71BFE78E0FFE704 -:10BE300094F80A0230B16E701020287084F80A62FB -:10BE4000AF806DE094F8DC0190B16E700A2028702C -:10BE50002088A880D4F8E011C5F80610D4F8E411C1 -:10BE6000C5F80A10B4F8E801E88184F8DC6157E00D -:10BE700094F8040270B16E701A20287005E000BFBB -:10BE800084F80462D4F80602686094F8040200287A -:10BE9000F6D145E094F8EA0188B16E70152028705B -:10BEA00008E000BF84F8EA6104F5F6702B1D07C8AE -:10BEB00083E8070094F8EA010028F3D130E094F811 -:10BEC000F80170B16E701C20287084F8F861D4F805 -:10BED000FA016860D4F8FE01A860B4F80202A881F3 -:10BEE0001EE094F80C0238B11D20287084F80C6212 -:10BEF000D4F80E02686013E094F81202002883D090 -:10BF00006E701620287007E084F81262D4F81402CC -:10BF10006860B4F81802288194F812020028F3D15E -:10BF2000012071E735480021C16101620846704770 -:10BF300030B5324D0C46E860FFF7F4FF00B1FFDF8B -:10BF40002C7130BD002180F87C1080F87D1080F8C5 -:10BF5000801090F8FB1009B1022100E00321FEF7E8 -:10BF60003FBC2DE9F041254C0546206909B100216F -:10BF700004E0B0F80611B0F8F6201144A0F806115C -:10BF800090F88C1139B990F87F2001231946703050 -:10BF9000F4F7F8FF30B1206930F89C1FB0F85A2050 -:10BFA00011440180206990F8A23033B1B0F89E109E -:10BFB000B0F8F6201144A0F89E1090F9A670002F5A -:10BFC00006DDB0F8A410B0F8F6201144A0F8A410D3 -:10BFD00001213D2615B180F88D6017E02278022AF4 -:10BFE0000ED0012A15D0A2784AB380F88C1012F036 -:10BFF000140F11D01E2117E0FC6202000001002086 -:10C0000090F8E620062A3CD016223AE080F88C1000 -:10C0100044E090F88E2134E0110702D580F88D605D -:10C020003CE0910603D5232180F88D1036E090077F -:10C0300000D1FFDF21692A2081F88D002AE02BB191 -:10C04000B0F89E20B0F8A0309A4210D2002F05DD43 -:10C05000B0F8A420B0F8A0309A4208D2B0F89C30D2 -:10C06000B0F89A20934204D390F88C310BB122227D -:10C0700007E090F880303BB1B0F89830934209D394 -:10C08000082280F88D20C1E7B0F89820062A01D355 -:10C090003E22F6E7206990F88C1019B12069BDE8BE -:10C0A000F0414FE7BDE8F0410021FEF799BB2DE9D3 -:10C0B000F047FF4C81460D4620690088F8F739F8B3 -:10C0C000060000D1FFDFA0782843A070A0794FF0D0 -:10C0D00000058006206904D5A0F8985080F8045126 -:10C0E00003E030F8981F491C0180FFF7CFFD4FF0A7 -:10C0F000010830B3E088000506D5206990F8821069 -:10C1000011B1A0F88E501CE02069B0F88E10491CC7 -:10C1100089B2A0F88E10B0F890208A4201D3531A49 -:10C1200000E0002327897F1DBB4201D880F896805C -:10C13000914206D3A0F88E5080F80A822079E6F763 -:10C14000E3FEA0794FF0020710F0600F0ED02069D7 -:10C1500090F8801011B1032908D102E080F88080A6 -:10C1600001E080F880700121FEF73AFB206990F829 -:10C170008010012904D1E188C90501D580F88070BB -:10C18000B9F1000F72D1E188890502D5A0F81851E4 -:10C1900004E0B0F81811491CA0F8181100F035FBA4 -:10C1A000FEF719FDFFF72EFC2769B7F8F800401CD1 -:10C1B000A7F8F80097F8FC0028B100F01BFFA8B121 -:10C1C000A7F8F85012E000F012FF08B1A7F8F850F5 -:10C1D00000F015FF50B197F80401401CC0B287F879 -:10C1E0000401022802D927F8F85F3D732069012372 -:10C1F000002190F87D207030F4F7C4FE20B920694A -:10C2000090F87D000C2859D120690123002190F875 -:10C210007C207030F4F7B6FE48B32069012300217A -:10C2200090F87F207030F4F7ADFE00B3206990F8ED -:10C230008010022942D190F80401C0B93046F7F7C6 -:10C24000E6F9A0B1216991F8E400FE2836D1B1F8F1 -:10C25000F200012832D981F8FA80B1F89A00B1F8D9 -:10C260009820831E9A4203DB012004E032E025E09F -:10C27000801A401E80B2B1F8F82023899A4201D377 -:10C28000012202E09A1A521C92B2904200D9104642 -:10C29000012801D181F8FA5091F86F2092B98A6E85 -:10C2A00082B1B1F89420B1F87010511A09B2002986 -:10C2B00008DD884200DB084680B203E021690120E6 -:10C2C00081F8FA502169B1F870201044A1F8F40007 -:10C2D000FFF7EDFCE088C0F340214846FFF741FE40 -:10C2E000206980F8FB50BDE8F047FDF7FCB87049C5 -:10C2F00002468878CB78184312D10846006942B1CB -:10C300008979090703D590F87F00082808D0012013 -:10C310007047B0F84C10028E914201D8FEF7B1B9C7 -:10C320000020704770B5624C05460E46E0882843F1 -:10C33000E080A80703D5E80700D0FFDF6661EA07C1 -:10C340004FF000014FF001001AD0A661F278062AE2 -:10C3500002D00B2A14D10AE0226992F87D30172B03 -:10C360000ED10023E2E92E3302F8370C08E02269EF -:10C3700092F87D30112B03D182F8811082F8A80049 -:10C38000AA0718D56269D278052A02D00B2A12D1E1 -:10C390000AE0216991F87D20152A0CD10022E1E9FB -:10C3A000302201F83E0C06E0206990F87D20102A2A -:10C3B00001D180F88210280601D50820E07083E4BE -:10C3C0002DE9F84301273A4C002567F30701E58082 -:10C3D000A570E570257020618946804680F8FB7065 -:10C3E0000088F7F7A6FE00B9FFDF20690088FDF797 -:10C3F00042F820690088FDF764F82069B0F8F2106F -:10C4000071B190F8E410FE290FD190F88C1189B128 -:10C4100090F87F20012319467030F4F7B3FD78B10E -:10C42000206990F8E400FE2804D0206990F8E40028 -:10C43000FFF774FB206990F8FD1089B1258118E0A1 -:10C440002069A0F89C5090F88D1180F8E61000212A -:10C450000220FFF7CBF9206980F8FA500220E7E7C5 -:10C4600090F8C81119B9018C8288914200D881884E -:10C47000218130F8F61F491E8EB230F8021F314478 -:10C4800020F86019018831440180FFF7FFFB20B1DB -:10C49000206930F88E1F314401802069B0F8F21015 -:10C4A000012902D8491CA0F8F2102EB102E00000C8 -:10C4B0000001002080F8045180F8FA5090F87D10B7 -:10C4C0000B2901D00C2916D1B0F87020B0F8AA3190 -:10C4D000D21A12B2002A0EDBD0F8AC11816090F8AB -:10C4E000B01101730321F4F773F8206980F87D50CF -:10C4F00080F8B27026E0242910D1B0F87010B0F89E -:10C50000AA21891A09B2002908DB90F8C001FFF7B7 -:10C510004BF9206900F87D5F857613E090F87C1078 -:10C52000242901D025290DD1B0F87010B0F8AA0146 -:10C53000081A00B2002805DB0120FFF735F9206951 -:10C5400080F87C5020690146B0F8F6207030F4F78E -:10C55000B2FAFC480090FC4BFC4A4146484600F0C9 -:10C560007DFC216A11B16078FCF7B5FA20690123DE -:10C57000052190F87D207030F4F704FD002803D0E9 -:10C58000BDE8F84300F0FDB9BDE8F88300F015BD43 -:10C59000EF49C8617047EE48C069002800D001200B -:10C5A0007047EB4A50701162704710B5044600881E -:10C5B000A4F8CC01B4F8B001A4F8CE01B4F8B201EB -:10C5C000A4F8D001B4F8B401A4F8D201012084F891 -:10C5D000C801DF480079E6F797FC02212046F3F70F -:10C5E000F7FF002004F87D0F0320E07010BD401A13 -:10C5F00000B247F6FE71884201DC002801DC012010 -:10C6000070470020704710B5012808D0022808D0D4 -:10C61000042808D0082806D0FFDF204610BD0124DA -:10C62000FBE70224F9E70324F7E7C9480021006982 -:10C6300020F8A41F8178491C81707047C44800B558 -:10C64000016911F8A60F401E40B20870002800DAF8 -:10C65000FFDF00BDBE482721006980F87C10002163 -:10C6600080F8A011704710B5B94C206990F8A81156 -:10C67000042916D190F87C20012300217030F4F7B2 -:10C6800081FC00B9FFDF206990F8AA10890703D464 -:10C69000062180F87C1004E0002180F8A21080F8C8 -:10C6A000A811206990F87E00800707D5FFF7C6FF24 -:10C6B000206910F87E1F21F00201017010BDA4490D -:10C6C00010B5096991F87C200A2A09D191F8E22075 -:10C6D000824205D1002081F87C0081F8A20010BDC3 -:10C6E00091F87E20130706D522F0080081F87E001D -:10C6F000BDE81040A2E7FF2801D0FFDF10BDBDE874 -:10C700001040A7E7F8B5924C01230A21206990F860 -:10C710007C207030F4F736FC38B3A06901F07CFE61 -:10C72000C8B1A06901F072FE0746A06901F072FE6F -:10C730000646A06901F068FE0546A06901F068FEA2 -:10C7400001460097206933462A46303001F059FFF0 -:10C75000206901F082FF2169002081F8A20081F8A0 -:10C760007C00BDE8F840FEF7D2BBA07840F00100A5 -:10C77000A070F8BD10B5764C01230021206990F817 -:10C780007D207030F4F7FEFB30B1FFF74EFF2169DA -:10C79000102081F87D0010BD20690123052190F84B -:10C7A0007D207030F4F7EEFB08B1082000E0012096 -:10C7B000A07010BD70B5664C01230021206990F86F -:10C7C0007D207030F4F7DEFB012588B1A06901F00F -:10C7D000C4FD2169A1F8AA01B1F87010FFF707FFA5 -:10C7E00040B12069282180F88D1080F88C50E6E552 -:10C7F000A570E4E52169A06901F5D67101F0A8FDF5 -:10C8000021690B2081F87D00D9E510B5FEF779FF8D -:10C81000FEF760FE4E4CA079400708D5A07830B9ED -:10C82000206990F87F00072801D101202070FEF7D1 -:10C8300071FAA079C00609D5A07838B9206990F8B6 -:10C840007D100B2902D10C2180F87D10E0780007C3 -:10C850000ED520690123052190F87D207030F4F772 -:10C8600091FB30B10820A0702169002081F8D4012B -:10C8700010BDBDE81040002000F0C4BB10B5344C22 -:10C88000216991F87D2048B3102A06D0142A07D0D8 -:10C89000152A1AD01B2A2CD11AE001210B2019E0ED -:10C8A000FAF702FE0C2817D32069082100F58870DA -:10C8B000FAF7FEFD28B120690421DC30FAF7F8FD13 -:10C8C00000B9FFDF0121042004E000F017F803E0C5 -:10C8D00001210620FEF78AFF012010BD212A08D180 -:10C8E00091F8970038B991F8C00110B191F8C101E1 -:10C8F00008B1002010BD01211720EBE770B5144CE2 -:10C900000025206990F88F1101290AD002292ED123 -:10C9100090F8A810F1B1062180F8E610012102205C -:10C9200020E090F8D411002921D100F1C80300F5CE -:10C930008471002200F5C870F4F796FA01210520F1 -:10C9400010E00000AFC00100EFC2010025C30100EC -:10C950000001002090F8B000400701D5112000E050 -:10C960000D200121FEF742FF206980F88F5126E556 -:10C9700030B5FB4C05462078002818BFFFDFE57175 -:10C9800030BDF7490120887170472DE9F14FF54D11 -:10C990002846446804F1700794F86510608F94F895 -:10C9A0008280268F082978D0F4F797FBB8F1000F22 -:10C9B00004BF001D80B2864238BF304600F0FF0839 -:10C9C000DFF89C93E848C9F8240009F134006E6848 -:10C9D000406800F1700A90F882B096F86510358FC3 -:10C9E000708F08295DD0F4F778FB00BFBBF1000F12 -:10C9F00004BF001D80B2854238BF2846C0B29AF8F5 -:10CA00001210002918BF04210844C0B296F865101E -:10CA1000FBF735FCB87C002847D007F15801D24815 -:10CA200091E80E1000F5027585E80E10B96EC0F899 -:10CA30002112F96EC0F8251200F58170FBF7DBFFBB -:10CA4000C848007800280CBF0120002080F00101B8 -:10CA5000C6480176D7E91412C0E90412A0F5837222 -:10CA6000D9F82410FBF7F5F994F86500012808BF00 -:10CA700000220CD0022808BF012208D0042808BFD9 -:10CA8000032204D008281ABFFFDF002202224146F9 -:10CA90000120FBF7F9F90EE0FFE70421F4F71DFB95 -:10CAA00084E70421F4F719FBA0E7D9F82400FBF789 -:10CAB000A2FFFBF715FA009850B994F8650094F8B6 -:10CAC000661010F00C0F08BF00219620FBF7B4FF92 -:10CAD00094F8642001210020FCF76BF894F82C00F6 -:10CAE000012808BFFCF735F8022089F80000FCF7A0 -:10CAF0003FFC002818BFFFDFBDE8F88F2DE9F04F9D -:10CB0000DFF860A28BB050469AF800204068AAF186 -:10CB10001401059190F8751000F1700504464FF06E -:10CB200008080127AAF13406A1B3012900F0068103 -:10CB3000022900F00781032918BFFFDF00F01881E8 -:10CB4000306A0423017821F008010170AA7908EA0B -:10CB5000C202114321F004010170EA7903EA820262 -:10CB6000114321F01001017095F80590F06AF6F775 -:10CB70005EFD8046FCF7C9FCB9F1020F00F00081B0 -:10CB8000B9F1010F00F00081B9F1030F00F000814D -:10CB900000F003B9FFE795F80CC04FF002094FF021 -:10CBA000000BBCF1240F1CBF6B7B242B08D0BCF105 -:10CBB0001F0F18BFBCF1200F2AD0222B4DD077E0D9 -:10CBC00094F864109AB190F8AC01002874D0082948 -:10CBD00018BF042969D0082818BF042865D0012986 -:10CBE00018BF012853D000BF4FF0020164E090F855 -:10CBF0001201002860D0082918BF042955D0082840 -:10CC000018BF042851D0012918BF01283FD0EBE7F5 -:10CC1000222B22D0002A4BD090F8C20194F8641045 -:10CC200010F0040F18BF40460CD0082918BF042983 -:10CC30003BD0082818BF042837D0012918BF012885 -:10CC400025D0D1E710F0010F18BF3846EDD110F014 -:10CC5000020F18BF4846E8D12EE04AB390F8C2212F -:10CC600090F85D0094F8641002EA000010F0040FE0 -:10CC700018BF40460ED0082918BF042915D008282F -:10CC800018BF042811D0012918BF0128ACD14FF0DA -:10CC9000010111E010F0010F18BF3846EBD110F080 -:10CCA000020F18BF4846E6D106E04FF0080103E046 -:10CCB00094F864100429F8D0A08E11F00C0F18BF5E -:10CCC0004FF42960F4F709FA218E814238BF0846F3 -:10CCD000ADF80400A4F84C000598FCF7F5FB60B132 -:10CCE0007289316A42F48062728172694FF48060A5 -:10CCF000904703206871EF7022E709AA01A9F06A42 -:10CD0000F6F7CFFB306210B195F8371021B10598D6 -:10CD1000FCF7AEFB6F7113E79DF8241031B9A0F852 -:10CD200000B080F802B0012101F09EFABDF80410B5 -:10CD3000306A01F0C7FB85F8059001E70598FCF71C -:10CD400097FBFDE6B4F84C00ADF8040009AA01A970 -:10CD5000F06AF6F7A6FB3062002808BFFFDFEFE6B7 -:10CD60002401002058010020300D0020380F002041 -:10CD70000598FCF7A9FB002808BFFFDFE0E600BF2D -:10CD800030EA080009D106E030EA080005D102E0E7 -:10CD9000B8F1000F01D0012100E00021306A0278D3 -:10CDA00042EA01110170697C00291CBF69790129DF -:10CDB0003BD005F15801FD4891E80E1000F50278CE -:10CDC00088E80E10A96EC0F82112E96EC0F825128D -:10CDD00000F58170FBF70FFE9AF8000000280CBFE9 -:10CDE00001210021F2480176D5E91212C0E90412AE -:10CDF000A0F58371326AFBF72CF894F864000128DF -:10CE000008BF00220CD0022808BF012208D0042845 -:10CE100008BF032204D008281ABFFFDF0022022225 -:10CE2000FB210020FBF730F803E0FBF7E4FDFBF704 -:10CE300057F8012194F865200846FBF7BAFE3771D0 -:10CE4000306A0188F181807830743770FCF799FA84 -:10CE5000002818BFFFDF0BB0BDE8F08F2DE9F043CD -:10CE6000D44D87B081462878DDF838801E461746B5 -:10CE70000C4628B9002F1CBF002EB8F1000F00D1BE -:10CE8000FFDFC5F81C80C5E90D94C5E905764FF0B4 -:10CE90000000A8716871E870A8702871C64E68819A -:10CEA000A881307804F170072088F7F742F9E8622A -:10CEB0002088F7F72CF92863FBF705FA94F9670047 -:10CEC000FBF7DAFA04F11200FBF76CFD04F10E0037 -:10CED000FBF7D8FA307800280CBF03200120FBF7BD -:10CEE00087FDB64890E80E108DE80E10D0E90410CA -:10CEF000CDE90410307800280CBFB148B148049047 -:10CF00006846FBF763FDF87EFBF7C4FAFBF76AFDA2 -:10CF100094F86F0078B9A06E68B1B88C39888842EF -:10CF200009D1B4F86C1001220844B88494F86E005A -:10CF3000A16EF8F7D8FE3078002804BFFF2094F8DF -:10CF400064401AD094F8651097F81280258F608F8E -:10CF5000082926D0F4F7C1F8B8F1000F04BF001D6E -:10CF600080B2854238BF2846C0B2B97C002918BFBC -:10CF70000421084494F86540C0B22146FBF77FF9CC -:10CF80003078214688B10120FBF74BFB7068D0F860 -:10CF90000001FBF733FD0120FFF7F7FC07B0BDE808 -:10CFA000F0830421F4F799F8D6E70020FBF739FB6A -:10CFB000FFF7A4FD07B0BDE8F0837F4800B5017816 -:10CFC0003438007819B1022818BFFFDF00BD0128EE -:10CFD00018BFFFDF00BD774810B50078022818BFE2 -:10CFE000FFDFBDE8104000F070BA00F06EBA714883 -:10CFF000007970476F488089C0F3002070476D4802 -:10D00000C07870472DE9F04706006B48694D4068CD -:10D0100000F17004686A90F8019018BF012E03D1E6 -:10D02000296B07F0F1FF6870687800274FF001085E -:10D03000A0B101283CD0022860D003281CBFFFDF2C -:10D04000BDE8F087012E08BFBDE8F087286BF6F732 -:10D05000E3FCE879BDE8F047E5F756BF012E14D0B0 -:10D06000A86A002808BFFFDF2889C21CD5E909107B -:10D07000F1F7E3F9A86A686201224946286BF6F7DE -:10D0800047FB022E08BFBDE8F087D4E91401401C1D -:10D0900041F10001C4E91401E079012801D1E771EF -:10D0A00001E084F80780E879BDE8F047E5F72CBF98 -:10D0B000012E14D0A86A002808BFFFDF2889C21CEF -:10D0C000D5E90910F1F7B9F9A86A68620022494662 -:10D0D000286BF6F71DFB022E08BFBDE8F087D4E9E8 -:10D0E0001410491C40F10000C4E91410E079012833 -:10D0F0000CBFE77184F80780BDE8F087012E06D0E9 -:10D10000286BF6F789FC022E08BFBDE8F087D4E94A -:10D110001410491C40F10000C4E91410E079012802 -:10D12000BFD1BCE72DE9F041234D2846A5F13404D9 -:10D13000406800F170062078012818BFFFDFB07842 -:10D140000127002158B1B1706289042042F0040225 -:10D150006281626990472878002818BF3771216A78 -:10D160000322087832EA000009D1628912F4806F44 -:10D1700005D042F002026281626902209047A169F3 -:10D180000020884760B3607950BB287818B30E48F8 -:10D19000007810F0100F04D10449097811F0100F35 -:10D1A0001ED06189E1B9A16AA9B90FE0300D002054 -:10D1B000380F0020240100205801002004630200E1 -:10D1C000BB220200A7A8010032010020218911B171 -:10D1D00010F0100F04D0BDE8F0410020FFF7D5BBE0 -:10D1E000BDE8F04100F071B92DE9F05FCC4E044686 -:10D1F0003046A6F134054068002700F1700A28780F -:10D20000B846022818BFFFDFA889FF2240F400704B -:10D21000A881706890F864101046FBF730F89AF80F -:10D2200012004FF00109002C00F0F080FAF77DFEAB -:10D23000FAF76BFE90B99AF8120078B1686A4178F3 -:10D2400061B100789AF80710C0F3C000884205D198 -:10D2500085F80290BDE8F05F00F037B9686A417860 -:10D260002981002908BFAF6203D0286BF6F70AFABC -:10D27000A862A88940F02000A881EF70706800F1D2 -:10D28000700B044690F82C0001281BD1FBF757FCCB -:10D2900059462046F3F729FEA0B13078002870687F -:10D2A0000CBF00F59A7000F50170218841809BF851 -:10D2B000081001719BF80910417180F80090E8791D -:10D2C000E5F722FE686A9AF806100078C0F380003D -:10D2D00088423AD0706800F1700490F87500002818 -:10D2E0002FD002284AD06771307800281CBF2079DF -:10D2F000002809D027716A89394642F010026A81F4 -:10D300006A694FF010009047E078A0B1E770FCF731 -:10D31000EAF8002808BFFFDF08206A89002142F0F0 -:10D3200008026A816A699047D4E91210491C40F1E9 -:10D330000000C4E91210A07901280CBFA77184F87D -:10D340000690A88940F48070A881696A9AF807302D -:10D350000878C0F3C0029A424DD1726800F0030011 -:10D3600002F17004012818BF02282DD003281CBF29 -:10D37000687940F0040012D068713CE0E86AF6F782 -:10D38000BCF8002808BFFFDFD4E91210491C40F1A7 -:10D390000000C4E91210E879E5F7B6FDA3E784F8C8 -:10D3A0000290AA89484642F40062AA816A8942F042 -:10D3B00001026A816A699047E079012801D1E77129 -:10D3C00019E084F8079016E04878D8B1A98941F4AB -:10D3D0000061A981A96A71B1FB2884BF687940F016 -:10D3E0001000C9D8A879002808BFC84603D08020FB -:10D3F0006A69002190470120A9698847E0B36879EC -:10D40000A0B13AE0E0790128DBD1D8E7002818BFC5 -:10D41000FAF7C5FDA88940F04000A881E97801200D -:10D42000491CC9B2E97001292DD8E5E7307890B9D7 -:10D430003C48007810F0100F04D13B49097811F0F6 -:10D44000100F1AD06989B9B9A96A21B9298911B10E -:10D4500010F0100F11D0B8F1000F1CBF0120FFF722 -:10D46000D1FDFFF74BFBB8F1000F08BFBDE8F09FFF -:10D470000220BDE8F05FC5E5FFE7B8F1000F1CBF73 -:10D480000020FFF7BFFDBDE8F05F00F01EB870B5EB -:10D490000D4606462248224900784C6850B1FAF7FA -:10D4A000F7FD034694F8642029463046BDE87040F5 -:10D4B000FDF78BBAFAF7ECFD034694F86420294691 -:10D4C0003046BDE8704004F0FCBE154910B54C680C -:10D4D000FBF714FBFBF7F3FAFBF7BCF9FBF768FA71 -:10D4E000FAF7FEFC94F82C00012808BFFBF727FB95 -:10D4F00094F86F0038B9A06E28B1002294F86E003D -:10D500001146F8F7F0FB094C00216269A0899047A9 -:10D51000E2696179A07890470020207010BD00007A -:10D520005801002032010020300D0020240100208D -:10D530002DE9F047FA4F894680463D782C0014D0FB -:10D540000126012D11DB601EC4B207EBC40090F868 -:10D550005311414506D10622494600F5AA70F0F75D -:10D560003FFF28B1761CAE42EDDD1020BDE8F0870C -:10D570002046BDE8F087EA498A78824286BF08449F -:10D5800090F843010020704710B540F2D3120021FB -:10D59000E348F0F77CFF0822FF21E248F0F777FF2D -:10D5A000E1480021417081704FF46171818010BDAC -:10D5B0002DE9F0410E460546FFF7BAFFD84C10287A -:10D5C00016D004EBC00191F85A0110F0010F1CBFF6 -:10D5D0000120BDE8F081607808283CBF012081F877 -:10D5E0005A011CD26078401C60700120BDE8F081B7 -:10D5F0006078082813D222780127501C207004EB91 -:10D60000C2083068C8F85401B088A8F85801102A38 -:10D6100028BFFFDF88F8535188F85A71E2E70020ED -:10D62000BDE8F081C04988707047BF488078704776 -:10D630002DE9F041BA4D00272878401E44B2002C55 -:10D6400030DB00BF05EBC40090F85A0110F0010F69 -:10D6500024D06878E6B2401E687005EBC6083046F4 -:10D6600088F85A7100F0E8FA102817D12878401E7F -:10D67000C0B22870B04211D005EBC001D1F85301FF -:10D68000C8F85301D1F85701C8F85701287800F0BD -:10D69000D3FA10281CBF284480F80361601E44B2EE -:10D6A000002CCFDAA0488770BDE8F0819C498A78C9 -:10D6B000824286BF01EB0010C01C002070472DE99C -:10D6C000F0470127994690463D460026FFF730FF78 -:10D6D000102820D0924C04EBC00191F85A1101F0AF -:10D6E000010600F0A9FA102815D0B9F1000F18BFF3 -:10D6F00089F80000A17881420DD904EB001111F1E5 -:10D70000030F08D0204490F84B5190F83B010128BA -:10D710000CBF0127002748EA060047EA0501084038 -:10D72000BDE8F0872DE9F05F1F4690468946064622 -:10D73000FFF7FEFE7A4C054610282ED000F07CFA4A -:10D7400010281CBF1220BDE8F09FA07808283ED208 -:10D75000A6781022701CA07004EB061909F10300D2 -:10D760004146F3F768FB09F1830010223946F3F7CD -:10D7700062FB10213846F3F74BFB3444102184F848 -:10D7800043014046F3F744FB84F84B0184F803510E -:10D79000002084F83B01BDE8F09FA078082816D24D -:10D7A00025784FF0000A681C207004EBC50BD9F8EF -:10D7B0000000CBF85401B9F80400ABF85801102D63 -:10D7C00028BFFFDF8BF853618BF85AA1C0E7072011 -:10D7D000BDE8F09F2DE9F041514CA078401E45B2C4 -:10D7E000002DB8BFBDE8F081EAB2A078401EC1B2FA -:10D7F000A17054FA85F090F803618A423DD004EBA1 -:10D80000011004EB0213D0F803C0C3F803C0D0F832 -:10D8100007C0C3F807C0D0F80BC0C3F80BC0D0F8DE -:10D820000FC0C3F80FC0D0F883C0C3F883C0D0F8CE -:10D8300087C0C3F887C0D0F88BC0C3F88BC0D0F8BE -:10D840008F00C3F88F006318A01801EB410193F813 -:10D8500003C102EB420204EB410180F803C104EB77 -:10D860004202D1F80BC1C2F80BC1B1F80F11A2F8F6 -:10D870000F1193F83B1180F83B1104EBC60797F8A2 -:10D880005A0110F0010F1CD1304600F0D5F91028D4 -:10D8900017D12078401EC0B22070B04211D004EBE6 -:10D8A000C000D0F85311C7F85311D0F85701C7F88A -:10D8B0005701207800F0C0F910281CBF204480F8E0 -:10D8C0000361681E45B2002D8EDABDE8F08116496D -:10D8D0004870704714484078704738B14AF2B81120 -:10D8E000884203D810498880012070470020704783 -:10D8F0000D488088704710B5FFF71AFE102804D035 -:10D9000000F09AF9102818BF10BD082010BD044976 -:10D910008A78824286BF01EB001083300020704776 -:10D92000600F00206C01002060010020FE4B93F886 -:10D9300002C084459CBF00207047184490F8030142 -:10D9400003EBC00090F853310B70D0F85411116004 -:10D95000B0F85801908001207047F34A114491F8C3 -:10D960000321F2490A700268C1F8062080884881C4 -:10D97000704770B516460C460546FBF7D5F8FAF722 -:10D98000C4F9EA48407868B1E748817851B12A196A -:10D99000002E0CBF8330C01CFAF791F9FAF7D8F9C2 -:10D9A000012070BD002070BD10B5FAF7FFF9002806 -:10D9B00004BFFF2010BDBDE81040FAF71DBAFAF70A -:10D9C000F5B9D9498A7882429CBF00207047084443 -:10D9D00090F8030101EBC00090F85A0100F001003B -:10D9E00070472DE9F047D04D00273E4628780028A3 -:10D9F00086BF4FF01009DFF83883BDE8F087AC78B8 -:10DA000021000CD00122012909DB601EC4B22819B3 -:10DA100090F80331B34203D0521C8A42F5DD4C46E4 -:10DA2000A14286BF05EB0410C01C002005EBC60A0E -:10DA30009AF85A1111F0010F16D050B1102C04D0E1 -:10DA4000291991F83B11012903D01021F3F7E0F9CE -:10DA500050B108F8074038467B1C9AF853210AF564 -:10DA6000AA71DFB2FAF7B5FC701CC6B22878B042D2 -:10DA7000C5D8BDE8F0872DE9F041AB4C002635460E -:10DA8000A07800288CBFAA4FBDE8F0816119C0B210 -:10DA900091F80381A84286BF04EB0510C01C00204A -:10DAA00091F83B11012903D01021F3F7B1F958B1D6 -:10DAB00004EBC800BD5590F8532100F5AA7130461B -:10DAC000731CDEB2FAF785FC681CC5B2A078A842C8 -:10DAD000DCD8BDE8F0810144934810B500EB02109A -:10DAE0000A4601218330FAF7EAF8BDE81040FAF758 -:10DAF0002FB90A468D4910B5497841B18A4B9978BA -:10DB000029B10244D81CFAF7DAF8012010BD002030 -:10DB100010BD854A01EB410102EB41010268C1F8E9 -:10DB20000B218088A1F80F0170472DE9F0417E4D4F -:10DB300007460024A878002898BFBDE8F081C0B24D -:10DB4000A04217D905EB041010F1830612D0102162 -:10DB50003046F3F75DF968B904EB440005EB400883 -:10DB600008F20B113A463046FBF74EFDB8F80F01AC -:10DB7000A8F80F01601CC4B2A878A042DFD8BDE8A5 -:10DB8000F081014610226B48F3F755B96948704798 -:10DB900065498A78824203D90A1892F843210AB16A -:10DBA0000020704700EB400001EB400000F20B103A -:10DBB00070475D498A78824206D9084490F83B0153 -:10DBC000002804BF01207047002070472DE9F04174 -:10DBD0000E460746144606213046F3F719F9524D12 -:10DBE00098B1A97871B105F59D7011F0010F18BFBA -:10DBF00000F8014FA978490804D0447000F8024F9A -:10DC0000491EFAD10120BDE8F08138463146FFF7C0 -:10DC10008FFC10280CD000F00FF8102818BF08282F -:10DC200006D0284480F83B414FF00100BDE8F08168 -:10DC30004FF00000BDE8F0813B4B10B4844698786B -:10DC400001000ED0012201290BDB401EC0B21C18BE -:10DC500094F80341644504BF10BC7047521C8A42CB -:10DC6000F3DD10BC1020704770B52F4C01466218D0 -:10DC7000A078401EC0B2A07092F8035181423CD0FF -:10DC800004EB011304EB001C01EB4101DCF8036021 -:10DC9000C3F80360DCF80760C3F80760DCF80B60CA -:10DCA000C3F80B60DCF80F60C3F80F60DCF883602A -:10DCB000C3F88360DCF88760C3F88760DCF88B60AA -:10DCC000C3F88B60DCF88FC0C3F88FC0231800EB5B -:10DCD000400093F803C104EB400082F803C104EB59 -:10DCE0004101D0F80BC1C1F80BC1B0F80F01A1F888 -:10DCF0000F0193F83B0182F83B0104EBC50696F84F -:10DD00005A0110F0010F18BF70BD2846FFF794FFAD -:10DD1000102818BF70BD2078401EC0B22070A842E5 -:10DD200008BF70BD08E00000600F00206001002007 -:10DD30006C0100203311002004EBC000D0F8531117 -:10DD4000C6F85311D0F85701C6F857012078FFF7ED -:10DD500073FF10281CBF204480F8035170BD0000E1 -:10DD60004078704730B50546007801F00F0220F08A -:10DD70000F0010432870092912D2DFE801F00507CF -:10DD800005070509050B0F0006240BE00C2409E02C -:10DD9000222407E001240020E87003E00E2401E0C3 -:10DDA0000024FFDF6C7030BD007800F00F0070477A -:10DDB0000A68C0F803208988A0F807107047D0F8D7 -:10DDC00003200A60B0F80700888070470A68C0F82E -:10DDD00009208988A0F80D107047D0F809200A6042 -:10DDE000B0F80D00888070470278402322F040028E -:10DDF00003EA81111143017070470078C0F380106D -:10DE000070470278802322F0800203EAC111114397 -:10DE1000017070470078C009704770B514460E460F -:10DE200005461F2A88BFFFDF2246314605F109005B -:10DE3000F0F703FBA01D687070BD70B544780E4606 -:10DE40000546062C38BFFFDFA01F84B21F2C88BFF9 -:10DE50001F24224605F109013046F0F7EEFA20466C -:10DE600070BD70B514460E4605461F2A88BFFFDFF9 -:10DE70002246314605F10900F0F7DFFAA01D68706F -:10DE800070BD0968C0F80F1070470A88A0F8132009 -:10DE900089784175704790F8242001F01F0122F025 -:10DEA0001F02114380F824107047072988BF0721FB -:10DEB00090F82420E02322F0E00203EA411111430C -:10DEC00080F8241070471F3008F065B810B504467C -:10DED00000F000FB002818BF204410BDC17811F0ED -:10DEE0003F0F1BBF027912F0010F0022012211F037 -:10DEF0003F0F1BBF037913F0020F002301231A44C5 -:10DF000002EB4202530011F03F0F1BBF027912F0E7 -:10DF1000080F0022012203EB420311F03F0F1BBF49 -:10DF2000027912F0040F00220122134411F03F0F76 -:10DF30001BBF027912F0200F0022012202EBC20265 -:10DF400003EB420311F03F0F1BBF027912F0100FD9 -:10DF50000022012202EB42021A4411F03F0F1BBFC4 -:10DF6000007910F0400F00200120104410F0FF0055 -:10DF700014BF012100210844C0B2704770B5027877 -:10DF8000417802F00F02082A4DD2DFE802F00408BF -:10DF90000B4C4C4C0F14881F1F280AD943E00C2946 -:10DFA00007D040E0881F1F2803D93CE0881F1F28A6 -:10DFB00039D8012070BD4A1EFE2A34D88446C07864 -:10DFC00000258209032A09D000F03F04601C884222 -:10DFD00004D86046FFF782FFA04201D9284670BDF1 -:10DFE0009CF803004FF0010610F03F0F1EBF1CF11C -:10DFF0000400007810F0100F13D06446042160462E -:10E0000000F068FA002818BF14EB0000E6D0017891 -:10E0100001F03F012529E1D280780221B1EB501FA8 -:10E02000DCD3304670BD002070BD70B5017801258D -:10E0300001F00F01002404290AD007290DD0082976 -:10E040001CBF002070BD40780E2836D0204670BD21 -:10E050004078801F1F2830D9F8E7844640789CF824 -:10E0600003108A09032AF1D001F03F06711C814296 -:10E07000ECD86046FFF732FFB042E7D89CF80300C7 -:10E0800010F03F0F1EBF1CF10400007810F0100FBD -:10E0900013D066460421604600F01CFA002818BF21 -:10E0A00016EB0000D2D0017801F03F012529CDD236 -:10E0B00080780221B1EB501FC8D3284670BD10B440 -:10E0C000017801F00F01032920D0052921D14478DE -:10E0D000B0F81910B0F81BC0B0F81730827D222CB0 -:10E0E00017D1062915D3B1F5486F98BFBCF5FA7F53 -:10E0F0000FD272B1082A98BF8A420AD28B429CBFC3 -:10E10000B0F81D00B0F5486F03D805E040780C2842 -:10E1100002D010BC0020704710BC012070472DE9D0 -:10E12000F0411F4614460D00064608BFFFDF21469A -:10E13000304600F0CFF9040008BFFFDF30193A463F -:10E140002946BDE8F041F0F778B9C07800F03F000B -:10E150007047C02202EA8111C27802F03F021143E7 -:10E16000C1707047C07880097047C9B201F00102E0 -:10E17000C1F340031A4402EB4202C1F3800303EBF4 -:10E180004202C1F3C00302EB4302C1F3001303EBED -:10E1900043031A44C1F3401303EBC30302EB4302EE -:10E1A000C1F380131A4412F0FF0202D0521CD2B203 -:10E1B0000171C37802F03F0103F0C0031943C1703D -:10E1C000511C417070472DE9F0410546C078164654 -:10E1D00000F03F041019401C0F46FF2888BFFFDFE6 -:10E1E000281932463946001DF0F727F9A019401CBE -:10E1F0006870BDE8F081C178407801F03F01401AB5 -:10E20000401E80B2704710B590F803C00B460CF06A -:10E210003F0144780CF03F0CA4EB0C0CACF1010C6A -:10E220001FFA8CF4944288BF14462BB10844011D98 -:10E2300022461846F0F701F9204610BD4078704795 -:10E2400000B5027801F0030322F003021A430270C2 -:10E25000012914BF0229002104D0032916BFFFDFC2 -:10E26000012100BD417000BD00B5027801F003033B -:10E2700022F003021A430270012914BF022900216F -:10E2800004D0032916BFFFDF012100BD417000BD8E -:10E29000007800F003007047417841B1C078192838 -:10E2A00003D2BC4A105C884201D101207047002093 -:10E2B000704730B501240546C17019293CBFB548E7 -:10E2C000445C02D3FF2918BFFFDF6C7030BD70B50E -:10E2D00015460E4604461B2A88BFFFDF65702A4696 -:10E2E0003146E01CBDE87040F0F7A7B8B0F8070071 -:10E2F0007047B0F809007047C172090A017370478E -:10E30000B0F80B00704730B4B0F80720B0F809C07F -:10E31000B0F805300179941F40F67A45AC4298BFB9 -:10E32000BCF5FA7F0ED269B1082998BF914209D293 -:10E3300093429FBFB0F80B00B0F5486F012030BC8E -:10E3400098BF7047002030BC7047001D07F023BE07 -:10E35000021D0846114607F01EBEB0F809007047BE -:10E36000007970470A684260496881607047426876 -:10E370000A60806848607047098881817047808999 -:10E38000088070470A68C0F80E204968C0F812106B -:10E390007047D0F80E200A60D0F81200486070472D -:10E3A0000968C0F816107047D0F81600086070476A -:10E3B0000A68426049688160704742680A60806804 -:10E3C000486070470968C1607047C068086070475E -:10E3D000007970470A684260496881607047426806 -:10E3E0000A608068486070470171090A417170478E -:10E3F0008171090AC17170470172090A417270473F -:10E400008172090AC172704780887047C08870475E -:10E41000008970474089704701891B2924BF4189C1 -:10E42000B1F5A47F07D381881B2921BFC088B0F52F -:10E43000A47F01207047002070470A684260496845 -:10E440008160704742680A6080684860704701795F -:10E4500011F0070F1BBF407910F0070F00200120BB -:10E460007047017911F0070F1BBF407910F0070FBB -:10E470000020012070470171704700797047417199 -:10E480007047407970478171090AC1717047C0882F -:10E4900070470179407901F007023F498A5C012AFF -:10E4A00006D800F00700085C01289CBF01207047D7 -:10E4B00000207047017170470079704741717047C3 -:10E4C0004079704730B50C460546FB2988BFFFDF11 -:10E4D0006C7030BDC378024613F03F0008BF704730 -:10E4E0000520127903F03F0312F0010F37D0002905 -:10E4F00014BF0B20704700BF12F0020F32D0012969 -:10E5000014BF801D704700BF12F0040F2DD00229E8 -:10E5100014BF401C704700BF12F0080F28D0032919 -:10E5200014BF801C704700BF12F0100F23D00429C5 -:10E5300014BFC01C704700BF12F0200F1ED0052969 -:10E540001ABF1230C0B2704712F0400F19D006291E -:10E550001ABF401CC0B27047072918D114E0002927 -:10E56000CAD114E00129CFD111E00229D4D10EE0A3 -:10E570000329D9D10BE00429DED108E00529E3D134 -:10E5800005E00629E8D102E0834288BF70470020F9 -:10E5900070470000246302001C63020030B490F84E -:10E5A00064508C88B1F808C015F00C0F1BD000BF68 -:10E5B000B4F5296F98BF4FF4296490F8655015F0B1 -:10E5C0000C0F17D0BCF5296F98BF4FF4296C4A88FF -:10E5D000C988A0F84420A0F84810A0F84640A0F848 -:10E5E0004AC030BC7047002B1CBF157815F00C0FCB -:10E5F000DED1E2E7002B1CBF527812F00C0FE1D104 -:10E60000E5E7DDF800C08181C2810382A0F812C075 -:10E6100070471B2202838282C281828142800281F2 -:10E62000028042848284828359B14FF429614183FC -:10E63000C18241820182C18041818180C184018582 -:10E6400070474FF4A4714183C18241820182C1802D -:10E6500041818180C18401857047F0B4B0F84820C1 -:10E66000818F468EC58E8A4228BF0A4690F8651073 -:10E670004FF0000311F00C0F18BF4FF4296106D1C1 -:10E68000B0F84AC0B0F840108C4538BF61464286A9 -:10E69000C186048FB0F83AC0944238BF14468C4506 -:10E6A00038BF8C460487A0F83AC0B2420ABFA942DC -:10E6B0004FF0010C4FF0000C058EB0F84410C28FE3 -:10E6C000848E914228BF114690F8642012F00C0FFE -:10E6D00018BF4FF4296206D1B0F84660B0F8422066 -:10E6E000964238BF324690F85A60022E0AD0018610 -:10E6F0008286A9420ABFA2420120002040EA0C0003 -:10E70000F0BC70478D4238BF2946944238BF22463C -:10E7100080F85A30EBE7508088899080C889D08093 -:10E72000088A1081488A508101201070704730B4E7 -:10E7300002884A80B0F830C0A1F804C0838ECB8034 -:10E74000428E0A81C48E4C81B0F85650A54204BF57 -:10E75000B0F85240944208D1B0F858409C4202BFF1 -:10E76000B0F854306345002301D04FF001030B7320 -:10E7700000F13003A0F852201A464B89D3848B88CD -:10E780009384CA88A0F858204FF00100087030BC6C -:10E79000704730B404460A46088E91F864104FF46E -:10E7A000747311F00C0F1CBF03EB801080B21ED0ED -:10E7B000918E814238BF0846118F92F865C01CF0D7 -:10E7C0000C0F1CBF03EB811189B218D0538F8B4201 -:10E7D00038BF194692F866301CF00C0F08BF0023B2 -:10E7E000002C0CBF0122002230BCF2F798BC022999 -:10E7F00007BF80003C30C000703080B2D8E7BCF169 -:10E80000020F07BF89003C31C900703189B2DDE7D2 -:10E810002DE9F041044606F099FCC8B9FE4F78682E -:10E8200090F8221001260025012914D00178012931 -:10E830001BD090F8281001291CBF0020BDE8F081F2 -:10E84000657018212170D0F82A10616080F8285076 -:10E850000120BDE8F081657007212170416A616087 -:10E8600080F822500120BDE8F081657014212170EC -:10E87000811C2022201DEFF7E0FD257279680D70C4 -:10E8800081F82850E54882888284C26B527B80F8E8 -:10E89000262080F82260C86B0088F5F738FCF5F771 -:10E8A000E0F8D5E7DC4840680178002914BF80888B -:10E8B0004FF6FF70704730B5D74C83B00D462078C7 -:10E8C0007F2808BFFFDF94F900307F202070D4F844 -:10E8D00004C09CF85000062808BF002205D09CF810 -:10E8E000500008280CBF022201229CF85400CDE9F8 -:10E8F000000302929CF873309CF880200CF13201E6 -:10E90000284606F08FFC03B0BDE8304006F01FBE7D -:10E910002DE9F04106F05FFC002818BF06F0E4FB8B -:10E92000BD4C606800F1840290F87610895C80F834 -:10E930008010002003F07EF828B3FAF753F86068DF -:10E94000B74990F855000D5C2846F9F7A3FD6068BB -:10E950004FF0000680F8735090F8801011F00C0F03 -:10E960000CBF25200F20F9F76CFC606890F8801030 -:10E970000120F9F711FE606890F84010032918BFD4 -:10E9800002290FD103E0BDE8F04101F02FB990F862 -:10E9900076108430085C012804D101221146002041 -:10E9A000FAF707F9FAF7D5F8606890F88050012D6A -:10E9B00007BF0127032100270521A068FFF799F869 -:10E9C000616881F8520040B1002F18BF402521D066 -:10E9D000F9F787F92846FAF79DF86068806DFAF72D -:10E9E0000DF8606890F85410FF291CBF6D30FEF7D9 -:10E9F000B4FFFF21606880F8531080F8541080F84D -:10EA0000626080F8616080F87D60062180F85010B7 -:10EA1000BDE8F08115F00C0F14BF55255025D7E740 -:10EA200070B57D4C0646606800F150052046806850 -:10EA300041B1D0F80510C5F81D10B0F80900A5F8CF -:10EA4000210003E005F11D01FFF7B9F9A068FFF708 -:10EA5000D4F985F82400A0680021032E018002D09B -:10EA6000052E04D03DE00321FFF77CF939E00521B4 -:10EA7000FFF778F96068C06B00F10E01A068FFF73E -:10EA800000FA6068C06B00F11201A068FFF7FDF9A1 -:10EA9000D4E90110CA6B527D8275CA6BD28AC275E5 -:10EAA000120A0276CA6B52884276120A8276CA6BC2 -:10EAB0009288C276120A0277CA6BD2884277120A0B -:10EAC0008277C96B0831FFF7FEF96068C06B017E81 -:10EAD000A068FFF7E0F9606890F88610A068FFF77B -:10EAE000E4F905F11D01A068FFF770F995F824100D -:10EAF000A068FFF786F9606800F1320590F8316090 -:10EB000090F8511091B190F84010032906D190F877 -:10EB10003910002918BF90F8560001D190F8530021 -:10EB2000FFF736F800281CBF012605462946A068D5 -:10EB3000FFF73EF93146A068BDE87040FFF754B9D1 -:10EB40003549496881F84B00704770B5324D002453 -:10EB50000126A8606968A1F8814081F8834081F8A6 -:10EB6000506091F85020022A1FBF91F850100129DF -:10EB7000FFDF70BD06F0CDFA6868047080F82240AF -:10EB800080F8284090F8520030B1F9F7CDFFF9F73E -:10EB9000BCF8686880F852406868072180F84A40ED -:10EBA00080F8396080F8404080F8554080F84B404C -:10EBB00080F87D4080F8381070BD2DE9F041164C8A -:10EBC000054686B0606890F85000012818BF0228FA -:10EBD00005D003281EBF0C2006B0BDE8F081687A7E -:10EBE000022839D0F9F76FFB0220F9F701FF0D4930 -:10EBF00001F10C0090E80D108DE80D10D1E907012E -:10EC0000CDE904016846F9F7E1FE606890F94B0030 -:10EC1000F9F732FCA06807E07401002044110020DD -:10EC20004363020040630200F9F7E5FEFC48F9F790 -:10EC3000B9FEFC48F9F726FC606890F831103230D4 -:10EC4000F9F7A5FB0F210720F9F7BFFB606890F8E3 -:10EC50003900E0B1FEF70FFF6168287A01F1840204 -:10EC600081F87600287A805C81F880006868886581 -:10EC70002A68CA65687A68B1012824D00525022867 -:10EC800008BF81F850506FD0032878D080E0FEF79D -:10EC9000A8FEE1E7E44B91F83850002291F85500C6 -:10ECA000401CA3FB006C4FEA5C0CACEB8C0C60448A -:10ECB00081F8550025FA00F010F0010F03D1501C27 -:10ECC000C2B2032AEAD3002681F87D6091F8490098 -:10ECD000002804BF91F85100002841D0F7F744FA0A -:10ECE000074660683946406CF7F736FFDFF83C832B -:10ECF000054690FBF8F008FB105041423846F6F705 -:10ED00001AFF6168486495FBF8F08A6F10448867C1 -:10ED1000FEF7EEFD01466068826F914220D847649D -:10ED2000866790F8510000281CBF0120FEF7FDFE09 -:10ED30000121606890F84A20002A1CBF90F8492001 -:10ED4000002A0DD090F8313000F13202012B04D1AD -:10ED5000527902F0C002402A08D03230FAF78CFC17 -:10ED60006168042081F8500012E008E00125FEF7F8 -:10ED70000DFF61682A463231FAF746FCF0E7002AB7 -:10ED800018BFFFDF012000F089FF606880F8505055 -:10ED900006B00020BDE8F08170B5A54D686890F818 -:10EDA000501004292ED005291CBF0C2070BD90F8EE -:10EDB0007D100026002990F883104FEA511124D0CD -:10EDC000002908BF012407D0012908BF022403D06D -:10EDD000022914BF00240824C06D00281CBF002095 -:10EDE00000F05CFF6868806DF9F708FE686890F8CD -:10EDF0004010022943D0032904BF90F86C10012968 -:10EE000041D04DE0FFF784FD52E0002908BF012406 -:10EE100007D0012908BF022403D0022914BF00240F -:10EE20000824C06D00281CBF002000F037FF686870 -:10EE3000806DF9F7E3FD686890F84010022906D06C -:10EE4000032904BF90F86C10012904D010E090F859 -:10EE50006C1002290CD1224614F00C0F04D090F84B -:10EE60004C00012808BF042201210020F9F7A1FE6F -:10EE70006868072180F8804080F8616016E090F8AB -:10EE80006C1002290CD1224614F00C0F04D090F81B -:10EE90004C00012808BF042201210020F9F789FE57 -:10EEA0006868082180F8804080F8616080F8501020 -:10EEB000002070BD5E49002210F0010F496802D0A9 -:10EEC000012281F8842010F0080F03D0114408209B -:10EED00081F88400002070475549496881F848004E -:10EEE000704710B5524C636893F83030022B14BF52 -:10EEF000032B00280BD100291ABF02290120002072 -:10EF00001146FEF7F8FC08281CBF012010BD606800 -:10EF100090F83000002816BF022800200120BDE82C -:10EF20001040FAF731BB4248406890F830000028A2 -:10EF300016BF022800200120FAF726BB3C49496889 -:10EF400081F8300070473A49496881F84A007047B3 -:10EF500070B5374C616891F83000002816BF022860 -:10EF60000020012081F8310001F13201FAF7F6FAB0 -:10EF7000606890F83010022916BF03290121002192 -:10EF800080F8511090F8312000F132034FF0000565 -:10EF9000012A04BF5B7913F0C00F0AD000F13203DD -:10EFA000012A04D15A7902F0C002402A01D000227D -:10EFB00000E0012280F84920002A04BF002970BD2A -:10EFC0008567F7F7D1F86168486491F85100002827 -:10EFD0001CBF0020FEF7A9FD0026606890F84A10CB -:10EFE00000291ABF90F84910002970BD90F831200F -:10EFF00000F13201012A04D1497901F0C001402910 -:10F0000005D02946BDE870403230FAF735BBFEF72F -:10F01000BDFD61683246BDE870403231FAF7F4BA9E -:10F020004063020046630200ABAAAAAA40420F0056 -:10F030007401002070B5FF4D0C4600280CBF012361 -:10F040000023696881F8393081F842004FF00800E8 -:10F0500081F856000CD1002C1ABF022C0120002090 -:10F060001146FEF748FC6968082881F8560001D06F -:10F07000002070BD022C14BF032C1220F8D170BDEB -:10F08000002818BF112070470328EA4A526808BFB9 -:10F09000D16382F840000020704710B5E54C6068ED -:10F0A00090F8401003291CBF002180F8601001D0A7 -:10F0B000002010BD0123C16B1A460020F2F738F87A -:10F0C0006168CA6B526A904294BF0120002081F8A7 -:10F0D0006000EDE7D748416891F84000032804D06C -:10F0E000012818BF022807D004E091F84200012847 -:10F0F00008BF70470020704791F84100012814BFF5 -:10F1000003280120F6D1704770B5F9F7F7FCF9F73D -:10F11000D6FCF9F79FFBF9F74BFCC64C002560685D -:10F1200090F8520030B1F9F7FFFCF8F7EEFD606897 -:10F1300080F8525060680121A0F8815080F8835017 -:10F1400080F8501080F82850002070BDB94810B5E4 -:10F150004068643006F0B1FB002010BDB5480121C5 -:10F16000406890F84020032A03BF80F82A10C26B41 -:10F170001288002218BF80F82A20828580F8281083 -:10F180007047AC49496881F88600704701780023D0 -:10F1900011F0010FA749496809D04278032A08BF36 -:10F1A000CB6381F84020012281F884201346027845 -:10F1B00012F0040F0CD082784FF0000C032A08BF25 -:10F1C000C1F83CC081F840200B44082283F8842019 -:10F1D000C27881F830200279002A16BF022A012362 -:10F1E000002381F8393081F84120427981F83820B4 -:10F1F000807981F848004FF0000070478D484068E2 -:10F200008030704770B58B4C06460D46606890F8AC -:10F210005000032818BFFFDF022E1EBF032EFFDFA2 -:10F2200070BD002D18BF06F0A1F900216068A0F89C -:10F23000811080F88310012180F8501070BD00F01B -:10F24000D5BC2DE9F0477B4C0646894660684FF0F7 -:10F250000108072E90F8397038BF032540D3082ED7 -:10F2600084BF0020BDE8F08790F85010062908BF41 -:10F27000002105D090F8501008290CBF022101216F -:10F2800090F8800005F0AEFF002873D1A068C17827 -:10F2900011F03F0F12D0027912F0010F0ED0616809 -:10F2A0004FF0050591F85220002A18BFB9F1000F60 -:10F2B00016D091F88010012909D011E011F03F0F0C -:10F2C0001ABF007910F0100F002F53D14CE04FF00F -:10F2D00001024FF00501FEF74CFB616881F8520016 -:10F2E000A16808782944C0F3801030B1487900F053 -:10F2F000C000402808BF012000D00020616891F8BC -:10F300005210002918BF002807D0FEF74DFB014618 -:10F31000606880F8531080F86180606890F853103E -:10F32000FF292AD080F854100846FEF74AFB40EA2D -:10F330000705606890F85320FF2A18BF002D10D0F1 -:10F34000072E0ED3A068C17811F03F0F09D00179C4 -:10F3500011F0020F05D00B21FEF7BDFB606880F8AD -:10F3600062802846BDE8F087FEF75FF9002808BFF5 -:10F37000BDE8F0870120BDE8F087A36890F8392048 -:10F3800059191B78C3F3801C00F153036046FEF744 -:10F3900096F90546CDE72DE9F043264C87B0A068E5 -:10F3A000FEF7E0FE7F264FF00108002558B1022746 -:10F3B00001287DD0022800F0EF80F9F74BFA07B062 -:10F3C0000620BDE8F083F9F745FA616891F840003E -:10F3D000032800F01581A068C27812F03F0F05D015 -:10F3E000037913F0100F18BF012700D10027002F59 -:10F3F00014BF0823012312F03F0F00F001810079B0 -:10F4000033EA000240F0FC8010F0020F08D091F8BF -:10F410008000002105F064FE002808BF012000D014 -:10F4200000208DF80C508DF810508DF814504FF0CE -:10F43000FF0801E074010020D0B105AA03A904A8C7 -:10F4400000F07AFC606890F831809DF80C0000288C -:10F4500018BF48F002080BD1A068FEF7DBFC81461C -:10F460000121A068FEF732FD4946F8F79AFF28B35C -:10F47000FFB1012000F0DDFB002852D020787F286A -:10F4800008BFFFDF94F900102670606890F85420E0 -:10F49000CDE90021029590F8733090F8802000F1BA -:10F4A0003201404605F0BEFE606880F86C50A3E073 -:10F4B00038E041460020FFF7FEF9A1E0606890F8CF -:10F4C0004100032818BF02282BD19DF81000002806 -:10F4D00027D09DF80C00002823D1F7B1012000F0BF -:10F4E000A8FB00281DD020787F2808BFFFDF94F9F3 -:10F4F00000102670606890F85420CDE90021029534 -:10F5000090F8733090F8802000F13201FE2005F071 -:10F5100089FE606880F86C506EE0FE210020FFF7E5 -:10F52000CAF96DE0F9F796F9A0681821C27812F0CF -:10F530003F0F65D00279914362D10421FEF7C6FCEA -:10F54000616891F84020032A01BF8078B7EB501F13 -:10F5500091F86000002853D04FF0010000F069FBE3 -:10F56000E8B320787F2808BFFFDF94F900102670E9 -:10F57000606890F85420CDE90021029590F873302E -:10F5800090F8802000F13201FF2005F04BFE60680A -:10F5900080F86C8030E000BFF9F75CF9606890F8A3 -:10F5A000400003282CD0A0681821C27812F03F0F29 -:10F5B00026D0007931EA000022D1012000F039FB89 -:10F5C00068B120787F2808BFFFDF94F9001026700B -:10F5D000606890F85420CDE90021029500E00FE02A -:10F5E00090F8733090F8802000F13201FF2005F090 -:10F5F00019FE606880F86C7007B00320BDE8F083E6 -:10F6000007B00620BDE8F083F0B5FE4C074683B096 -:10F6100060686D460078002818BFFFDF002661682B -:10F620008E70C86B02888A8042884A8382888A8367 -:10F63000C088C88381F8206047B10121A068FEF727 -:10F6400045FC0546A0680078C10907E06946A06846 -:10F65000FEF7B5FBA0680078C0F380116068012751 -:10F6600090F85120002A18BF002904D06A7902F0CE -:10F67000C002402A26D090F84A20002A18BF00294C -:10F6800003D0697911F0C00F1CD000F10E00E3F730 -:10F69000B3FC616891F85400FF2819D001F1080209 -:10F6A000C91DFEF743F9002808BFFFDF6068C17974 -:10F6B00041F00201C171D0F86D104161B0F87110D4 -:10F6C00001830FE02968C0F80E10A9884182E0E7A5 -:10F6D000C86B427ECA71D0F81A208A60C08B8881BC -:10F6E0004E610E8360680770C26B90F84B1082F811 -:10F6F0006710C06B0088F4F70AFDF4F7A3F903B0B4 -:10F70000F0BD2DE9F041BF4C0546002760684FF081 -:10F7100001083E4690F84000012818BF022802D098 -:10F72000032818BFFFDF5DB1A068FEF727FC18B9FA -:10F73000A068FEF77AFC18B100F08FFB074645E0A1 -:10F74000606890F850007F25801F06283ED2DFE8D1 -:10F7500000F003191924352FAA48F9F709FA0028EF -:10F7600008BF2570F9F7EBF9606890F8520030B1E6 -:10F77000F9F7DAF9F8F7C9FA606880F85260F9F732 -:10F7800069F830E09F48F9F7F3F9002808BF2570C1 -:10F79000F9F7D5F905F0EAFEC3E09A48F9F7E8F978 -:10F7A000002808BF2570F9F7CAF9F9F753F81AE0ED -:10F7B0009448F9F7DDF930B9257004E09148F9F77C -:10F7C000D7F90028F8D0F9F7BAF9AAE0102F80F09D -:10F7D0003881DFE807F01E9DA6AAF1F108B3F2F127 -:10F7E000F1F10C832051BDE8F041FFF791B80320FF -:10F7F00002F020F9002870D000210320FFF710F953 -:10F80000012211461046F9F7D4F961680C2081F8FD -:10F810005000BDE8F081606800F15005042002F05E -:10F8200009F900287DD00E202870012002F0FDFC8F -:10F83000A06861680078C0F3401081F8750000216D -:10F840000520FFF7EDF87048A1684FF0200CC26B5F -:10F850000B78527B23F020030CEA42121A430A7001 -:10F86000C16B95F825304A7B1A404A73C06B28213A -:10F8700080F86610BDE8F081062002F0DBF8002871 -:10F880004FD0614D0F2085F85000022002F0CDFCD2 -:10F890006068012190F880200846F9F78AF9A0688D -:10F8A00061680078C0F3401081F8750001210520DF -:10F8B000FFF7B6F8E86B80F80D80A068017821F0BA -:10F8C00020010170F9F75DFD002818BFFFDF282037 -:10F8D000E96B81F86600BDE8F08122E0052002F0C6 -:10F8E000A9F8F0B101210320FFF79AF8F9F749FDD3 -:10F8F000002818BFFFDF6068012190F880200846CB -:10F90000F9F757F961680D2081F85000BDE8F081E2 -:10F910006068A0F8816080F8836080F85080BDE85E -:10F92000F081BDE8F04100F061B96168032081F821 -:10F930005000BDE8F041082002F077BC606890F804 -:10F940008310490908BF012507D0012908BF0225F6 -:10F9500003D0022914BF00250825C06D00281CBF54 -:10F96000002000F09BF96068806DF9F747F8606847 -:10F9700090F84010022906D0032904BF90F86C10BB -:10F98000012904D010E090F86C1002290CD12A460D -:10F9900015F00C0F04D090F84C00012808BF042289 -:10F9A00001210020F9F705F96068072180F88050EF -:10F9B00080F8616041E000E043E0606890F8831007 -:10F9C000490908BF012507D0012908BF022503D036 -:10F9D000022914BF00250825C06D00281CBF002087 -:10F9E00000F05CF96068806DF9F708F8606890F8DD -:10F9F000401002290AD0032904BF90F86C10012995 -:10FA000008D014E0740100204411002090F86C101C -:10FA100002290CD12A4615F00C0F04D090F84C00A6 -:10FA2000012808BF042201210020F9F7C2F860680C -:10FA3000082180F8805080F8616080F85010BDE89F -:10FA4000F081FFDFBDE8F08170B5FE4C606890F892 -:10FA5000503000210C2B38D001220D2B40D00E2B22 -:10FA600055D00F2B1CBFFFDF70BD042002F0DDFB63 -:10FA7000606890F880100E20F8F7E3FB606890F85B -:10FA8000800010F00C0F14BF282100219620F8F7F9 -:10FA9000D3FFF9F75EF86068052190F88050A06800 -:10FAA000FEF727F8616881F8520048B115F00C0F95 -:10FAB0000CBF50255525F8F714F92846F9F72AF810 -:10FAC00061680B2081F8500070BDF9F742F8002101 -:10FAD0009620F8F7B1FF6168092081F8500070BDE9 -:10FAE00090F88010FF20F8F7ACFB606890F8800079 -:10FAF00010F00C0F14BF282100219620F8F79CFF6E -:10FB0000F9F727F861680A2081F8500070BDA0F865 -:10FB1000811080F8831080F850200020FFF774FDDA -:10FB2000BDE87040032002F080BB70B5C54C606832 -:10FB300090F850007F25801F062828BF70BDDFE8A1 -:10FB400000F0171F1D032A11BE48F9F711F800280D -:10FB500008BF2570F8F7F3FFF8F77CFEBDE87040AA -:10FB6000FEF7D6BEB748F9F703F8C8B9257017E015 -:10FB7000B448F8F7FDFF40B9257006E005F0F6FC43 -:10FB8000B048F8F7F5FF0028F6D0F8F7D8FFBDE841 -:10FB9000704000F02BB8AB48F8F7EAFF0028E5D03A -:10FBA000F8F7CDFF60680021643005F037FEBDE84E -:10FBB000704000F01BB870B5A24C06460D460129F6 -:10FBC00008D0606890F880203046BDE87040134649 -:10FBD00002F077BBF8F75CFA61680346304691F8AB -:10FBE00080202946BDE8704002F06BBB70B5F8F785 -:10FBF00085FFF8F764FFF8F72DFEF8F7D9FE914C72 -:10FC00000025606890F8520030B1F8F78DFFF8F7E2 -:10FC10007CF8606880F852506068022180F85010CB -:10FC2000A0F8815080F88350BDE87040002002F0B9 -:10FC3000FCBA70B5834D06460421A868FEF746F964 -:10FC4000044605F0C8FA002808BF70BD207800F00F -:10FC50003F00252814D2F8F761FA217811F0800FBF -:10FC60000CBF1E214FF49671B4F80120C2F30C02B0 -:10FC700012FB01F10A1AB2F5877F28BF814201D237 -:10FC8000002070BD68682188A0F88110A17880F8F4 -:10FC900083103046BDE8704001F0CCBE2DE9F04144 -:10FCA000684C0746606800F1810690F883004009BF -:10FCB00008BF012507D0012808BF022503D002286C -:10FCC00014BF00250825F8F78DFE307800F03F06B8 -:10FCD0003046F8F7DFFB606880F8736090F86C00DE -:10FCE00002280CBF4020FF202946F8F7AAFA27B1C6 -:10FCF00029460120F8F795FC05E060682A46C16DA9 -:10FD00000120F8F7E2FCF8F724FF0521A068FDF7D1 -:10FD1000F0FE6168002881F8520008BFBDE8F0815C -:10FD200015F00C0F0CBF50245524F7F7DAFF2046CE -:10FD3000BDE8F041F8F7EEBE2DE9F74F414C002544 -:10FD4000914660688A4690F8510000280CBF4FF039 -:10FD500001084FF00008A0680178CE090121FEF7E4 -:10FD6000B5F836B1407900F0C000402808BF012640 -:10FD700000D00026606890F85210002961D090F8F9 -:10FD800040104FF0000B032906D190F839100029DC -:10FD900018BF90F856700ED1A068C17811F03F0FCF -:10FDA0001CBF007910F0010F02D105F061F940B3DA -:10FDB000606890F85370FF2F18BF082F21D0384685 -:10FDC000FDF7D9FB002818BF4FF00108002E38D0EE -:10FDD000606890F8620030B1FDF7F1FD054660689B -:10FDE00080F862B02DE03846FDF791FD054601210F -:10FDF000A068FEF76BF801462846F9F7D3FB0546E5 -:10FE00001FE0F6B1606890F86100D0B9A068C178D1 -:10FE100011F03F0F05D0017911F0010F18BF0B2130 -:10FE200000D105210022FDF7A4FD616881F8520090 -:10FE300038B1FDF7B9FDFF2803D06168012581F8CD -:10FE4000530001E0740100208AF800500098067009 -:10FE500089F8008003B0BDE8F08F2DE9F04FFF4C2A -:10FE600087B00025606890F850002E46801F4FF044 -:10FE70007F08062880F0D581DFE800F00308088BB2 -:10FE8000FDDB00F0F8FB054600F0CCB9F348F8F7CD -:10FE90006FFE002808BF84F80080F8F750FEA068C5 -:10FEA000FDF782FF0546072861D1A068FEF75AF9E1 -:10FEB0000146606890F86C208A4258D190F8501042 -:10FEC000062908BF002005D090F8500008280CBF74 -:10FED0000220012005F08AF970B90321A068FDF71E -:10FEE000F5FF002843D001884078C1F30B010009D9 -:10FEF00005F07BFC00283AD000212846FFF7A1F945 -:10FF0000A0B38DF80C608DF808608DF8046062680D -:10FF1000FF2592F8500008280CBF02210121A0689B -:10FF2000C37813F03F0F1CBF007910F0020F12D0FE -:10FF300092F8800005F0D4F868B901AA03A902A8D4 -:10FF4000FFF7FAFE606890F831509DF80C00002829 -:10FF500018BF45F002052B469DF804209DF80810B7 -:10FF60009DF80C0000F0D5F9054603E0FFE705F029 -:10FF7000FDFA0225606890F85200002800F05281D6 -:10FF8000F8F7D2FDF7F7C1FE606880F8526000F024 -:10FF900049B9A068FDF708FF0646A1686068CA78FD -:10FFA00090F86D309A4221D10A7990F86E309A42D9 -:10FFB0001CD14A7990F86F309A4217D18A7990F81B -:10FFC00070309A4212D1CA7990F871309A420DD1AC -:10FFD0000A7A90F872309A4208D1097890F8740041 -:10FFE000C1F38011814208BF012500D00025F8F738 -:10FFF00031FC9A48F8F7BCFD002808BF84F800805F -:020000040002F8 -:10000000F8F79DFD042E11D185B120787F2808BF17 -:10001000FFDF94F9003084F80080606890F8732066 -:1000200090F87D1090F8540005F06EFB062500F066 -:10003000F9B802278948F8F79BFD002808BF84F823 -:100040000080F8F77CFDA068FDF7AEFE0546A068CD -:10005000FEF788F8082D08BF00287CD1A0684FF073 -:100060000301C27812F03F0F75D0007931EA000029 -:1000700071D1606800E095E000F1500890F8390017 -:10008000002814BF98F8066098F803604FF0000944 -:1000900098F8020078B1FDF787FC0546FF280AD0E2 -:1000A0000146A068401DFDF758FCB5420CBF4FF05B -:1000B00001094FF000090021A068FDF707FF0622A3 -:1000C00008F11D01EEF78CF940B9A068FDF795FE27 -:1000D00098F82410884208BF012000D0002059EA77 -:1000E00000095DD0606800F1320590F831A098F801 -:1000F000010038B13046FDF74BFD00281CBF054616 -:100100004FF0010A4FF00008A06801784FEAD11BB8 -:100110000121FDF7DBFEBBF1000F07D0407900F0B5 -:10012000C000402808BF4FF0010B01D04FF0000B7A -:100130000121A068FDF7CAFE06222946EEF750F914 -:1001400030B9A068FDF766FE504508BF012501D013 -:100150004FF0000500E023E03BEA050018BFFF2E4A -:100160000DD03046FDF7D3FB060008D00121A06872 -:10017000FDF7ACFE01463046F9F714FA804645EA31 -:10018000080019EA000F0BD060680121643005F007 -:1001900045FB01273846FFF737FA052002F045F8FE -:1001A0003D463FE002252D48F8F7E2FC002808BF55 -:1001B00084F80080F8F7C3FCA068FDF7F5FD06465B -:1001C000A068FDF7CFFF072E08BF00282AD1A0683E -:1001D0004FF00101C27812F03F0F23D00279914312 -:1001E00020D1616801F150060021FDF76FFE062263 -:1001F00006F11D01EEF7F4F8A0B9A068FDF7FDFDCA -:1002000096F8241088420DD160680121643005F011 -:1002100005FBFF21022000F009F8002818BF032584 -:1002200000E0FFDF07B02846BDE8F08F2DE9F0437E -:100230000A4C0F4601466068002683B090F87D2086 -:10024000002A35D090F8500008280CBF022501255F -:10025000A168C87810F03F0F02E000007401002090 -:10026000FD484FF000084FF07F0990F900001CBFD7 -:10027000097911F0100F22D07F2808BFFFDF94F911 -:10028000001084F80090606890F85420CDE90021B7 -:10029000029590F8733090F8802000F132013846D2 -:1002A00004F0C0FF05F0AAFA10B305F050F92CE0F5 -:1002B000002914BF0221012180F87D10C2E77F28A8 -:1002C00008BFFFDF94F9001084F80090606890F890 -:1002D0005420CDE90021029590F8733090F88020E9 -:1002E00000F13201384604F09DFF05F030F90CE0D2 -:1002F0000220FFF79EFC30B16068012680F86C8018 -:10030000F8F7A8FA01E005F031F903B03046BDE88E -:10031000F0832DE9F047D04C054684B09A46174645 -:100320000E46A068FDF71EFF4FF00109002800F0FF -:10033000CF804FF00208012808D0022800F00E817B -:1003400005F014F904B04046BDE8F087A068092123 -:10035000C27812F03F0F00F059810279914340F0CA -:100360005581616891F84010032906D012F0020F00 -:1003700008BFFF2118D05DB115E00021FDF7A6FDF3 -:1003800061680622C96B1A31EEF72AF848BB1EE0F5 -:10039000FDF740FD05460121A068FDF797FD2946C0 -:1003A000F7F7FFFF18B15146012000F051B960681E -:1003B00090F84100032818BF022840F02781002E42 -:1003C0001CBFFE21012040F0438100F01FB9A0684E -:1003D000FDF713FD6168C96B497E884208BF01269D -:1003E00000D00026A068C17811F03F0F05D0017938 -:1003F00011F0020F01D06DB338E0616891F842202E -:10040000012A01D096B11BE0D6B90021FDF75EFDAF -:1004100061680268C96BC1F81A208088C883A06827 -:10042000FDF7EBFC6168C96B487609E091F8530071 -:1004300091F85610884203D004B04046BDE8F087DA -:100440006068643005F02EFA002840D004B00F2018 -:10045000BDE8F08767B1FDF7DDFC05460121A06826 -:10046000FDF734FD2946F7F79CFF08B1012200E0B3 -:100470000022616891F84200012807D040B92EB9E6 -:1004800091F8533091F856108B4201D1012100E0D0 -:1004900000210A421BD0012808BF002E11D14FF0C5 -:1004A0000001A068FDF712FD61680268C96BC1F820 -:1004B0001A208088C883A068FDF79FFC6168C96B1B -:1004C00048766068643005F0EDF90028BED19DE003 -:1004D00060682F46554690F840104FF002080329F7 -:1004E000AAD0A168CA7812F03F0F1BBF097911F09A -:1004F000020F002201224FF0FF0A90F85010082945 -:100500000CBF0221012192B190F8800004F0E8FDB7 -:1005100068B95FB9A068FDF77DFC07460121A068B6 -:10052000FDF7D4FC3946F7F73CFF48B1AA465146DF -:100530000020FFF77BFE002818BF4FF003087BE781 -:10054000606890F84100032818BF02287FF474AF58 -:10055000002E18BF4FF0FE0AE9D16DE7616891F8EF -:100560004030032B52D0A0684FF0090CC27812F033 -:100570003F0F4BD002793CEA020C47D1022B06D048 -:1005800012F0020F08BFFF2161D0E5B35EE012F068 -:10059000020F4FF07F0801D04DB114E001F164006B -:1005A00005F080F980B320787F2842D013E067B34C -:1005B000FDF730FC05460121A068FDF787FC2946C0 -:1005C000F7F7EFFE08B36068643005F06BF9D8B157 -:1005D00020787F282DD094F9001084F8008060687E -:1005E00090F85420CDE90021CDF8089090F87330B0 -:1005F00090F8802000F13201504604F013FE0D20E7 -:1006000004B0BDE8F08716E000E001E00220F7E763 -:10061000606890F84100032818BF0228F6D1002E28 -:10062000F4D04FF0FE014FF00200FEF744F9022033 -:10063000E6E7FFDFCFE7FDF7EDFB05460121A06808 -:10064000FDF744FC2946F7F7ACFE38B151460220CD -:10065000FEF731F9DAE7000074010020606890F8D5 -:100660004100032818BF0228D0D1002E1CBFFE2154 -:100670000220EDD1CAE72DE9F84F4FF00008F74806 -:10068000F8F776FA7F27F54C002808BF2770F8F7AF -:1006900056FAA068FDF788FB81460121FEF7D1FDDF -:1006A000616891F88020012A14D0042A1CBF082A0E -:1006B000FFDF00F0D781606890F8520038B1F8F79A -:1006C00033FAF7F722FB6168002081F852004046B8 -:1006D000BDE8F88F0125E24EB9F1080F3AD2DFE804 -:1006E00009F03EC00439393914FC0546F8F7B2F870 -:1006F000002D72D0606890F84000012818BF0228D1 -:100700006BD120787F2869D122E018B391F840009E -:10071000022802D0012818D01CE020787F2808BFCA -:10072000FFDF94F90000277000906068FF2190F8C7 -:10073000733090F85420323004F02FFF61680020AD -:100740004FF00C0881F87D00B5E720787F2860D154 -:10075000FFDF5EE0F8F77EF84FF00608ABE74FF0FA -:100760000008002800F0508191F84000022836D09F -:1007700001284BD003289ED1A068CA6BC37892F899 -:100780001AC0634521D1037992F81BC063451CD17F -:10079000437992F81CC0634517D1837992F81DC044 -:1007A000634512D1C37992F81EC063450DD1037A17 -:1007B00092F81FC0634508D1037892F819C0C3F3BB -:1007C0008013634508BF012300D0002391F8421035 -:1007D00001292CD0C3B300F013B93FE019E0207811 -:1007E0007F2808BFFFDF94F9000027700090606841 -:1007F000FF2190F8733090F85420323004F0CDFE91 -:1008000060684FF00C0880F87D5054E720787F280E -:100810009ED094F90000277000906068FF2190F846 -:10082000733090F85420323004F0B7FE16E0002BFD -:100830007ED102F11A01FDF7C2FAA068FDF7DDFAD8 -:100840006168C96B4876DBE0FFE796F85600082838 -:1008500070D096F8531081426AD0D5E04FF0060868 -:1008600029E7054691F8510000280CBF4FF0010B15 -:100870004FF0000B4FF00008A06810F8092BD209C8 -:1008800007D0407900F0C000402808BF4FF0010AAF -:1008900001D04FF0000A91F84000032806D191F8EA -:1008A0003900002818BF91F8569001D191F8539063 -:1008B0004846FDF72CF80090D8B34846FCF75BFE9D -:1008C000002818BF4FF0010BBAF1000F37D0A06815 -:1008D000A14600F10901009800E0B6E0F8F762FED9 -:1008E0005FEA0008D9F8040090F8319018BF49F089 -:1008F0000209606890F84010032924D0F7F7AAFF96 -:10090000002DABD0F7F75DFD002808BFB8F1000F50 -:100910007DD020787F2808BFFFDF94F90000277082 -:1009200000906068494690F8733090F8542002E0D7 -:1009300066E004E068E0323004F02FFE8EE7606885 -:1009400090F83190D5E7A168C06BCA78837E9A424F -:100950001BD10A79C37E9A4217D14A79037F9A4202 -:1009600013D18A79437F9A420FD1CA79837F9A4201 -:100970000BD10A7AC37F9A4207D10978407EC1F32E -:100980008011814208BF012700D0002796F853004C -:10099000082806D096F85610884208BF4FF0010983 -:1009A00001D04FF00009B8F1000F05D1BBF1000FE5 -:1009B00004D0F7F706FD08B1012000E000204DB19A -:1009C00096F84210012903D021B957EA090101D054 -:1009D000012100E00021084216D0606890F8421022 -:1009E000012908BF002F0BD1C06B00F11A01A068CC -:1009F000FDF7E5F9A068FDF700FA6168C96B487674 -:100A00004FF00E0857E602E0F7F724FF26E760688C -:100A100090F84100032818BF02287FF41FAFBAF1F5 -:100A2000000F3FF41BAF20787F2808BFFFDF94F949 -:100A30000000277000906068FE2190F8733090F8F5 -:100A40005420323004F0A9FD08E791F8481000293D -:100A500018BF00283FF47EAE0BE0000074010020B8 -:100A600044110020B9F1070F7FF474AE00283FF461 -:100A700071AEFEF790FC80461DE60000D0F8001134 -:100A800049B1D0E941231A448B691A448A61D0E9FB -:100A90003F12D16003E0FE4AD0F8FC101162D0E9A9 -:100AA0003F1009B1086170470028FCD00021816126 -:100AB00070472DE9FF4F06460C46488883B040F248 -:100AC000E24148430190E08A002500FB01FA94F8D6 -:100AD0007C0090460D2822D00C2820D024281ED03F -:100AE00094F87D0024281AD000208346069818B177 -:100AF0000121204603F0C0F894F8641094F86500D2 -:100B0000009094F8F0200F464FF47A794AB1012A08 -:100B100061D0022A44D0032A5DD0FFDFB5E0012076 -:100B2000E3E7B8F1000F00D1FFDFD94814F8641FE4 -:100B3000243090F83400F0F7C4FC01902078F8F7E6 -:100B4000CFFB4D4600F2E730B0FBF5F1DFF8409304 -:100B5000D9F80C0001EB00082078F8F7C1FB01463A -:100B600014F86409022816D0012816D040F6340083 -:100B700008444AF2EF010844B0FBF5F10198D9F8B6 -:100B80001C20411A514402EB08000D18012084F882 -:100B9000F0002D1D78E02846EAE74FF4C860E7E74B -:100BA000DFF8EC92A8F10100D9F80810014300D158 -:100BB000FFDFB848B8F1000F016801EB0A0506D065 -:100BC000D9F8080000F22630A84200D9FFDF032040 -:100BD00084F8F00058E094F87C20019D242A05D088 -:100BE00094F87D30242B01D0252A3AD1B4F8702016 -:100BF000B4F81031D21A521C12B2002A31DB94F828 -:100C0000122172B3174694F8132102B110460090D6 -:100C1000022916D0012916D040F6340049F60852B0 -:100C20008118022F12D0012F12D040F63400104448 -:100C3000814210D9081A00F5FA70B0FBF9F00544AA -:100C40000FE04846EAE74FF4C860E7E74846EEE7BA -:100C50004FF4C860EBE7401A00F5FA70B0FBF9F00A -:100C60002D1AB8F1000F0FD0DFF82482D8F8080051 -:100C700018B9B8F8020000B1FFDFD8F8080000F298 -:100C80002630A84200D9FFDF05B9FFDF2946D4F896 -:100C9000F400F4F750FFC4F8F400B06000203070A6 -:100CA0004FF0010886F80480204603F040F8ABF1CD -:100CB0000101084202D186F8058005E094F8F000B1 -:100CC000012844D003207071606A3946009A01F00F -:100CD00042FBF060069830EA0B0035D029463046DA -:100CE000F0F7BAF987B2204603F021F8B8420FD8DE -:100CF000074686F8058005FB07F1D4F8F400F4F701 -:100D00001AFFB06029463046F0F7A6F9384487B29A -:100D10003946204602F0B0FFB068C4F8F400A06E77 -:100D2000002811D0B4F87000B4F89420801A01B2F1 -:100D3000002909DD34F86C0F0144491E91FBF0F1E4 -:100D400089B201FB0020208507B0BDE8F08F0220AA -:100D5000B9E72DE9F04106460C46012001F0DBFA27 -:100D6000C5B20B2001F0D7FAC0B2854200D0FFDF38 -:100D70000025082C7ED2DFE804F00461696965C6AD -:100D80008293304601F0DDFA0621F3F78FF8040074 -:100D900000D1FFDF304601F0D4FA2188884200D02C -:100DA000FFDF94F8F00000B9FFDF204602F00FFEED -:100DB000374E21460020B5607580F561FDF7E9FCEE -:100DC00000F19807606AB84217D994F86500F7F700 -:100DD0000BF9014694F864004FF47A72022828D087 -:100DE000012828D040F6340008444AF2473108442C -:100DF000B0FBF2F1606A0844C51B21460020356152 -:100E0000FDF7C7FC618840F2E24251439830081A6E -:100E1000A0F22630706194F8652094F86410606A3E -:100E200001F099FAA0F5CB70B061BDE8F041F5F79B -:100E300060BE1046D8E74FF4C860D5E7BDE8F04182 -:100E400002F02FBEBDE8F041F7F7D5BE304601F005 -:100E500078FA0621F3F72AF8040000D1FFDF3046C4 -:100E600001F06FFA2188884200D0FFDF01220021C3 -:100E7000204600E047E0BDE8F04101F089BAF7F70D -:100E800073FDF7F7B8FE02204FF0E02104E0000008 -:100E9000CC11002084010020C1F88002BDE8F0815F -:100EA000304601F04EFA0621F3F700F8040000D1B5 -:100EB000FFDF304601F045FA2188884200D0FFDF8D -:100EC00094F8F000042800D0FFDF84F8F05094F884 -:100ED000FA504FF6FF76202D00D3FFDFFA4820F8B6 -:100EE000156094F8FA00F5F720F900B9FFDF20202B -:100EF00084F8FA002046FFF7C1FDF4480078BDE809 -:100F0000F041E2F701B8FFDFC8E770B5EE4C00250D -:100F1000443C84F82850E07868B1E570FEF71EF98B -:100F20002078042803D0606AFFF7A8FD6562E748CF -:100F30000078E1F7E9FFBDE8704001F03ABA70B51A -:100F4000E14C0146443CE069F5F706FE6568A2788D -:100F500090FBF5F172B140F27122B5FBF2F292B260 -:100F6000A36B01FB02F6B34202D901FB123200E08F -:100F70000022A2634D43002800DAFFDF2946E06922 -:100F8000F4F7D9FDE06170BD2DE9F05FFEF736F9A9 -:100F90008246CD48683800F1240881684646D8F872 -:100FA0001800F4F7C8FD0146F069F5F7D5FD4FF0DC -:100FB0000009074686F835903C4640F28F254E469C -:100FC0001EE000BF0AEB06000079F7F70DF80146B6 -:100FD0004AF2B12001444FF47A70B1FBF0F008EB13 -:100FE0008602414692681044844207D3241A91F83D -:100FF0003500A4F28F24401C88F83500761CF6B228 -:1010000098F83600B042DDD8002C10DD98F8351085 -:10101000404608EB81018968A14208D24168C91B9A -:10102000B1F5247F00D30D466C4288F8359098F8CE -:101030003560C3460AEB060898F80400F6F7D4FFBB -:101040004AF2B12101444FF47A7AB1FBFAF298F8EE -:101050000410082909D0042909D0002013180429F4 -:101060000AD0082908D0252207E0082000E0022045 -:1010700000EB40002830F1E70F22521D4FF4A8701A -:10108000082914D0042915D0022916D04FF0080CD5 -:101090005FF0280012FB0C00184462190BEB86036A -:1010A00010449A68D84690420BD8791925E04FF041 -:1010B000400CEFE74FF0100CECE74FF0040C182059 -:1010C000E8E798F8352098F836604046B24210D2EA -:1010D000521C88F835203C1B986862198418084611 -:1010E000F6F782FF4AF2B1210144B1FBFAF001198F -:1010F00003E080F83590D8F80410D8F81C00BDE85B -:10110000F05FF4F718BD2DE9FE4F14460546FEF7D3 -:1011100075F8DFF8B4A10290AAF1440A50469AF893 -:1011200035604FF0000B0AEB86018968CAF83C1065 -:10113000F4B3044600780027042825D005283ED0C3 -:10114000FFDFA04639466069F4F7F5FC0746F5F77E -:101150000BF881463946D8F80440F5F7FDFC401EEF -:1011600090FBF4F0C14361433846F4F7E4FC0146D8 -:10117000C8F81C004846F5F7EFFC002800DDFFDF4B -:10118000012188F813108DE0D4F81490D4F804806D -:1011900001F07AF9070010D0387800B9FFDF7969DB -:1011A00078684A460844414601F05AF9074600E08B -:1011B0000BE04045C5D9FFDFC3E75F46C1E7606A82 -:1011C00001F004F940F6B837BBE7C1690AEB460005 -:1011D0000191408D10B35446DAF81400FFF7AFFECA -:1011E0006168E069F4F7A7FC074684F835B0019C14 -:1011F000D0462046DAF81410F5F7AEFC81463946A1 -:101200002046F5F7A9FCD8F804200146B9FBF2F016 -:10121000B1FBF2F1884242D0012041E0F4F7A4FF93 -:10122000FFF78DFEFFF7B0FE9AF83510DAF804905C -:101230000AEB81010746896800913946DAF81C00FB -:10124000F5F78AFC00248046484504DB98FBF9F456 -:1012500004FB09F41AE0002052469AF8351007E022 -:1012600002EB800304F28F249B68401C1C44C0B234 -:101270008142F5D851B10120F6F7B6FE4AF2B1210C -:1012800001444FF47A70B1FBF0F004440099A8EBEC -:1012900004000C1A00D5FFDFCAF83C40A7E7002085 -:1012A00088F813009AF802005446B8B13946E0694C -:1012B000F5F752FC0146A26B40F2712042438A428C -:1012C00006D2C4F83CB009E03412002080010020AE -:1012D000E06B511A884200D30846E063AF6085F89E -:1012E00000B001202871029F94F835003F1DC05DB9 -:1012F000F6F77AFE4AF23B5101444FF47A70B1FBA3 -:10130000F0F0E16BFE300844E8602078042808D152 -:1013100094F8350004EB4000408D0A2801D20320E8 -:1013200000E00220687104EB4600408DC0B1284601 -:101330006168EFF791FE82B20020761C0CE000BFDE -:1013400004EB4001B0424B8D13449BB24B8501D35B -:101350005B1C4B85401CC0B294F836108142EFD222 -:10136000A8686061A06194F8350004EB4001488DE5 -:10137000401C488594F83500C05D082803D0042837 -:1013800003D000210BE0082100E0022101EB410124 -:1013900028314FF4A872082804D0042802D002286B -:1013A00007D028220A44042805D0082803D0252184 -:1013B00002E01822F6E70F21491D08280CD0042866 -:1013C0000CD002280CD0082011FB0020E16B8842D1 -:1013D00008D20120BDE8FE8F4020F5E71020F3E79A -:1013E0000420F1E70020F5E770B5FE4C061D14F867 -:1013F000352F905DF6F7F8FD4FF47A7100F2E73083 -:10140000B0FBF1F0D4F8071045182078805DF6F7AE -:1014100073FE2178895D082903D0042903D00022B6 -:101420000BE0082200E0022202EB420228324FF4D5 -:10143000A873082904D0042902D0022907D0282340 -:101440001344042905D0082903D0252202E01823DB -:10145000F6E70F22521D08290AD004290AD00229D2 -:101460000AD0082112FB0131081A281A293070BD50 -:101470004021F7E71021F5E70421F3E72DE9FF41CB -:1014800007460C46012000F046FFC5B20B2000F0D5 -:1014900042FFC0B2854200D0FFDF20460126002572 -:1014A000D04C082869D2DFE800F004304646426894 -:1014B0006865667426746078002819D1FDF79EFE71 -:1014C000009594F835108DF808104188C90411D0A2 -:1014D000206C019003208DF80900C24824388560F3 -:1014E000C56125746846FDF768FB002800D0FFDF62 -:1014F000BDE8FF81FFF778FF0190E07C10B18DF827 -:101500000950EAE78DF80960E7E7607840B1207C90 -:1015100008B9FDF7F9FD6574BDE8FF41F4F72FBD8B -:10152000A674FDF739FC0028E2D0FFDFE0E7BDE854 -:10153000FF41F7F760BBFDF761FE4088C00407D0AC -:1015400001210320FDF75EFEA7480078E1F7DCFCEF -:10155000002239466846FFF7D6FD38B1694638465D -:1015600000F0EDFE0028C3D1FFDFC1E7E670FFF712 -:10157000CCFCBDE7BDE8FF41C7E4FFDFB8E7994910 -:1015800050B101228A704A6840F27123B2FBF3F233 -:1015900002EB0010886370470020887070472DE9C7 -:1015A000F05F894640F271218E4E48430025044683 -:1015B000706090462F46D0074AF2B12A4FF47A7BEA -:1015C0000FD0B9F800004843B0600120F6F70CFDD9 -:1015D00000EB0A01B1FBFBF0241AB7680125A4F265 -:1015E0008F245FEA087016D539F8151040F2712083 -:1015F000414306EB85080820C8F80810F6F7F4FC0C -:1016000000EB0A01B1FBFBF0241AD8F80800A4F2A1 -:101610008F2407446D1CA74219D9002D17D0391B00 -:10162000B1FBF5F0B268101AB1FBF5F205FB12122E -:10163000801AB060012008E0B1FBF5F306EB8002F0 -:101640009468E31A401CC0B29360A842F4D3BDE88A -:10165000F09F2DE9F041634C00262078042804D047 -:101660002078052801D00C2018E401206070607CEF -:10167000002538B1EFF3108010F0010F72B610D0D2 -:1016800001270FE0FDF7BAFD074694F82000F5F7B3 -:10169000B2F87888C00411D000210320FDF7B2FD14 -:1016A0000CE00027607C38B1A07C28B1FDF72CFD50 -:1016B0006574A574F4F763FC07B962B694F820006A -:1016C000F5F705FB94F8280030B184F8285020780D -:1016D000052800D0FFDF0C26657000F06AFE30465A -:1016E00012E4404810B5007808B1FFF7B2FF00F0EF -:1016F000D4FE3C4900202439086210BD10B53A4C94 -:1017000058B1012807D0FFDFA06841F66A0188427E -:1017100000D3FFDF10BD40F6C410A060F4E73249EB -:1017200008B508702F4900200870487081F828001B -:10173000C8700874487488742022486281F8202098 -:10174000243948704FF6FF7211F1680121F810201A -:10175000401CC0B22028F9D30020FFF7CFFFFFF7CD -:10176000C0FF1020ADF80000012269460420FFF7F9 -:1017700016FF08BD7FB51B4C05460E46207810B1FC -:101780000C2004B070BD95F8652095F86410686A67 -:1017900000F0C5FEC5F80401656295F8F00000B1DF -:1017A000FFDF104900202439C861052121706070D5 -:1017B00084F82800014604E004EB4102491C5085EE -:1017C000C9B294F836208A42F6D284F83500304601 -:1017D000FFF7D5FE0548F4F74DFC84F820002028DB -:1017E00007D105E0F0110020800100207D140200E7 -:1017F000FFDFF4F7B9FC606194F82010012268461D -:10180000FFF781FC00B9FFDF94F82000694600F083 -:1018100096FD00B9FFDF0020B3E7F94810B5007866 -:1018200008B1002010BD0620F2F7DAFA80F00100BE -:1018300010BDF8B5F24D0446287800B1FFDF002056 -:10184000009023780246DE0701466B4605D060888B -:10185000A188ADF80010012211462678760706D53A -:10186000E088248923F8114042F00802491C491EEF -:1018700085F836101946FFF792FE0020F8BD1FB517 -:1018800011B1112004B010BDDD4C217809B10C203C -:10189000F8E70022627004212170114605E000BFC4 -:1018A00004EB4103491C5A85C9B294F836308B4287 -:1018B000F6D284F83520FFF762FED248F4F7DAFB5F -:1018C00084F82000202800D1FFDF00F0DDFD10B1FA -:1018D000F4F74AFC05E0F4F747FC40F6B831F4F7BA -:1018E0002AF9606194F8201001226846FFF70BFC8A -:1018F00000B9FFDF94F82000694600F020FD00B930 -:10190000FFDF0020BEE770B5BD4C616A0160FFF7E4 -:10191000A0FE050002D1606AFFF7B0F80020606207 -:10192000284670BD7FB5B64C2178052901D00C2022 -:1019300027E7B3492439C860606A00B9FFDF606AED -:1019400090F8F00000B1FFDF606A90F8FA002028FC -:1019500000D0FFDFAC48F4F78DFB616A0546202814 -:1019600081F8FA000E8800D3FFDFA548443020F844 -:101970001560606A90F8FA00202800D1FFDF00238C -:1019800001226846616AFFF794F8606A694690F838 -:10199000FA0000F0D4FC00B9FFDF00206062F0E63E -:1019A000974924394870704710B540F2E24300FB74 -:1019B00003F4002000F0B3FD844201D9201A10BDC9 -:1019C000002010BD70B50D46064601460020FCF70C -:1019D000E0FE044696F86500F6F706FB014696F829 -:1019E00064004FF47A72022815D0012815D040F611 -:1019F000340008444AF247310844B0FBF2F17088E1 -:101A000040F271225043C1EB4000A0F22630A542C3 -:101A100006D2214605E01046EBE74FF4C860E8E740 -:101A20002946814204D2A54201D2204600E0284640 -:101A3000706270BD70B50546FDF7E0FB7049007837 -:101A400024398C689834072D30D2DFE805F004344F -:101A500034252C34340014214FF4A873042810D0FA -:101A60000822082809D02A2102280FD011FB0240A1 -:101A700000222823D118441819E0402211FB02400B -:101A8000F8E7102211FB02402E22F3E7042211FB9B -:101A9000024000221823EDE7282100F04BFC04440B -:101AA00004F5317403E004F5B07400E0FFDF54483E -:101AB000C06BA04201D9012070BD002070BD70B57F -:101AC0004F4C243C607870B1D4E904512846A26898 -:101AD000EFF7EDFA2061A84205D0A169401B084448 -:101AE000A061F5F706F82169A068884201D820783E -:101AF00008B1002070BD012070BD2DE9F04F0546F2 -:101B000085B016460F461C461846F6F7F5FA05EB63 -:101B100047014718204600F0F5FB4AF2C5714FF423 -:101B20007A7908444D46B0FBF5F0384400F160087E -:101B30003348761C24388068304404902046F6F7F9 -:101B4000DBFAA8EB0007204600F0DCFB0646204647 -:101B5000F6F74AFA301AB0FBF5F03A1A18252820A1 -:101B60004FF4C8764FF4BF774FF0020B082C30D0FB -:101B7000042C2BD00021022C2ED0082311F1280197 -:101B800003EB830C0CEB831319440A444FF0000A57 -:101B9000082C29D0042C22D00021022C29D0054663 -:101BA000082001F5B07100BF00EB0010284481420D -:101BB00032D2082C2AD0042C1ED00020022C28D08F -:101BC0000821283001EB0111084434E03946102384 -:101BD000D6E731464023D3E704231831D0E73D460A -:101BE00040F2EE311020DFE735464FF435614020FA -:101BF000DAE70420B431D7E738461021E2E70000E5 -:101C0000F01100207D140200530D020030464021E7 -:101C1000D8E704211830D5E7082C4FD0042C4AD03F -:101C20000021022C4DD0082311F12801C3EBC30081 -:101C300000EB4310084415182821204600F07AFBD9 -:101C400005EB4001082C42D0042C3DD00026022C8C -:101C50003FD0082016F1280600EB801006EB80002C -:101C60000E180120FA4D8DF804008DF800A08DF8B3 -:101C700005B0A86906F22A260499F3F75CFFCDE9BE -:101C800002062046F6F7B0F94AF23B510144B1FB97 -:101C9000F9F0301AFE38E8630298C5F84080A86170 -:101CA00095F82000694600F04AFB002800D1FFDFCC -:101CB00005B0BDE8F08F39461023B7E73146402321 -:101CC000B4E704231831B1E73E461020C4E74020B2 -:101CD000C2E704201836BFE72DE9FE4F06461C4632 -:101CE000174688464FF0010A1846F6F705FAD84D10 -:101CF000243DA9688A1907EB48011144471820467A -:101D000000F000FB4FF47A7BD84600F6FB00B0FBF6 -:101D1000F8F0384400F120092046F6F7EDF9A968FB -:101D20000246A9EB0100801B871A204600F0EAFA60 -:101D300005462046F6F758F9281AB0FBF8F03A1A8B -:101D4000182528204FF4C8774FF4BF78082C2DD0E1 -:101D5000042C28D00021022C2BD0082311F12801BB -:101D600003EB830C0CEB831319440A44082C28D092 -:101D7000042C21D00021022C28D00546082001F592 -:101D8000B07100BF00EB0010284481422AD2082C19 -:101D900022D0042C1DD00020022C20D00821283075 -:101DA00001EB01112CE041461023D9E739464023CD -:101DB000D6E704231831D3E7454640F2EE31102030 -:101DC000E0E73D464FF435614020DBE70420B431C5 -:101DD000D8E740461021E3E738464021E0E70421F8 -:101DE0001830DDE7082C48D0042C43D00020022C0A -:101DF00046D0082110F12800C1EBC10303EB4111CB -:101E0000084415182821204600F094FA05EB4001FB -:101E1000082C3BD0042C36D00027022C38D00820C8 -:101E200017F1280700EB801007EB80000C1804F571 -:101E300096740C98F6F7D8F84AF23B510144B1FB7E -:101E4000FBF0834DFE30A5F12407E96B06F1FE029D -:101E50000844B9680B191A44824224D93219114432 -:101E60000C1AFE342044B0F1807F37D2642C12D299 -:101E7000642011E040461021BEE738464021BBE710 -:101E800004211830B8E747461020CBE74020C9E7C7 -:101E900004201837C6E720460421F4F790FEE8B185 -:101EA000E86B2044E863E0F703FFB9682938314460 -:101EB0000844CDE9000995F835008DF808000220A6 -:101EC0008DF809006846FCF778FE00B1FFDFFCF7EB -:101ED00063FF00B1FFDF5046BDE8FE8F4FF0000A00 -:101EE000F9E71FB500F021FB594C607880B994F8F0 -:101EF000201000226846FFF706F938B194F8200058 -:101F0000694600F01CFA18B9FFDF01E00120E0701B -:101F1000F4F735F800206074A0741FBD2DE9F84F68 -:101F2000FDF76CF90646451CC07840090CD0012825 -:101F30000CD002280CD000202978824608064FF4E5 -:101F4000967407D41E2006E00120F5E70220F3E78F -:101F50000820F1E72046B5F80120C2F30C0212FB7D -:101F600000F7C80901D010B103E01E2401E0FFDF33 -:101F70000024F6F7D3F8A7EB00092878B77909EB26 -:101F80000408C0F3801010B120B1322504E04FF4F2 -:101F9000FA7501E0FFDF00250C2F00D3FFDF2D488D -:101FA0002D4A30F81700291801FB0821501CB1FBFD -:101FB000F0F5F6F76DF8F6F717F84FF47A7100F2CE -:101FC0007160B0FBF1F1A9EB0100471BA7F15900CB -:101FD000103FB0F5247F11D31D4E717829B9024608 -:101FE000534629462046FFF788FD00F09EFAF3F796 -:101FF000C6FF00207074B074BDE8F88F3078009090 -:102000005346224629463846FFF766FE0028F3D19C -:1020100001210220FDF7F6F8BDE8F84F61E710B5A1 -:102020000446012903D10A482438007830B104203D -:1020300084F8F000BDE81040F3F7A1BF00220121B1 -:10204000204600F0A5F934F8700F401C2080F1E71D -:10205000F0110020646302003F420F002DE9F041BF -:102060000746FDF7CBF8050000D1FFDF287810F018 -:102070000C0F01D0012100E00021F74C606A3030E4 -:10208000FCF7C7FA29783846EFF71BFAA4F12406C3 -:102090000146A069B26802446FB32878082803D0CB -:1020A000042803D000230BE0082300E0022303EB05 -:1020B000430328334FF4A877082804D0042802D01B -:1020C000022810D028273B4408280ED004280ED020 -:1020D00002280ED05FF00800C0EBC00707EB4010ED -:1020E0001844983009E01827EDE74020F4E7102065 -:1020F000F2E70420F0E74FF4FC701044471828780A -:102100003F1DF5F771FF014628784FF47A720228D7 -:102110001DD001281DD040F6340008444AF2EF01DA -:102120000844B0FBF2F03A1A606A40F2E241B0466D -:102130004788F0304F43316A81420DD03946206BD9 -:1021400000F08EF90646B84207D9FFDF05E01046D9 -:10215000E3E74FF4C860E0E70026C04880688642A5 -:1021600007D2616A40F271224888424306EB420678 -:1021700004E040F2E240B6FBF0F0616AC882606AB7 -:10218000297880F86410297880F865100521417558 -:10219000C08A6FF41C71484306EB400040F635419D -:1021A000C8F81C00B0EB410F00D3FFDFBDE8F081A1 -:1021B00010B5052937D2DFE801F00509030D31001C -:1021C000002100E00121BDE8104028E7032180F84C -:1021D000F01010BD0446408840F2E24148439F4958 -:1021E000091D0860D4F818010089E082D4F81801AC -:1021F00080796075D4F8180140896080D4F818019E -:102200008089A080D4F81801C089E0802046A16AA6 -:10221000FFF7D8FB022084F8F00010BD816ABDE80A -:102220001040FFF7CFBBFFDF10BD70B58A4C243CD8 -:102230000928A1683FD2DFE800F0050B0B15131544 -:1022400038380800BDE870404BE6BDE8704065E6F0 -:10225000022803D00020BDE87040FFE60120FAE725 -:10226000E16070BD032802D005281CD000E0E160C9 -:102270005FF0000600F059F9774D012085F828003D -:1022800085F83460686AA9690026C0F8F41080F8FF -:10229000F060E068FFF746FB00B1FFDFF3F76FFE89 -:1022A0006E74AE7470BD0126E4E76C480078BDE83A -:1022B0007040E0F729BEFFDF70BD674924394860F0 -:1022C000704770B5644D0446243DB1B14FF47A7641 -:1022D000012903D0022905D0FFDF70BD1846F5F7AC -:1022E000FCFE05E06888401C68801046F6F7F8FFA1 -:1022F00000F2E730B0FBF6F0201AA86070BD564837 -:1023000000787047082803D0042801D0F5F76CBE88 -:102310004EF628307047002804DB00F1E02090F8EA -:10232000000405E000F00F0000F1E02090F8140D2B -:102330004009704710F00C0000D008467047F4F7D1 -:102340003EB910B50446202800D3FFDF4248443090 -:1023500030F8140010BD70B505460C461046F5F770 -:1023600043FE4FF47A71022C0DD0012C0DD040F6B3 -:10237000340210444AF247321044B0FBF1F02844D2 -:1023800000F5CB7070BD0A46F3E74FF4C862F0E782 -:102390001FB513460A46044601466846FEF789FB08 -:1023A00094F8FA006946FFF7CAFF002800D1FFDF62 -:1023B0001FBD70B5284C0025257094F82000F3F758 -:1023C000B4FE00B9FFDF84F8205070BD2DE9F04164 -:1023D000050000D1FFDF204A0024243AD5F804612B -:1023E0002046631E116A08E08869B04203D3984210 -:1023F00001D203460C460846C9680029F4D104B945 -:1024000004460021C5F80041F035C4B1E068E5603C -:10241000E86000B105612E698846A96156B1B069CE -:1024200030B16F69B84200D2FFDFB069C01BA8614C -:10243000C6F81880084D5CB1207820B902E0E96048 -:102440001562E8E7FFDF6169606808442863ADE66C -:10245000C5F83080AAE60000F011002080010020BD -:1024600010B50C4601461046F4F776FB002806DA54 -:10247000211A491EB1FBF4F101FB040010BD90FBD1 -:10248000F4F101FB140010BD2E48016A002001E0A8 -:102490000846C9680029FBD170472DE9FE43294D44 -:1024A0000120287000264FF6FF7420E00621F1F786 -:1024B000FDFC070000D1FFDF97F8FA00F037F4F7D2 -:1024C00006FC07F80A6BA14617F8FA89B8F1200F45 -:1024D00000D3FFDF1B4A683222F8189097F8FA0001 -:1024E000F3F723FE00B9FFDF202087F8FA006946E2 -:1024F0000620F1F764FC50B1FFDF08E0029830B12C -:1025000090F8F01019B10088A042CFD104E06846DD -:10251000F1F733FC0028F1D02E70BDE8FE8310B532 -:10252000FFF719FF00F5C87010BD064800212430E0 -:1025300090F8352000EB4200418503480078E0F731 -:10254000E3BC0000CC11002080010020012804D051 -:10255000022805D0032808D105E0012907D004E0AE -:10256000022904D001E0042901D000207047012095 -:102570007047F748806890F8A21029B1B0F89E1013 -:10258000B0F8A020914215D290F8A61029B1B0F869 -:10259000A410B0F8A02091420CD2B0F89C20B0F862 -:1025A0009A108A4206D290F88020B0F898001AB1AA -:1025B000884203D3012070470628FBD200207047D1 -:1025C0002DE9F041E24D0746A86800F1700490F84B -:1025D000140130B9E27B002301212046EEF7D2FC42 -:1025E00010B1A08D401CA08501263D21AFB92878EF -:1025F000022808D001280AD06878C8B110F0140F5A -:1026000009D01E2039E0162037E026773EE0A86882 -:1026100090F8160131E0020701D56177F5E78107EF -:1026200001D02A2029E0800600D4FFDF232024E007 -:1026300094F8320028B1E08D411CE185218E88425A -:1026400013D294F8360028B1A08E411CA186218EA9 -:1026500088420AD2A18D608D814203D3AA6892F884 -:10266000142112B9228E914201D3222005E0217C4F -:1026700029B1218D814207D308206077C5E7208DDD -:10268000062801D33E20F8E7207FB0B10020207358 -:10269000607320740221A868FFF78AFDA86890F88B -:1026A000E410012904D1D0F81C110878401E0870EC -:1026B000E878BDE8F041E0F727BCA868BDE8F04144 -:1026C0000021FFF775BDA2490C28896881F8E40054 -:1026D00014D0132812D0182810D0002211280ED0A0 -:1026E00007280BD015280AD0012807D0002805D0CC -:1026F000022803D021F89E2F012008717047A1F80D -:10270000A420704710B5924CA1680A88A1F86021F6 -:1027100081F85E0191F8640001F046FBA16881F840 -:10272000620191F8650001F03FFBA16881F8630147 -:10273000012081F85C01002081F82E01E078BDE8DD -:102740001040E0F7E1BB70B5814C00231946A0684A -:1027500090F87C207030EEF715FC00283DD0A06882 -:1027600090F820110025C9B3A1690978B1BB90F890 -:102770007D00EEF7EFFB88BBA168B1F870000A2876 -:102780002DD905220831E069EBF72AFE10B3A068C5 -:10279000D0F81C11087858B10522491CE069EBF704 -:1027A0001FFE002819D1A068D0F81C01007840B99C -:1027B000A068E169D0F81C010A68C0F80120097915 -:1027C0004171A068D0F81C110878401C08700120E5 -:1027D000FFF779FFA06880F8205170BDFFE7A0687F -:1027E00090F8241111B190F82511C1B390F82E1171 -:1027F0000029F2D090F82F110029EED190F87D0039 -:10280000EEF7A8FB0028E8D1A06890F8640001F07A -:10281000CBFA0646A06890F8650001F0C5FA0546B7 -:10282000A06890F830113046FFF790FEA0B3A06882 -:1028300090F831112846FFF789FE68B3A268B2F814 -:10284000703092F86410B2F8320102F58872EEF737 -:1028500001FE20B3A168252081F87C00BDE7FFE7D9 -:1028600090F87D10242918D090F87C10242914D0D9 -:102870005FF0000300F5897200F59271FBF78EFEA0 -:10288000A16881F8245101F13000C28A21F8E62FB5 -:10289000408B4880142007E005E00123EAE7BDE80B -:1028A000704000202EE71620BDE870400BE710B501 -:1028B000F4F7FAFD0C2813D3254C0821A068D0F8B2 -:1028C00018011E30F4F7F4FD28B1A0680421D830B7 -:1028D000F4F7EEFD00B9FFDFBDE810400320F2E69B -:1028E00010BD10B51A4CA068D0F818110A78002A4B -:1028F0001FD04988028891421BD190F87C20002388 -:1029000019467030EEF73EFB002812D0A068D0F8D0 -:1029100018110978022907D003290BD0042919D0EE -:10292000052906D108200DE090F87D00EEF712FB96 -:1029300040B110BD90F8811039B190F8820000B913 -:10294000FFDF0A20BDE81040BDE6BDE81040AEE75D -:102950008C01002090F8AA008007EAD10C20FFF734 -:10296000B2FEA068002120F89E1F01210171017BA9 -:1029700041F00101017310BD70B5F74CA268556EAE -:10298000EEF702FDEBB2C1B200228B4203D0A36886 -:1029900083F8121102E0A16881F81221C5F3072122 -:1029A000C0F30720814203D0A16881F8130114E726 -:1029B000A06880F8132110E710B5E74C0421A06847 -:1029C000FFF7F6FBA06890F85A10012908D000F52F -:1029D0009E71FBF7ACFEE078BDE81040E0F794BADA -:1029E000022180F85A1010BD70B5DB4CA06890F839 -:1029F000E410FE2955D16178002952D190F87F204A -:102A0000002301217030EEF7BDFA002849D1A068FB -:102A100090F8141109B1022037E090F87C200023CF -:102A200019467030EEF7AEFA28B1A06890F896001B -:102A300008B1122029E0A068002590F87C20122A15 -:102A40001DD004DC032A23D0112A04D119E0182A4E -:102A50001AD0232A26D0002304217030EEF792FAF0 -:102A600000281ED1A06890F87D10192971D020DCB3 -:102A700001292AD0022935D0032932D120E00B20A8 -:102A800003E0BDE8704012E70620BDE870401AE69A -:102A900010F8E21F01710720FFF715FEA06880F80B -:102AA0007C509AE61820FFF70EFEA068A0F89E5012 -:102AB00093E61D2918D01E2916D0212966D149E098 -:102AC00010F8E11F4171072070E00C20FFF7FBFDBB -:102AD000A06820F8A45F817941F00101817100F8BC -:102AE000275C53E013202CE090F8252182BB90F85E -:102AF0002421B2B1242912D090F87C1024290ED0C0 -:102B00005FF0000300F5897200F59271FBF746FD56 -:102B1000A0681E2180F87D1080F8245103E0012375 -:102B2000F0E71E2932D1A068FBF797FDFFF744FFBD -:102B3000A16801F13000C28A21F8E62F408B48805D -:102B40001520FFF7C0FDA068A0F8A45080F87D50C4 -:102B50001CE02AE090F8971051B180F8125180F8EB -:102B600013511820FFF7AFFDA068A0F8A4500DE0A6 -:102B700090F82F1151B990F82E1139B1C16DD0F8DC -:102B80003001FFF7F9FE1820FFF79DFDA06890F8CF -:102B9000E400FE2885D1FFF7A4FEA06890F8E400C9 -:102BA000FE2885D1BDE87040CDE51120FFF78BFDF3 -:102BB000A068CBE7684A0129926819D0002302294E -:102BC0000FD003291ED010B301282BD0032807D122 -:102BD00092F87C00132803D0162801D0182804D1BD -:102BE000704792F8E4000028FAD0D2F8180117E0F4 -:102BF00092F8E4000128F3D0D2F81C110878401EA6 -:102C00000870704792F8E4000328EED17047D2F8BC -:102C10001801B2F870108288891A09B20029F5DB10 -:102C200003707047B2F87000B2F82211401A00B277 -:102C30000028F6DBD2F81C010178491E01707047AC -:102C400070B5044690F87C0000250C2810D00D28A3 -:102C50002ED1D4F81811B4F870008988401C88422D -:102C600026D1D4F864013C4E017811B3FFDF42E075 -:102C7000B4F87000B4F82211401C884218D1D4F87E -:102C80001C01D0F80110A160407920730321204677 -:102C9000EDF7F1FDD4F81C01007800B9FFDF012148 -:102CA000FE20FFF787FF84F87C50012084F8B200F3 -:102CB00093E52188C180D4F81801D4F864114089C3 -:102CC0000881D4F81801D4F8641180894881D4F8B7 -:102CD0001801D4F86411C0898881D4F864010571A1 -:102CE000D4F8641109200870D4F864112088488051 -:102CF000F078E0F709F902212046EDF7BCFD032149 -:102D00002046FFF755FAB068D0F81801007802287D -:102D100000D0FFDF0221FE20FFF74CFF84F87C503B -:102D20005BE52DE9F0410C4C00260327D4F808C0E0 -:102D3000012598B12069C0788CF8E20005FA00F00E -:102D4000C0F3C05000B9FFDFA06800F87C7F468464 -:102D500080F82650BDE8F0818C01002000239CF80B -:102D60007D2019460CF17000EEF70CF970B1607817 -:102D70000028EFD12069C178A06880F8E11080F8C0 -:102D80007D70A0F8A46080F8A650E3E76570E1E7E5 -:102D9000F0B5F74C002385B0A068194690F87D2067 -:102DA0007030EEF7EFF8012580B1A06890F87C0054 -:102DB00023280ED024280CD06846F6F785FB68B18E -:102DC000009801A9C0788DF8040008E0657005B08E -:102DD000F0BD607840F020006070F8E70021A06846 -:102DE00003AB162290F87C00EEF74FFB002648B1AB -:102DF000A0689DF80C20162180F80C2180F80D1198 -:102E0000192136E02069FBF722FB78B121690879A6 -:102E100000F00702A06880F85C20497901F0070102 -:102E200080F85D1090F82F310BBB03E00020FFF716 -:102E300078FFCCE790F82E31CBB900F164035F78CE -:102E4000974205D11A788A4202D180F897500EE055 -:102E500000F5AC71028821F8022990F85C200A7113 -:102E600090F85D0048710D70E078E0F74DF8A068CB -:102E7000212180F87D1080F8A650A0F8A460A6E774 -:102E8000F8B5BB4C00231946A06890F87D2070303F -:102E9000EEF778F840B32069FBF7BEFA48B3206933 -:102EA000FBF7B4FA07462069FBF7B4FA0646206937 -:102EB000FBF7AAFA05462069FBF7AAFA0146009734 -:102EC000A06833462A463030FBF79BFBA1680125FA -:102ED00091F87C001C2810D091F85A00012812D0DB -:102EE00091F8250178B90BE0607840F0010060703E -:102EF000F8BDBDE8F840002013E781F85A5002E021 -:102F000091F8240118B11E2081F87D000BE01D20EE -:102F100081F87D0001F5A57231F8300BFBF7FBFB62 -:102F2000E078DFF7F1FFA068002120F8A41F85708A -:102F3000F8BD10B58E4C00230921A06890F87C20C4 -:102F40007030EEF71FF848B16078002805D1A1680D -:102F500001F8960F087301F81A0C10BD012060707B -:102F600010BD7CB5824C00230721A06890F87C201E -:102F70007030EEF707F838B36078002826D169463C -:102F80002069FBF75FFA9DF80000002500F025019D -:102F9000A06880F8B0109DF8011001F0490180F898 -:102FA000B11080F8A250D0F81811008849888142E9 -:102FB00000D0FFDFA068D0F818110D70D0F86411B0 -:102FC0000A7822B1FFDF16E0012060707CBD30F886 -:102FD000E82BCA80C16F0D71C16F009A8A60019A97 -:102FE000CA60C26F0821117030F8E81CC06F4180C0 -:102FF000E078DFF789FFA06880F87C507CBD70B571 -:103000005B4C00231946A06890F87D207030EDF7E6 -:10301000B9FF012540B9A0680023082190F87C2061 -:103020007030EDF7AFFF10B36078002820D1A068B2 -:1030300090F8AA00800712D42069FBF7C9F9A168AB -:1030400081F8AB00206930F8052FA1F8AC2040884A -:10305000A1F8AE0011F8AA0F40F002000870A068B5 -:103060004FF0000690F8AA10C90702D011E0657071 -:103070009DE490F87D20002319467030EDF782FF23 -:1030800000B9FFDFA06880F87D5080F8A650A0F856 -:10309000A460A06890F87C10012906D180F87C60BB -:1030A00080F8A260E078DFF72FFFA168D1F818015F -:1030B000098842888A42DBD101780429D8D1067078 -:1030C000E078DFF721FFA06890F87C100029CFD1CD -:1030D00080F8A2606BE470B5254DA86890F87C106C -:1030E0001A2902D00220687061E469780029FBD1B6 -:1030F000002480F8A74080F8A240D0F8181100887A -:103100004988814200D0FFDFA868D0F818110C7000 -:10311000D0F864110A780AB1FFDF25E090F8A82002 -:1031200072B180F8A8400288CA80D0F864110C718E -:10313000D0F864210E2111700188D0F864010DE0EF -:1031400030F8E82BCA80C16F0C71C26F0121117277 -:10315000C26F0D21117030F8E81CC06F418000F083 -:10316000A1FEE878DFF7D0FEA86880F87C401EE476 -:103170008C01002070B5FA4CA16891F87C20162AC9 -:1031800001D0132A02D191F8A82012B10220607058 -:103190000DE46278002AFBD181F8E000002581F877 -:1031A000A75081F8A250D1F81801098840888842B8 -:1031B00000D0FFDFA068D0F818010078032800D005 -:1031C000FFDF0321FE20FFF7F5FCA068D0F86411B3 -:1031D0000A780AB1FFDF14E030F8E02BCA8010F85B -:1031E000081BC26F1171C16F0D72C26F0D2111707A -:1031F00030F8E81CC06F418000F054FEE078DFF743 -:1032000083FEA06880F87C504BE470B5D44C092153 -:103210000023A06890F87C207030EDF7B3FE002505 -:1032200018B12069007912281ED0A0680A21002355 -:1032300090F87C207030EDF7A5FE18B12069007978 -:10324000142814D02069007916281AD1A06890F8A3 -:103250007C101F2915D180F87C5080F8A250BDE861 -:1032600070401A20FFF74EBABDE8704061E6A068D2 -:1032700000F87C5F458480F82650BDE87040FFF779 -:103280009BBB0EE470B5B64C2079C00773D02069A3 -:1032900000230521C578A06890F87C207030EDF7F8 -:1032A00071FE98B1062D11D006DC022D0ED0042D32 -:1032B0000CD0052D06D109E00B2D07D00D2D05D022 -:1032C000112D03D0607840F008006070607800280D -:1032D00051D12069FAF7E0FF00287ED0206900254F -:1032E0000226C178891E162977D2DFE801F00B7615 -:1032F00034374722764D76254A457676763A5350CE -:103300006A6D7073A0680023012190F87F207030EF -:10331000EDF738FE08BB2069FBF722F8A16881F8B9 -:103320001601072081F87F0081F8A65081F8A2508D -:1033300056E0FFF76AFF53E0A06890F87C100F2971 -:1033400001D066704CE0617839B980F88150122163 -:1033500080F87C1044E000F0D0FD41E000F0ACFDCE -:103360003EE0FBF7A9F803283AD12069FBF7A8F85B -:10337000FFF700FF34E03BE00079F9E7FFF7ABFE31 -:103380002EE0FFF73CFE2BE0FFF7EBFD28E0FFF718 -:10339000D0FD25E0A0680023194690F87D2070300C -:1033A000EDF7F0FD012110B16078C8B901E061705E -:1033B00016E0A06820F8A45F817000F8276C0FE089 -:1033C0000BE0FFF75DFD0BE000F034FD08E0FFF7D8 -:1033D000DFFC05E000F0FAFC02E00020FFF7A1FCB2 -:1033E000A268F2E93001401C41F10001C2E900018C -:1033F0005EE42DE9F0415A4C2079800741D5607890 -:1034000000283ED1E06801270026C178204619290E -:10341000856805F170006FD2DFE801F04B3E0D6F5B -:10342000C1C1801C34C1556287C1C1C1C1BE8B9569 -:1034300098A4B0C1BA0095F87F2000230121EDF7D0 -:10344000A1FD00281DD1A068082180F87F1080F818 -:10345000A26090E0002395F87D201946EDF792FDDB -:1034600010B1A06880F8A660A0680023194690F803 -:103470007C207030EDF786FD002802D0A06880F82F -:10348000A26067E4002395F87C201946EDF77AFDE9 -:1034900000B9FFDF042008E0002395F87C201946DE -:1034A000EDF770FD00B9FFDF0C20A16881F87C000A -:1034B00050E4002395F87C201946EDF763FD00B930 -:1034C000FFDF0D20F1E7002395F87C201946EDF78A -:1034D00059FD00B9FFDFA0680F2180F8A77008E050 -:1034E00095F87C00122800D0FFDFA068112180F839 -:1034F000A87080F87C102DE451E0002395F87C2022 -:103500001946EDF73FFD20B9A06890F8A80000B972 -:10351000FFDFA068132180F8A770EAE795F87C0028 -:10352000182800D0FFDF1A20BFE7BDE8F04100F007 -:1035300063BD002395F87C201946EDF723FD00B903 -:10354000FFDF0520B1E785F8A66003E4002395F8C6 -:103550007C201946EDF716FD00B9FFDF1C20A4E71B -:103560008C010020002395F87D201946EDF70AFD17 -:1035700000B9FFDFA06880F8A66006E4002395F894 -:103580007C201946EDF7FEFC00B9FFDF1F208CE719 -:10359000BDE8F04100F0F8BC85F87D60D3E7FFDFBF -:1035A0006FE710B5F74C6078002837D120794007D5 -:1035B0000FD5A06890F87C00032800D1FFDFA06839 -:1035C00090F87F10072904D101212170002180F893 -:1035D0007F10FFF70EFF00F0B5FCFFF753FEA07859 -:1035E000000716D5A0680023052190F87C207030D4 -:1035F000EDF7C8FC50B108206070A068D0F86411E5 -:1036000008780D2800D10020087002E00020F9F7AA -:10361000F9FCA068BDE81040FFF712BB10BD2DE912 -:10362000F041D84C07464FF00005607808436070C1 -:10363000207981062046806802D5A0F8985004E0E1 -:10364000B0F89810491CA0F8981000F018FD012659 -:10365000F8B1A088000506D5A06890F8821011B1D5 -:10366000A0F88E5015E0A068B0F88E10491CA0F8A4 -:103670008E1000F0F3FCA068B0F88E10B0F8902027 -:10368000914206D3A0F88E5080F83A61E078DFF7D7 -:103690003BFC207910F0600F08D0A06890F88010F3 -:1036A00021B980F880600121FEF782FD1FB9FFF784 -:1036B00078FFFFF799F93846FEF782FFBDE8F04141 -:1036C000F5F711BFAF4A51789378194313D11146DA -:1036D0000128896808D01079400703D591F87F0048 -:1036E000072808D001207047B1F84C00098E8842A5 -:1036F00001D8FEF7E4B900207047A249C278896872 -:10370000012A06D05AB1182A08D1B1F81011FAF7D7 -:10371000BABEB1F822114172090A81727047D1F81C -:10372000181189884173090A8173704770B5954CE7 -:1037300005460E46A0882843A080A80703D5E807C1 -:1037400000D0FFDFE660E80700D02661A80719D5A2 -:10375000F078062802D00B2814D10BE0A06890F86E -:103760007C1018290ED10021E0E93011012100F868 -:103770003E1C07E0A06890F87C10122902D10021BD -:1037800080F88210280601D50820A07068050AD5A7 -:10379000A0688288B0F87010304600F07FFC304698 -:1037A000BDE87040A9E763E43EB505466846F5F715 -:1037B00065FE00B9FFDF222200210098EAF767FECC -:1037C00003210098FAF750FD0098017821F01001CC -:1037D00001702946FAF76DFD6A4C192D71D2DFE8A8 -:1037E00005F020180D3EC8C8C91266C8C9C959C815 -:1037F000C8C8C8BBC9C971718AC89300A1680098BC -:1038000091F8151103E0A168009891F8E610017194 -:10381000B0E0A068D0F81C110098491CFAF795FD9B -:10382000A8E0A1680098D1F8182192790271D1F826 -:10383000182112894271120A8271D1F81821528915 -:10384000C271120A0272D1F8182192894272120AC8 -:103850008272D1F81811C989FAF74EFD8AE0A06882 -:10386000D0F818110098091DFAF77CFDA068D0F86F -:10387000181100980C31FAF77FFDA068D0F81811E4 -:1038800000981E31FAF77EFDA1680098D831FAF74A -:1038900087FD6FE06269009811780171918841712C -:1038A000090A81715188C171090A017262E03649C1 -:1038B000D1E90001CDE9010101A90098FAF78AFDDB -:1038C00058E056E0A068B0F844100098FAF794FD6C -:1038D000A068B0F8E6100098FAF792FDA068B0F87A -:1038E00048100098FAF780FDA068B0F8E81000983A -:1038F000FAF77EFD3EE0A168009891F83021027150 -:1039000091F83111417135E0A06890F81301EDF79D -:1039100032FD01460098FAF7B2FDA06890F8120156 -:1039200000F03DFA70B1A06890F8640000F037FA3A -:1039300040B1A06890F8121190F86400814201D063 -:10394000002002E0A06890F81201EDF714FD014696 -:103950000098FAF790FD0DE0A06890F80D1100981E -:10396000FAF7A8FDA06890F80C110098FAF7A6FDE8 -:1039700000E0FFDFF5F795FD00B9FFDF0098FFF7E6 -:10398000BCFE3EBD8C0100207C63020010B5F94CEA -:10399000A06890F8121109B990F8641080F86410CA -:1039A00090F8131109B990F8651080F8651000209F -:1039B000FEF7A8FEA068FAF750FE002806D0A0681F -:1039C000BDE8104000F59E71FAF7B1BE10BDF8B524 -:1039D000E84E00250446B060B5807570B57035704E -:1039E0000088F5F748FDB0680088F5F76AFDB4F87F -:1039F000F800B168401C82B201F17000EDF75BF88D -:103A000000B1FFDF94F87D00242809D1B4F87010CC -:103A1000B4F81001081A00B2002801DB707830B148 -:103A200094F87C0024280AD0252808D015E0FFF758 -:103A3000ADFF84F87D50B16881F897500DE0B4F87F -:103A40007010B4F81001081A00B2002805DB707875 -:103A500018B9FFF79BFF84F87C50A4F8F850FEF7E4 -:103A600088FD00281CD1B06890F8E400FE2801D041 -:103A7000FFF79AFEC0480090C04BC14A2146284635 -:103A8000F9F7ECF9B0680023052190F87C2070303C -:103A9000EDF778FA002803D0BDE8F840F8F771BFD9 -:103AA000F8BD10B5FEF765FD20B10020BDE810405F -:103AB0000146B4E5BDE81040F9F77FBA70B50C4691 -:103AC000154606464FF4B47200212046EAF7DFFCA3 -:103AD000268005B9FFDF2868C4F818016868C4F8B3 -:103AE0001C01A868C4F8640182E4F0F7E9BA2DE982 -:103AF000F0410D4607460621F0F7D8F9041E3DD0E7 -:103B0000D4F864110026087858B14A8821888A427E -:103B100007D109280FD00E2819D00D2826D0082843 -:103B20003ED094F83A01D0B36E701020287084F81B -:103B30003A61AF809AE06E7009202870D4F8640171 -:103B4000416869608168A9608089A88133E008467E -:103B5000F0F7DDFA0746EFF78AFF70B96E700E20B6 -:103B60002870D4F864014068686011E00846F0F7F6 -:103B7000CEFA0746EFF77BFF08B1002081E46E70B4 -:103B80000D202870D4F8640141686960008928819B -:103B9000D4F8640106703846EFF763FF66E00EE084 -:103BA0006E7008202870D4F86401416869608168EB -:103BB000A960C068E860D4F86401067056E094F823 -:103BC0003C0198B16E70152028700AE084F83C61C1 -:103BD000D4F83E016860D4F84201A860D4F84601E8 -:103BE000E86094F83C010028F0D13FE094F84A01E5 -:103BF00058B16E701C20287084F84A610A2204F5BE -:103C0000A671281DEAF719FC30E094F8560140B17E -:103C10006E701D20287084F85661D4F858016860D1 -:103C200024E094F8340168B16E701A20287004E022 -:103C300084F83461D4F83601686094F834010028BF -:103C4000F6D113E094F85C01002897D06E7016202E -:103C5000287007E084F85C61D4F85E016860B4F80D -:103C60006201288194F85C010028F3D1012008E466 -:103C7000404A5061D170704770B50D4604464EE021 -:103C8000B4F8F800401CA4F8F800B4F89800401C00 -:103C9000A4F89800204600F0F2F9B8B1B4F88E000C -:103CA000401CA4F88E00204600F0D8F9B4F88E002D -:103CB000B4F89010884209D30020A4F88E000120A7 -:103CC00084F83A012B48C078DFF71EF994F8A20077 -:103CD00020B1B4F89E00401CA4F89E0094F8A60001 -:103CE00020B1B4F8A400401CA4F8A40094F8140176 -:103CF00040B994F87F200023012104F17000EDF712 -:103D000041F920B1B4F89C00401CA4F89C00204666 -:103D1000FEF796FFB4F87000401CA4F870006D1E0A -:103D2000ADB2ADD23FE5134AC2E90601704770B5A6 -:103D30000446B0F8980094F88010D1B1B4F89A1005 -:103D40000D1A2D1F94F8960040B194F87C200023A2 -:103D5000092104F17000EDF715F9B8B1B4F88E60DF -:103D6000204600F08CF980B1B4F89000801B001F51 -:103D70000CE007E08C0100201F360200C53602006F -:103D80002D370200C0F10205DCE72846A84200DA20 -:103D90000546002D01DC002005E5A8B203E510F082 -:103DA0000C0000D00120704710B5012808D002286F -:103DB00008D0042808D0082806D0FFDF204610BD10 -:103DC0000124FBE70224F9E70324F7E770B5CC4CA4 -:103DD000A06890F87C001F2804D0607840F00100B3 -:103DE0006070E0E42069FAF73CFBD8B12069012259 -:103DF0000179407901F0070161F30705294600F0D8 -:103E0000070060F30F21A06880F8A2200022A0F82C -:103E10009E20232200F87C2FD0F8B400BDE870402B -:103E2000FEF7AABD0120FEF77CFFBDE870401E2012 -:103E3000FEF768BCF8B5B24C00230A21A06890F8E0 -:103E40007C207030EDF79EF838B32069FAF7E4FA79 -:103E5000C8B12069FAF7DAFA07462069FAF7DAFA00 -:103E600006462069FAF7D0FA05462069FAF7D0FA33 -:103E700001460097A06833462A463030FAF7C1FB66 -:103E8000A068FAF7EAFBA168002081F8A20081F897 -:103E90007C00BDE8F840FEF78FBD607840F001007F -:103EA0006070F8BD964810B580680088F0F72FF96B -:103EB000BDE81040EFF7C6BD10B5914CA36893F86C -:103EC0007C00162802D00220607010BD60780028A7 -:103ED000FBD1D3F81801002200F11E010E30C833C7 -:103EE000ECF7C2FFA0680021C0E92E11012180F883 -:103EF0008110182180F87C1010BD10B5804CA0688E -:103F000090F87C10132902D00220607010BD6178F7 -:103F10000029FBD1D0F8181100884988814200D0CF -:103F2000FFDFA068D0F8181120692631FAF745FAAA -:103F3000A1682069DC31FAF748FAA168162081F8F7 -:103F40007C0010BD10B56E4C207900071BD5607841 -:103F5000002818D1A068002190F8E400FEF72AFE9E -:103F6000A06890F8E400FE2800D1FFDFA068FE21E1 -:103F700080F8E41090F87F10082904D10221217004 -:103F8000002180F87F1010BD70B55D4D2421002404 -:103F9000A86890F87D20212A05D090F87C20232A5B -:103FA00018D0FFDFA0E590F8122112B990F8132184 -:103FB0002AB180F87D10A86880F8A64094E500F842 -:103FC0007D4F847690F8B1000028F4D00020FEF7F1 -:103FD00099FBF0E790F8122112B990F813212AB159 -:103FE00080F87C10A86880F8A2407DE580F87C40CD -:103FF0000020FEF787FBF5E770B5414C0025A0686F -:10400000D0F8181103884A889A4219D109780429EE -:1040100016D190F87C20002319467030ECF7B2FFDF -:1040200000B9FFDFA06890F8AA10890703D4012126 -:1040300080F87C1004E080F8A250D0F818010570D8 -:10404000A0680023194690F87D207030ECF79AFFA5 -:10405000002802D0A06880F8A65045E5B0F890206E -:10406000B0F88E108A4201D3511A00E000218288F4 -:10407000521D8A4202D3012180F89610704710B574 -:1040800090F8821041B990F87C200023062170300E -:10409000ECF778FF002800D0012010BD70B5114466 -:1040A000174D891D8CB2C078A968012806D040B18F -:1040B000182805D191F8120138B109E0A1F8224180 -:1040C00012E5D1F8180184800EE591F8131191B131 -:1040D000FFF765FE80B1A86890F86400FFF75FFE07 -:1040E00050B1A86890F8121190F86420914203D062 -:1040F00090F8130100B90024A868A0F81041F3E477 -:104100008C01002070B58F4C0829207A6CD2DFE832 -:1041100001F004176464276B6B6458B1F4F7D3F8AB -:10412000F5F7FFF80020A072F4F7B4F9BDE870408D -:10413000F4F758BCF5F717F9BDE87040F1F71FBF69 -:10414000DEF7B6FDF5F752F8D4E90001F1F7F3FC1C -:104150002060A07A401CC0B2A072282824D370BD71 -:10416000A07A0025401EC6B2E0683044F4F700FD96 -:1041700010B9E1687F208855A07A272828BF01253B -:10418000DEF796FDA17A01EB4102C2EB81110844F2 -:104190002946F5F755F8A07A282809D2401CC0B264 -:1041A000A072282828BF70BDBDE87040F4F772B92E -:1041B000207A002818BF00F086F8F4F74BFBF4F7DC -:1041C000F7FBF5F7D0F80120E0725F480078DEF7E2 -:1041D0009BFEBDE87040F1F7D2BE002808BF70BD5D -:1041E000BDE8704000F06FB8FFDF70BD10B5554CF2 -:1041F000207A002804BF0C2010BD00202072E0723D -:10420000607AF2F7F8FA607AF2F761FD607AF1F716 -:104210008CFF00280CBF1F20002010BD002270B5AD -:10422000484C06460D46207A68B12272E272607AE6 -:10423000F2F7E1FA607AF2F74AFD607AF1F775FF7A -:10424000002808BFFFDF4048E560067070BD70B50C -:10425000050007D0A5F5E8503C494C3881429CBF89 -:10426000122070BD374CE068002804BF092070BDE3 -:10427000207A00281CBF0C2070BD3548F1F7FAFEEB -:104280006072202804BF1F2070BDF1F76DFF206011 -:104290001DB12946F1F74FFC2060012065602072B6 -:1042A00000F011F8002070BD2649CA7A002A04BF28 -:1042B000002070471E22027000224270CB684360CB -:1042C000CA7201207047F0B585B0F1F74DFF1D4D62 -:1042D0000746394668682C6800EB80004600204697 -:1042E000F2F73AFCB04206DB6868811B3846F1F70A -:1042F00022FC0446286040F2367621463846F2F722 -:104300002BFCB04204DA31463846F1F714FC04467F -:1043100000208DF8000040F6E210039004208DF894 -:10432000050001208DF8040068460294F2F7CAF8EF -:10433000687A6946F2F743F9002808BFFFDF05B045 -:10434000F0BD000074120020AC010020B5EB3C0071 -:10435000054102002DE9F0410C4612490D68114A51 -:10436000114908321160A0F12001312901D3012047 -:104370000CE0412810D040CC0C4F94E80E0007EB25 -:104380008000241F50F8807C3046B84720600548E4 -:10439000001D0560BDE8F081204601F0EBFCF5E76B -:1043A00006207047100502400100000184630200EE -:1043B00010B55548F2F7FAFF00B1FFDF5248401C34 -:1043C000F2F7F4FF002800D0FFDF10BD2DE9F14F18 -:1043D0004E4E82B0D6F800B001274B48F2F7EEFF00 -:1043E000DFF8248120B9002708F10100F2F7FCFF73 -:1043F000474C00254FF0030901206060C4F80051CC -:10440000C4F80451029931602060DFF808A11BE074 -:10441000DAF80000C00617D50E2000F068F8EFF3B8 -:10442000108010F0010072B600D001200090C4F896 -:104430000493D4F8000120B9D4F8040108B901F0BC -:10444000A3FC009800B962B6D4F8000118B9D4F8FA -:1044500004010028DCD0D4F804010028CCD137B105 -:10446000C6F800B008F10100F2F7A8FF11E008F16A -:104470000100F2F7A3FF0028B6D1C4F80893C4F8EE -:104480000451C4F800510E2000F031F81E48F2F734 -:10449000ABFF0020BDE8FE8F2DE9F0438DB00D4647 -:1044A000064600240DF110090DF1200818E000BFA8 -:1044B00004EB4407102255F827106846E9F7BDFFC2 -:1044C00005EB8707102248467968E9F7B6FF68468A -:1044D000FFF77CFF10224146B868E9F7AEFF641C85 -:1044E000B442E5DB0DB00020BDE8F0836EE70028A4 -:1044F00009DB00F01F02012191404009800000F11A -:10450000E020C0F880127047AD01002004E50040B3 -:1045100000E0004010ED00E0B54900200870704751 -:1045200070B5B44D01232B60B34B1C68002CFCD03C -:10453000002407E00E6806601E68002EFCD0001DF7 -:10454000091D641C9442F5D30020286018680028D7 -:10455000FCD070BD70B5A64E0446A84D3078022838 -:1045600000D0FFDFAC4200D3FFDF7169A44801290E -:1045700003D847F23052944201DD03224271491CB4 -:104580007161291BC1609E49707800F02EF90028E6 -:1045900000D1FFDF70BD70B5954C0D466178884243 -:1045A00000D0FFDF954E082D4BD2DFE805F04A041E -:1045B0001E2D4A4A4A382078022800D0FFDF032007 -:1045C0002070A078012801D020B108E0A06801F097 -:1045D00085F904E004F1080007C8FFF7A1FF0520F2 -:1045E0002070BDE87040F1F7CABCF1F7BDFD01468F -:1045F0006068F2F7B1FAB04202D2616902290BD3C6 -:104600000320F2F7FAFD12E0F1F7AEFD0146606813 -:10461000F2F7A2FAB042F3D2BDE870409AE72078F0 -:1046200002280AD0052806D0FFDF04202070BDE84C -:10463000704000F0D0B8022000E00320F2F7DDFD6A -:10464000F3E7FFDF70BD70B50546F1F78DFD684CEF -:1046500060602078012800D0FFDF694901200870E0 -:104660000020087104208D6048716448C8600220F1 -:104670002070607800F0B9F8002800D1FFDF70BD2D -:1046800010B55B4C207838B90220F2F7CCFD18B990 -:104690000320F2F7C8FD08B1112010BD5948F1F709 -:1046A000E9FC6070202804D00120207000206061A7 -:1046B00010BD032010BD2DE9F0471446054600EB60 -:1046C00084000E46A0F1040801F01BF907464FF0E4 -:1046D000805001694F4306EB8401091FB14201D2AA -:1046E000012100E0002189461CB10069B4EB900F64 -:1046F00002D90920BDE8F0872846DCF7A3FD90B970 -:10470000A84510D3BD4205D2B84503D245EA0600FC -:10471000800701D01020EDE73046DCF793FD10B99B -:10472000B9F1000F01D00F20E4E73748374900689E -:10473000884205D0224631462846FFF7F1FE1AE0AE -:10474000FFF79EFF0028D5D1294800218560C0E9E8 -:1047500003648170F2F7D3FD08B12D4801E04AF2FD -:10476000F87060434FF47A7100F2E730B0FBF1F07B -:104770001830FFF768FF0020BCE770B505464FF022 -:10478000805004696C432046DCF75CFD08B10F20C3 -:1047900070BD01F0B6F8A84201D8102070BD1A48CB -:1047A0001A490068884203D0204601F097F810E0CB -:1047B000FFF766FF0028F1D10D4801218460817068 -:1047C000F2F79DFD08B1134800E013481830FFF7D9 -:1047D0003AFF002070BD10B5054C6078F1F7A5FCDC -:1047E00000B9FFDF0020207010BDF1F7E8BE000027 -:1047F000B001002004E5014000E40140105C0C0021 -:1048000084120020974502005C000020BEBAFECA58 -:1048100050280500645E0100A85B01007E4909681C -:104820000160002070477C4908600020704701212A -:104830008A0720B1012804D042F204007047916732 -:1048400000E0D1670020704774490120086042F2FF -:104850000600704708B50423704A1907103230B1BA -:10486000C1F80433106840F0010010600BE01068DC -:1048700020F001001060C1F808330020C1F80801E1 -:10488000674800680090002008BD011F0B2909D867 -:10489000624910310A6822F01E0242EA40000860B4 -:1048A0000020704742F2050070470F2809D85B4985 -:1048B00010310A6822F4706242EA00200860002089 -:1048C000704742F205007047000100F18040C0F8D7 -:1048D000041900207047000100F18040C0F8081959 -:1048E00000207047000100F18040D0F80009086006 -:1048F00000207047012801D907207047494A52F823 -:10490000200002680A43026000207047012801D994 -:1049100007207047434A52F8200002688A43026029 -:1049200000207047012801D9072070473D4A52F8FE -:104930002000006808600020704702003A494FF0EC -:10494000000003D0012A01D0072070470A60704799 -:10495000020036494FF0000003D0012A01D00720A1 -:1049600070470A60704708B54FF40072510510B1E6 -:10497000C1F8042308E0C1F808230020C1F824018D -:1049800027481C3000680090002008BD08B5802230 -:10499000D10510B1C1F8042308E0C1F808230020B4 -:1049A000C1F81C011E48143000680090002008BDAA -:1049B00008B54FF48072910510B1C1F8042308E0E6 -:1049C000C1F808230020C1F82001154818300068FC -:1049D0000090002008BD10493831096801600020AE -:1049E000704770B54FF080450024C5F80841F2F7D4 -:1049F00092FC10B9F2F799FC28B1C5F82441C5F82A -:104A00001C41C5F820414FF0E020802180F80014BF -:104A10000121C0F8001170BD0004004000050040F5 -:104A2000080100404864020078050040800500400D -:104A30006249634B0A6863499A42096801D1C1F32C -:104A400010010160002070475C495D4B0A685D49B8 -:104A5000091D9A4201D1C0F3100008600020704780 -:104A60005649574B0A68574908319A4201D1C0F359 -:104A7000100008600020704730B5504B504D1C6846 -:104A800042F20803AC4202D0142802D203E01128FB -:104A900001D3184630BDC3004B481844C0F8101568 -:104AA000C0F81425002030BD4449454B0A6842F245 -:104AB00009019A4202D0062802D203E0042801D359 -:104AC00008467047404A012142F8301000207047E4 -:104AD0003A493B4B0A6842F209019A4202D0062841 -:104AE00002D203E0042801D308467047364A012168 -:104AF00002EBC00041600020704770B52F4A304E75 -:104B0000314C156842F2090304EB8002B54204D02F -:104B1000062804D2C2F8001807E0042801D318467A -:104B200070BDC1F31000C2F80008002070BD70B560 -:104B3000224A234E244C156842F2090304EB8002FA -:104B4000B54204D0062804D2D2F8000807E00428B1 -:104B500001D3184670BDD2F80008C0F310000860F9 -:104B6000002070BD174910B50831184808601120A1 -:104B7000154A002102EBC003C3F81015C3F8141541 -:104B8000401C1428F6D3002006E0042804D302EBCE -:104B90008003C3F8001807E002EB8003D3F8004855 -:104BA000C4F31004C3F80048401C0628EDD310BD20 -:104BB0000449064808310860704700005C00002086 -:104BC000BEBAFECA00F5014000F001400000FEFF41 -:104BD000814B1B6803B19847BFF34F8F7F48016833 -:104BE0007F4A01F4E06111430160BFF34F8F00BFC2 -:104BF000FDE710B5EFF3108010F0010F72B601D091 -:104C0000012400E0002400F0DDF850B1DCF7BFFB28 -:104C1000F1F755F8F2F793FAF2F7BEFF7149002069 -:104C2000086004B962B6002010BD2DE9F0410C46C1 -:104C30000546EFF3108010F0010F72B601D0012687 -:104C400000E0002600F0BEF820B106B962B60820E8 -:104C5000BDE8F08101F01EF9DCF79DFB0246002063 -:104C600001234709BF0007F1E02700F01F01D7F833 -:104C70000071CF40F9071BD0202803D222FA00F19F -:104C8000C90727D141B2002904DB01F1E02191F8E5 -:104C9000001405E001F00F0101F1E02191F8141D6D -:104CA0004909082916D203FA01F717F0EC0F11D0C1 -:104CB000401C6428D5D3F2F74DFF4B4A4B490020E6 -:104CC000F2F790FF47494A4808602046DCF7C1FAEE -:104CD00060B904E006B962B641F20100B8E73E48A7 -:104CE00004602DB12846DCF701FB18B1102428E040 -:104CF000404D19E02878022802D94FF4805420E072 -:104D000007240028687801D0D8B908E0C8B1202865 -:104D100017D8A878212814D8012812D001E0A87843 -:104D200078B9E8780B280CD8DCF735FB2946F2F780 -:104D3000ECF9F0F783FF00F017FE2846DCF7F4FAF1 -:104D4000044606B962B61CB1FFF753FF20467FE761 -:104D500000207DE710B5044600F034F800B10120D2 -:104D60002070002010BD244908600020704770B5F5 -:104D70000C4622490D682149214E08310E60102849 -:104D800007D011280CD012280FD0132811D00120E1 -:104D900013E0D4E90001FFF748FF354620600DE03D -:104DA000FFF727FF0025206008E02068FFF7D2FF0B -:104DB00003E0114920680860002020600F48001DB2 -:104DC000056070BD07480A490068884201D101208A -:104DD0007047002070470000C80100200CED00E083 -:104DE0000400FA055C0000204814002000000020A8 -:104DF000BEBAFECA50640200040000201005024042 -:104E0000010000017D49C0B20860704700B57C49CF -:104E1000012808BF03200CD0022808BF042008D0B6 -:104E2000042808BF062004D0082816BFFFDF05208D -:104E300000BD086000BD70B505460C46164610461C -:104E4000F3F7D2F8022C08BF4FF47A7105D0012C89 -:104E50000CBF4FF4C86140F6340144183046F3F7F4 -:104E60003CF9204449F6797108444FF47A71B0FB5B -:104E7000F1F0281A70BD70B505460C460846F4F7E7 -:104E80002FFA022C08BF40F24C4105D0012C0CBF78 -:104E900040F634014FF4AF5149F6CA62511A084442 -:104EA0004FF47A7100F2E140B0FBF1F0281A801E55 -:104EB00070BD70B5064615460C460846F4F710FA64 -:104EC000022D08BF4FF47A7105D0012D0CBF4FF4AD -:104ED000C86140F63401022C08BF40F24C4205D0B4 -:104EE000012C0CBF40F634024FF4AF52891A08442B -:104EF00049F6FC6108444FF47A71B0FBF1F0301AC6 -:104F000070BD70B504460E460846F3F76DF80546C9 -:104F10003046F3F7E2F828444AF2AB3108444FF444 -:104F20007A71B0FBF1F0201A801E70BD2DE9F041BE -:104F300007461E460D4614461046082A16BF04288A -:104F40004EF62830F3F750F807EB4701C1EBC711D5 -:104F500000EBC100022D08BF40F24C4105D0012DED -:104F60000CBF40F634014FF4AF5147182846F4F710 -:104F7000B7F9381A4FF47A7100F6B730B0FBF1F593 -:104F80002046F3F7B9F828443044401DBDE8F081CD -:104F900070B5054614460E460846F3F725F805EBAE -:104FA0004502C2EBC512C0EBC2053046F3F795F8D7 -:104FB0002D1A2046082C16BF04284EF62830F3F789 -:104FC00013F828444FF47A7100F6B730B0FBF1F5CE -:104FD0002046F3F791F82844401D70BD0949082880 -:104FE00018BF0428086803BF20F46C5040F4444004 -:104FF00040F0004020F00040086070470C15004071 -:105000001015004040170040F0B585B00C4605462D -:10501000F9F73EF907466E78204603A96A46EEF78F -:1050200002FD81198EB258B1012F02D0032005B0C4 -:10503000F0BD204604AA0399EEF717FC049D01E099 -:10504000022F0FD1ED1C042E0FD32888BDF80010BD -:10505000001D80B2884201D8864202D14FF0000084 -:10506000E5E702D34FF00200E1E74FF00100DEE791 -:10507000FA48C078FF2814BF0120002070472DE9AE -:10508000F041F74C0746160060680D4603D0F9F76B -:1050900069F8A0B121E0F9F765F8D8B96068F9F7C7 -:1050A00061F8D0B915F00C0F17D06068C17811F015 -:1050B0003F0F1CBF007910F0100F0ED00AE0022E37 -:1050C00008D0E6481FB1807DFF2806D002E0C078F6 -:1050D000FF2802D00120BDE8F0810020BDE8F0816A -:1050E0000A4601460120CAE710B5DC4C1D2200210A -:1050F000A01CE9F7CCF97F206077FF202074E070D6 -:10510000A075A08920F060002030A08100202070D0 -:1051100010BD70B5D249486001200870D248D1490D -:10512000002541600570CD4C1D222946A01CE9F7E1 -:10513000AEF97F206077FF202074E070A075A08911 -:1051400020F060002030A081257070BD2DE9F0476F -:10515000C24C06462078C24F4FF0010907F10808FB -:10516000002520B13878D0B998F80000B8B198F887 -:10517000000068B387F80090D8F804103C2239B3D7 -:105180007570301DE9F759F90520307086F80490E4 -:105190003878002818BF88F8005005D015E03D7019 -:1051A000A11C4FF48E72EAE71D220021A01CE9F732 -:1051B0006EF97F206077FF202074E070A075A089D1 -:1051C00020F060002030A08125700120BDE8F0872C -:1051D0000020BDE8F087A148007800280CBF01201E -:1051E000002070470A460146002048E710B510B17C -:1051F000022810D014E09A4C6068F8F7B3FF78B931 -:105200006068C17811F03F0F1CBF007910F0100FDB -:1052100006D1012010BD9148007B10F0080FF8D195 -:10522000002010BD2DE9FF4F81B08C4D8346DDE994 -:105230000F042978DDF838A09846164600291CBFCF -:1052400005B0BDE8F08F8849097800291CBF05B07A -:10525000BDE8F08FE872B4B1012E08BF012708D075 -:10526000022E08BF022704D0042E16BF082E0327E3 -:10527000FFDFEF7385F81E804FF00008784F8CB188 -:10528000022C1DD020E0012E08BF012708D0022EDD -:1052900008BF022704D0042E16BF082E0327FFDF05 -:1052A000AF73E7E77868F8F75DFF68B97868C178A9 -:1052B00011F03F0F1CBF007910F0100F04D110E067 -:1052C000287B10F0080F0CD14FF003017868F8F735 -:1052D000FDFD30B14178090929740088C0F30B0045 -:1052E0006882CDF800807868F8F73CFF0146012815 -:1052F000BDF8000005F102090CBF40F0010020F0EC -:105300000100ADF8000099F80A2012F0020F4ED10A -:10531000022918BF20F0020049D000BFADF80000FC -:1053200010F0020F04D0002908BF40F0080801D097 -:1053300020F00808ADF800807868C17811F03F0FC0 -:105340001CBF007910F0020F0CD0314622464FF0FE -:105350000100FFF794FE002804BF48F00400ADF8F8 -:10536000000006D099F80A00800860F38208ADF8C2 -:10537000008099F80A004109BDF8000061F3461069 -:10538000ADF8000080B20090BDF80000A8810421B3 -:105390007868F8F79BFD002804BFA88920F060001A -:1053A0000CD0B0F80100C004C00C03D007E040F0FE -:1053B0000200B3E7A88920F060004030A8815CB902 -:1053C00016F00C0F08D07868C17811F03F0F1CBFA1 -:1053D000007910F0100F0DD17868C17811F03F0FEF -:1053E00008D0017911F0400F04D00621F8F76EFDC6 -:1053F00000786877314622460020FFF740FE60BB08 -:105400007968C87810F03F0F3FD0087910F0010F8D -:105410003BD0504605F1040905F10308BAF1FF0F2E -:105420000DD04A464146F8F781FA002808BFFFDF51 -:1054300098F8000040F0020088F8000025E00846D7 -:10544000F8F7DBFC88F800007868F8F7ADFC07286F -:105450000CD249467868F8F7B2FC16E094120020A6 -:10546000CC010020D2120020D40100207868F8F787 -:105470009BFC072809D100217868F8F727FD01680F -:10548000C9F800108088A9F804003146224601209E -:10549000FFF7F5FD80BB7868C17811F03F0F2BD086 -:1054A000017911F0020F27D005F1170605F1160852 -:1054B000BBF1020F18BFBBF1030F08D0F8F774FC63 -:1054C00007280AD231467868F8F787FC12E002987C -:1054D000016831608088B0800CE07868F8F764FC7F -:1054E000072807D101217868F8F7F0FC01683160DE -:1054F0008088B08088F800B0002C04BF05B0BDE8FB -:10550000F08F7868F8F72EFE022804BF05B0BDE8DA -:10551000F08F05F11F047868F8F76DFEAB7AC3F1E0 -:10552000FF01884228BF084605D9A98921F06001FA -:1055300001F14001A981C2B203EB04017868F8F7D8 -:1055400062FEA97A0844A87205B0BDE8F08FB048A1 -:105550000178002918BF704701220270007B10F00B -:10556000080F14BF07200620FCF75FBEA848C17BC8 -:10557000002908BF70470122818921F06001403174 -:1055800081810378002B18BF7047027011F0080F5B -:1055900014BF07200620FCF748BE2DE9FF5F9C4F93 -:1055A000DDF838B0914638780E4600281CBF04B0AC -:1055B000BDE8F09FBC1C1D2200212046E8F767FFD4 -:1055C000944D4FF0010A84F800A06868F8F7ECFBEE -:1055D00018B3012826D0022829D0062818BFFFDFDB -:1055E0002AD000BF04F11D016868F8F726FC20727C -:1055F000484604F1020904F10108FF2821D04A4677 -:105600004146F8F793F9002808BFFFDF98F800003B -:1056100040F0020088F8000031E0608940F013009B -:105620006081DFE7608940F015006081E0E7608914 -:1056300040F010006081D5E7608940F01200608181 -:10564000D0E76868F8F7D9FB88F800006868F8F7D1 -:10565000ABFB072804D249466868F8F7B0FB0EE0B8 -:105660006868F8F7A1FB072809D100216868F8F7F6 -:105670002DFC0168C9F800108088A9F8040084F89E -:1056800009B084F80CA000206073FF20A073A17AF9 -:1056900011F0040F08BF20752AD004F1150804F199 -:1056A0001409022E18BF032E09D06868F8F77CFB96 -:1056B00007280CD241466868F8F78FFB16E000987F -:1056C0000168C8F800108088A8F804000EE0686837 -:1056D000F8F76AFB072809D101216868F8F7F6FB9B -:1056E0000168C8F800108088A8F8040089F80060F4 -:1056F0007F20E0760398207787F800A004B006208A -:10570000BDE8F05FFCF791BD2DE9FF5F424F814698 -:105710009A4638788B4600281CBF04B0BDE8F09F3D -:105720003B48017831B1007B10F0100F04BF04B08A -:10573000BDE8F09F1D227C6800212046E8F7A7FE07 -:1057400048464FF00108661C324D84F8008004F191 -:105750000209FF280BD04A463146F8F7E7F800283F -:1057600008BFFFDF307840F0020030701CE068684E -:10577000F8F743FB30706868F8F716FB072804D287 -:1057800049466868F8F71BFB0EE06868F8F70CFB01 -:10579000072809D100216868F8F798FB0168C9F863 -:1057A00000108088A9F8040004F11D016868F8F76A -:1057B00044FB207284F809A060896BF3000040F07C -:1057C0001A00608184F80C8000206073FF20A073B1 -:1057D00020757F20E0760298207787F8008004B05B -:1057E0000720BDE8F05FFCF720BD094A137C834227 -:1057F00005BF508A88420020012070470448007B82 -:10580000C0F3411002280CBF0120002070470000A7 -:1058100094120020CC010020D4010020C2790D2375 -:1058200041B342BB8188012904D94908818004BF62 -:10583000012282800168012918BF002930D0016847 -:105840006FEA0101C1EBC10202EB011281796FEA3B -:10585000010101EB8103C3EB811111444FEA914235 -:1058600001608188B2FBF1F301FB132181714FF0DC -:10587000010102E01AB14FF00001C1717047818847 -:10588000FF2908D24FF6FF7202EA41018180FF2909 -:1058900084BFFF2282800168012918BF0029CED170 -:1058A0000360CCE7817931B1491E11F0FF018171AC -:1058B0001CBF002070470120704710B50121C17145 -:1058C0008171818004460421F1F7E8FD002818BFAA -:1058D00010BD2068401C206010BD00000B4A022152 -:1058E00011600B490B68002BFCD0084B1B1D186086 -:1058F00008680028FCD00020106008680028FCD050 -:1059000070474FF0805040697047000004E5014047 -:1059100000E4014002000B464FF00000014620D099 -:10592000012A04D0022A04D0032A0DD103E0012069 -:1059300002E0022015E00320072B05D2DFE803F088 -:105940000406080A0C0E100007207047012108E029 -:10595000022106E0032104E0042102E0052100E029 -:105960000621F0F7A4BB0000E24805218170002168 -:10597000017041707047E0490A78012A05D0CA6871 -:105980001044C8604038F1F7B4B88A6810448860A1 -:10599000F8E7002819D00378D849D94A13B1012B68 -:1059A0000ED011E00379012B00D06BB943790BB114 -:1059B000012B09D18368643B8B4205D2C0680EE09D -:1059C0000379012B02D00BB10020704743790BB152 -:1059D000012BF9D1C368643B8B42F5D280689042B9 -:1059E000F2D801207047C44901220A70027972B1CD -:1059F00000220A71427962B104224A7182685232ED -:105A00008A60C068C860BB49022088707047032262 -:105A1000EFE70322F1E770B5B74D04460020287088 -:105A2000207988B100202871607978B10420B14EC6 -:105A30006871A168F068F0F77EF8A860E0685230FD -:105A4000E8600320B07070BD0120ECE70320EEE7B2 -:105A50002DE9F04105460226F0F777FF006800B116 -:105A6000FFDFA44C01273DB12878B8B1012805D04B -:105A7000022811D0032814D027710DE06868C828C7 -:105A800008D30421F1F79BF820B16868FFF773FF92 -:105A9000012603E0002601E000F014F93046BDE8DD -:105AA000F08120780028F7D16868FFF772FF00289E -:105AB000E2D06868017879B1A078042800D0FFDFCF -:105AC00001216868FFF7A7FF8B49E07800F003F930 -:105AD0000028E1D1FFDFDFE7FFF785FF6770DBE735 -:105AE0002DE9F041834C0F46E178884200D0FFDF7A -:105AF00000250126082F7DD2DFE807F0040B2828B7 -:105B00003D434F57A0780328C9D00228C7D0FFDFF4 -:105B1000C5E7A078032802D0022800D0FFDF0420C8 -:105B2000A07025712078B8BB0020FFF724FF7248D1 -:105B30000178012906D08068E06000F0EDF820616E -:105B4000002023E0E078F0F734FCF5E7A0780328A4 -:105B500002D0022800D0FFDF207880BB022F08D0BF -:105B60005FF00500F1F749FBA078032840D0A5704D -:105B700095E70420F6E7A078042800D0FFDF022094 -:105B800004E0A078042800D0FFDF0120A168884746 -:105B9000FFF75EFF054633E003E0A078042800D05D -:105BA000FFDFBDE8F04100F08DB8A078042804D0F4 -:105BB000617809B1022800D0FFDF207818B1BDE874 -:105BC000F04100F08AB8207920B10620F1F715FBEA -:105BD00025710DE0607840B14749E07800F07BF82E -:105BE00000B9FFDF65705AE704E00720F1F705FB15 -:105BF000A67054E7FFDF52E73DB1012D03D0FFDF70 -:105C0000022DF9D14BE70420C0E70320BEE770B5B1 -:105C1000050004D0374CA078052806D101E01020FB -:105C200070BD0820F1F7FFFA08B1112070BD3548AA -:105C3000F0F720FAE070202806D00121F1F7DCF817 -:105C40000020A560A07070BD032070BD294810B56C -:105C5000017809B1112010BD8178052906D00129EC -:105C600006D029B101210170002010BD0F2010BD08 -:105C700000F033F8F8E770B51E4C0546A07808B17F -:105C8000012809D155B12846FFF783FE40B1287895 -:105C900040B1A078012809D00F2070BD102070BD40 -:105CA000072070BD2846FFF79EFE03E0002128462E -:105CB000FFF7B1FE1049E07800F00DF800B9FFDF02 -:105CC000002070BD0B4810B5006900F01DF8BDE85C -:105CD0001040F0F754B9F0F772BC064810B5C07820 -:105CE000F0F723FA00B9FFDF0820F1F786FABDE8E4 -:105CF000104039E6DC010020B41300203D8601008D -:105D0000FF1FA107E15A02000C490A6848F202137A -:105D10009A4302430A607047084A116848F2021326 -:105D200001EA03009943116070470246044B1020BA -:105D30001344FC2B01D8116000207047C8060240B4 -:105D40000018FEBF1EF0040F0CBFEFF30880EFF346 -:105D50000980014A10470000FF7B010001B41EB416 -:105D600000B5F1F76DFC01B40198864601BC01B0A5 -:105D70001EBD00008269034981614FF0010010449B -:105D8000704700005D5D02000FF20C0000F10000A2 -:105D9000694641F8080C20BF70470000FEDF184933 -:105DA0000978F9B90420714608421BD10699154AB1 -:105DB000914217DC0699022914DB02394878DF2862 -:105DC00010D10878FE2807D0FF280BD14FF0010032 -:105DD0004FF000020C4B184741F201000099019A64 -:105DE000094B1847094B002B02D01B68DB6818478A -:105DF0004FF0FF3071464FF00002034B1847000090 -:105E000028ED00E000700200D14B020004000020E9 -:105E1000174818497047FFF7FBFFDBF7CFF900BDC4 -:105E2000154816490968884203D1154A13605B6812 -:105E3000184700BD20BFFDE70F4810490968884298 -:105E400010D1104B18684FF0FF318842F2D080F328 -:105E500008884FF02021884204DD0B4802680321A6 -:105E60000A4302600948804709488047FFDF000075 -:105E7000C8130020C81300200010000000000020FC -:105E8000040000200070020014090040B92F000037 -:105E9000215E0200F0B44046494652465B460FB4CC -:105EA00002A0013001B50648004700BF01BC86468C -:105EB0000FBC8046894692469B46F0BC7047000066 -:105EC0000911000004207146084202D0EFF3098155 -:105ED00001E0EFF30881886902380078102813DBAD -:105EE00020280FDB2C280BDB0A4A12680A4B9A4247 -:105EF00003D1602804DB094A10470220086070477C -:105F0000074A1047074A1047074A12682C3212689E -:105F1000104700005C000020BEBAFECA9B130000C0 -:105F2000554302006F4D0200040000200D4B0E4946 -:105F300008470E4B0C4908470D4B0B4908470D4BC2 -:105F4000094908470C4B084908470C4B06490847C4 -:105F50000B4B054908470B4B034908470A4B0249BD -:105F60000847000041BF000079C10000792D000002 -:105F7000F32B0000812B0000012E0000B71300005E -:105F80003F2900007D2F0000455D020000210160D7 -:105F90004160017270470A6802600B7903717047B3 -:105FA00089970000FF9800005B9A0000C59A0000E6 -:105FB000FF9A0000339B0000659B00009D9B000042 -:105FC0003D9C00007D980000859A0000331200007F -:105FD0000744000053440000B94400004745000056 -:105FE0006146000037470000694700004148000053 -:105FF000DB4800002F490000154A0000354A000028 -:10600000AD160000D1160000F11500004D1600007D -:10601000031700009717000003610000C36200002F -:10602000A1660000BB67000043680000C168000073 -:10603000256900004D6A00001D6B0000896B00009F -:10604000574A00005D4A0000674A0000CF4A00003E -:10605000FB4A0000B74C0000E14C0000194D000065 -:10606000834D00006D4E0000834E00007744000019 -:10607000974E0000B94E0000FF4E000033120000A2 -:10608000331200003312000033120000C12500005B -:1060900047260000632600007F2600000D28000030 -:1060A000A9260000B3260000F526000017270000EF -:1060B000F3270000352800003312000033120000DF -:1060C00097840000B7840000B9840000FD840000BC -:1060D0002B8500001B860000A7860000BB86000001 -:1060E000098700001F880000C1890000E98A0000BC -:1060F0003D740000018B00003312000033120000D9 -:10610000EBB700004DB90000A7B9000021BA0000AC -:10611000CDBA0000010000000000000010011001D5 -:106120003A0200001A020000020004050600000006 -:1061300007111102FFFFFFFF0000FFFFF3B3000094 -:10614000273D0000532100008774000001900000EB -:1061500000000000BF9200009B920000AD92000082 -:10616000000002000000000000020000000000002B -:1061700000010000000000004382000023820000B4 -:10618000918200002D250000EF2400000F25000063 -:10619000DBAA000007AB00000FAD0000FD590000B6 -:1061A000B182000000000000E18200007B250000B9 -:1061B000000000000000000000000000F1AB000043 -:1061C00000000000915A00000300000001555555E1 -:1061D000D6BE898E00006606660C661200000A03B1 -:1061E000AE055208000056044608360CC7FD0000F4 -:1061F0005BFF0000A1FB0000C3FD0000A7A8010099 -:106200009B040100AAAED7AB15412010000000008E -:10621000900A0000900A00007B5700007B570000A6 -:10622000E143000053B200000B7700006320000040 -:10623000BD3A020063BD0100BD570000BD5700001C -:1062400005440000E5B2000093770000D72000006D -:10625000EB3A020079BD0100700170014000380086 -:106260005C0024006801200200000300656C746279 -:10627000000000000000000000000000000000001E -:106280008700000000000000000000000000000087 -:10629000BE83605ADB0B376038A5F5AA9183886C02 -:1062A000010000007746010049550100000000018F -:1062B0000206030405000000070000FB349B5F801A -:1062C000000080001000000000000000000000003E -:1062D000060000000A000000320000007300000009 -:1062E000B4000000F401FA00960064004B00320094 -:1062F0001E0014000A000500020001000049000011 -:1063000000000000D7CF0100E9D1010025D1010034 -:10631000EBCF0100000000008FD40100000101025A -:10632000010202030C0802170D0101020909010113 -:1063300006020918180301010909030305000000FA -:10634000555555252627D6BE898E00002BFB01000A -:1063500003F7010049FA01003FF20100BB220200ED -:10636000B7FB0100F401FA00960064004B00320014 -:106370001E0014000A00050002000100254900006B -:1063800000000000314A0200494A0200614A02004E -:10639000794A0200A94A0200D14A0200FB4A0200DF -:1063A0002F4B02007B470200B7460200A1430200C8 -:1063B0002B5D0200AD730100BD730100E9730100A4 -:1063C000BB740100C3740100D57401002F480200A2 -:1063D000494802001D4802002748020055480200B3 -:1063E0008B480200AB480200C9480200D7480200AF -:1063F000E5480200F54802000D4902002549020067 -:106400003B4902005149020000000000DFBC0000CF -:1064100035BD00004BBD000015590200CD43020000 -:10642000994402000F5C02004D5C0200775C0200A0 -:106430009D710100FD760100674902008D4902004F -:10644000B1490200D74902001C0500402005004068 -:10645000001002007464020008000020E80100003F -:106460004411000098640200F0010020D8110000DF -:10647000A011000001181348140244200B440C061C -:106480004813770B1B2034041ABA0401A40213101A -:08649000327F0B744411C000BF -:00000001FF diff --git a/bin/setup-python-for-esp-debug.sh b/bin/setup-python-for-esp-debug.sh deleted file mode 100644 index edba43e72b..0000000000 --- a/bin/setup-python-for-esp-debug.sh +++ /dev/null @@ -1,12 +0,0 @@ -# shellcheck shell=bash -# (this minor script is actually shell agnostic, and is intended to be sourced rather than run in a subshell) - -# This is a little script you can source if you want to make ESP debugging work on a modern (24.04) ubuntu machine -# It assumes you have built and installed python 2.7 from source with: -# ./configure --enable-optimizations --enable-shared --enable-unicode=ucs4 -# sudo make clean -# make -# sudo make altinstall - -export LD_LIBRARY_PATH=$HOME/packages/python-2.7.18/ -export PYTHON_HOME=/usr/local/lib/python2.7/ diff --git a/bin/uf2conv.py b/bin/uf2conv.py index a1e241b7a6..b619d14db0 100755 --- a/bin/uf2conv.py +++ b/bin/uf2conv.py @@ -1,38 +1,39 @@ #!/usr/bin/env python3 -import argparse -import os -import os.path -import re +import sys import struct import subprocess -import sys +import re +import os +import os.path +import argparse + -UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" -UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected -UF2_MAGIC_END = 0x0AB16F30 # Ditto +UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" +UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected +UF2_MAGIC_END = 0x0AB16F30 # Ditto families = { - "SAMD21": 0x68ED2B88, - "SAML21": 0x1851780A, - "SAMD51": 0x55114460, - "NRF52": 0x1B57745F, - "STM32F0": 0x647824B6, - "STM32F1": 0x5EE21072, - "STM32F2": 0x5D1A0A2E, - "STM32F3": 0x6B846188, - "STM32F4": 0x57755A57, - "STM32F7": 0x53B80F00, - "STM32G0": 0x300F5633, - "STM32G4": 0x4C71240A, - "STM32H7": 0x6DB66082, - "STM32L0": 0x202E3A91, - "STM32L1": 0x1E1F432D, - "STM32L4": 0x00FF6919, - "STM32L5": 0x04240BDF, - "STM32WB": 0x70D16653, - "STM32WL": 0x21460FF0, - "ATMEGA32": 0x16573617, - "MIMXRT10XX": 0x4FB2D5BD, + 'SAMD21': 0x68ed2b88, + 'SAML21': 0x1851780a, + 'SAMD51': 0x55114460, + 'NRF52': 0x1b57745f, + 'STM32F0': 0x647824b6, + 'STM32F1': 0x5ee21072, + 'STM32F2': 0x5d1a0a2e, + 'STM32F3': 0x6b846188, + 'STM32F4': 0x57755a57, + 'STM32F7': 0x53b80f00, + 'STM32G0': 0x300f5633, + 'STM32G4': 0x4c71240a, + 'STM32H7': 0x6db66082, + 'STM32L0': 0x202e3a91, + 'STM32L1': 0x1e1f432d, + 'STM32L4': 0x00ff6919, + 'STM32L5': 0x04240bdf, + 'STM32WB': 0x70d16653, + 'STM32WL': 0x21460ff0, + 'ATMEGA32': 0x16573617, + 'MIMXRT10XX': 0x4FB2D5BD } INFO_FILE = "/INFO_UF2.TXT" @@ -45,17 +46,15 @@ def is_uf2(buf): w = struct.unpack(" 10 * 1024 * 1024: + if padding > 10*1024*1024: assert False, "More than 10M of padding needed at " + ptr if padding % 4 != 0: assert False, "Non-word padding size at " + ptr @@ -92,7 +91,6 @@ def convert_from_uf2(buf): curraddr = newaddr + datalen return outp - def convert_to_carray(file_content): outp = "const unsigned char bindata[] __attribute__((aligned(16))) = {" for i in range(len(file_content)): @@ -102,7 +100,6 @@ def convert_to_carray(file_content): outp += "\n};\n" return outp - def convert_to_uf2(file_content): global familyid datapadding = b"" @@ -112,21 +109,13 @@ def convert_to_uf2(file_content): outp = b"" for blockno in range(numblocks): ptr = 256 * blockno - chunk = file_content[ptr : ptr + 256] + chunk = file_content[ptr:ptr + 256] flags = 0x0 if familyid: flags |= 0x2000 - hd = struct.pack( - b"= 3 and words[1] == "2" and words[2] == "FAT": drives.append(words[0]) else: @@ -238,6 +206,7 @@ def get_drives(): for d in os.listdir(rootpath): drives.append(os.path.join(rootpath, d)) + def has_info(d): try: return os.path.isfile(d + INFO_FILE) @@ -248,7 +217,7 @@ def has_info(d): def board_id(path): - with open(path + INFO_FILE, mode="r") as file: + with open(path + INFO_FILE, mode='r') as file: file_content = file.read() return re.search("Board-ID: ([^\r\n]*)", file_content).group(1) @@ -266,61 +235,30 @@ def write_file(name, buf): def main(): global appstartaddr, familyid - def error(msg): print(msg) sys.exit(1) - - parser = argparse.ArgumentParser(description="Convert to UF2 or flash directly.") - parser.add_argument( - "input", - metavar="INPUT", - type=str, - nargs="?", - help="input file (HEX, BIN or UF2)", - ) - parser.add_argument( - "-b", - "--base", - dest="base", - type=str, - default="0x2000", - help="set base address of application for BIN format (default: 0x2000)", - ) - parser.add_argument( - "-o", - "--output", - metavar="FILE", - dest="output", - type=str, - help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible', - ) - parser.add_argument( - "-d", "--device", dest="device_path", help="select a device path to flash" - ) - parser.add_argument( - "-l", "--list", action="store_true", help="list connected devices" - ) - parser.add_argument( - "-c", "--convert", action="store_true", help="do not flash, just convert" - ) - parser.add_argument( - "-D", "--deploy", action="store_true", help="just flash, do not convert" - ) - parser.add_argument( - "-f", - "--family", - dest="family", - type=str, - default="0x0", - help="specify familyID - number or name (default: 0x0)", - ) - parser.add_argument( - "-C", - "--carray", - action="store_true", - help="convert binary file to a C array, not UF2", - ) + parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.') + parser.add_argument('input', metavar='INPUT', type=str, nargs='?', + help='input file (HEX, BIN or UF2)') + parser.add_argument('-b' , '--base', dest='base', type=str, + default="0x2000", + help='set base address of application for BIN format (default: 0x2000)') + parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str, + help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible') + parser.add_argument('-d' , '--device', dest="device_path", + help='select a device path to flash') + parser.add_argument('-l' , '--list', action='store_true', + help='list connected devices') + parser.add_argument('-c' , '--convert', action='store_true', + help='do not flash, just convert') + parser.add_argument('-D' , '--deploy', action='store_true', + help='just flash, do not convert') + parser.add_argument('-f' , '--family', dest='family', type=str, + default="0x0", + help='specify familyID - number or name (default: 0x0)') + parser.add_argument('-C' , '--carray', action='store_true', + help='convert binary file to a C array, not UF2') args = parser.parse_args() appstartaddr = int(args.base, 0) @@ -330,17 +268,14 @@ def error(msg): try: familyid = int(args.family, 0) except ValueError: - error( - "Family ID needs to be a number or one of: " - + ", ".join(families.keys()) - ) + error("Family ID needs to be a number or one of: " + ", ".join(families.keys())) if args.list: list_drives() else: if not args.input: error("Need input file") - with open(args.input, mode="rb") as f: + with open(args.input, mode='rb') as f: inpbuf = f.read() from_uf2 = is_uf2(inpbuf) ext = "uf2" @@ -356,10 +291,8 @@ def error(msg): ext = "h" else: outbuf = convert_to_uf2(inpbuf) - print( - "Converting to %s, output size: %d, start address: 0x%x" - % (ext, len(outbuf), appstartaddr) - ) + print("Converting to %s, output size: %d, start address: 0x%x" % + (ext, len(outbuf), appstartaddr)) if args.convert or ext != "uf2": drives = [] if args.output == None: diff --git a/boards/heltec_mesh_node_t114.json b/boards/heltec_mesh_node_t114.json deleted file mode 100644 index 5c97d8c755..0000000000 --- a/boards/heltec_mesh_node_t114.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "build": { - "arduino": { - "ldscript": "nrf52840_s140_v6.ld" - }, - "core": "nRF5", - "cpu": "cortex-m4", - "extra_flags": "-DARDUINO_NRF52840_PCA10056 -DNRF52840_XXAA", - "f_cpu": "64000000L", - "hwids": [ - ["0x239A", "0x4405"], - ["0x239A", "0x0029"], - ["0x239A", "0x002A"] - ], - "usb_product": "HT-n5262", - "mcu": "nrf52840", - "variant": "heltec_mesh_node_t114", - "variants_dir": "variants", - "bsp": { - "name": "adafruit" - }, - "softdevice": { - "sd_flags": "-DS140", - "sd_name": "s140", - "sd_version": "6.1.1", - "sd_fwid": "0x00B6" - }, - "bootloader": { - "settings_addr": "0xFF000" - } - }, - "connectivity": ["bluetooth"], - "debug": { - "jlink_device": "nRF52840_xxAA", - "onboard_tools": ["jlink"], - "svd_path": "nrf52840.svd", - "openocd_target": "nrf52840-mdk-rs" - }, - "frameworks": ["arduino"], - "name": "Heltec nrf (Adafruit BSP)", - "upload": { - "maximum_ram_size": 248832, - "maximum_size": 815104, - "speed": 115200, - "protocol": "nrfutil", - "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"], - "use_1200bps_touch": true, - "require_upload_port": true, - "wait_for_upload_port": true - }, - "url": "FIXME", - "vendor": "Heltec" -} diff --git a/boards/wio-sdk-wm1110.json b/boards/wio-sdk-wm1110.json index f45b030d1f..9db60e2036 100644 --- a/boards/wio-sdk-wm1110.json +++ b/boards/wio-sdk-wm1110.json @@ -27,7 +27,7 @@ "jlink_device": "nRF52840_xxAA", "svd_path": "nrf52840.svd" }, - "frameworks": ["arduino", "freertos"], + "frameworks": ["arduino"], "name": "Seeed WIO WM1110", "upload": { "maximum_ram_size": 248832, diff --git a/boards/wio-tracker-wm1110.json b/boards/wio-tracker-wm1110.json index 37a9186abb..b4ab8db118 100644 --- a/boards/wio-tracker-wm1110.json +++ b/boards/wio-tracker-wm1110.json @@ -23,7 +23,7 @@ "sd_flags": "-DS140", "sd_name": "s140", "sd_version": "7.3.0", - "sd_fwid": "0x0123" + "sd_fwid": "0x00B6" }, "bootloader": { "settings_addr": "0xFF000" diff --git a/boards/wiscore_rak4631.json b/boards/wiscore_rak4631.json index c783f33a69..6dec3f7cb4 100644 --- a/boards/wiscore_rak4631.json +++ b/boards/wiscore_rak4631.json @@ -35,7 +35,7 @@ "svd_path": "nrf52840.svd", "openocd_target": "nrf52840-mdk-rs" }, - "frameworks": ["arduino", "freertos"], + "frameworks": ["arduino"], "name": "WisCore RAK4631 Board", "upload": { "maximum_ram_size": 248832, diff --git a/platformio.ini b/platformio.ini index b3f6772470..23ff53a102 100644 --- a/platformio.ini +++ b/platformio.ini @@ -35,10 +35,6 @@ default_envs = tbeam ;default_envs = radiomaster_900_bandit_nano ;default_envs = radiomaster_900_bandit_micro ;default_envs = heltec_capsule_sensor_v3 -;default_envs = heltec_vision_master_t190 -;default_envs = heltec_vision_master_e213 -;default_envs = heltec_vision_master_e290 -;default_envs = heltec_mesh_node_t114 extra_configs = arch/*/*.ini @@ -81,11 +77,10 @@ build_flags = -Wno-missing-field-initializers -DMESHTASTIC_EXCLUDE_DROPZONE=1 monitor_speed = 115200 -monitor_filters = direct lib_deps = jgromes/RadioLib@~6.6.0 - https://github.com/meshtastic/esp8266-oled-ssd1306.git#e16cee124fe26490cb14880c679321ad8ac89c95 ; ESP8266_SSD1306 + https://github.com/meshtastic/esp8266-oled-ssd1306.git#2b40affbe7f7dc63b6c00fa88e7e12ed1f8e1719 ; ESP8266_SSD1306 mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4 @@ -155,4 +150,5 @@ lib_deps = mprograms/QMC5883LCompass@^1.2.0 - https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee \ No newline at end of file + https://github.com/meshtastic/DFRobot_LarkWeatherStation#dee914270dc7cb3e43fbf034edd85a63a16a12ee + diff --git a/pyocd.yaml b/pyocd.yaml deleted file mode 100644 index 84bd9336b9..0000000000 --- a/pyocd.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# This is a config file to control pyocd ICE debugger probe options (only used for NRF52 targets with hardware debugging connections) -# for more info see FIXMEURL - -# console or telnet -semihost_console_type: telnet -enable_semihosting: True -telnet_port: 4444 diff --git a/src/AccelerometerThread.h b/src/AccelerometerThread.h index c2910007e3..f45511cca3 100644 --- a/src/AccelerometerThread.h +++ b/src/AccelerometerThread.h @@ -16,8 +16,6 @@ #include #ifdef RAK_4631 #include "Fusion/Fusion.h" -#include "graphics/Screen.h" -#include "graphics/ScreenFonts.h" #include #endif @@ -103,11 +101,7 @@ class AccelerometerThread : public concurrency::OSThread bmx160.getAllData(&magAccel, NULL, &gAccel); // expirimental calibrate routine. Limited to between 10 and 30 seconds after boot - if (millis() > 12 * 1000 && millis() < 30 * 1000) { - if (!showingScreen) { - showingScreen = true; - screen->startAlert((FrameCallback)drawFrameCalibration); - } + if (millis() > 10 * 1000 && millis() < 30 * 1000) { if (magAccel.x > highestX) highestX = magAccel.x; if (magAccel.x < lowestX) @@ -120,9 +114,6 @@ class AccelerometerThread : public concurrency::OSThread highestZ = magAccel.z; if (magAccel.z < lowestZ) lowestZ = magAccel.z; - } else if (showingScreen && millis() >= 30 * 1000) { - showingScreen = false; - screen->endAlert(); } int highestRealX = highestX - (highestX + lowestX) / 2; @@ -264,34 +255,11 @@ class AccelerometerThread : public concurrency::OSThread Adafruit_LIS3DH lis; Adafruit_LSM6DS3TRC lsm; SensorBMA423 bmaSensor; - bool BMA_IRQ = false; #ifdef RAK_4631 - bool showingScreen = false; RAK_BMX160 bmx160; float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0; - - static void drawFrameCalibration(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) - { - int x_offset = display->width() / 2; - int y_offset = display->height() <= 80 ? 0 : 32; - display->setTextAlignment(TEXT_ALIGN_LEFT); - display->setFont(FONT_MEDIUM); - display->drawString(x, y, "Calibrating\nCompass"); - int16_t compassX = 0, compassY = 0; - uint16_t compassDiam = graphics::Screen::getCompassDiam(display->getWidth(), display->getHeight()); - - // coordinates for the center of the compass/circle - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { - compassX = x + display->getWidth() - compassDiam / 2 - 5; - compassY = y + display->getHeight() / 2; - } else { - compassX = x + display->getWidth() - compassDiam / 2 - 5; - compassY = y + FONT_HEIGHT_SMALL + (display->getHeight() - FONT_HEIGHT_SMALL) / 2; - } - display->drawCircle(compassX, compassY, compassDiam / 2); - screen->drawCompassNorth(display, compassX, compassY, screen->getHeading() * PI / 180); - } #endif + bool BMA_IRQ = false; }; #endif \ No newline at end of file diff --git a/src/BluetoothCommon.cpp b/src/BluetoothCommon.cpp index d9502e4f51..53faae997c 100644 --- a/src/BluetoothCommon.cpp +++ b/src/BluetoothCommon.cpp @@ -10,8 +10,4 @@ const uint8_t TORADIO_UUID_16[16u] = {0xe7, 0x01, 0x44, 0x12, 0x66, 0x78, 0xdd, const uint8_t FROMRADIO_UUID_16[16u] = {0x02, 0x00, 0x12, 0xac, 0x42, 0x02, 0x78, 0xb8, 0xed, 0x11, 0x93, 0x49, 0x9e, 0xe6, 0x55, 0x2c}; const uint8_t FROMNUM_UUID_16[16u] = {0x53, 0x44, 0xe3, 0x47, 0x75, 0xaa, 0x70, 0xa6, - 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed}; -const uint8_t LEGACY_LOGRADIO_UUID_16[16u] = {0xe2, 0xf2, 0x1e, 0xbe, 0xc5, 0x15, 0xcf, 0xaa, - 0x6b, 0x43, 0xfa, 0x78, 0x38, 0xd2, 0x6f, 0x6c}; -const uint8_t LOGRADIO_UUID_16[16u] = {0x47, 0x95, 0xDF, 0x8C, 0xDE, 0xE9, 0x44, 0x99, - 0x23, 0x44, 0xE6, 0x06, 0x49, 0x6E, 0x3D, 0x5A}; \ No newline at end of file + 0x66, 0x4f, 0x00, 0xa8, 0x8c, 0xa1, 0x9d, 0xed}; \ No newline at end of file diff --git a/src/BluetoothCommon.h b/src/BluetoothCommon.h index 440d138441..586ffaa3c1 100644 --- a/src/BluetoothCommon.h +++ b/src/BluetoothCommon.h @@ -11,12 +11,10 @@ #define TORADIO_UUID "f75c76d2-129e-4dad-a1dd-7866124401e7" #define FROMRADIO_UUID "2c55e69e-4993-11ed-b878-0242ac120002" #define FROMNUM_UUID "ed9da18c-a800-4f66-a670-aa7547e34453" -#define LEGACY_LOGRADIO_UUID "6c6fd238-78fa-436b-aacf-15c5be1ef2e2" -#define LOGRADIO_UUID "5a3d6e49-06e6-4423-9944-e9de8cdf9547" // NRF52 wants these constants as byte arrays // Generated here https://yupana-engineering.com/online-uuid-to-c-array-converter - but in REVERSE BYTE ORDER -extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[], LOGRADIO_UUID_16[]; +extern const uint8_t MESH_SERVICE_UUID_16[], TORADIO_UUID_16[16u], FROMRADIO_UUID_16[], FROMNUM_UUID_16[]; /// Given a level between 0-100, update the BLE attribute void updateBatteryLevel(uint8_t level); diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index a81518f313..dc062fce46 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -187,9 +187,8 @@ int32_t ButtonThread::runOnce() case BUTTON_EVENT_LONG_PRESSED: { LOG_BUTTON("Long press!\n"); powerFSM.trigger(EVENT_PRESS); - if (screen) { - screen->startAlert("Shutting down..."); - } + if (screen) + screen->startShutdownScreen(); playBeep(); break; } diff --git a/src/DebugConfiguration.cpp b/src/DebugConfiguration.cpp index d9ecd9fe39..9df402e77b 100644 --- a/src/DebugConfiguration.cpp +++ b/src/DebugConfiguration.cpp @@ -26,7 +26,7 @@ SOFTWARE.*/ #include "DebugConfiguration.h" -#if HAS_NETWORKING +#if HAS_WIFI || HAS_ETHERNET Syslog::Syslog(UDP &client) { diff --git a/src/DebugConfiguration.h b/src/DebugConfiguration.h index ebe9da8d44..ca908197ed 100644 --- a/src/DebugConfiguration.h +++ b/src/DebugConfiguration.h @@ -1,6 +1,5 @@ -#pragma once - -#include "configuration.h" +#ifndef SYSLOG_H +#define SYSLOG_H // DEBUG LED #ifndef LED_INVERTED @@ -26,14 +25,6 @@ #include "SerialConsole.h" -// If defined we will include support for ARM ICE "semihosting" for a virtual -// console over the JTAG port (to replace the normal serial port) -// Note: Normally this flag is passed into the gcc commandline by platformio.ini. -// for an example see env:rak4631_dap. -// #ifndef USE_SEMIHOSTING -// #define USE_SEMIHOSTING -// #endif - #define DEBUG_PORT (*console) // Serial debug port #ifdef USE_SEGGER @@ -126,7 +117,7 @@ #include #endif // HAS_WIFI -#if HAS_NETWORKING +#if HAS_WIFI || HAS_ETHERNET class Syslog { @@ -161,4 +152,6 @@ class Syslog bool vlogf(uint16_t pri, const char *appName, const char *fmt, va_list args) __attribute__((format(printf, 3, 0))); }; -#endif // HAS_ETHERNET || HAS_WIFI \ No newline at end of file +#endif // HAS_ETHERNET || HAS_WIFI + +#endif // SYSLOG_H \ No newline at end of file diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index 7d3788c4d9..96aad1a9a4 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -84,58 +84,6 @@ bool renameFile(const char *pathFrom, const char *pathTo) #endif } -#include - -/** - * @brief Get the list of files in a directory. - * - * This function returns a list of files in a directory. The list includes the full path of each file. - * - * @param dirname The name of the directory. - * @param levels The number of levels of subdirectories to list. - * @return A vector of strings containing the full path of each file in the directory. - */ -std::vector getFiles(const char *dirname, uint8_t levels) -{ - std::vector filenames = {}; -#ifdef FSCom - File root = FSCom.open(dirname, FILE_O_READ); - if (!root) - return filenames; - if (!root.isDirectory()) - return filenames; - - File file = root.openNextFile(); - while (file) { - if (file.isDirectory() && !String(file.name()).endsWith(".")) { - if (levels) { -#ifdef ARCH_ESP32 - std::vector subDirFilenames = getFiles(file.path(), levels - 1); -#else - std::vector subDirFilenames = getFiles(file.name(), levels - 1); -#endif - filenames.insert(filenames.end(), subDirFilenames.begin(), subDirFilenames.end()); - file.close(); - } - } else { - meshtastic_FileInfo fileInfo = {"", file.size()}; -#ifdef ARCH_ESP32 - strcpy(fileInfo.file_name, file.path()); -#else - strcpy(fileInfo.file_name, file.name()); -#endif - if (!String(fileInfo.file_name).endsWith(".")) { - filenames.push_back(fileInfo); - } - file.close(); - } - file = root.openNextFile(); - } - root.close(); -#endif - return filenames; -} - /** * Lists the contents of a directory. * diff --git a/src/FSCommon.h b/src/FSCommon.h index 8fbabd9526..ef1d3e4c17 100644 --- a/src/FSCommon.h +++ b/src/FSCommon.h @@ -1,7 +1,6 @@ #pragma once #include "configuration.h" -#include // Cross platform filesystem API @@ -50,7 +49,6 @@ using namespace Adafruit_LittleFS_Namespace; void fsInit(); bool copyFile(const char *from, const char *to); bool renameFile(const char *pathFrom, const char *pathTo); -std::vector getFiles(const char *dirname, uint8_t levels); void listDir(const char *dirname, uint8_t levels, bool del); void rmDir(const char *dirname); void setupSDCard(); \ No newline at end of file diff --git a/src/GPSStatus.h b/src/GPSStatus.h index c2ab16c86f..1245d5e5dc 100644 --- a/src/GPSStatus.h +++ b/src/GPSStatus.h @@ -124,7 +124,7 @@ class GPSStatus : public Status if (isDirty) { if (hasLock) { // In debug logs, identify position by @timestamp:stage (stage 3 = notify) - LOG_DEBUG("New GPS pos@%x:3 lat=%f lon=%f alt=%d pdop=%.2f track=%.2f speed=%.2f sats=%d\n", p.timestamp, + LOG_DEBUG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, speed=%.2f, sats=%d\n", p.timestamp, p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5, p.ground_speed * 1e-2, p.sats_in_view); } else { diff --git a/src/Power.cpp b/src/Power.cpp index 19c5c99375..18a527cee7 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -27,7 +27,7 @@ #if defined(DEBUG_HEAP_MQTT) && !MESHTASTIC_EXCLUDE_MQTT #include "mqtt/MQTT.h" #include "target_specific.h" -#if HAS_WIFI +#if !MESTASTIC_EXCLUDE_WIFI #include #endif #endif @@ -232,20 +232,12 @@ class AnalogBatteryLevel : public HasBatteryLevel raw = espAdcRead(); scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs); scaled *= operativeAdcMultiplier; -#else // block for all other platforms -#ifdef ADC_CTRL // enable adc voltage divider when we need to read - pinMode(ADC_CTRL, OUTPUT); - digitalWrite(ADC_CTRL, ADC_CTRL_ENABLED); - delay(10); -#endif +#else // block for all other platforms for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) { raw += analogRead(BATTERY_PIN); } raw = raw / BATTERY_SENSE_SAMPLES; scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw; -#ifdef ADC_CTRL // disable adc voltage divider when we need to read - digitalWrite(ADC_CTRL, !ADC_CTRL_ENABLED); -#endif #endif if (!initial_read_done) { @@ -449,11 +441,6 @@ class AnalogBatteryLevel : public HasBatteryLevel if (!ina260Sensor.isInitialized()) return ina260Sensor.runOnce() > 0; return ina260Sensor.isRunning(); - } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA3221].first == - config.power.device_battery_ina_address) { - if (!ina3221Sensor.isInitialized()) - return ina3221Sensor.runOnce() > 0; - return ina3221Sensor.isRunning(); } return false; } diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 72e00810bb..a7bc18f1a3 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -11,7 +11,6 @@ #include "Default.h" #include "MeshService.h" #include "NodeDB.h" -#include "PowerMon.h" #include "configuration.h" #include "graphics/Screen.h" #include "main.h" @@ -50,7 +49,6 @@ static bool isPowered() static void sdsEnter() { LOG_DEBUG("Enter state: SDS\n"); - powerMon->setState(meshtastic_PowerMon_State_CPU_DeepSleep); // FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw doDeepSleep(Default::getConfiguredOrDefaultMs(config.power.sds_secs), false); } @@ -70,7 +68,6 @@ static uint32_t secsSlept; static void lsEnter() { LOG_INFO("lsEnter begin, ls_secs=%u\n", config.power.ls_secs); - powerMon->clearState(meshtastic_PowerMon_State_Screen_On); screen->setOn(false); secsSlept = 0; // How long have we been sleeping this time @@ -90,10 +87,8 @@ static void lsIdle() // Briefly come out of sleep long enough to blink the led once every few seconds uint32_t sleepTime = SLEEP_TIME; - powerMon->setState(meshtastic_PowerMon_State_CPU_LightSleep); setLed(false); // Never leave led on while in light sleep esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL); - powerMon->clearState(meshtastic_PowerMon_State_CPU_LightSleep); switch (wakeCause2) { case ESP_SLEEP_WAKEUP_TIMER: @@ -149,7 +144,6 @@ static void lsExit() static void nbEnter() { LOG_DEBUG("Enter state: NB\n"); - powerMon->clearState(meshtastic_PowerMon_State_BT_On); screen->setOn(false); #ifdef ARCH_ESP32 // Only ESP32 should turn off bluetooth @@ -161,8 +155,6 @@ static void nbEnter() static void darkEnter() { - powerMon->clearState(meshtastic_PowerMon_State_BT_On); - powerMon->clearState(meshtastic_PowerMon_State_Screen_On); setBluetoothEnable(true); screen->setOn(false); } @@ -170,8 +162,6 @@ static void darkEnter() static void serialEnter() { LOG_DEBUG("Enter state: SERIAL\n"); - powerMon->clearState(meshtastic_PowerMon_State_BT_On); - powerMon->setState(meshtastic_PowerMon_State_Screen_On); setBluetoothEnable(false); screen->setOn(true); screen->print("Serial connected\n"); @@ -180,7 +170,6 @@ static void serialEnter() static void serialExit() { // Turn bluetooth back on when we leave serial stream API - powerMon->setState(meshtastic_PowerMon_State_BT_On); setBluetoothEnable(true); screen->print("Serial disconnected\n"); } @@ -193,8 +182,6 @@ static void powerEnter() LOG_INFO("Loss of power in Powered\n"); powerFSM.trigger(EVENT_POWER_DISCONNECTED); } else { - powerMon->setState(meshtastic_PowerMon_State_BT_On); - powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); // within enter() the function getState() returns the state we came from @@ -218,8 +205,6 @@ static void powerIdle() static void powerExit() { - powerMon->setState(meshtastic_PowerMon_State_BT_On); - powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); @@ -231,8 +216,6 @@ static void powerExit() static void onEnter() { LOG_DEBUG("Enter state: ON\n"); - powerMon->setState(meshtastic_PowerMon_State_BT_On); - powerMon->setState(meshtastic_PowerMon_State_Screen_On); screen->setOn(true); setBluetoothEnable(true); } diff --git a/src/PowerMon.cpp b/src/PowerMon.cpp deleted file mode 100644 index 3d28715e0c..0000000000 --- a/src/PowerMon.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "PowerMon.h" -#include "NodeDB.h" - -// Use the 'live' config flag to figure out if we should be showing this message -static bool is_power_enabled(uint64_t m) -{ - return (m & config.power.powermon_enables) ? true : false; -} - -void PowerMon::setState(_meshtastic_PowerMon_State state, const char *reason) -{ -#ifdef USE_POWERMON - auto oldstates = states; - states |= state; - if (oldstates != states && is_power_enabled(state)) { - emitLog(reason); - } -#endif -} - -void PowerMon::clearState(_meshtastic_PowerMon_State state, const char *reason) -{ -#ifdef USE_POWERMON - auto oldstates = states; - states &= ~state; - if (oldstates != states && is_power_enabled(state)) { - emitLog(reason); - } -#endif -} - -void PowerMon::emitLog(const char *reason) -{ -#ifdef USE_POWERMON - // The nrf52 printf doesn't understand 64 bit ints, so if we ever reach that point this function will need to change. - LOG_INFO("S:PM:0x%08lx,%s\n", (uint32_t)states, reason); -#endif -} - -PowerMon *powerMon; - -void powerMonInit() -{ - powerMon = new PowerMon(); -} \ No newline at end of file diff --git a/src/PowerMon.h b/src/PowerMon.h deleted file mode 100644 index e9f5dbd59c..0000000000 --- a/src/PowerMon.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include "configuration.h" - -#include "meshtastic/powermon.pb.h" - -#ifndef MESHTASTIC_EXCLUDE_POWERMON -#define USE_POWERMON // FIXME turn this only for certain builds -#endif - -/** - * The singleton class for monitoring power consumption of device - * subsystems/modes. - * - * For more information see the PowerMon docs. - */ -class PowerMon -{ - uint64_t states = 0UL; - - public: - PowerMon() {} - - // Mark entry/exit of a power consuming state - void setState(_meshtastic_PowerMon_State state, const char *reason = ""); - void clearState(_meshtastic_PowerMon_State state, const char *reason = ""); - - private: - // Emit the coded log message - void emitLog(const char *reason); -}; - -extern PowerMon *powerMon; - -void powerMonInit(); \ No newline at end of file diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 9c3dcdc987..e09e5fe30a 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -3,8 +3,6 @@ #include "RTC.h" #include "concurrency/OSThread.h" #include "configuration.h" -#include "main.h" -#include "mesh/generated/meshtastic/mesh.pb.h" #include #include #include @@ -16,7 +14,12 @@ #include "platform/portduino/PortduinoGlue.h" #endif -#if HAS_NETWORKING +/** + * A printer that doesn't go anywhere + */ +NoopPrint noopPrint; + +#if HAS_WIFI || HAS_ETHERNET extern Syslog syslog; #endif void RedirectablePrint::rpInit() @@ -35,7 +38,7 @@ void RedirectablePrint::setDestination(Print *_dest) size_t RedirectablePrint::write(uint8_t c) { // Always send the characters to our segger JTAG debugger -#ifdef USE_SEGGER +#ifdef SEGGER_STDOUT_CH SEGGER_RTT_PutChar(SEGGER_STDOUT_CH, c); #endif @@ -46,7 +49,7 @@ size_t RedirectablePrint::write(uint8_t c) // serial port said (which could be zero) } -size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_list arg) +size_t RedirectablePrint::vprintf(const char *format, va_list arg) { va_list copy; static char printBuf[160]; @@ -62,200 +65,25 @@ size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_l len = sizeof(printBuf) - 1; printBuf[sizeof(printBuf) - 2] = '\n'; } - for (size_t f = 0; f < len; f++) { - if (!std::isprint(static_cast(printBuf[f])) && printBuf[f] != '\n') - printBuf[f] = '#'; - } - if (logLevel != nullptr) { - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) - Print::write("\u001b[34m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) - Print::write("\u001b[32m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) - Print::write("\u001b[33m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) - Print::write("\u001b[31m", 6); - } + len = Print::write(printBuf, len); - Print::write("\u001b[0m", 5); return len; } -void RedirectablePrint::log_to_serial(const char *logLevel, const char *format, va_list arg) -{ - size_t r = 0; - - // Cope with 0 len format strings, but look for new line terminator - bool hasNewline = *format && format[strlen(format) - 1] == '\n'; - - // If we are the first message on a report, include the header - if (!isContinuationMessage) { - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) - Print::write("\u001b[34m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) - Print::write("\u001b[32m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) - Print::write("\u001b[33m", 6); - if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) - Print::write("\u001b[31m", 6); - uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile - if (rtc_sec > 0) { - long hms = rtc_sec % SEC_PER_DAY; - // hms += tz.tz_dsttime * SEC_PER_HOUR; - // hms -= tz.tz_minuteswest * SEC_PER_MIN; - // mod `hms` to ensure in positive range of [0...SEC_PER_DAY) - hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; - - // Tear apart hms into h:m:s - int hour = hms / SEC_PER_HOUR; - int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; - int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN -#ifdef ARCH_PORTDUINO - ::printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); -#else - printf("%s \u001b[0m| %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); -#endif - } else -#ifdef ARCH_PORTDUINO - ::printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); -#else - printf("%s \u001b[0m| ??:??:?? %u ", logLevel, millis() / 1000); -#endif - - auto thread = concurrency::OSThread::currentThread; - if (thread) { - print("["); - // printf("%p ", thread); - // assert(thread->ThreadName.length()); - print(thread->ThreadName); - print("] "); - } - } - r += vprintf(logLevel, format, arg); - - isContinuationMessage = !hasNewline; -} - -void RedirectablePrint::log_to_syslog(const char *logLevel, const char *format, va_list arg) -{ -#if HAS_NETWORKING && !defined(ARCH_PORTDUINO) - // if syslog is in use, collect the log messages and send them to syslog - if (syslog.isEnabled()) { - int ll = 0; - switch (logLevel[0]) { - case 'D': - ll = SYSLOG_DEBUG; - break; - case 'I': - ll = SYSLOG_INFO; - break; - case 'W': - ll = SYSLOG_WARN; - break; - case 'E': - ll = SYSLOG_ERR; - break; - case 'C': - ll = SYSLOG_CRIT; - break; - default: - ll = 0; - } - auto thread = concurrency::OSThread::currentThread; - if (thread) { - syslog.vlogf(ll, thread->ThreadName.c_str(), format, arg); - } else { - syslog.vlogf(ll, format, arg); - } - } -#endif -} - -void RedirectablePrint::log_to_ble(const char *logLevel, const char *format, va_list arg) -{ -#if !MESHTASTIC_EXCLUDE_BLUETOOTH - if (config.bluetooth.device_logging_enabled && !pauseBluetoothLogging) { - bool isBleConnected = false; -#ifdef ARCH_ESP32 - isBleConnected = nimbleBluetooth && nimbleBluetooth->isActive() && nimbleBluetooth->isConnected(); -#elif defined(ARCH_NRF52) - isBleConnected = nrf52Bluetooth != nullptr && nrf52Bluetooth->isConnected(); -#endif - if (isBleConnected) { - char *message; - size_t initialLen; - size_t len; - initialLen = strlen(format); - message = new char[initialLen + 1]; - len = vsnprintf(message, initialLen + 1, format, arg); - if (len > initialLen) { - delete[] message; - message = new char[len + 1]; - vsnprintf(message, len + 1, format, arg); - } - auto thread = concurrency::OSThread::currentThread; - meshtastic_LogRecord logRecord = meshtastic_LogRecord_init_zero; - logRecord.level = getLogLevel(logLevel); - strcpy(logRecord.message, message); - if (thread) - strcpy(logRecord.source, thread->ThreadName.c_str()); - logRecord.time = getValidTime(RTCQuality::RTCQualityDevice, true); - - uint8_t *buffer = new uint8_t[meshtastic_LogRecord_size]; - size_t size = pb_encode_to_bytes(buffer, meshtastic_LogRecord_size, meshtastic_LogRecord_fields, &logRecord); -#ifdef ARCH_ESP32 - nimbleBluetooth->sendLog(buffer, size); -#elif defined(ARCH_NRF52) - nrf52Bluetooth->sendLog(buffer, size); -#endif - delete[] message; - delete[] buffer; - } - } -#else - (void)logLevel; - (void)format; - (void)arg; -#endif -} - -meshtastic_LogRecord_Level RedirectablePrint::getLogLevel(const char *logLevel) -{ - meshtastic_LogRecord_Level ll = meshtastic_LogRecord_Level_UNSET; // default to unset - switch (logLevel[0]) { - case 'D': - ll = meshtastic_LogRecord_Level_DEBUG; - break; - case 'I': - ll = meshtastic_LogRecord_Level_INFO; - break; - case 'W': - ll = meshtastic_LogRecord_Level_WARNING; - break; - case 'E': - ll = meshtastic_LogRecord_Level_ERROR; - break; - case 'C': - ll = meshtastic_LogRecord_Level_CRITICAL; - break; - } - return ll; -} - -void RedirectablePrint::log(const char *logLevel, const char *format, ...) +size_t RedirectablePrint::log(const char *logLevel, const char *format, ...) { #ifdef ARCH_PORTDUINO if (settingsMap[logoutputlevel] < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) - return; + return 0; else if (settingsMap[logoutputlevel] < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) - return; + return 0; else if (settingsMap[logoutputlevel] < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0) - return; + return 0; #endif if (moduleConfig.serial.override_console_serial_port && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) { - return; + return 0; } - + size_t r = 0; #ifdef HAS_FREE_RTOS if (inDebugPrint != nullptr && xSemaphoreTake(inDebugPrint, portMAX_DELAY) == pdTRUE) { #else @@ -266,11 +94,81 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...) va_list arg; va_start(arg, format); - log_to_serial(logLevel, format, arg); - log_to_syslog(logLevel, format, arg); - log_to_ble(logLevel, format, arg); + // Cope with 0 len format strings, but look for new line terminator + bool hasNewline = *format && format[strlen(format) - 1] == '\n'; + + // If we are the first message on a report, include the header + if (!isContinuationMessage) { + uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile + if (rtc_sec > 0) { + long hms = rtc_sec % SEC_PER_DAY; + // hms += tz.tz_dsttime * SEC_PER_HOUR; + // hms -= tz.tz_minuteswest * SEC_PER_MIN; + // mod `hms` to ensure in positive range of [0...SEC_PER_DAY) + hms = (hms + SEC_PER_DAY) % SEC_PER_DAY; + + // Tear apart hms into h:m:s + int hour = hms / SEC_PER_HOUR; + int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN; + int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN +#ifdef ARCH_PORTDUINO + r += ::printf("%s | %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); +#else + r += printf("%s | %02d:%02d:%02d %u ", logLevel, hour, min, sec, millis() / 1000); +#endif + } else +#ifdef ARCH_PORTDUINO + r += ::printf("%s | ??:??:?? %u ", logLevel, millis() / 1000); +#else + r += printf("%s | ??:??:?? %u ", logLevel, millis() / 1000); +#endif + + auto thread = concurrency::OSThread::currentThread; + if (thread) { + print("["); + // printf("%p ", thread); + // assert(thread->ThreadName.length()); + print(thread->ThreadName); + print("] "); + } + } + r += vprintf(format, arg); + +#if (HAS_WIFI || HAS_ETHERNET) && !defined(ARCH_PORTDUINO) + // if syslog is in use, collect the log messages and send them to syslog + if (syslog.isEnabled()) { + int ll = 0; + switch (logLevel[0]) { + case 'D': + ll = SYSLOG_DEBUG; + break; + case 'I': + ll = SYSLOG_INFO; + break; + case 'W': + ll = SYSLOG_WARN; + break; + case 'E': + ll = SYSLOG_ERR; + break; + case 'C': + ll = SYSLOG_CRIT; + break; + default: + ll = 0; + } + auto thread = concurrency::OSThread::currentThread; + if (thread) { + syslog.vlogf(ll, thread->ThreadName.c_str(), format, arg); + } else { + syslog.vlogf(ll, format, arg); + } + } +#endif va_end(arg); + + isContinuationMessage = !hasNewline; #ifdef HAS_FREE_RTOS xSemaphoreGive(inDebugPrint); #else @@ -278,7 +176,7 @@ void RedirectablePrint::log(const char *logLevel, const char *format, ...) #endif } - return; + return r; } void RedirectablePrint::hexDump(const char *logLevel, unsigned char *buf, uint16_t len) diff --git a/src/RedirectablePrint.h b/src/RedirectablePrint.h index 23ae3c44de..31cc1b6ef7 100644 --- a/src/RedirectablePrint.h +++ b/src/RedirectablePrint.h @@ -1,7 +1,6 @@ #pragma once #include "../freertosinc.h" -#include "mesh/generated/meshtastic/mesh.pb.h" #include #include #include @@ -42,21 +41,23 @@ class RedirectablePrint : public Print * log message. Otherwise we assume more prints will come before the log message ends. This * allows you to call logDebug a few times to build up a single log message line if you wish. */ - void log(const char *logLevel, const char *format, ...) __attribute__((format(printf, 3, 4))); + size_t log(const char *logLevel, const char *format, ...) __attribute__((format(printf, 3, 4))); /** like printf but va_list based */ - size_t vprintf(const char *logLevel, const char *format, va_list arg); + size_t vprintf(const char *format, va_list arg); void hexDump(const char *logLevel, unsigned char *buf, uint16_t len); std::string mt_sprintf(const std::string fmt_str, ...); +}; - protected: - /// Subclasses can override if they need to change how we format over the serial port - virtual void log_to_serial(const char *logLevel, const char *format, va_list arg); +class NoopPrint : public Print +{ + public: + virtual size_t write(uint8_t c) { return 1; } +}; - private: - void log_to_syslog(const char *logLevel, const char *format, va_list arg); - void log_to_ble(const char *logLevel, const char *format, va_list arg); - meshtastic_LogRecord_Level getLogLevel(const char *logLevel); -}; \ No newline at end of file +/** + * A printer that doesn't go anywhere + */ +extern NoopPrint noopPrint; \ No newline at end of file diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index 9a9331e473..cf6375585c 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -28,7 +28,7 @@ void consolePrintf(const char *format, ...) { va_list arg; va_start(arg, format); - console->vprintf(nullptr, format, arg); + console->vprintf(format, arg); va_end(arg); console->flush(); } @@ -38,6 +38,7 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), con assert(!console); console = this; canWrite = false; // We don't send packets to our port until it has talked to us first + // setDestination(&noopPrint); for testing, try turning off 'all' debug output and see what leaks #ifdef RP2040_SLOW_CLOCK Port.setTX(SERIAL2_TX); @@ -84,40 +85,13 @@ bool SerialConsole::handleToRadio(const uint8_t *buf, size_t len) { // only talk to the API once the configuration has been loaded and we're sure the serial port is not disabled. if (config.has_lora && config.device.serial_enabled) { - // Switch to protobufs for log messages - usingProtobufs = true; + // Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets + if (!config.device.debug_log_enabled) + setDestination(&noopPrint); canWrite = true; return StreamAPI::handleToRadio(buf, len); } else { return false; } -} - -void SerialConsole::log_to_serial(const char *logLevel, const char *format, va_list arg) -{ - if (usingProtobufs) { - meshtastic_LogRecord_Level ll = meshtastic_LogRecord_Level_UNSET; // default to unset - switch (logLevel[0]) { - case 'D': - ll = meshtastic_LogRecord_Level_DEBUG; - break; - case 'I': - ll = meshtastic_LogRecord_Level_INFO; - break; - case 'W': - ll = meshtastic_LogRecord_Level_WARNING; - break; - case 'E': - ll = meshtastic_LogRecord_Level_ERROR; - break; - case 'C': - ll = meshtastic_LogRecord_Level_CRITICAL; - break; - } - - auto thread = concurrency::OSThread::currentThread; - emitLogRecord(ll, thread ? thread->ThreadName.c_str() : "", format, arg); - } else - RedirectablePrint::log_to_serial(logLevel, format, arg); } \ No newline at end of file diff --git a/src/SerialConsole.h b/src/SerialConsole.h index f1e636c9de..f8891ba14f 100644 --- a/src/SerialConsole.h +++ b/src/SerialConsole.h @@ -8,11 +8,6 @@ */ class SerialConsole : public StreamAPI, public RedirectablePrint, private concurrency::OSThread { - /** - * If true we are talking to a smart host and all messages (including log messages) must be framed as protobufs. - */ - bool usingProtobufs = false; - public: SerialConsole(); @@ -36,13 +31,10 @@ class SerialConsole : public StreamAPI, public RedirectablePrint, private concur protected: /// Check the current underlying physical link to see if the client is currently connected virtual bool checkIsConnected() override; - - /// Possibly switch to protobufs if we see a valid protobuf message - virtual void log_to_serial(const char *logLevel, const char *format, va_list arg); }; // A simple wrapper to allow non class aware code write to the console void consolePrintf(const char *format, ...); void consoleInit(); -extern SerialConsole *console; \ No newline at end of file +extern SerialConsole *console; diff --git a/src/commands.h b/src/commands.h index f2b7830105..03ede5982e 100644 --- a/src/commands.h +++ b/src/commands.h @@ -8,11 +8,13 @@ enum class Cmd { SET_ON, SET_OFF, ON_PRESS, - START_ALERT_FRAME, - STOP_ALERT_FRAME, + START_BLUETOOTH_PIN_SCREEN, START_FIRMWARE_UPDATE_SCREEN, + STOP_BLUETOOTH_PIN_SCREEN, STOP_BOOT_SCREEN, PRINT, + START_SHUTDOWN_SCREEN, + START_REBOOT_SCREEN, SHOW_PREV_FRAME, SHOW_NEXT_FRAME }; \ No newline at end of file diff --git a/src/configuration.h b/src/configuration.h index aad4ac4572..3d10feeaaf 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -242,6 +242,9 @@ along with this program. If not, see . #define HAS_BLUETOOTH 0 #endif +#include "DebugConfiguration.h" +#include "RF95Configuration.h" + #ifndef HW_VENDOR #error HW_VENDOR must be defined #endif @@ -258,7 +261,6 @@ along with this program. If not, see . #define MESHTASTIC_EXCLUDE_GPS 1 #define MESHTASTIC_EXCLUDE_SCREEN 1 #define MESHTASTIC_EXCLUDE_MQTT 1 -#define MESHTASTIC_EXCLUDE_POWERMON 1 #endif // Turn off all optional modules @@ -279,7 +281,6 @@ along with this program. If not, see . #define MESHTASTIC_EXCLUDE_WAYPOINT 1 #define MESHTASTIC_EXCLUDE_INPUTBROKER 1 #define MESHTASTIC_EXCLUDE_SERIAL 1 -#define MESHTASTIC_EXCLUDE_POWERSTRESS 1 #endif // // Turn off wifi even if HW supports wifi (webserver relies on wifi and is also disabled) @@ -289,9 +290,6 @@ along with this program. If not, see . #define HAS_WIFI 0 #endif -// Allow code that needs internet to just check HAS_NETWORKING rather than HAS_WIFI || HAS_ETHERNET -#define HAS_NETWORKING (HAS_WIFI || HAS_ETHERNET) - // // Turn off Bluetooth #ifdef MESHTASTIC_EXCLUDE_BLUETOOTH #undef HAS_BLUETOOTH @@ -310,7 +308,4 @@ along with this program. If not, see . #ifdef MESHTASTIC_EXCLUDE_SCREEN #undef HAS_SCREEN #define HAS_SCREEN 0 -#endif - -#include "DebugConfiguration.h" -#include "RF95Configuration.h" \ No newline at end of file +#endif \ No newline at end of file diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 8738e2722d..86408b8d2e 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -314,7 +314,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) case SHT31_4x_ADDR: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2); - if (registerValue == 0x11a2 || registerValue == 0x11da) { + if (registerValue == 0x11a2) { type = SHT4X; LOG_INFO("SHT4X sensor found\n"); } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) { @@ -402,4 +402,4 @@ TwoWire *ScanI2CTwoWire::fetchI2CBus(ScanI2C::DeviceAddress address) const size_t ScanI2CTwoWire::countDevices() const { return foundDevices.size(); -} +} \ No newline at end of file diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 017a2d025e..40ee4ea032 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -3,13 +3,11 @@ #include "Default.h" #include "GPS.h" #include "NodeDB.h" -#include "PowerMon.h" #include "RTC.h" #include "main.h" // pmu_found #include "sleep.h" -#include "GPSUpdateScheduling.h" #include "cas.h" #include "ubx.h" @@ -23,6 +21,19 @@ #define GPS_RESET_MODE HIGH #endif +// How many minutes of sleep make it worthwhile to power-off the GPS +// Shorter than this, and GPS will only enter standby +// Affected by lock-time, and config.position.gps_update_interval +#ifndef GPS_STANDBY_THRESHOLD_MINUTES +#define GPS_STANDBY_THRESHOLD_MINUTES 15 +#endif + +// How many seconds of sleep make it worthwhile for the GPS to use powered-on standby +// Shorter than this, and we'll just wait instead +#ifndef GPS_IDLE_THRESHOLD_SECONDS +#define GPS_IDLE_THRESHOLD_SECONDS 10 +#endif + #if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) HardwareSerial *GPS::_serial_gps = &Serial1; #else @@ -31,8 +42,6 @@ HardwareSerial *GPS::_serial_gps = NULL; GPS *gps = nullptr; -GPSUpdateScheduling scheduling; - /// Multiple GPS instances might use the same serial port (in sequence), but we can /// only init that port once. static bool didSerialInit; @@ -42,25 +51,6 @@ uint8_t uBloxProtocolVersion; #define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway #define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc) -// For logging -const char *getGPSPowerStateString(GPSPowerState state) -{ - switch (state) { - case GPS_ACTIVE: - return "ACTIVE"; - case GPS_IDLE: - return "IDLE"; - case GPS_SOFTSLEEP: - return "SOFTSLEEP"; - case GPS_HARDSLEEP: - return "HARDSLEEP"; - case GPS_OFF: - return "OFF"; - default: - assert(false); // Unhandled enum value.. - } -} - void GPS::UBXChecksum(uint8_t *message, size_t length) { uint8_t CK_A = 0, CK_B = 0; @@ -782,6 +772,7 @@ bool GPS::setup() } notifyDeepSleepObserver.observe(¬ifyDeepSleep); + notifyGPSSleepObserver.observe(¬ifyGPSSleep); return true; } @@ -790,192 +781,113 @@ GPS::~GPS() { // we really should unregister our sleep observer notifyDeepSleepObserver.unobserve(¬ifyDeepSleep); + notifyGPSSleepObserver.observe(¬ifyGPSSleep); } -// Put the GPS hardware into a specified state -void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime) -{ - // Update the stored GPSPowerstate, and create local copies - GPSPowerState oldState = powerState; - powerState = newState; - LOG_INFO("GPS power state moving from %s to %s\n", getGPSPowerStateString(oldState), getGPSPowerStateString(newState)); - - switch (newState) { - case GPS_ACTIVE: - case GPS_IDLE: - if (oldState == GPS_ACTIVE || oldState == GPS_IDLE) // If hardware already awake, no changes needed - break; - if (oldState != GPS_ACTIVE && oldState != GPS_IDLE) // If hardware just waking now, clear buffer - clearBuffer(); - powerMon->setState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) - writePinEN(true); // Power (EN pin): on - setPowerPMU(true); // Power (PMU): on - writePinStandby(false); // Standby (pin): awake (not standby) - setPowerUBLOX(true); // Standby (UBLOX): awake - break; - - case GPS_SOFTSLEEP: - powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) - writePinEN(true); // Power (EN pin): on - setPowerPMU(true); // Power (PMU): on - writePinStandby(true); // Standby (pin): asleep (not awake) - setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed - break; - - case GPS_HARDSLEEP: - powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) - writePinEN(false); // Power (EN pin): off - setPowerPMU(false); // Power (PMU): off - writePinStandby(true); // Standby (pin): asleep (not awake) - setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed - break; - - case GPS_OFF: - assert(sleepTime == 0); // This is an indefinite sleep - powerMon->clearState(meshtastic_PowerMon_State_GPS_Active); // Report change for power monitoring (during testing) - writePinEN(false); // Power (EN pin): off - setPowerPMU(false); // Power (PMU): off - writePinStandby(true); // Standby (pin): asleep - setPowerUBLOX(false, 0); // Standby (UBLOX): asleep, indefinitely - break; - } -} - -// Set power with EN pin, if relevant -void GPS::writePinEN(bool on) +void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime) { - // Abort: if conflict with Canned Messages when using Wisblock(?) - if (HW_VENDOR == meshtastic_HardwareModel_RAK4631 && (rotaryEncoderInterruptImpl1 || upDownInterruptImpl1)) + // Record the current powerState + if (on) + powerState = GPS_ACTIVE; + else if (!enabled) // User has disabled with triple press + powerState = GPS_OFF; + else if (sleepTime <= GPS_IDLE_THRESHOLD_SECONDS * 1000UL) + powerState = GPS_IDLE; + else if (standbyOnly) + powerState = GPS_STANDBY; + else + powerState = GPS_OFF; + + LOG_DEBUG("GPS::powerState=%d\n", powerState); + + // If the next update is due *really soon*, don't actually power off or enter standby. Just wait it out. + if (!on && powerState == GPS_IDLE) return; - // Abort: if pin unset - if (!en_gpio) + if (on) { + clearBuffer(); // drop any old data waiting in the buffer before re-enabling + if (en_gpio) + digitalWrite(en_gpio, on ? GPS_EN_ACTIVE : !GPS_EN_ACTIVE); // turn this on if defined, every time + } + isInPowersave = !on; + if (!standbyOnly && en_gpio != 0 && + !(HW_VENDOR == meshtastic_HardwareModel_RAK4631 && (rotaryEncoderInterruptImpl1 || upDownInterruptImpl1))) { + LOG_DEBUG("GPS powerdown using GPS_EN_ACTIVE\n"); + digitalWrite(en_gpio, on ? GPS_EN_ACTIVE : !GPS_EN_ACTIVE); return; - - // Determine new value for the pin - bool val = GPS_EN_ACTIVE ? on : !on; - - // Write and log - pinMode(en_gpio, OUTPUT); - digitalWrite(en_gpio, val); -#ifdef GPS_EXTRAVERBOSE - LOG_DEBUG("Pin EN %s\n", val == HIGH ? "HIGH" : "LOW"); + } +#ifdef HAS_PMU // We only have PMUs on the T-Beam, and that board has a tiny battery to save GPS ephemera, so treat as a standby. + if (pmu_found && PMU) { + uint8_t model = PMU->getChipModel(); + if (model == XPOWERS_AXP2101) { + if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) { + // t-beam v1.2 GNSS power channel + on ? PMU->enablePowerOutput(XPOWERS_ALDO3) : PMU->disablePowerOutput(XPOWERS_ALDO3); + } else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) { + // t-beam-s3-core GNSS power channel + on ? PMU->enablePowerOutput(XPOWERS_ALDO4) : PMU->disablePowerOutput(XPOWERS_ALDO4); + } + } else if (model == XPOWERS_AXP192) { + // t-beam v1.1 GNSS power channel + on ? PMU->enablePowerOutput(XPOWERS_LDO3) : PMU->disablePowerOutput(XPOWERS_LDO3); + } + return; + } #endif -} - -// Set the value of the STANDBY pin, if relevant -// true for standby state, false for awake -void GPS::writePinStandby(bool standby) -{ #ifdef PIN_GPS_STANDBY // Specifically the standby pin for L76B, L76K and clones - -// Determine the new value for the pin -// Normally: active HIGH for awake -#if PIN_GPS_STANDBY_INVERTED - bool val = standby; + if (on) { + LOG_INFO("Waking GPS\n"); + pinMode(PIN_GPS_STANDBY, OUTPUT); + // Some PCB's use an inverse logic due to a transistor driver + // Example for this is the Pico-Waveshare Lora+GPS HAT +#ifdef PIN_GPS_STANDBY_INVERTED + digitalWrite(PIN_GPS_STANDBY, 0); #else - bool val = !standby; -#endif - - // Write and log - pinMode(PIN_GPS_STANDBY, OUTPUT); - digitalWrite(PIN_GPS_STANDBY, val); -#ifdef GPS_EXTRAVERBOSE - LOG_DEBUG("Pin STANDBY %s\n", val == HIGH ? "HIGH" : "LOW"); + digitalWrite(PIN_GPS_STANDBY, 1); #endif -#endif -} - -// Enable / Disable GPS with PMU, if present -void GPS::setPowerPMU(bool on) -{ - // We only have PMUs on the T-Beam, and that board has a tiny battery to save GPS ephemera, - // so treat as a standby. -#ifdef HAS_PMU - // Abort: if no PMU - if (!pmu_found) return; - - // Abort: if PMU not initialized - if (!PMU) - return; - - uint8_t model = PMU->getChipModel(); - if (model == XPOWERS_AXP2101) { - if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) { - // t-beam v1.2 GNSS power channel - on ? PMU->enablePowerOutput(XPOWERS_ALDO3) : PMU->disablePowerOutput(XPOWERS_ALDO3); - } else if (HW_VENDOR == meshtastic_HardwareModel_LILYGO_TBEAM_S3_CORE) { - // t-beam-s3-core GNSS power channel - on ? PMU->enablePowerOutput(XPOWERS_ALDO4) : PMU->disablePowerOutput(XPOWERS_ALDO4); - } - } else if (model == XPOWERS_AXP192) { - // t-beam v1.1 GNSS power channel - on ? PMU->enablePowerOutput(XPOWERS_LDO3) : PMU->disablePowerOutput(XPOWERS_LDO3); - } - -#ifdef GPS_EXTRAVERBOSE - LOG_DEBUG("PMU %s\n", on ? "on" : "off"); -#endif + } else { + LOG_INFO("GPS entering sleep\n"); + // notifyGPSSleep.notifyObservers(NULL); + pinMode(PIN_GPS_STANDBY, OUTPUT); +#ifdef PIN_GPS_STANDBY_INVERTED + digitalWrite(PIN_GPS_STANDBY, 1); +#else + digitalWrite(PIN_GPS_STANDBY, 0); #endif -} - -// Set UBLOX power, if relevant -void GPS::setPowerUBLOX(bool on, uint32_t sleepMs) -{ - // Abort: if not UBLOX hardware - if (gnssModel != GNSS_MODEL_UBLOX) return; - - // If waking - if (on) { - gps->_serial_gps->write(0xFF); - clearBuffer(); // This often returns old data, so drop it -#ifdef GPS_EXTRAVERBOSE - LOG_DEBUG("UBLOX: wake\n"); -#endif } - - // If putting to sleep - else { - uint8_t msglen; - - // If we're being asked to sleep indefinitely, make *sure* we're awake first, to process the new sleep command - if (sleepMs == 0) { - setPowerUBLOX(true); - delay(500); +#endif + if (!on) { + if (gnssModel == GNSS_MODEL_UBLOX) { + uint8_t msglen; + LOG_DEBUG("Sleep Time: %i\n", sleepTime); + if (strncmp(info.hwVersion, "000A0000", 8) != 0) { + for (int i = 0; i < 4; i++) { + gps->_message_PMREQ[0 + i] = sleepTime >> (i * 8); // Encode the sleep time in millis into the packet + } + msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ), gps->_message_PMREQ); + } else { + for (int i = 0; i < 4; i++) { + gps->_message_PMREQ_10[4 + i] = sleepTime >> (i * 8); // Encode the sleep time in millis into the packet + } + msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ_10), gps->_message_PMREQ_10); + } + gps->_serial_gps->write(gps->UBXscratch, msglen); } - - // Determine hardware version - if (strncmp(info.hwVersion, "000A0000", 8) != 0) { - // Encode the sleep time in millis into the packet - for (int i = 0; i < 4; i++) - gps->_message_PMREQ[0 + i] = sleepMs >> (i * 8); - - // Record the message length - msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ), gps->_message_PMREQ); - } else { - // Encode the sleep time in millis into the packet - for (int i = 0; i < 4; i++) - gps->_message_PMREQ_10[4 + i] = sleepMs >> (i * 8); - - // Record the message length - msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ_10), gps->_message_PMREQ_10); - #ifdef GNSS_Airoha // add by WayenWeng + else { if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) { // TODO, send rtc mode command digitalWrite(PIN_GPS_EN, LOW); } -#endif } - - // Send the UBX packet - gps->_serial_gps->write(gps->UBXscratch, msglen); - -#ifdef GPS_EXTRAVERBOSE - LOG_DEBUG("UBLOX: sleep for %dmS\n", sleepMs); #endif + } else { + if (gnssModel == GNSS_MODEL_UBLOX) { + gps->_serial_gps->write(0xFF); + clearBuffer(); // This often returns old data, so drop it + } } } @@ -988,57 +900,111 @@ void GPS::setConnected() } } -// We want a GPS lock. Wake the hardware -void GPS::up() +/** + * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode + * + * calls sleep/wake + */ +void GPS::setAwake(bool wantAwake) { - scheduling.informSearching(); - setPowerState(GPS_ACTIVE); -} -// We've got a GPS lock. Enter a low power state, potentially. -void GPS::down() -{ - scheduling.informGotLock(); - uint32_t predictedSearchDuration = scheduling.predictedSearchDurationMs(); - uint32_t sleepTime = scheduling.msUntilNextSearch(); - uint32_t updateInterval = Default::getConfiguredOrDefaultMs(config.position.gps_update_interval); + // If user has disabled GPS, make sure it is off, not just in standby or idle + if (!wantAwake && !enabled && powerState != GPS_OFF) { + setGPSPower(false, false, 0); + return; + } - LOG_DEBUG("%us until next search\n", sleepTime / 1000); + // If GPS power state needs to change + if ((wantAwake && powerState != GPS_ACTIVE) || (!wantAwake && powerState == GPS_ACTIVE)) { + LOG_DEBUG("WANT GPS=%d\n", wantAwake); + // Calculate how long it takes to get a GPS lock + if (wantAwake) { + // Record the time we start looking for a lock + lastWakeStartMsec = millis(); #ifdef GNSS_Airoha - lastFixStartMsec = 0; + lastFixStartMsec = 0; #endif + } else { + // Record by how much we missed our ideal target postion.gps_update_interval (for logging only) + // Need to calculate this before we update lastSleepStartMsec, to make the new prediction + int32_t lateByMsec = (int32_t)(millis() - lastSleepStartMsec) - (int32_t)getSleepTime(); - // If update interval less than 10 seconds, no attempt to sleep - if (updateInterval <= 10 * 1000UL) - setPowerState(GPS_IDLE); - else { - // Check whether the GPS hardware is capable of GPS_SOFTSLEEP - // If not, fallback to GPS_HARDSLEEP instead - bool softsleepSupported = false; - if (gnssModel == GNSS_MODEL_UBLOX) // U-blox is supported via PMREQ - softsleepSupported = true; -#ifdef PIN_GPS_STANDBY // L76B, L76K and clones have a standby pin - softsleepSupported = true; -#endif + // Record the time we finish looking for a lock + lastSleepStartMsec = millis(); - // How long does gps_update_interval need to be, for GPS_HARDSLEEP to become more efficient than GPS_SOFTSLEEP? - // Heuristic equation. A compromise manually fitted to power observations from U-blox NEO-6M and M10050 - // https://www.desmos.com/calculator/6gvjghoumr - // This is not particularly accurate, but probably an impromevement over a single, fixed threshold - uint32_t hardsleepThreshold = (2750 * pow(predictedSearchDuration / 1000, 1.22)); - LOG_DEBUG("gps_update_interval >= %us needed to justify hardsleep\n", hardsleepThreshold / 1000); + // How long did it take to get GPS lock this time? + uint32_t lockTime = lastSleepStartMsec - lastWakeStartMsec; - // If update interval too short: softsleep (if supported by hardware) - if (softsleepSupported && updateInterval < hardsleepThreshold) - setPowerState(GPS_SOFTSLEEP, sleepTime); + // Update the lock-time prediction + // Used pre-emptively, attempting to hit target of gps.position_update_interval + switch (GPSCycles) { + case 0: + LOG_DEBUG("Initial GPS lock took %ds\n", lockTime / 1000); + break; + case 1: + predictedLockTime = lockTime; // Avoid slow ramp-up - start with a real value + LOG_DEBUG("GPS Lock took %ds\n", lockTime / 1000); + break; + default: + // Predict lock-time using exponential smoothing: respond slowly to changes + predictedLockTime = (lockTime * 0.2) + (predictedLockTime * 0.8); // Latest lock time has 20% weight on prediction + LOG_INFO("GPS Lock took %ds. %s by %ds. Next lock predicted to take %ds.\n", lockTime / 1000, + (lateByMsec > 0) ? "Late" : "Early", abs(lateByMsec) / 1000, predictedLockTime / 1000); + } + GPSCycles++; + } - // If update interval long enough (or softsleep unsupported): hardsleep instead - else - setPowerState(GPS_HARDSLEEP, sleepTime); + // How long to wait before attempting next GPS update + // Aims to hit position.gps_update_interval by using the lock-time prediction + uint32_t compensatedSleepTime = (getSleepTime() > predictedLockTime) ? (getSleepTime() - predictedLockTime) : 0; + + // If long interval between updates: power off between updates + if (compensatedSleepTime > GPS_STANDBY_THRESHOLD_MINUTES * MS_IN_MINUTE) { + setGPSPower(wantAwake, false, getSleepTime() - predictedLockTime); + } + + // If waking relatively frequently: don't power off. Would use more energy trying to reacquire lock each time + // We'll either use a "powered-on" standby, or just wait it out, depending on how soon the next update is due + // Will decide which inside setGPSPower method + else { +#ifdef GPS_UC6580 + setGPSPower(wantAwake, false, compensatedSleepTime); +#else + setGPSPower(wantAwake, true, compensatedSleepTime); +#endif + } } } +/** Get how long we should stay looking for each acquisition in msecs + */ +uint32_t GPS::getWakeTime() const +{ + uint32_t t = config.position.position_broadcast_secs; + + if (t == UINT32_MAX) + return t; // already maxint + + return Default::getConfiguredOrDefaultMs(t, default_broadcast_interval_secs); +} + +/** Get how long we should sleep between aqusition attempts in msecs + */ +uint32_t GPS::getSleepTime() const +{ + uint32_t t = config.position.gps_update_interval; + + // We'll not need the GPS thread to wake up again after first acq. with fixed position. + if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED || config.position.fixed_position) + t = UINT32_MAX; // Sleep forever now + + if (t == UINT32_MAX) + return t; // already maxint + + return Default::getConfiguredOrDefaultMs(t, default_gps_update_interval); +} + void GPS::publishUpdate() { if (shouldPublish) { @@ -1087,13 +1053,13 @@ int32_t GPS::runOnce() return disable(); } - if (whileActive()) { + if (whileIdle()) { // if we have received valid NMEA claim we are connected setConnected(); } else { if ((config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) && (gnssModel == GNSS_MODEL_UBLOX)) { // reset the GPS on next bootup - if (devicestate.did_gps_reset && scheduling.elapsedSearchMs() > 60 * 1000UL && !hasFlow()) { + if (devicestate.did_gps_reset && (millis() - lastWakeStartMsec > 60000) && !hasFlow()) { LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n"); devicestate.did_gps_reset = false; nodeDB->saveDeviceStateToDisk(); @@ -1108,43 +1074,54 @@ int32_t GPS::runOnce() // gps->factoryReset(); } - // If we're due for an update, wake the GPS - if (!config.position.fixed_position && powerState != GPS_ACTIVE && scheduling.isUpdateDue()) - up(); + // If we are overdue for an update, turn on the GPS and at least publish the current status + uint32_t now = millis(); + uint32_t timeAsleep = now - lastSleepStartMsec; - // If we've already set time from the GPS, no need to ask the GPS - bool gotTime = (getRTCQuality() >= RTCQualityGPS); - if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time - gotTime = true; - shouldPublish = true; + auto sleepTime = getSleepTime(); + if (powerState != GPS_ACTIVE && (sleepTime != UINT32_MAX) && + ((timeAsleep > sleepTime) || (isInPowersave && timeAsleep > (sleepTime - predictedLockTime)))) { + // We now want to be awake - so wake up the GPS + setAwake(true); } - bool gotLoc = lookForLocation(); - if (gotLoc && !hasValidLocation) { // declare that we have location ASAP - LOG_DEBUG("hasValidLocation RISING EDGE\n"); - hasValidLocation = true; - shouldPublish = true; - } + // While we are awake + if (powerState == GPS_ACTIVE) { + // LOG_DEBUG("looking for location\n"); + // If we've already set time from the GPS, no need to ask the GPS + bool gotTime = (getRTCQuality() >= RTCQualityGPS); + if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time + gotTime = true; + shouldPublish = true; + } - bool tooLong = scheduling.searchedTooLong(); - if (tooLong) - LOG_WARN("Couldn't publish a valid location: didn't get a GPS lock in time.\n"); + bool gotLoc = lookForLocation(); + if (gotLoc && !hasValidLocation) { // declare that we have location ASAP + LOG_DEBUG("hasValidLocation RISING EDGE\n"); + hasValidLocation = true; + shouldPublish = true; + } + + now = millis(); + auto wakeTime = getWakeTime(); + bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime; - // Once we get a location we no longer desperately want an update - // LOG_DEBUG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime); - if ((gotLoc && gotTime) || tooLong) { + // Once we get a location we no longer desperately want an update + // LOG_DEBUG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime); + if ((gotLoc && gotTime) || tooLong) { - if (tooLong) { - // we didn't get a location during this ack window, therefore declare loss of lock - if (hasValidLocation) { - LOG_DEBUG("hasValidLocation FALLING EDGE\n"); + if (tooLong) { + // we didn't get a location during this ack window, therefore declare loss of lock + if (hasValidLocation) { + LOG_DEBUG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc); + } + p = meshtastic_Position_init_default; + hasValidLocation = false; } - p = meshtastic_Position_init_default; - hasValidLocation = false; - } - down(); - shouldPublish = true; // publish our update for this just finished acquisition window + setAwake(false); + shouldPublish = true; // publish our update for this just finished acquisition window + } } // If state has changed do a publish @@ -1170,7 +1147,9 @@ void GPS::clearBuffer() int GPS::prepareDeepSleep(void *unused) { LOG_INFO("GPS deep sleep!\n"); - disable(); + + setAwake(false); + return 0; } @@ -1370,6 +1349,12 @@ GPS *GPS::createGps() new_gps->tx_gpio = _tx_gpio; new_gps->en_gpio = _en_gpio; + if (_en_gpio != 0) { + LOG_DEBUG("Setting %d to output.\n", _en_gpio); + pinMode(_en_gpio, OUTPUT); + digitalWrite(_en_gpio, !GPS_EN_ACTIVE); + } + #ifdef PIN_GPS_PPS // pulse per second pinMode(PIN_GPS_PPS, INPUT); @@ -1384,8 +1369,7 @@ GPS *GPS::createGps() LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n"); #endif - // Make sure the GPS is awake before performing any init. - new_gps->up(); + new_gps->setGPSPower(true, false, 0); #ifdef PIN_GPS_RESET pinMode(PIN_GPS_RESET, OUTPUT); @@ -1393,6 +1377,7 @@ GPS *GPS::createGps() delay(10); digitalWrite(PIN_GPS_RESET, !GPS_RESET_MODE); #endif + new_gps->setAwake(true); // Wake GPS power before doing any init if (_serial_gps) { #ifdef ARCH_ESP32 @@ -1718,13 +1703,13 @@ bool GPS::hasFlow() return reader.passedChecksum() > 0; } -bool GPS::whileActive() +bool GPS::whileIdle() { unsigned int charsInBuf = 0; bool isValid = false; if (powerState != GPS_ACTIVE) { clearBuffer(); - return false; + return (powerState == GPS_ACTIVE); } #ifdef SERIAL_BUFFER_SIZE if (_serial_gps->available() >= SERIAL_BUFFER_SIZE - 1) { @@ -1755,21 +1740,20 @@ bool GPS::whileActive() } void GPS::enable() { - // Clear the old scheduling info (reset the lock-time prediction) - scheduling.reset(); + // Clear the old lock-time prediction + GPSCycles = 0; + predictedLockTime = 0; enabled = true; setInterval(GPS_THREAD_INTERVAL); - - scheduling.informSearching(); - setPowerState(GPS_ACTIVE); + setAwake(true); } int32_t GPS::disable() { enabled = false; setInterval(INT32_MAX); - setPowerState(GPS_OFF); + setAwake(false); return INT32_MAX; } @@ -1778,7 +1762,7 @@ void GPS::toggleGpsMode() { if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED; - LOG_INFO("User toggled GpsMode. Now DISABLED.\n"); + LOG_DEBUG("Flag set to false for gps power. GpsMode: DISABLED\n"); #ifdef GNSS_Airoha if (powerState != GPS_ACTIVE) { LOG_DEBUG("User power Off GPS\n"); @@ -1788,8 +1772,8 @@ void GPS::toggleGpsMode() disable(); } else if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_DISABLED) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED; - LOG_INFO("User toggled GpsMode. Now ENABLED\n"); + LOG_DEBUG("Flag set to true to restore power. GpsMode: ENABLED\n"); enable(); } } -#endif // Exclude GPS +#endif // Exclude GPS \ No newline at end of file diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 1505b98434..91548ce2cf 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -39,11 +39,10 @@ typedef enum { } GPS_RESPONSE; enum GPSPowerState : uint8_t { - GPS_ACTIVE, // Awake and want a position - GPS_IDLE, // Awake, but not wanting another position yet - GPS_SOFTSLEEP, // Physically powered on, but soft-sleeping - GPS_HARDSLEEP, // Physically powered off, but scheduled to wake - GPS_OFF // Powered off indefinitely + GPS_OFF = 0, // Physically powered off + GPS_ACTIVE = 1, // Awake and want a position + GPS_STANDBY = 2, // Physically powered on, but soft-sleeping + GPS_IDLE = 3, // Awake, but not wanting another position yet }; // Generate a string representation of DOP @@ -74,6 +73,8 @@ class GPS : private concurrency::OSThread uint32_t rx_gpio = 0; uint32_t tx_gpio = 0; uint32_t en_gpio = 0; + uint32_t predictedLockTime = 0; + uint32_t GPSCycles = 0; int speedSelect = 0; int probeTries = 2; @@ -98,6 +99,7 @@ class GPS : private concurrency::OSThread uint8_t numSatellites = 0; CallbackObserver notifyDeepSleepObserver = CallbackObserver(this, &GPS::prepareDeepSleep); + CallbackObserver notifyGPSSleepObserver = CallbackObserver(this, &GPS::prepareDeepSleep); public: /** If !NULL we will use this serial port to construct our GPS */ @@ -173,8 +175,7 @@ class GPS : private concurrency::OSThread // toggle between enabled/disabled void toggleGpsMode(); - // Change the power state of the GPS - for power saving / shutdown - void setPowerState(GPSPowerState newState, uint32_t sleepMs = 0); + void setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime); /// Returns true if we have acquired GPS lock. virtual bool hasLock(); @@ -205,18 +206,18 @@ class GPS : private concurrency::OSThread GPS_RESPONSE getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis); + /** + * Switch the GPS into a mode where we are actively looking for a lock, or alternatively switch GPS into a low power mode + * + * calls sleep/wake + */ + void setAwake(bool on); virtual bool factoryReset(); // Creates an instance of the GPS class. // Returns the new instance or null if the GPS is not present. static GPS *createGps(); - // Wake the GPS hardware - ready for an update - void up(); - - // Let the GPS hardware save power between updates - void down(); - protected: /** * Perform any processing that should be done only while the GPS is awake and looking for a fix. @@ -239,7 +240,7 @@ class GPS : private concurrency::OSThread * * Return true if we received a valid message from the GPS */ - virtual bool whileActive(); + virtual bool whileIdle(); /** * Perform any processing that should be done only while the GPS is awake and looking for a fix. @@ -266,21 +267,13 @@ class GPS : private concurrency::OSThread void UBXChecksum(uint8_t *message, size_t length); void CASChecksum(uint8_t *message, size_t length); - /** Set power with EN pin, if relevant + /** Get how long we should stay looking for each aquisition */ - void writePinEN(bool on); + uint32_t getWakeTime() const; - /** Set the value of the STANDBY pin, if relevant + /** Get how long we should sleep between aqusition attempts */ - void writePinStandby(bool standby); - - /** Set GPS power with PMU, if relevant - */ - void setPowerPMU(bool on); - - /** Set UBLOX power, if relevant - */ - void setPowerUBLOX(bool on, uint32_t sleepMs = 0); + uint32_t getSleepTime() const; /** * Tell users we have new GPS readings @@ -296,11 +289,9 @@ class GPS : private concurrency::OSThread // delay counter to allow more sats before fixed position stops GPS thread uint8_t fixeddelayCtr = 0; - const char *powerStateToString(); - protected: GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN; }; extern GPS *gps; -#endif // Exclude GPS +#endif // Exclude GPS \ No newline at end of file diff --git a/src/gps/GPSUpdateScheduling.cpp b/src/gps/GPSUpdateScheduling.cpp deleted file mode 100644 index 949ef60397..0000000000 --- a/src/gps/GPSUpdateScheduling.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "GPSUpdateScheduling.h" - -#include "Default.h" - -// Mark the time when searching for GPS position begins -void GPSUpdateScheduling::informSearching() -{ - searchStartedMs = millis(); -} - -// Mark the time when searching for GPS is complete, -// then update the predicted lock-time -void GPSUpdateScheduling::informGotLock() -{ - searchEndedMs = millis(); - LOG_DEBUG("Took %us to get lock\n", (searchEndedMs - searchStartedMs) / 1000); - updateLockTimePrediction(); -} - -// Clear old lock-time prediction data. -// When re-enabling GPS with user button. -void GPSUpdateScheduling::reset() -{ - searchStartedMs = 0; - searchEndedMs = 0; - searchCount = 0; - predictedMsToGetLock = 0; -} - -// How many milliseconds before we should next search for GPS position -// Used by GPS hardware directly, to enter timed hardware sleep -uint32_t GPSUpdateScheduling::msUntilNextSearch() -{ - uint32_t now = millis(); - - // Target interval (seconds), between GPS updates - uint32_t updateInterval = Default::getConfiguredOrDefaultMs(config.position.gps_update_interval, default_gps_update_interval); - - // Check how long until we should start searching, to hopefully hit our target interval - uint32_t dueAtMs = searchEndedMs + updateInterval; - uint32_t compensatedStart = dueAtMs - predictedMsToGetLock; - int32_t remainingMs = compensatedStart - now; - - // If we should have already started (negative value), start ASAP - if (remainingMs < 0) - remainingMs = 0; - - return (uint32_t)remainingMs; -} - -// How long have we already been searching? -// Used to abort a search in progress, if it runs unnaceptably long -uint32_t GPSUpdateScheduling::elapsedSearchMs() -{ - // If searching - if (searchStartedMs > searchEndedMs) - return millis() - searchStartedMs; - - // If not searching - 0ms. We shouldn't really consume this value - else - return 0; -} - -// Is it now time to begin searching for a GPS position? -bool GPSUpdateScheduling::isUpdateDue() -{ - return (msUntilNextSearch() == 0); -} - -// Have we been searching for a GPS position for too long? -bool GPSUpdateScheduling::searchedTooLong() -{ - uint32_t maxSearchMs = - Default::getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs); - - // If broadcast interval set to max, no such thing as "too long" - if (maxSearchMs == UINT32_MAX) - return false; - - // If we've been searching longer than our position broadcast interval: that's too long - else if (elapsedSearchMs() > maxSearchMs) - return true; - - // Otherwise, not too long yet! - else - return false; -} - -// Updates the predicted time-to-get-lock, by exponentially smoothing the latest observation -void GPSUpdateScheduling::updateLockTimePrediction() -{ - - // How long did it take to get GPS lock this time? - // Duration between down() calls - int32_t lockTime = searchEndedMs - searchStartedMs; - if (lockTime < 0) - lockTime = 0; - - // Ignore the first lock-time: likely to be long, will skew data - - // Second locktime: likely stable. Use to intialize the smoothing filter - if (searchCount == 1) - predictedMsToGetLock = lockTime; - - // Third locktime and after: predict using exponential smoothing. Respond slowly to changes - else if (searchCount > 1) - predictedMsToGetLock = (lockTime * weighting) + (predictedMsToGetLock * (1 - weighting)); - - searchCount++; // Only tracked so we can diregard initial lock-times - - LOG_DEBUG("Predicting %us to get next lock\n", predictedMsToGetLock / 1000); -} - -// How long do we expect to spend searching for a lock? -uint32_t GPSUpdateScheduling::predictedSearchDurationMs() -{ - return GPSUpdateScheduling::predictedMsToGetLock; -} \ No newline at end of file diff --git a/src/gps/GPSUpdateScheduling.h b/src/gps/GPSUpdateScheduling.h deleted file mode 100644 index 7e121c9b68..0000000000 --- a/src/gps/GPSUpdateScheduling.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "configuration.h" - -// Encapsulates code responsible for the timing of GPS updates -class GPSUpdateScheduling -{ - public: - // Marks the time of these events, for calculation use - void informSearching(); - void informGotLock(); // Predicted lock-time is recalculated here - - void reset(); // Reset the prediction - after GPS::disable() / GPS::enable() - bool isUpdateDue(); // Is it time to begin searching for a GPS position? - bool searchedTooLong(); // Have we been searching for too long? - - uint32_t msUntilNextSearch(); // How long until we need to begin searching for a GPS? Info provided to GPS hardware for sleep - uint32_t elapsedSearchMs(); // How long have we been searching so far? - uint32_t predictedSearchDurationMs(); // How long do we expect to spend searching for a lock? - - private: - void updateLockTimePrediction(); // Called from informGotLock - uint32_t searchStartedMs = 0; - uint32_t searchEndedMs = 0; - uint32_t searchCount = 0; - uint32_t predictedMsToGetLock = 0; - - const float weighting = 0.2; // Controls exponential smoothing of lock-times prediction. 20% weighting of "latest lock-time". -}; \ No newline at end of file diff --git a/src/graphics/EInkDisplay2.cpp b/src/graphics/EInkDisplay2.cpp index d81ab6ff4e..bbc12521a0 100644 --- a/src/graphics/EInkDisplay2.cpp +++ b/src/graphics/EInkDisplay2.cpp @@ -156,8 +156,7 @@ bool EInkDisplay::connect() } } -#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213) || \ - defined(HELTEC_VISION_MASTER_E290) +#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) { // Start HSPI hspi = new SPIClass(HSPI); diff --git a/src/graphics/EInkDisplay2.h b/src/graphics/EInkDisplay2.h index 26091b2cd2..f744164949 100644 --- a/src/graphics/EInkDisplay2.h +++ b/src/graphics/EInkDisplay2.h @@ -5,6 +5,11 @@ #include "GxEPD2_BW.h" #include +#if defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_WIRELESS_PAPER) +// Re-enable SPI after deep sleep: rtc_gpio_hold_dis() +#include "driver/rtc_io.h" +#endif + /** * An adapter class that allows using the GxEPD2 library as if it was an OLEDDisplay implementation. * @@ -67,8 +72,7 @@ class EInkDisplay : public OLEDDisplay GxEPD2_BW *adafruitDisplay = NULL; // If display uses HSPI -#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \ - defined(HELTEC_VISION_MASTER_E290) +#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) SPIClass *hspi = NULL; #endif diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index b2059b71c6..60168cffcf 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -41,7 +41,6 @@ along with this program. If not, see . #include "mesh/Channels.h" #include "mesh/generated/meshtastic/deviceonly.pb.h" #include "meshUtils.h" -#include "modules/AdminModule.h" #include "modules/ExternalNotificationModule.h" #include "modules/TextMessageModule.h" #include "sleep.h" @@ -76,6 +75,7 @@ namespace graphics // A text message frame + debug frame + all the node infos FrameCallback *normalFrames; static uint32_t targetFramerate = IDLE_FRAMERATE; +static char btPIN[16] = "888888"; uint32_t logo_timeout = 5000; // 4 seconds for EACH logo @@ -108,39 +108,15 @@ GeoCoord geoCoord; static bool heartbeat = false; #endif -// Quick access to screen dimensions from static drawing functions -// DEPRECATED. To-do: move static functions inside Screen class -#define SCREEN_WIDTH display->getWidth() -#define SCREEN_HEIGHT display->getHeight() +static uint16_t displayWidth, displayHeight; + +#define SCREEN_WIDTH displayWidth +#define SCREEN_HEIGHT displayHeight #include "graphics/ScreenFonts.h" #define getStringCenteredX(s) ((SCREEN_WIDTH - display->getStringWidth(s)) / 2) -/// Check if the display can render a string (detect special chars; emoji) -static bool haveGlyphs(const char *str) -{ -#if defined(OLED_UA) || defined(OLED_RU) - // Don't want to make any assumptions about custom language support - return true; -#endif - - // Check each character with the lookup function for the OLED library - // We're not really meant to use this directly.. - bool have = true; - for (uint16_t i = 0; i < strlen(str); i++) { - uint8_t result = Screen::customFontTableLookup((uint8_t)str[i]); - // If font doesn't support a character, it is substituted for ¿ - if (result == 191 && (uint8_t)str[i] != 191) { - have = false; - break; - } - } - - LOG_DEBUG("haveGlyphs=%d\n", have); - return have; -} - /** * Draw the icon with extra info printed around the corners */ @@ -164,15 +140,13 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl if (upperMsg) display->drawString(x + 0, y + 0, upperMsg); - // Draw version and short name in upper right - char buf[25]; - snprintf(buf, sizeof(buf), "%s\n%s", xstr(APP_VERSION_SHORT), haveGlyphs(owner.short_name) ? owner.short_name : ""); - - display->setTextAlignment(TEXT_ALIGN_RIGHT); - display->drawString(x + SCREEN_WIDTH, y + 0, buf); + // Draw version in upper right + char buf[16]; + snprintf(buf, sizeof(buf), "%s", + xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long + display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf); screen->forceDisplay(); - - display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code + // FIXME - draw serial # somewhere? } static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) @@ -207,15 +181,14 @@ static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDi if (upperMsg) display->drawString(x + 0, y + 0, upperMsg); - // Draw version and shortname in upper right - char buf[25]; - snprintf(buf, sizeof(buf), "%s\n%s", xstr(APP_VERSION_SHORT), haveGlyphs(owner.short_name) ? owner.short_name : ""); - - display->setTextAlignment(TEXT_ALIGN_RIGHT); - display->drawString(x + SCREEN_WIDTH, y + 0, buf); + // Draw version in upper right + char buf[16]; + snprintf(buf, sizeof(buf), "%s", + xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long + display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf); screen->forceDisplay(); - display->setTextAlignment(TEXT_ALIGN_LEFT); // Restore left align, just to be kind to any other unsuspecting code + // FIXME - draw serial # somewhere? } static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) @@ -225,7 +198,7 @@ static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i drawOEMIconScreen(region, display, state, x, y); } -void Screen::drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *message) +static void drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *message) { uint16_t x_offset = display->width() / 2; display->setTextAlignment(TEXT_ALIGN_CENTER); @@ -233,6 +206,20 @@ void Screen::drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int1 display->drawString(x_offset + x, 26 + y, message); } +static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ +#ifdef ARCH_ESP32 + if (wakeCause == ESP_SLEEP_WAKEUP_TIMER || wakeCause == ESP_SLEEP_WAKEUP_EXT1) { + drawFrameText(display, state, x, y, "Resuming..."); + } else +#endif + { + // Draw region in upper left + const char *region = myRegion ? myRegion->name : NULL; + drawIconScreen(region, display, state, x, y); + } +} + // Used on boot when a certificate is being created static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { @@ -290,19 +277,40 @@ static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state) } } +/// Check if the display can render a string (detect special chars; emoji) +static bool haveGlyphs(const char *str) +{ +#if defined(OLED_UA) || defined(OLED_RU) + // Don't want to make any assumptions about custom language support + return true; +#endif + + // Check each character with the lookup function for the OLED library + // We're not really meant to use this directly.. + bool have = true; + for (uint16_t i = 0; i < strlen(str); i++) { + uint8_t result = Screen::customFontTableLookup((uint8_t)str[i]); + // If font doesn't support a character, it is substituted for ¿ + if (result == 191 && (uint8_t)str[i] != 191) { + have = false; + break; + } + } + + LOG_DEBUG("haveGlyphs=%d\n", have); + return have; +} + #ifdef USE_EINK /// Used on eink displays while in deep sleep static void drawDeepSleepScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { - // Next frame should use full-refresh, and block while running, else device will sleep before async callback EINK_ADD_FRAMEFLAG(display, COSMETIC); EINK_ADD_FRAMEFLAG(display, BLOCKING); LOG_DEBUG("Drawing deep sleep screen\n"); - - // Display displayStr on the screen - drawIconScreen("Sleeping", display, state, x, y); + drawIconScreen("Sleeping...", display, state, x, y); } /// Used on eink displays when screen updates are paused @@ -367,7 +375,7 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int // in the array of "drawScreen" functions; however, // the passed-state doesn't quite reflect the "current" // screen, so we have to detect it. - if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == TransitionRelationship_INCOMING) { + if (state->frameState == IN_TRANSITION && state->transitionFrameRelationship == INCOMING) { // if we're transitioning from the end of the frame list back around to the first // frame, then we want this to be `0` module_frame = state->transitionFrameTarget; @@ -381,6 +389,31 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int pi.drawFrame(display, state, x, y); } +static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + int x_offset = display->width() / 2; + int y_offset = display->height() <= 80 ? 0 : 32; + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(x_offset + x, y_offset + y, "Bluetooth"); + + display->setFont(FONT_SMALL); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5; + display->drawString(x_offset + x, y_offset + y, "Enter this code"); + + display->setFont(FONT_LARGE); + String displayPin(btPIN); + String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5; + display->drawString(x_offset + x, y_offset + y, pin); + + display->setFont(FONT_SMALL); + String deviceName = "Name: "; + deviceName.concat(getDeviceName()); + y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; + display->drawString(x_offset + x, y_offset + y, deviceName); +} + static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { display->setTextAlignment(TEXT_ALIGN_CENTER); @@ -1058,8 +1091,45 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state #endif } +/// Draw the last waypoint we received +static void drawWaypointFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + static char tempBuf[237]; + + meshtastic_MeshPacket &mp = devicestate.rx_waypoint; + meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(getFrom(&mp)); + + display->setTextAlignment(TEXT_ALIGN_LEFT); + display->setFont(FONT_SMALL); + if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { + display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); + display->setColor(BLACK); + } + + uint32_t seconds = sinceReceived(&mp); + uint32_t minutes = seconds / 60; + uint32_t hours = minutes / 60; + uint32_t days = hours / 24; + + if (config.display.heading_bold) { + display->drawStringf(1 + x, 0 + y, tempBuf, "%s ago from %s", + screen->drawTimeDelta(days, hours, minutes, seconds).c_str(), + (node && node->has_user) ? node->user.short_name : "???"); + } + display->drawStringf(0 + x, 0 + y, tempBuf, "%s ago from %s", screen->drawTimeDelta(days, hours, minutes, seconds).c_str(), + (node && node->has_user) ? node->user.short_name : "???"); + + display->setColor(WHITE); + meshtastic_Waypoint scratch; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) { + snprintf(tempBuf, sizeof(tempBuf), "Received waypoint: %s", scratch.name); + display->drawStringMaxWidth(0 + x, 0 + y + FONT_HEIGHT_SMALL, x + display->getWidth(), tempBuf); + } +} + /// Draw a series of fields in a column, wrapping to multiple columns if needed -void Screen::drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields) +static void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields) { // The coordinates define the left starting point of the text display->setTextAlignment(TEXT_ALIGN_LEFT); @@ -1239,13 +1309,56 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const } } #endif +namespace +{ + +/// A basic 2D point class for drawing +class Point +{ + public: + float x, y; + + Point(float _x, float _y) : x(_x), y(_y) {} + + /// Apply a rotation around zero (standard rotation matrix math) + void rotate(float radian) + { + float cos = cosf(radian), sin = sinf(radian); + float rx = x * cos + y * sin, ry = -x * sin + y * cos; + + x = rx; + y = ry; + } + + void translate(int16_t dx, int dy) + { + x += dx; + y += dy; + } + + void scale(float f) + { + // We use -f here to counter the flip that happens + // on the y axis when drawing and rotating on screen + x *= f; + y *= -f; + } +}; + +} // namespace + +static void drawLine(OLEDDisplay *d, const Point &p1, const Point &p2) +{ + d->drawLine(p1.x, p1.y, p2.x, p2.y); +} + /** * Given a recent lat/lon return a guess of the heading the user is walking on. * * We keep a series of "after you've gone 10 meters, what is your heading since * the last reference point?" */ -float Screen::estimatedHeading(double lat, double lon) +static float estimatedHeading(double lat, double lon) { static double oldLat, oldLon; static float b; @@ -1269,13 +1382,38 @@ float Screen::estimatedHeading(double lat, double lon) return b; } +static uint16_t getCompassDiam(OLEDDisplay *display) +{ + uint16_t diam = 0; + uint16_t offset = 0; + + if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) + offset = FONT_HEIGHT_SMALL; + + // get the smaller of the 2 dimensions and subtract 20 + if (display->getWidth() > (display->getHeight() - offset)) { + diam = display->getHeight() - offset; + // if 2/3 of the other size would be smaller, use that + if (diam > (display->getWidth() * 2 / 3)) { + diam = display->getWidth() * 2 / 3; + } + } else { + diam = display->getWidth(); + if (diam > ((display->getHeight() - offset) * 2 / 3)) { + diam = (display->getHeight() - offset) * 2 / 3; + } + } + + return diam - 20; +}; + /// We will skip one node - the one for us, so we just blindly loop over all /// nodes static size_t nodeIndex; static int8_t prevFrame = -1; // Draw the arrow pointing to a node's location -void Screen::drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, uint16_t compassDiam, float headingRadian) +static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, float headingRadian) { Point tip(0.0f, 0.5f), tail(0.0f, -0.5f); // pointing up initially float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f; @@ -1285,45 +1423,16 @@ void Screen::drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t com for (int i = 0; i < 4; i++) { arrowPoints[i]->rotate(headingRadian); - arrowPoints[i]->scale(compassDiam * 0.6); + arrowPoints[i]->scale(getCompassDiam(display) * 0.6); arrowPoints[i]->translate(compassX, compassY); } - display->drawLine(tip.x, tip.y, tail.x, tail.y); - display->drawLine(leftArrow.x, leftArrow.y, tip.x, tip.y); - display->drawLine(rightArrow.x, rightArrow.y, tip.x, tip.y); -} - -// Get a string representation of the time passed since something happened -void Screen::getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength) -{ - // Use an absolute timestamp in some cases. - // Particularly useful with E-Ink displays. Static UI, fewer refreshes. - uint8_t timestampHours, timestampMinutes; - int32_t daysAgo; - bool useTimestamp = deltaToTimestamp(agoSecs, ×tampHours, ×tampMinutes, &daysAgo); - - if (agoSecs < 120) // last 2 mins? - snprintf(timeStr, maxLength, "%u seconds ago", agoSecs); - // -- if suitable for timestamp -- - else if (useTimestamp && agoSecs < 15 * SECONDS_IN_MINUTE) // Last 15 minutes - snprintf(timeStr, maxLength, "%u minutes ago", agoSecs / SECONDS_IN_MINUTE); - else if (useTimestamp && daysAgo == 0) // Today - snprintf(timeStr, maxLength, "Last seen: %02u:%02u", (unsigned int)timestampHours, (unsigned int)timestampMinutes); - else if (useTimestamp && daysAgo == 1) // Yesterday - snprintf(timeStr, maxLength, "Seen yesterday"); - else if (useTimestamp && daysAgo > 1) // Last six months (capped by deltaToTimestamp method) - snprintf(timeStr, maxLength, "%li days ago", (long)daysAgo); - // -- if using time delta instead -- - else if (agoSecs < 120 * 60) // last 2 hrs - snprintf(timeStr, maxLength, "%u minutes ago", agoSecs / 60); - // Only show hours ago if it's been less than 6 months. Otherwise, we may have bad data. - else if ((agoSecs / 60 / 60) < (hours_in_month * 6)) - snprintf(timeStr, maxLength, "%u hours ago", agoSecs / 60 / 60); - else - snprintf(timeStr, maxLength, "unknown age"); + drawLine(display, tip, tail); + drawLine(display, leftArrow, tip); + drawLine(display, rightArrow, tip); } -void Screen::drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading) +// Draw north +static void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading) { // If north is supposed to be at the top of the compass we want rotation to be +0 if (config.display.compass_north_top) @@ -1333,43 +1442,19 @@ void Screen::drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t co Point N3(-0.04f, 0.55f), N4(0.04f, 0.55f); Point *rosePoints[] = {&N1, &N2, &N3, &N4}; - uint16_t compassDiam = Screen::getCompassDiam(SCREEN_WIDTH, SCREEN_HEIGHT); - for (int i = 0; i < 4; i++) { // North on compass will be negative of heading rosePoints[i]->rotate(-myHeading); - rosePoints[i]->scale(compassDiam); + rosePoints[i]->scale(getCompassDiam(display)); rosePoints[i]->translate(compassX, compassY); } - display->drawLine(N1.x, N1.y, N3.x, N3.y); - display->drawLine(N2.x, N2.y, N4.x, N4.y); - display->drawLine(N1.x, N1.y, N4.x, N4.y); + drawLine(display, N1, N3); + drawLine(display, N2, N4); + drawLine(display, N1, N4); } -uint16_t Screen::getCompassDiam(uint32_t displayWidth, uint32_t displayHeight) -{ - uint16_t diam = 0; - uint16_t offset = 0; - - if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) - offset = FONT_HEIGHT_SMALL; - - // get the smaller of the 2 dimensions and subtract 20 - if (displayWidth > (displayHeight - offset)) { - diam = displayHeight - offset; - // if 2/3 of the other size would be smaller, use that - if (diam > (displayWidth * 2 / 3)) { - diam = displayWidth * 2 / 3; - } - } else { - diam = displayWidth; - if (diam > ((displayHeight - offset) * 2 / 3)) { - diam = (displayHeight - offset) * 2 / 3; - } - } - - return diam - 20; -}; +/// Convert an integer GPS coords to a floating point +#define DegD(i) (i * 1e-7) static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { @@ -1409,8 +1494,34 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ snprintf(signalStr, sizeof(signalStr), "Signal: %d%%", clamp((int)((node->snr + 10) * 5), 0, 100)); } + uint32_t agoSecs = sinceLastSeen(node); static char lastStr[20]; - screen->getTimeAgoStr(sinceLastSeen(node), lastStr, sizeof(lastStr)); + + // Use an absolute timestamp in some cases. + // Particularly useful with E-Ink displays. Static UI, fewer refreshes. + uint8_t timestampHours, timestampMinutes; + int32_t daysAgo; + bool useTimestamp = deltaToTimestamp(agoSecs, ×tampHours, ×tampMinutes, &daysAgo); + + if (agoSecs < 120) // last 2 mins? + snprintf(lastStr, sizeof(lastStr), "%u seconds ago", agoSecs); + // -- if suitable for timestamp -- + else if (useTimestamp && agoSecs < 15 * SECONDS_IN_MINUTE) // Last 15 minutes + snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / SECONDS_IN_MINUTE); + else if (useTimestamp && daysAgo == 0) // Today + snprintf(lastStr, sizeof(lastStr), "Last seen: %02u:%02u", (unsigned int)timestampHours, (unsigned int)timestampMinutes); + else if (useTimestamp && daysAgo == 1) // Yesterday + snprintf(lastStr, sizeof(lastStr), "Seen yesterday"); + else if (useTimestamp && daysAgo > 1) // Last six months (capped by deltaToTimestamp method) + snprintf(lastStr, sizeof(lastStr), "%li days ago", (long)daysAgo); + // -- if using time delta instead -- + else if (agoSecs < 120 * 60) // last 2 hrs + snprintf(lastStr, sizeof(lastStr), "%u minutes ago", agoSecs / 60); + // Only show hours ago if it's been less than 6 months. Otherwise, we may have bad data. + else if ((agoSecs / 60 / 60) < (hours_in_month * 6)) + snprintf(lastStr, sizeof(lastStr), "%u hours ago", agoSecs / 60 / 60); + else + snprintf(lastStr, sizeof(lastStr), "unknown age"); static char distStr[20]; if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) { @@ -1421,14 +1532,13 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); const char *fields[] = {username, lastStr, signalStr, distStr, NULL}; int16_t compassX = 0, compassY = 0; - uint16_t compassDiam = Screen::getCompassDiam(SCREEN_WIDTH, SCREEN_HEIGHT); // coordinates for the center of the compass/circle if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { - compassX = x + SCREEN_WIDTH - compassDiam / 2 - 5; + compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5; compassY = y + SCREEN_HEIGHT / 2; } else { - compassX = x + SCREEN_WIDTH - compassDiam / 2 - 5; + compassX = x + SCREEN_WIDTH - getCompassDiam(display) / 2 - 5; compassY = y + FONT_HEIGHT_SMALL + (SCREEN_HEIGHT - FONT_HEIGHT_SMALL) / 2; } bool hasNodeHeading = false; @@ -1439,8 +1549,8 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ if (screen->hasHeading()) myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians else - myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); - screen->drawCompassNorth(display, compassX, compassY, myHeading); + myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); + drawCompassNorth(display, compassX, compassY, myHeading); if (hasValidPosition(node)) { // display direction toward node @@ -1467,7 +1577,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ // If the top of the compass is not a static north we need adjust bearingToOther based on heading if (!config.display.compass_north_top) bearingToOther -= myHeading; - screen->drawNodeHeading(display, compassX, compassY, compassDiam, bearingToOther); + drawNodeHeading(display, compassX, compassY, bearingToOther); } } if (!hasNodeHeading) { @@ -1477,19 +1587,15 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ // hasValidPosition(node)); display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?"); } - display->drawCircle(compassX, compassY, compassDiam / 2); + display->drawCircle(compassX, compassY, getCompassDiam(display) / 2); if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { display->setColor(BLACK); } // Must be after distStr is populated - screen->drawColumns(display, x, y, fields); + drawColumns(display, x, y, fields); } -#if defined(ESP_PLATFORM) && defined(USE_ST7789) -SPIClass SPI1(HSPI); -#endif - Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry) : concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32) { @@ -1497,13 +1603,6 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O #if defined(USE_SH1106) || defined(USE_SH1107) || defined(USE_SH1107_128_64) dispdev = new SH1106Wire(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); -#elif defined(USE_ST7789) -#ifdef ESP_PLATFORM - dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT, ST7789_SDA, - ST7789_MISO, ST7789_SCK); -#else - dispdev = new ST7789Spi(&SPI1, ST7789_RESET, ST7789_RS, ST7789_NSS, GEOMETRY_RAWMODE, TFT_WIDTH, TFT_HEIGHT); -#endif #elif defined(USE_SSD1306) dispdev = new SSD1306Wire(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE); @@ -1582,14 +1681,7 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) #endif dispdev->displayOn(); -#ifdef USE_ST7789 -#ifdef ESP_PLATFORM - analogWrite(VTFT_LEDA, BRIGHTNESS_DEFAULT); -#else - pinMode(VTFT_LEDA, OUTPUT); - digitalWrite(VTFT_LEDA, TFT_BACKLIGHT_ON); -#endif -#endif + enabled = true; setInterval(0); // Draw ASAP runASAP = true; @@ -1600,12 +1692,6 @@ void Screen::handleSetOn(bool on, FrameCallback einkScreensaver) #endif LOG_INFO("Turning off screen\n"); dispdev->displayOff(); - -#ifdef USE_ST7789 - pinMode(VTFT_LEDA, OUTPUT); - digitalWrite(VTFT_LEDA, !TFT_BACKLIGHT_ON); -#endif - #ifdef T_WATCH_S3 PMU->disablePowerOutput(XPOWERS_ALDO2); #endif @@ -1655,19 +1741,9 @@ void Screen::setup() // Add frames. EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); - alertFrames[0] = [this](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { -#ifdef ARCH_ESP32 - if (wakeCause == ESP_SLEEP_WAKEUP_TIMER || wakeCause == ESP_SLEEP_WAKEUP_EXT1) { - drawFrameText(display, state, x, y, "Resuming..."); - } else -#endif - { - // Draw region in upper left - const char *region = myRegion ? myRegion->name : NULL; - drawIconScreen(region, display, state, x, y); - } - }; - ui->setFrames(alertFrames, 1); + static FrameCallback bootFrames[] = {drawBootScreen}; + static const int bootFrameCount = sizeof(bootFrames) / sizeof(bootFrames[0]); + ui->setFrames(bootFrames, bootFrameCount); // No overlays. ui->setOverlays(nullptr, 0); @@ -1726,7 +1802,6 @@ void Screen::setup() powerStatusObserver.observe(&powerStatus->onNewStatus); gpsStatusObserver.observe(&gpsStatus->onNewStatus); nodeStatusObserver.observe(&nodeStatus->onNewStatus); - adminMessageObserver.observe(adminModule); if (textMessageModule) textMessageObserver.observe(textMessageModule); if (inputBroker) @@ -1841,22 +1916,13 @@ int32_t Screen::runOnce() case Cmd::SHOW_NEXT_FRAME: handleShowNextFrame(); break; - case Cmd::START_ALERT_FRAME: { - showingBootScreen = false; // this should avoid the edge case where an alert triggers before the boot screen goes away - showingNormalScreen = false; - alertFrames[0] = alertFrame; -#ifdef USE_EINK - EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Use fast-refresh for next frame, no skip please - EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update - handleSetOn(true); // Ensure power-on to receive deep-sleep screensaver (PowerFSM should handle?) -#endif - setFrameImmediateDraw(alertFrames); + case Cmd::START_BLUETOOTH_PIN_SCREEN: + handleStartBluetoothPinScreen(cmd.bluetooth_pin); break; - } case Cmd::START_FIRMWARE_UPDATE_SCREEN: handleStartFirmwareUpdateScreen(); break; - case Cmd::STOP_ALERT_FRAME: + case Cmd::STOP_BLUETOOTH_PIN_SCREEN: case Cmd::STOP_BOOT_SCREEN: EINK_ADD_FRAMEFLAG(dispdev, COSMETIC); // E-Ink: Explicitly use full-refresh for next frame setFrames(); @@ -1865,6 +1931,12 @@ int32_t Screen::runOnce() handlePrint(cmd.print_text); free(cmd.print_text); break; + case Cmd::START_SHUTDOWN_SCREEN: + handleShutdownScreen(); + break; + case Cmd::START_REBOOT_SCREEN: + handleRebootScreen(); + break; default: LOG_ERROR("Invalid screen cmd\n"); } @@ -1955,6 +2027,9 @@ void Screen::setWelcomeFrames() /// Determine which screensaver frame to use, then set the FrameCallback void Screen::setScreensaverFrames(FrameCallback einkScreensaver) { + // Remember current frame, restore position at power-on + uint8_t frameNumber = ui->getUiState()->currentFrame; + // Retain specified frame / overlay callback beyond scope of this method static FrameCallback screensaverFrame; static OverlayCallback screensaverOverlay; @@ -1992,8 +2067,9 @@ void Screen::setScreensaverFrames(FrameCallback einkScreensaver) #endif // Prepare now for next frame, shown when display wakes - ui->setOverlays(NULL, 0); // Clear overlay - setFrames(FOCUS_PRESERVE); // Return to normal display updates, showing same frame as before screensaver, ideally + ui->setOverlays(NULL, 0); // Clear overlay + setFrames(); // Return to normal display updates + ui->switchToFrame(frameNumber); // Attempt to return to same frame after power-on // Pick a refresh method, for when display wakes #ifdef EINK_HASQUIRK_GHOSTING @@ -2004,13 +2080,9 @@ void Screen::setScreensaverFrames(FrameCallback einkScreensaver) } #endif -// Regenerate the normal set of frames, focusing a specific frame if requested -// Called when a frame should be added / removed, or custom frames should be cleared -void Screen::setFrames(FrameFocus focus) +// restore our regular frame list +void Screen::setFrames() { - uint8_t originalPosition = ui->getUiState()->currentFrame; - FramesetInfo fsi; // Location of specific frames, for applying focus parameter - LOG_DEBUG("showing standard frames\n"); showingNormalScreen = true; @@ -2044,36 +2116,27 @@ void Screen::setFrames(FrameFocus focus) // is the same offset into the moduleFrames vector // so that we can invoke the module's callback for (auto i = moduleFrames.begin(); i != moduleFrames.end(); ++i) { - // Draw the module frame, using the hack described above - normalFrames[numframes] = drawModuleFrame; - - // Check if the module being drawn has requested focus - // We will honor this request later, if setFrames was triggered by a UIFrameEvent - MeshModule *m = *i; - if (m->isRequestingFocus()) - fsi.positions.focusedModule = numframes; - - numframes++; + normalFrames[numframes++] = drawModuleFrame; } LOG_DEBUG("Added modules. numframes: %d\n", numframes); // If we have a critical fault, show it first - fsi.positions.fault = numframes; - if (error_code) { + if (error_code) normalFrames[numframes++] = drawCriticalFaultFrame; - focus = FOCUS_FAULT; // Change our "focus" parameter, to ensure we show the fault frame - } #ifdef T_WATCH_S3 normalFrames[numframes++] = screen->digitalWatchFace ? &Screen::drawDigitalClockFrame : &Screen::drawAnalogClockFrame; #endif // If we have a text message - show it next, unless it's a phone message and we aren't using any special modules - fsi.positions.textMessage = numframes; if (devicestate.has_rx_text_message && shouldDrawMessage(&devicestate.rx_text_message)) { normalFrames[numframes++] = drawTextMessageFrame; } + // If we have a waypoint - show it next, unless it's a phone message and we aren't using any special modules + if (devicestate.has_rx_waypoint && shouldDrawMessage(&devicestate.rx_waypoint)) { + normalFrames[numframes++] = drawWaypointFrame; + } // then all the nodes // We only show a few nodes in our scrolling list - because meshes with many nodes would have too many screens @@ -2085,14 +2148,11 @@ void Screen::setFrames(FrameFocus focus) // // Since frames are basic function pointers, we have to use a helper to // call a method on debugInfo object. - fsi.positions.log = numframes; normalFrames[numframes++] = &Screen::drawDebugInfoTrampoline; // call a method on debugInfoScreen object (for more details) - fsi.positions.settings = numframes; normalFrames[numframes++] = &Screen::drawDebugInfoSettingsTrampoline; - fsi.positions.wifi = numframes; #if HAS_WIFI && !defined(ARCH_PORTDUINO) if (isWifiAvailable()) { // call a method on debugInfoScreen object (for more details) @@ -2100,7 +2160,6 @@ void Screen::setFrames(FrameFocus focus) } #endif - fsi.frameCount = numframes; // Total framecount is used to apply FOCUS_PRESERVE LOG_DEBUG("Finished building frames. numframes: %d\n", numframes); ui->setFrames(normalFrames, numframes); @@ -2114,56 +2173,18 @@ void Screen::setFrames(FrameFocus focus) prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list // just changed) - // Focus on a specific frame, in the frame set we just created - switch (focus) { - case FOCUS_DEFAULT: - ui->switchToFrame(0); // First frame - break; - case FOCUS_FAULT: - ui->switchToFrame(fsi.positions.fault); - break; - case FOCUS_TEXTMESSAGE: - ui->switchToFrame(fsi.positions.textMessage); - break; - case FOCUS_MODULE: - // Whichever frame was marked by MeshModule::requestFocus(), if any - // If no module requested focus, will show the first frame instead - ui->switchToFrame(fsi.positions.focusedModule); - break; - - case FOCUS_PRESERVE: - // If we can identify which type of frame "originalPosition" was, can move directly to it in the new frameset - FramesetInfo &oldFsi = this->framesetInfo; - if (originalPosition == oldFsi.positions.log) - ui->switchToFrame(fsi.positions.log); - else if (originalPosition == oldFsi.positions.settings) - ui->switchToFrame(fsi.positions.settings); - else if (originalPosition == oldFsi.positions.wifi) - ui->switchToFrame(fsi.positions.wifi); - - // If frame count has decreased - else if (fsi.frameCount < oldFsi.frameCount) { - uint8_t numDropped = oldFsi.frameCount - fsi.frameCount; - // Move n frames backwards - if (numDropped <= originalPosition) - ui->switchToFrame(originalPosition - numDropped); - // Unless that would put us "out of bounds" (< 0) - else - ui->switchToFrame(0); - } - - // If we're not sure exactly which frame we were on, at least return to the same frame number - // (node frames; module frames) - else - ui->switchToFrame(originalPosition); - - break; - } + setFastFramerate(); // Draw ASAP +} - // Store the info about this frameset, for future setFrames calls - this->framesetInfo = fsi; +void Screen::handleStartBluetoothPinScreen(uint32_t pin) +{ + LOG_DEBUG("showing bluetooth screen\n"); + showingNormalScreen = false; + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame - setFastFramerate(); // Draw ASAP + static FrameCallback frames[] = {drawFrameBluetooth}; + snprintf(btPIN, sizeof(btPIN), "%06u", pin); + setFrameImmediateDraw(frames); } void Screen::setFrameImmediateDraw(FrameCallback *drawFrames) @@ -2173,6 +2194,41 @@ void Screen::setFrameImmediateDraw(FrameCallback *drawFrames) setFastFramerate(); } +void Screen::handleShutdownScreen() +{ + LOG_DEBUG("showing shutdown screen\n"); + showingNormalScreen = false; +#ifdef USE_EINK + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Use fast-refresh for next frame, no skip please + EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update + handleSetOn(true); // Ensure power-on to receive deep-sleep screensaver (PowerFSM should handle?) +#endif + + auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { + drawFrameText(display, state, x, y, "Shutting down..."); + }; + static FrameCallback frames[] = {frame}; + + setFrameImmediateDraw(frames); +} + +void Screen::handleRebootScreen() +{ + LOG_DEBUG("showing reboot screen\n"); + showingNormalScreen = false; +#ifdef USE_EINK + EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // Use fast-refresh for next frame, no skip please + EINK_ADD_FRAMEFLAG(dispdev, BLOCKING); // Edge case: if this frame is promoted to COSMETIC, wait for update + handleSetOn(true); // Power-on to show rebooting screen (PowerFSM should handle?) +#endif + + auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { + drawFrameText(display, state, x, y, "Rebooting..."); + }; + static FrameCallback frames[] = {frame}; + setFrameImmediateDraw(frames); +} + void Screen::handleStartFirmwareUpdateScreen() { LOG_DEBUG("showing firmware screen\n"); @@ -2189,7 +2245,7 @@ void Screen::blink() uint8_t count = 10; dispdev->setBrightness(254); while (count > 0) { - dispdev->fillRect(0, 0, dispdev->getWidth(), dispdev->getHeight()); + dispdev->fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); dispdev->display(); delay(50); dispdev->clear(); @@ -2617,7 +2673,7 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg) switch (arg->getStatusType()) { case STATUS_TYPE_NODE: if (showingNormalScreen && nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) { - setFrames(FOCUS_PRESERVE); // Regen the list of screen frames (returning to same frame, if possible) + setFrames(); // Regen the list of screens } nodeDB->updateGUI = false; break; @@ -2629,33 +2685,23 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg) int Screen::handleTextMessage(const meshtastic_MeshPacket *packet) { if (showingNormalScreen) { - // Outgoing message - if (packet->from == 0) - setFrames(FOCUS_PRESERVE); // Return to same frame (quietly hiding the rx text message frame) - - // Incoming message - else - setFrames(FOCUS_TEXTMESSAGE); // Focus on the new message + setFrames(); // Regen the list of screens (will show new text message) } return 0; } -// Triggered by MeshModules int Screen::handleUIFrameEvent(const UIFrameEvent *event) { if (showingNormalScreen) { - // Regenerate the frameset, potentially honoring a module's internal requestFocus() call - if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET) - setFrames(FOCUS_MODULE); - - // Regenerate the frameset, while attempting to maintain focus on the current frame - else if (event->action == UIFrameEvent::Action::REGENERATE_FRAMESET_BACKGROUND) - setFrames(FOCUS_PRESERVE); - - // Don't regenerate the frameset, just re-draw whatever is on screen ASAP - else if (event->action == UIFrameEvent::Action::REDRAW_ONLY) + if (event->frameChanged) { + setFrames(); // Regen the list of screens (will show new text message) + } else if (event->needRedraw) { setFastFramerate(); + // TODO: We might also want switch to corresponding frame, + // but we don't know the exact frame number. + // ui->switchToFrame(0); + } } return 0; @@ -2690,24 +2736,6 @@ int Screen::handleInputEvent(const InputEvent *event) return 0; } -int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg) -{ - // Note: only selected admin messages notify this observer - // If you wish to handle a new type of message, you should modify AdminModule.cpp first - - switch (arg->which_payload_variant) { - // Node removed manually (i.e. via app) - case meshtastic_AdminMessage_remove_by_nodenum_tag: - setFrames(FOCUS_PRESERVE); - break; - - // Default no-op, in case the admin message observable gets used by other classes in future - default: - break; - } - return 0; -} - } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 93e5f2ef78..f4d7197152 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -21,13 +21,11 @@ class Screen void print(const char *) {} void doDeepSleep() {} void forceDisplay(bool forceUiUpdate = false) {} + void startBluetoothPinScreen(uint32_t pin) {} + void stopBluetoothPinScreen() {} + void startRebootScreen() {} + void startShutdownScreen() {} void startFirmwareUpdateScreen() {} - void increaseBrightness() {} - void decreaseBrightness() {} - void setFunctionSymbal(std::string) {} - void removeFunctionSymbal(std::string) {} - void startAlert(const char *) {} - void endAlert() {} }; } // namespace graphics #else @@ -36,8 +34,6 @@ class Screen #include #include "../configuration.h" -#include "gps/GeoCoord.h" -#include "graphics/ScreenFonts.h" #ifdef USE_ST7567 #include @@ -45,8 +41,6 @@ class Screen #include #elif defined(USE_SSD1306) #include -#elif defined(USE_ST7789) -#include #else // the SH1106/SSD1306 variant is auto-detected #include @@ -88,46 +82,6 @@ class Screen #define SEGMENT_WIDTH 16 #define SEGMENT_HEIGHT 4 -/// Convert an integer GPS coords to a floating point -#define DegD(i) (i * 1e-7) - -namespace -{ -/// A basic 2D point class for drawing -class Point -{ - public: - float x, y; - - Point(float _x, float _y) : x(_x), y(_y) {} - - /// Apply a rotation around zero (standard rotation matrix math) - void rotate(float radian) - { - float cos = cosf(radian), sin = sinf(radian); - float rx = x * cos + y * sin, ry = -x * sin + y * cos; - - x = rx; - y = ry; - } - - void translate(int16_t dx, int dy) - { - x += dx; - y += dy; - } - - void scale(float f) - { - // We use -f here to counter the flip that happens - // on the y axis when drawing and rotating on screen - x *= f; - y *= -f; - } -}; - -} // namespace - namespace graphics { @@ -173,11 +127,9 @@ class Screen : public concurrency::OSThread CallbackObserver textMessageObserver = CallbackObserver(this, &Screen::handleTextMessage); CallbackObserver uiFrameEventObserver = - CallbackObserver(this, &Screen::handleUIFrameEvent); // Sent by Mesh Modules + CallbackObserver(this, &Screen::handleUIFrameEvent); CallbackObserver inputObserver = CallbackObserver(this, &Screen::handleInputEvent); - CallbackObserver adminMessageObserver = - CallbackObserver(this, &Screen::handleAdminMessage); public: explicit Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY); @@ -214,56 +166,41 @@ class Screen : public concurrency::OSThread void blink(); - void drawFrameText(OLEDDisplay *, OLEDDisplayUiState *, int16_t, int16_t, const char *); - - void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength); - - // Draw north - void drawCompassNorth(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading); - - static uint16_t getCompassDiam(uint32_t displayWidth, uint32_t displayHeight); - - float estimatedHeading(double lat, double lon); - - void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, uint16_t compassDiam, float headingRadian); - - void drawColumns(OLEDDisplay *display, int16_t x, int16_t y, const char **fields); - /// Handle button press, trackball or swipe action) void onPress() { enqueueCmd(ScreenCmd{.cmd = Cmd::ON_PRESS}); } void showPrevFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_PREV_FRAME}); } void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); } - // generic alert start - void startAlert(FrameCallback _alertFrame) + /// Starts showing the Bluetooth PIN screen. + // + // Switches over to a static frame showing the Bluetooth pairing screen + // with the PIN. + void startBluetoothPinScreen(uint32_t pin) { - alertFrame = _alertFrame; ScreenCmd cmd; - cmd.cmd = Cmd::START_ALERT_FRAME; + cmd.cmd = Cmd::START_BLUETOOTH_PIN_SCREEN; + cmd.bluetooth_pin = pin; enqueueCmd(cmd); } - void startAlert(const char *_alertMessage) + void startFirmwareUpdateScreen() { - startAlert([_alertMessage](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { - uint16_t x_offset = display->width() / 2; - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->setFont(FONT_MEDIUM); - display->drawString(x_offset + x, 26 + y, _alertMessage); - }); + ScreenCmd cmd; + cmd.cmd = Cmd::START_FIRMWARE_UPDATE_SCREEN; + enqueueCmd(cmd); } - void endAlert() + void startShutdownScreen() { ScreenCmd cmd; - cmd.cmd = Cmd::STOP_ALERT_FRAME; + cmd.cmd = Cmd::START_SHUTDOWN_SCREEN; enqueueCmd(cmd); } - void startFirmwareUpdateScreen() + void startRebootScreen() { ScreenCmd cmd; - cmd.cmd = Cmd::START_FIRMWARE_UPDATE_SCREEN; + cmd.cmd = Cmd::START_REBOOT_SCREEN; enqueueCmd(cmd); } @@ -285,6 +222,9 @@ class Screen : public concurrency::OSThread void setFunctionSymbal(std::string sym); void removeFunctionSymbal(std::string sym); + /// Stops showing the bluetooth PIN screen. + void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); } + /// Stops showing the boot screen. void stopBootScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BOOT_SCREEN}); } @@ -396,7 +336,6 @@ class Screen : public concurrency::OSThread int handleTextMessage(const meshtastic_MeshPacket *arg); int handleUIFrameEvent(const UIFrameEvent *arg); int handleInputEvent(const InputEvent *arg); - int handleAdminMessage(const meshtastic_AdminMessage *arg); /// Used to force (super slow) eink displays to draw critical frames void forceDisplay(bool forceUiUpdate = false); @@ -419,13 +358,7 @@ class Screen : public concurrency::OSThread bool isAUTOOled = false; - // Screen dimensions (for convenience) - // Defined during Screen::setup - uint16_t displayWidth = 0; - uint16_t displayHeight = 0; - private: - FrameCallback alertFrames[1]; struct ScreenCmd { Cmd cmd; union { @@ -451,36 +384,13 @@ class Screen : public concurrency::OSThread void handleOnPress(); void handleShowNextFrame(); void handleShowPrevFrame(); + void handleStartBluetoothPinScreen(uint32_t pin); void handlePrint(const char *text); void handleStartFirmwareUpdateScreen(); - - // Info collected by setFrames method. - // Index location of specific frames. Used to apply the FrameFocus parameter of setFrames - struct FramesetInfo { - struct FramePositions { - uint8_t fault = 0; - uint8_t textMessage = 0; - uint8_t focusedModule = 0; - uint8_t log = 0; - uint8_t settings = 0; - uint8_t wifi = 0; - } positions; - - uint8_t frameCount = 0; - } framesetInfo; - - // Which frame we want to be displayed, after we regen the frameset by calling setFrames - enum FrameFocus : uint8_t { - FOCUS_DEFAULT, // No specific frame - FOCUS_PRESERVE, // Return to the previous frame - FOCUS_FAULT, - FOCUS_TEXTMESSAGE, - FOCUS_MODULE, // Note: target module should call requestFocus(), otherwise no info about which module to focus - }; - - // Regenerate the normal set of frames, focusing a specific frame if requested - // Call when a frame should be added / removed, or custom frames should be cleared - void setFrames(FrameFocus focus = FOCUS_DEFAULT); + void handleShutdownScreen(); + void handleRebootScreen(); + /// Rebuilds our list of frames (screens) to default ones. + void setFrames(); /// Try to start drawing ASAP void setFastFramerate(); @@ -516,9 +426,6 @@ class Screen : public concurrency::OSThread bool digitalWatchFace = true; #endif - /// callback for current alert frame - FrameCallback alertFrame; - /// Queue of commands to execute in doTask. TypedQueue cmdQueue; /// Whether we are using a display @@ -545,5 +452,4 @@ class Screen : public concurrency::OSThread }; } // namespace graphics - #endif \ No newline at end of file diff --git a/src/graphics/ScreenFonts.h b/src/graphics/ScreenFonts.h index 8a48d053e9..4b34563f70 100644 --- a/src/graphics/ScreenFonts.h +++ b/src/graphics/ScreenFonts.h @@ -28,8 +28,8 @@ #define FONT_LARGE ArialMT_Plain_24 // Height: 28 #endif -#define _fontHeight(font) ((font)[1] + 1) // height is position 1 +#define fontHeight(font) ((font)[1] + 1) // height is position 1 -#define FONT_HEIGHT_SMALL _fontHeight(FONT_SMALL) -#define FONT_HEIGHT_MEDIUM _fontHeight(FONT_MEDIUM) -#define FONT_HEIGHT_LARGE _fontHeight(FONT_LARGE) \ No newline at end of file +#define FONT_HEIGHT_SMALL fontHeight(FONT_SMALL) +#define FONT_HEIGHT_MEDIUM fontHeight(FONT_MEDIUM) +#define FONT_HEIGHT_LARGE fontHeight(FONT_LARGE) diff --git a/src/main.cpp b/src/main.cpp index 95eeb998d9..ddb99568da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,6 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" -#include "PowerMon.h" #include "ReliableRouter.h" #include "airtime.h" #include "buzz.h" @@ -49,6 +48,7 @@ NimbleBluetooth *nimbleBluetooth = nullptr; #ifdef ARCH_NRF52 #include "NRF52Bluetooth.h" NRF52Bluetooth *nrf52Bluetooth = nullptr; +; #endif #if HAS_WIFI @@ -155,7 +155,6 @@ bool isVibrating = false; bool eink_found = true; uint32_t serialSinceMsec; -bool pauseBluetoothLogging = false; bool pmu_found; @@ -174,7 +173,7 @@ const char *getDeviceName() static char name[20]; snprintf(name, sizeof(name), "%02x%02x", dmac[4], dmac[5]); // if the shortname exists and is NOT the new default of ab3c, use it for BLE name. - if (strcmp(owner.short_name, name) != 0) { + if ((owner.short_name != NULL) && (strcmp(owner.short_name, name) != 0)) { snprintf(name, sizeof(name), "%s_%02x%02x", owner.short_name, dmac[4], dmac[5]); } else { snprintf(name, sizeof(name), "Meshtastic_%02x%02x", dmac[4], dmac[5]); @@ -215,14 +214,6 @@ __attribute__((weak, noinline)) bool loopCanSleep() return true; } -/** - * Print info as a structured log message (for automated log processing) - */ -void printInfo() -{ - LOG_INFO("S:B:%d,%s\n", HW_VENDOR, optstr(APP_VERSION)); -} - void setup() { concurrency::hasBeenSetup = true; @@ -230,7 +221,7 @@ void setup() meshtastic_Config_DisplayConfig_OledType::meshtastic_Config_DisplayConfig_OledType_OLED_AUTO; OLEDDISPLAY_GEOMETRY screen_geometry = GEOMETRY_128_64; -#ifdef USE_SEGGER +#ifdef SEGGER_STDOUT_CH auto mode = false ? SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL : SEGGER_RTT_MODE_NO_BLOCK_TRIM; #ifdef NRF52840_XXAA auto buflen = 4096; // this board has a fair amount of ram @@ -243,7 +234,6 @@ void setup() #ifdef DEBUG_PORT consoleInit(); // Set serial baud rate and init our mesh console #endif - powerMonInit(); serialSinceMsec = millis(); @@ -275,9 +265,6 @@ void setup() digitalWrite(VEXT_ENABLE_V05, 1); // turn on the lora antenna boost digitalWrite(ST7735_BL_V05, 1); // turn on display backligth LOG_DEBUG("HELTEC Detect Tracker V1.1\n"); -#elif defined(VEXT_ENABLE) && defined(VEXT_ON_VALUE) - pinMode(VEXT_ENABLE, OUTPUT); - digitalWrite(VEXT_ENABLE, VEXT_ON_VALUE); // turn on the display power #elif defined(VEXT_ENABLE) pinMode(VEXT_ENABLE, OUTPUT); digitalWrite(VEXT_ENABLE, 0); // turn on the display power @@ -566,7 +553,7 @@ void setup() #endif // Hello - printInfo(); + LOG_INFO("Meshtastic hwvendor=%d, swver=%s\n", HW_VENDOR, optstr(APP_VERSION)); #ifdef ARCH_ESP32 esp32Setup(); @@ -716,8 +703,7 @@ void setup() // Don't call screen setup until after nodedb is setup (because we need // the current region name) -#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || \ - defined(USE_ST7789) +#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) screen->setup(); #elif defined(ARCH_PORTDUINO) if (screen_found.port != ScanI2C::I2CPort::NO_I2C || settingsMap[displayPanel]) { @@ -944,7 +930,7 @@ void setup() nodeDB->saveToDisk(SEGMENT_CONFIG); if (!rIf->reconfigure()) { LOG_WARN("Reconfigure failed, rebooting\n"); - screen->startAlert("Rebooting..."); + screen->startRebootScreen(); rebootAtMsec = millis() + 5000; } } diff --git a/src/main.h b/src/main.h index ea2d80f94a..2ef7edb3a9 100644 --- a/src/main.h +++ b/src/main.h @@ -85,8 +85,6 @@ extern uint32_t serialSinceMsec; // This will suppress the current delay and instead try to run ASAP. extern bool runASAP; -extern bool pauseBluetoothLogging; - void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds(), enterDfuMode(); meshtastic_DeviceMetadata getDeviceMetadata(); diff --git a/src/mesh/Default.h b/src/mesh/Default.h index cc3927914b..95723744b1 100644 --- a/src/mesh/Default.h +++ b/src/mesh/Default.h @@ -5,7 +5,6 @@ #define ONE_MINUTE_MS 60 * 1000 #define default_gps_update_interval IF_ROUTER(ONE_DAY, 2 * 60) -#define default_telemetry_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 30 * 60) #define default_broadcast_interval_secs IF_ROUTER(ONE_DAY / 2, 15 * 60) #define default_wait_bluetooth_secs IF_ROUTER(1, 60) #define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 0fdde52772..dd547a6f1a 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -20,8 +20,9 @@ ErrorCode FloodingRouter::send(meshtastic_MeshPacket *p) bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) { if (wasSeenRecently(p)) { // Note: this will also add a recent packet record - printPacket("Ignoring incoming msg we've already seen", p); + printPacket("Ignoring incoming msg, because we've already seen it", p); if (config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER && + config.device.role != meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) { // cancel rebroadcast of this message *if* there was already one, unless we're a router/repeater! Router::cancelSending(p->from, p->id); diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp index fc059ec16d..bffca0c448 100644 --- a/src/mesh/LR11x0Interface.cpp +++ b/src/mesh/LR11x0Interface.cpp @@ -184,7 +184,6 @@ template void LR11x0Interface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore - RadioLibInterface::setStandby(); } /** @@ -224,7 +223,7 @@ template void LR11x0Interface::startReceive() 0); // only RX_DONE IRQ is needed, we'll check for PREAMBLE_DETECTED and HEADER_VALID in isActivelyReceiving assert(err == RADIOLIB_ERR_NONE); - RadioLibInterface::startReceive(); + isReceiving = true; // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp index 1ef4f60d8c..04fa250bff 100644 --- a/src/mesh/MeshModule.cpp +++ b/src/mesh/MeshModule.cpp @@ -284,17 +284,4 @@ AdminMessageHandleResult MeshModule::handleAdminMessageForAllModules(const mesht } } return handled; -} - -#if HAS_SCREEN -// Would our module like its frame to be focused after Screen::setFrames has regenerated the list of frames? -// Only considered if setFrames is triggered by a UIFrameEvent -bool MeshModule::isRequestingFocus() -{ - if (_requestingFocus) { - _requestingFocus = false; // Consume the request - return true; - } else - return false; -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/mesh/MeshModule.h b/src/mesh/MeshModule.h index c341b301ad..2e2af33e07 100644 --- a/src/mesh/MeshModule.h +++ b/src/mesh/MeshModule.h @@ -35,16 +35,10 @@ enum class AdminMessageHandleResult { /* * This struct is used by Screen to figure out whether screen frame should be updated. */ -struct UIFrameEvent { - // What do we actually want to happen? - enum Action { - REDRAW_ONLY, // Don't change which frames are show, just redraw, asap - REGENERATE_FRAMESET, // Regenerate (change? add? remove?) screen frames, honoring requestFocus() - REGENERATE_FRAMESET_BACKGROUND, // Regenerate screen frames, attempting to remain on the same frame throughout - } action = REDRAW_ONLY; - - // We might want to pass additional data inside this struct at some point -}; +typedef struct _UIFrameEvent { + bool frameChanged; + bool needRedraw; +} UIFrameEvent; /** A baseclass for any mesh "module". * @@ -79,7 +73,6 @@ class MeshModule meshtastic_AdminMessage *response); #if HAS_SCREEN virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { return; } - virtual bool isRequestingFocus(); // Checked by screen, when regenerating frameset #endif protected: const char *name; @@ -183,19 +176,6 @@ class MeshModule return AdminMessageHandleResult::NOT_HANDLED; }; -#if HAS_SCREEN - /** Request that our module's screen frame be focused when Screen::setFrames runs - * Only considered if Screen::setFrames is triggered via a UIFrameEvent - * - * Having this as a separate call, instead of part of the UIFrameEvent, allows the module to delay decision - * until drawFrame() is called. This required less restructuring. - */ - bool _requestingFocus = false; - void requestFocus() { _requestingFocus = true; } -#else - void requestFocus(){}; // No-op -#endif - private: /** * If any of the current chain of modules has already sent a reply, it will be here. This is useful to allow diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index a652d0a50e..2cfb4843cd 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -94,11 +94,7 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp) } else if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag && !nodeDB->getMeshNode(mp->from)->has_user && nodeInfoModule) { LOG_INFO("Heard a node on channel %d we don't know, sending NodeInfo and asking for a response.\n", mp->channel); - if (airTime->isTxAllowedChannelUtil(true)) { - nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel); - } else { - LOG_DEBUG("Skip sending NodeInfo due to > 25 percent channel util.\n"); - } + nodeInfoModule->sendOurNodeInfo(mp->from, true, mp->channel); } printPacket("Forwarding to phone", mp); @@ -273,7 +269,7 @@ bool MeshService::trySendPosition(NodeNum dest, bool wantReplies) assert(node); if (hasValidPosition(node)) { -#if HAS_GPS && !MESHTASTIC_EXCLUDE_GPS +#if HAS_GPS if (positionModule) { LOG_INFO("Sending position ping to 0x%x, wantReplies=%d, channel=%d\n", dest, wantReplies, node->channel); positionModule->sendOurPosition(dest, wantReplies, node->channel); @@ -303,7 +299,6 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p) } else { LOG_WARN("ToPhone queue is full, dropping packet.\n"); releaseToPool(p); - fromNum++; // Make sure to notify observers in case they are reconnected so they can get the packets return; } } @@ -378,8 +373,8 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus) pos.time = getValidTime(RTCQualityFromNet); // In debug logs, identify position by @timestamp:stage (stage 4 = nodeDB) - LOG_DEBUG("onGPSChanged() pos@%x time=%u lat=%d lon=%d alt=%d\n", pos.timestamp, pos.time, pos.latitude_i, pos.longitude_i, - pos.altitude); + LOG_DEBUG("onGPSChanged() pos@%x, time=%u, lat=%d, lon=%d, alt=%d\n", pos.timestamp, pos.time, pos.latitude_i, + pos.longitude_i, pos.altitude); // Update our current position in the local DB nodeDB->updatePosition(nodeDB->getNodeNum(), pos, RX_SRC_LOCAL); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index fa5c437c42..cf576e94fe 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -26,7 +26,7 @@ #include #ifdef ARCH_ESP32 -#if HAS_WIFI +#if !MESHTASTIC_EXCLUDE_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "modules/esp32/StoreForwardModule.h" @@ -141,6 +141,11 @@ NodeDB::NodeDB() if (channelFileCRC != crc32Buffer(&channelFile, sizeof(channelFile))) saveWhat |= SEGMENT_CHANNELS; + if (!devicestate.node_remote_hardware_pins) { + meshtastic_NodeRemoteHardwarePin empty[12] = {meshtastic_RemoteHardwarePin_init_default}; + memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty)); + } + if (config.position.gps_enabled) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED; config.position.gps_enabled = 0; @@ -180,7 +185,7 @@ bool NodeDB::resetRadioConfig(bool factory_reset) if (didFactoryReset) { LOG_INFO("Rebooting due to factory reset"); - screen->startAlert("Rebooting..."); + screen->startRebootScreen(); rebootAtMsec = millis() + (5 * 1000); } @@ -268,8 +273,7 @@ void NodeDB::installDefaultConfig() // FIXME: Default to bluetooth capability of platform as default config.bluetooth.enabled = true; config.bluetooth.fixed_pin = defaultBLEPin; -#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || \ - defined(USE_ST7789) +#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) bool hasScreen = true; #elif ARCH_PORTDUINO bool hasScreen = false; @@ -822,8 +826,8 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou if (src == RX_SRC_LOCAL) { // Local packet, fully authoritative - LOG_INFO("updatePosition LOCAL pos@%x time=%u lat=%d lon=%d alt=%d\n", p.timestamp, p.time, p.latitude_i, p.longitude_i, - p.altitude); + LOG_INFO("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.timestamp, p.time, p.latitude_i, + p.longitude_i, p.altitude); setLocalPosition(p); info->position = TypeConversions::ConvertToPositionLite(p); @@ -838,7 +842,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou // recorded based on the packet rxTime // // FIXME perhaps handle RX_SRC_USER separately? - LOG_INFO("updatePosition REMOTE node=0x%x time=%u lat=%d lon=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i); + LOG_INFO("updatePosition REMOTE node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i); // First, back up fields that we want to protect from overwrite uint32_t tmp_time = info->position.time; diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 61bf90d4d3..e9e36cc617 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -155,8 +155,8 @@ class NodeDB localPosition.timestamp = position.timestamp > 0 ? position.timestamp : position.time; return; } - LOG_DEBUG("Setting local position: lat=%i lon=%i time=%u timestamp=%u\n", position.latitude_i, position.longitude_i, - position.time, position.timestamp); + LOG_DEBUG("Setting local position: latitude=%i, longitude=%i, time=%u, timestamp=%u\n", position.latitude_i, + position.longitude_i, position.time, position.timestamp); localPosition = position; } diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 0f69b21f9c..26d0d9525a 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -5,7 +5,6 @@ #include "Channels.h" #include "Default.h" -#include "FSCommon.h" #include "MeshService.h" #include "NodeDB.h" #include "PhoneAPI.h" @@ -47,9 +46,6 @@ void PhoneAPI::handleStartConfig() // even if we were already connected - restart our state machine state = STATE_SEND_MY_INFO; - pauseBluetoothLogging = true; - filesManifest = getFiles("/", 10); - LOG_DEBUG("Got %d files in manifest\n", filesManifest.size()); LOG_INFO("Starting API client config\n"); nodeInfoForPhone.num = 0; // Don't keep returning old nodeinfos @@ -152,7 +148,6 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) STATE_SEND_CONFIG, STATE_SEND_MODULE_CONFIG, STATE_SEND_OTHER_NODEINFOS, // states progress in this order as the device sends to the client - STATE_SEND_FILEMANIFEST, STATE_SEND_COMPLETE_ID, STATE_SEND_PACKETS // send packets or debug strings */ @@ -328,7 +323,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Advance when we have sent all of our ModuleConfig objects if (config_state > (_meshtastic_AdminMessage_ModuleConfigType_MAX + 1)) { // Clients sending special nonce don't want to see other nodeinfos - state = config_nonce == SPECIAL_NONCE ? STATE_SEND_FILEMANIFEST : STATE_SEND_OTHER_NODEINFOS; + state = config_nonce == SPECIAL_NONCE ? STATE_SEND_COMPLETE_ID : STATE_SEND_OTHER_NODEINFOS; config_state = 0; } break; @@ -344,36 +339,22 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) nodeInfoForPhone.num = 0; // We just consumed a nodeinfo, will need a new one next time } else { LOG_INFO("Done sending nodeinfos\n"); - state = STATE_SEND_FILEMANIFEST; + state = STATE_SEND_COMPLETE_ID; // Go ahead and send that ID right now return getFromRadio(buf); } break; } - case STATE_SEND_FILEMANIFEST: { - LOG_INFO("getFromRadio=STATE_SEND_FILEMANIFEST\n"); - // last element - if (config_state == filesManifest.size()) { // also handles an empty filesManifest - config_state = 0; - filesManifest.clear(); - // Skip to complete packet - sendConfigComplete(); - } else { - fromRadioScratch.which_payload_variant = meshtastic_FromRadio_fileInfo_tag; - fromRadioScratch.fileInfo = filesManifest.at(config_state); - LOG_DEBUG("File: %s (%d) bytes\n", fromRadioScratch.fileInfo.file_name, fromRadioScratch.fileInfo.size_bytes); - config_state++; - } - break; - } - case STATE_SEND_COMPLETE_ID: - sendConfigComplete(); + LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n"); + fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag; + fromRadioScratch.config_complete_id = config_nonce; + config_nonce = 0; + state = STATE_SEND_PACKETS; break; case STATE_SEND_PACKETS: - pauseBluetoothLogging = false; // Do we have a message from the mesh or packet from the local device? LOG_INFO("getFromRadio=STATE_SEND_PACKETS\n"); if (queueStatusPacketForPhone) { @@ -407,9 +388,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Encapsulate as a FromRadio packet size_t numbytes = pb_encode_to_bytes(buf, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch); - // VERY IMPORTANT to not print debug messages while writing to fromRadioScratch - because we use that same buffer - // for logging (when we are encapsulating with protobufs) - // LOG_DEBUG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes); + LOG_DEBUG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes); return numbytes; } @@ -417,20 +396,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) return 0; } -void PhoneAPI::sendConfigComplete() -{ - LOG_INFO("getFromRadio=STATE_SEND_COMPLETE_ID\n"); - fromRadioScratch.which_payload_variant = meshtastic_FromRadio_config_complete_id_tag; - fromRadioScratch.config_complete_id = config_nonce; - config_nonce = 0; - state = STATE_SEND_PACKETS; - pauseBluetoothLogging = false; -} - void PhoneAPI::handleDisconnect() { - filesManifest.clear(); - pauseBluetoothLogging = false; LOG_INFO("PhoneAPI disconnect\n"); } @@ -472,7 +439,6 @@ bool PhoneAPI::available() case STATE_SEND_MODULECONFIG: case STATE_SEND_METADATA: case STATE_SEND_OWN_NODEINFO: - case STATE_SEND_FILEMANIFEST: case STATE_SEND_COMPLETE_ID: return true; @@ -487,6 +453,7 @@ bool PhoneAPI::available() } } return true; // Always say we have something, because we might need to advance our state machine + case STATE_SEND_PACKETS: { if (!queueStatusPacketForPhone) queueStatusPacketForPhone = service.getQueueStatusForPhone(); diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index 3c3668300a..49bf0e292b 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -2,20 +2,10 @@ #include "Observer.h" #include "mesh-pb-constants.h" -#include #include -#include // Make sure that we never let our packets grow too large for one BLE packet #define MAX_TO_FROM_RADIO_SIZE 512 - -#if meshtastic_FromRadio_size > MAX_TO_FROM_RADIO_SIZE -#error "meshtastic_FromRadio_size is too large for our BLE packets" -#endif -#if meshtastic_ToRadio_size > MAX_TO_FROM_RADIO_SIZE -#error "meshtastic_ToRadio_size is too large for our BLE packets" -#endif - #define SPECIAL_NONCE 69420 /** @@ -39,7 +29,6 @@ class PhoneAPI STATE_SEND_CONFIG, // Replacement for the old Radioconfig STATE_SEND_MODULECONFIG, // Send Module specific config STATE_SEND_OTHER_NODEINFOS, // states progress in this order as the device sends to to the client - STATE_SEND_FILEMANIFEST, // Send file manifest STATE_SEND_COMPLETE_ID, STATE_SEND_PACKETS // send packets or debug strings }; @@ -76,8 +65,6 @@ class PhoneAPI uint32_t config_nonce = 0; uint32_t readIndex = 0; - std::vector filesManifest = {}; - void resetReadIndex() { readIndex = 0; } public: @@ -104,8 +91,6 @@ class PhoneAPI */ size_t getFromRadio(uint8_t *buf); - void sendConfigComplete(); - /** * Return true if we have data available to send to the phone */ @@ -113,6 +98,8 @@ class PhoneAPI bool isConnected() { return state != STATE_SEND_NOTHING; } + void setInitialState() { state = STATE_SEND_MY_INFO; } + protected: /// Our fromradio packet while it is being assembled meshtastic_FromRadio fromRadioScratch = {}; diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp index bd1ebdb0e6..c5356ad3bd 100644 --- a/src/mesh/RF95Interface.cpp +++ b/src/mesh/RF95Interface.cpp @@ -25,8 +25,7 @@ typedef struct { } DACDB; // Interpolation function -DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val2) -{ +DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val2) { DACDB result; double fraction = (double)(dbm - dbm1) / (dbm2 - dbm1); result.dac = (uint8_t)(val1.dac + fraction * (val2.dac - val1.dac)); @@ -35,17 +34,16 @@ DACDB interpolate(uint8_t dbm, uint8_t dbm1, uint8_t dbm2, DACDB val1, DACDB val } // Function to find the correct DAC and DB values based on dBm using interpolation -DACDB getDACandDB(uint8_t dbm) -{ +DACDB getDACandDB(uint8_t dbm) { // Predefined values static const struct { uint8_t dbm; DACDB values; } dbmToDACDB[] = { - {20, {168, 2}}, // 100mW - {24, {148, 6}}, // 250mW - {27, {128, 9}}, // 500mW - {30, {90, 12}} // 1000mW + {20, {168, 2}}, // 100mW + {24, {148, 6}}, // 250mW + {27, {128, 9}}, // 500mW + {30, {90, 12}} // 1000mW }; const int numValues = sizeof(dbmToDACDB) / sizeof(dbmToDACDB[0]); @@ -105,7 +103,7 @@ bool RF95Interface::init() if (power > RF95_MAX_POWER) // This chip has lower power limits than some power = RF95_MAX_POWER; - + limitPower(); iface = lora = new RadioLibRF95(&module); @@ -118,13 +116,13 @@ bool RF95Interface::init() // enable PA #ifdef RF95_PA_EN #if defined(RF95_PA_DAC_EN) -#ifdef RADIOMASTER_900_BANDIT_NANO - // Use calculated DAC value - dacWrite(RF95_PA_EN, powerDAC); -#else - // Use Value set in /*/variant.h - dacWrite(RF95_PA_EN, RF95_PA_LEVEL); -#endif + #ifdef RADIOMASTER_900_BANDIT_NANO + // Use calculated DAC value + dacWrite(RF95_PA_EN, powerDAC); + #else + // Use Value set in /*/variant.h + dacWrite(RF95_PA_EN, RF95_PA_LEVEL); + #endif #endif #endif @@ -256,7 +254,6 @@ void RF95Interface::setStandby() isReceiving = false; // If we were receiving, not any more disableInterrupt(); completeSending(); // If we were sending, not anymore - RadioLibInterface::setStandby(); } /** We override to turn on transmitter power as needed. diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 343b7f2008..78228c077c 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -261,6 +261,7 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr) uint8_t CWsize = map(snr, SNR_MIN, SNR_MAX, CWmin, CWmax); // LOG_DEBUG("rx_snr of %f so setting CWsize to:%d\n", snr, CWsize); if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || + config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT || config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { delay = random(0, 2 * CWsize) * slotTimeMsec; LOG_DEBUG("rx_snr found in packet. As a router, setting tx delay:%d\n", delay); @@ -521,7 +522,7 @@ void RadioInterface::applyModemConfig() LOG_INFO("Radio freq=%.3f, config.lora.frequency_offset=%.3f\n", freq, loraConfig.frequency_offset); LOG_INFO("Set radio: region=%s, name=%s, config=%u, ch=%d, power=%d\n", myRegion->name, channelName, loraConfig.modem_preset, channel_num, power); - LOG_INFO("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f MHz)\n", myRegion->freqStart, myRegion->freqEnd, + LOG_INFO("Radio myRegion->freqStart -> myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd, myRegion->freqEnd - myRegion->freqStart); LOG_INFO("Radio myRegion->numChannels: %d x %.3fkHz\n", numChannels, bw); LOG_INFO("Radio channel_num: %d\n", channel_num + 1); diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index f299ebff2c..a4ceac9f12 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -1,7 +1,6 @@ #include "RadioLibInterface.h" #include "MeshTypes.h" #include "NodeDB.h" -#include "PowerMon.h" #include "SPILock.h" #include "configuration.h" #include "error.h" @@ -318,7 +317,6 @@ void RadioLibInterface::handleTransmitInterrupt() // ignore the transmit interrupt if (sendingPacket) completeSending(); - powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // But our transmitter is deffinitely off now } void RadioLibInterface::completeSending() @@ -414,24 +412,6 @@ void RadioLibInterface::handleReceiveInterrupt() } } -void RadioLibInterface::startReceive() -{ - isReceiving = true; - powerMon->setState(meshtastic_PowerMon_State_Lora_RXOn); -} - -void RadioLibInterface::configHardwareForSend() -{ - powerMon->setState(meshtastic_PowerMon_State_Lora_TXOn); -} - -void RadioLibInterface::setStandby() -{ - // neither sending nor receiving - powerMon->clearState(meshtastic_PowerMon_State_Lora_RXOn); - powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); -} - /** start an immediate transmit */ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp) { @@ -451,7 +431,6 @@ void RadioLibInterface::startSend(meshtastic_MeshPacket *txp) // This send failed, but make sure to 'complete' it properly completeSending(); - powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // Transmitter off now startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode) } diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index dd01d2037f..2c841a19ef 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -126,9 +126,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified * Start waiting to receive a message * * External functions can call this method to wake the device from sleep. - * Subclasses must override and call this base method */ - virtual void startReceive(); + virtual void startReceive() = 0; /** can we detect a LoRa preamble on the current channel? */ virtual bool isChannelActive() = 0; @@ -167,9 +166,8 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified meshtastic_QueueStatus getQueueStatus(); protected: - /** Do any hardware setup needed on entry into send configuration for the radio. - * Subclasses can customize, but must also call this base method */ - virtual void configHardwareForSend(); + /** Do any hardware setup needed on entry into send configuration for the radio. Subclasses can customize */ + virtual void configHardwareForSend() {} /** Could we send right now (i.e. either not actively receiving or transmitting)? */ virtual bool canSendImmediately(); @@ -188,8 +186,5 @@ class RadioLibInterface : public RadioInterface, protected concurrency::Notified */ virtual void addReceiveMetadata(meshtastic_MeshPacket *mp) = 0; - /** - * Subclasses must override, implement and then call into this base class implementation - */ - virtual void setStandby(); + virtual void setStandby() = 0; }; \ No newline at end of file diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index c8c18ae6d5..3141d986bb 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -244,10 +244,8 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) // If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it) - if (!(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag || - p->which_payload_variant == meshtastic_MeshPacket_decoded_tag)) { - return meshtastic_Routing_Error_BAD_REQUEST; - } + assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag || + p->which_payload_variant == meshtastic_MeshPacket_decoded_tag); // I _think_ all packets should have a payload by now // If the packet is not yet encrypted, do so now if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index b564ba287e..afaa13b7f0 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -231,7 +231,6 @@ template void SX126xInterface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore - RadioLibInterface::setStandby(); } /** @@ -271,7 +270,7 @@ template void SX126xInterface::startReceive() LOG_ERROR("Radiolib error %d when attempting SX126X startReceiveDutyCycleAuto!\n", err); assert(err == RADIOLIB_ERR_NONE); - RadioLibInterface::startReceive(); + isReceiving = true; // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp index fdb2b9a395..9e4fbfa772 100644 --- a/src/mesh/SX128xInterface.cpp +++ b/src/mesh/SX128xInterface.cpp @@ -190,7 +190,6 @@ template void SX128xInterface::setStandby() activeReceiveStart = 0; disableInterrupt(); completeSending(); // If we were sending, not anymore - RadioLibInterface::setStandby(); } /** @@ -264,7 +263,7 @@ template void SX128xInterface::startReceive() LOG_ERROR("Radiolib error %d when attempting SX128X startReceive!\n", err); assert(err == RADIOLIB_ERR_NONE); - RadioLibInterface::startReceive(); + isReceiving = true; // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits enableInterrupt(isrRxLevel0); diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp index 9f59aa971c..4d04dffe48 100644 --- a/src/mesh/StreamAPI.cpp +++ b/src/mesh/StreamAPI.cpp @@ -1,6 +1,5 @@ #include "StreamAPI.h" #include "PowerFSM.h" -#include "RTC.h" #include "configuration.h" #define START1 0x94 @@ -97,6 +96,7 @@ void StreamAPI::writeStream() void StreamAPI::emitTxBuffer(size_t len) { if (len != 0) { + // LOG_DEBUG("emit tx %d\n", len); txBuf[0] = START1; txBuf[1] = START2; txBuf[2] = (len >> 8) & 0xff; @@ -119,25 +119,6 @@ void StreamAPI::emitRebooted() emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch)); } -void StreamAPI::emitLogRecord(meshtastic_LogRecord_Level level, const char *src, const char *format, va_list arg) -{ - // In case we send a FromRadio packet - memset(&fromRadioScratch, 0, sizeof(fromRadioScratch)); - fromRadioScratch.which_payload_variant = meshtastic_FromRadio_log_record_tag; - fromRadioScratch.log_record.level = level; - - uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); - fromRadioScratch.log_record.time = rtc_sec; - strncpy(fromRadioScratch.log_record.source, src, sizeof(fromRadioScratch.log_record.source) - 1); - - auto num_printed = - vsnprintf(fromRadioScratch.log_record.message, sizeof(fromRadioScratch.log_record.message) - 1, format, arg); - if (num_printed > 0 && fromRadioScratch.log_record.message[num_printed - 1] == - '\n') // Strip any ending newline, because we have records for framing instead. - fromRadioScratch.log_record.message[num_printed - 1] = '\0'; - emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, meshtastic_FromRadio_size, &meshtastic_FromRadio_msg, &fromRadioScratch)); -} - /// Hookable to find out when connection changes void StreamAPI::onConnectionChanged(bool connected) { @@ -150,4 +131,4 @@ void StreamAPI::onConnectionChanged(bool connected) // received a packet in a while powerFSM.trigger(EVENT_SERIAL_DISCONNECTED); } -} \ No newline at end of file +} diff --git a/src/mesh/StreamAPI.h b/src/mesh/StreamAPI.h index 45cbb231c7..3196e96f8b 100644 --- a/src/mesh/StreamAPI.h +++ b/src/mesh/StreamAPI.h @@ -82,7 +82,4 @@ class StreamAPI : public PhoneAPI /// Subclasses can use this scratch buffer if they wish uint8_t txBuf[MAX_STREAM_BUF_SIZE] = {0}; - - /// Low level function to emit a protobuf encapsulated log record - void emitLogRecord(meshtastic_LogRecord_Level level, const char *src, const char *format, va_list arg); -}; \ No newline at end of file +}; diff --git a/src/mesh/eth/ethClient.cpp b/src/mesh/eth/ethClient.cpp index 9f3bb8ab7f..5373f243e6 100644 --- a/src/mesh/eth/ethClient.cpp +++ b/src/mesh/eth/ethClient.cpp @@ -12,8 +12,6 @@ #include #include -#if HAS_NETWORKING - #ifndef DISABLE_NTP #include @@ -185,5 +183,3 @@ bool isEthernetAvailable() return true; } } - -#endif \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/apponly.pb.h b/src/mesh/generated/meshtastic/apponly.pb.h index f5bacea52d..ba9f90873b 100644 --- a/src/mesh/generated/meshtastic/apponly.pb.h +++ b/src/mesh/generated/meshtastic/apponly.pb.h @@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size -#define meshtastic_ChannelSet_size 676 +#define meshtastic_ChannelSet_size 674 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 44a86f4d64..5a78f13668 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -22,6 +22,7 @@ typedef enum _meshtastic_Config_DeviceConfig_Role { The wifi radio and the oled screen will be put to sleep. This mode may still potentially have higher power usage due to it's preference in message rebroadcasting on the mesh. */ meshtastic_Config_DeviceConfig_Role_ROUTER = 2, + /* Description: Combination of both ROUTER and CLIENT. Not for mobile devices. */ meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT = 3, /* Description: Infrastructure node for extending network coverage by relaying messages with minimal overhead. Not visible in Nodes list. Technical Details: Mesh packets will simply be rebroadcasted over this node. Nodes configured with this role will not originate NodeInfo, Position, Telemetry @@ -371,9 +372,6 @@ typedef struct _meshtastic_Config_PowerConfig { uint32_t min_wake_secs; /* I2C address of INA_2XX to use for reading device battery voltage */ uint8_t device_battery_ina_address; - /* If non-zero, we want powermon log outputs. With the particular (bitfield) sources enabled. - Note: we picked an ID of 32 so that lower more efficient IDs can be used for more frequently used options. */ - uint64_t powermon_enables; } meshtastic_Config_PowerConfig; typedef struct _meshtastic_Config_NetworkConfig_IpV4Config { @@ -497,8 +495,6 @@ typedef struct _meshtastic_Config_LoRaConfig { Please respect your local laws and regulations. If you are a HAM, make sure you enable HAM mode and turn off encryption. */ float override_frequency; - /* If true, disable the build-in PA FAN using pin define in RF95_FAN_EN. */ - bool pa_fan_disabled; /* For testing it is useful sometimes to force a node to never listen to particular other nodes (simulating radio out of range). All nodenums listed in ignore_incoming will have packets they send dropped on receive (by router.cpp) */ @@ -616,20 +612,20 @@ extern "C" { #define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}} #define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} #define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} -#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_default {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} -#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} +#define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} #define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} #define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}} #define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} #define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} -#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""} #define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0} #define meshtastic_Config_DisplayConfig_init_zero {0, _meshtastic_Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _meshtastic_Config_DisplayConfig_DisplayUnits_MIN, _meshtastic_Config_DisplayConfig_OledType_MIN, _meshtastic_Config_DisplayConfig_DisplayMode_MIN, 0, 0, _meshtastic_Config_DisplayConfig_CompassOrientation_MIN} -#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} +#define meshtastic_Config_LoRaConfig_init_zero {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} #define meshtastic_Config_BluetoothConfig_init_zero {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} /* Field tags (for use in manual encoding/decoding) */ @@ -666,7 +662,6 @@ extern "C" { #define meshtastic_Config_PowerConfig_ls_secs_tag 7 #define meshtastic_Config_PowerConfig_min_wake_secs_tag 8 #define meshtastic_Config_PowerConfig_device_battery_ina_address_tag 9 -#define meshtastic_Config_PowerConfig_powermon_enables_tag 32 #define meshtastic_Config_NetworkConfig_IpV4Config_ip_tag 1 #define meshtastic_Config_NetworkConfig_IpV4Config_gateway_tag 2 #define meshtastic_Config_NetworkConfig_IpV4Config_subnet_tag 3 @@ -704,7 +699,6 @@ extern "C" { #define meshtastic_Config_LoRaConfig_override_duty_cycle_tag 12 #define meshtastic_Config_LoRaConfig_sx126x_rx_boosted_gain_tag 13 #define meshtastic_Config_LoRaConfig_override_frequency_tag 14 -#define meshtastic_Config_LoRaConfig_pa_fan_disabled_tag 15 #define meshtastic_Config_LoRaConfig_ignore_incoming_tag 103 #define meshtastic_Config_LoRaConfig_ignore_mqtt_tag 104 #define meshtastic_Config_BluetoothConfig_enabled_tag 1 @@ -779,8 +773,7 @@ X(a, STATIC, SINGULAR, UINT32, wait_bluetooth_secs, 4) \ X(a, STATIC, SINGULAR, UINT32, sds_secs, 6) \ X(a, STATIC, SINGULAR, UINT32, ls_secs, 7) \ X(a, STATIC, SINGULAR, UINT32, min_wake_secs, 8) \ -X(a, STATIC, SINGULAR, UINT32, device_battery_ina_address, 9) \ -X(a, STATIC, SINGULAR, UINT64, powermon_enables, 32) +X(a, STATIC, SINGULAR, UINT32, device_battery_ina_address, 9) #define meshtastic_Config_PowerConfig_CALLBACK NULL #define meshtastic_Config_PowerConfig_DEFAULT NULL @@ -835,7 +828,6 @@ X(a, STATIC, SINGULAR, UINT32, channel_num, 11) \ X(a, STATIC, SINGULAR, BOOL, override_duty_cycle, 12) \ X(a, STATIC, SINGULAR, BOOL, sx126x_rx_boosted_gain, 13) \ X(a, STATIC, SINGULAR, FLOAT, override_frequency, 14) \ -X(a, STATIC, SINGULAR, BOOL, pa_fan_disabled, 15) \ X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103) \ X(a, STATIC, SINGULAR, BOOL, ignore_mqtt, 104) #define meshtastic_Config_LoRaConfig_CALLBACK NULL @@ -875,11 +867,11 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; #define meshtastic_Config_BluetoothConfig_size 12 #define meshtastic_Config_DeviceConfig_size 100 #define meshtastic_Config_DisplayConfig_size 30 -#define meshtastic_Config_LoRaConfig_size 82 +#define meshtastic_Config_LoRaConfig_size 80 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_size 196 #define meshtastic_Config_PositionConfig_size 62 -#define meshtastic_Config_PowerConfig_size 52 +#define meshtastic_Config_PowerConfig_size 40 #define meshtastic_Config_size 199 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index eb37f4f957..5e291ee947 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -8,6 +8,7 @@ #include "meshtastic/channel.pb.h" #include "meshtastic/localonly.pb.h" #include "meshtastic/mesh.pb.h" +#include "meshtastic/module_config.pb.h" #include "meshtastic/telemetry.pb.h" #if PB_PROTO_HEADER_VERSION != 40 @@ -307,7 +308,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size #define meshtastic_ChannelFile_size 718 #define meshtastic_NodeInfoLite_size 166 -#define meshtastic_OEMStore_size 3388 +#define meshtastic_OEMStore_size 3372 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 983f48ad3f..96a9976f03 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -181,8 +181,8 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size -#define meshtastic_LocalConfig_size 555 -#define meshtastic_LocalModuleConfig_size 687 +#define meshtastic_LocalConfig_size 541 +#define meshtastic_LocalModuleConfig_size 685 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/meshtastic/mesh.pb.cpp b/src/mesh/generated/meshtastic/mesh.pb.cpp index 3fa81e1312..46d59d6094 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.cpp +++ b/src/mesh/generated/meshtastic/mesh.pb.cpp @@ -36,7 +36,7 @@ PB_BIND(meshtastic_NodeInfo, meshtastic_NodeInfo, AUTO) PB_BIND(meshtastic_MyNodeInfo, meshtastic_MyNodeInfo, AUTO) -PB_BIND(meshtastic_LogRecord, meshtastic_LogRecord, 2) +PB_BIND(meshtastic_LogRecord, meshtastic_LogRecord, AUTO) PB_BIND(meshtastic_QueueStatus, meshtastic_QueueStatus, AUTO) @@ -45,9 +45,6 @@ PB_BIND(meshtastic_QueueStatus, meshtastic_QueueStatus, AUTO) PB_BIND(meshtastic_FromRadio, meshtastic_FromRadio, 2) -PB_BIND(meshtastic_FileInfo, meshtastic_FileInfo, AUTO) - - PB_BIND(meshtastic_ToRadio, meshtastic_ToRadio, 2) diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index dbe9281ec0..0641158155 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -167,15 +167,6 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO = 64, /* Heltec Capsule Sensor V3 with ESP32-S3 CPU, Portable LoRa device that can replace GNSS modules or sensors */ meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3 = 65, - /* Heltec Vision Master T190 with ESP32-S3 CPU, and a 1.90 inch TFT display */ - meshtastic_HardwareModel_HELTEC_VISION_MASTER_T190 = 66, - /* Heltec Vision Master E213 with ESP32-S3 CPU, and a 2.13 inch E-Ink display */ - meshtastic_HardwareModel_HELTEC_VISION_MASTER_E213 = 67, - /* Heltec Vision Master E290 with ESP32-S3 CPU, and a 2.9 inch E-Ink display */ - meshtastic_HardwareModel_HELTEC_VISION_MASTER_E290 = 68, - /* Heltec Mesh Node T114 board with nRF52840 CPU, and a 1.14 inch TFT display, Ultimate low-power design, - specifically adapted for the Meshtatic project */ - meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 = 69, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ @@ -700,11 +691,11 @@ typedef struct _meshtastic_MyNodeInfo { and then extend as needed by emitting multiple records. */ typedef struct _meshtastic_LogRecord { /* Log levels, chosen to match python logging conventions. */ - char message[384]; + char message[64]; /* Seconds since 1970 - or 0 for unknown/unset */ uint32_t time; /* Usually based on thread name - if known */ - char source[32]; + char source[8]; /* Not yet set */ meshtastic_LogRecord_Level level; } meshtastic_LogRecord; @@ -720,14 +711,6 @@ typedef struct _meshtastic_QueueStatus { uint32_t mesh_packet_id; } meshtastic_QueueStatus; -/* Individual File info for the device */ -typedef struct _meshtastic_FileInfo { - /* The fully qualified path of the file */ - char file_name[228]; - /* The size of the file in bytes */ - uint32_t size_bytes; -} meshtastic_FileInfo; - typedef PB_BYTES_ARRAY_T(237) meshtastic_Compressed_data_t; /* Compressed message payload */ typedef struct _meshtastic_Compressed { @@ -832,8 +815,6 @@ typedef struct _meshtastic_FromRadio { meshtastic_DeviceMetadata metadata; /* MQTT Client Proxy Message (device sending to client / phone for publishing to MQTT) */ meshtastic_MqttClientProxyMessage mqttClientProxyMessage; - /* File system manifest messages */ - meshtastic_FileInfo fileInfo; }; } meshtastic_FromRadio; @@ -977,7 +958,6 @@ extern "C" { - #define meshtastic_Compressed_portnum_ENUMTYPE meshtastic_PortNum @@ -1005,7 +985,6 @@ extern "C" { #define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_default {0, 0, 0, 0} #define meshtastic_FromRadio_init_default {0, 0, {meshtastic_MeshPacket_init_default}} -#define meshtastic_FileInfo_init_default {"", 0} #define meshtastic_ToRadio_init_default {0, {meshtastic_MeshPacket_init_default}} #define meshtastic_Compressed_init_default {_meshtastic_PortNum_MIN, {0, {0}}} #define meshtastic_NeighborInfo_init_default {0, 0, 0, 0, {meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default, meshtastic_Neighbor_init_default}} @@ -1029,7 +1008,6 @@ extern "C" { #define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN} #define meshtastic_QueueStatus_init_zero {0, 0, 0, 0} #define meshtastic_FromRadio_init_zero {0, 0, {meshtastic_MeshPacket_init_zero}} -#define meshtastic_FileInfo_init_zero {"", 0} #define meshtastic_ToRadio_init_zero {0, {meshtastic_MeshPacket_init_zero}} #define meshtastic_Compressed_init_zero {_meshtastic_PortNum_MIN, {0, {0}}} #define meshtastic_NeighborInfo_init_zero {0, 0, 0, 0, {meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero, meshtastic_Neighbor_init_zero}} @@ -1132,8 +1110,6 @@ extern "C" { #define meshtastic_QueueStatus_free_tag 2 #define meshtastic_QueueStatus_maxlen_tag 3 #define meshtastic_QueueStatus_mesh_packet_id_tag 4 -#define meshtastic_FileInfo_file_name_tag 1 -#define meshtastic_FileInfo_size_bytes_tag 2 #define meshtastic_Compressed_portnum_tag 1 #define meshtastic_Compressed_data_tag 2 #define meshtastic_Neighbor_node_id_tag 1 @@ -1168,7 +1144,6 @@ extern "C" { #define meshtastic_FromRadio_xmodemPacket_tag 12 #define meshtastic_FromRadio_metadata_tag 13 #define meshtastic_FromRadio_mqttClientProxyMessage_tag 14 -#define meshtastic_FromRadio_fileInfo_tag 15 #define meshtastic_ToRadio_packet_tag 1 #define meshtastic_ToRadio_want_config_id_tag 3 #define meshtastic_ToRadio_disconnect_tag 4 @@ -1346,8 +1321,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,channel,channel), 10) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,queueStatus,queueStatus), 11) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 12) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,metadata,metadata), 13) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 14) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,fileInfo,fileInfo), 15) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 14) #define meshtastic_FromRadio_CALLBACK NULL #define meshtastic_FromRadio_DEFAULT NULL #define meshtastic_FromRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket @@ -1361,13 +1335,6 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,fileInfo,fileInfo), 15) #define meshtastic_FromRadio_payload_variant_xmodemPacket_MSGTYPE meshtastic_XModem #define meshtastic_FromRadio_payload_variant_metadata_MSGTYPE meshtastic_DeviceMetadata #define meshtastic_FromRadio_payload_variant_mqttClientProxyMessage_MSGTYPE meshtastic_MqttClientProxyMessage -#define meshtastic_FromRadio_payload_variant_fileInfo_MSGTYPE meshtastic_FileInfo - -#define meshtastic_FileInfo_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, STRING, file_name, 1) \ -X(a, STATIC, SINGULAR, UINT32, size_bytes, 2) -#define meshtastic_FileInfo_CALLBACK NULL -#define meshtastic_FileInfo_DEFAULT NULL #define meshtastic_ToRadio_FIELDLIST(X, a) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,packet,packet), 1) \ @@ -1467,7 +1434,6 @@ extern const pb_msgdesc_t meshtastic_MyNodeInfo_msg; extern const pb_msgdesc_t meshtastic_LogRecord_msg; extern const pb_msgdesc_t meshtastic_QueueStatus_msg; extern const pb_msgdesc_t meshtastic_FromRadio_msg; -extern const pb_msgdesc_t meshtastic_FileInfo_msg; extern const pb_msgdesc_t meshtastic_ToRadio_msg; extern const pb_msgdesc_t meshtastic_Compressed_msg; extern const pb_msgdesc_t meshtastic_NeighborInfo_msg; @@ -1493,7 +1459,6 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_LogRecord_fields &meshtastic_LogRecord_msg #define meshtastic_QueueStatus_fields &meshtastic_QueueStatus_msg #define meshtastic_FromRadio_fields &meshtastic_FromRadio_msg -#define meshtastic_FileInfo_fields &meshtastic_FileInfo_msg #define meshtastic_ToRadio_fields &meshtastic_ToRadio_msg #define meshtastic_Compressed_fields &meshtastic_Compressed_msg #define meshtastic_NeighborInfo_fields &meshtastic_NeighborInfo_msg @@ -1513,10 +1478,9 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_Compressed_size 243 #define meshtastic_Data_size 270 #define meshtastic_DeviceMetadata_size 46 -#define meshtastic_FileInfo_size 236 #define meshtastic_FromRadio_size 510 #define meshtastic_Heartbeat_size 0 -#define meshtastic_LogRecord_size 426 +#define meshtastic_LogRecord_size 81 #define meshtastic_MeshPacket_size 326 #define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 18 diff --git a/src/mesh/generated/meshtastic/module_config.pb.h b/src/mesh/generated/meshtastic/module_config.pb.h index 7fd57fe006..f3c48ee6df 100644 --- a/src/mesh/generated/meshtastic/module_config.pb.h +++ b/src/mesh/generated/meshtastic/module_config.pb.h @@ -60,9 +60,7 @@ typedef enum _meshtastic_ModuleConfig_SerialConfig_Serial_Mode { meshtastic_ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG = 3, meshtastic_ModuleConfig_SerialConfig_Serial_Mode_NMEA = 4, /* NMEA messages specifically tailored for CalTopo */ - meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO = 5, - /* Ecowitt WS85 weather station */ - meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85 = 6 + meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO = 5 } meshtastic_ModuleConfig_SerialConfig_Serial_Mode; /* TODO: REPLACE */ @@ -275,8 +273,6 @@ typedef struct _meshtastic_ModuleConfig_StoreForwardConfig { uint32_t history_return_max; /* TODO: REPLACE */ uint32_t history_return_window; - /* Set to true to let this node act as a server that stores received messages and resends them upon request. */ - bool is_server; } meshtastic_ModuleConfig_StoreForwardConfig; /* Preferences for the RangeTestModule */ @@ -436,8 +432,8 @@ extern "C" { #define _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Baud)(meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600+1)) #define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN meshtastic_ModuleConfig_SerialConfig_Serial_Mode_DEFAULT -#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MAX meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85 -#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Mode)(meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85+1)) +#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MAX meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO +#define _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_ARRAYSIZE ((meshtastic_ModuleConfig_SerialConfig_Serial_Mode)(meshtastic_ModuleConfig_SerialConfig_Serial_Mode_CALTOPO+1)) #define _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE #define _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MAX meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_BACK @@ -478,7 +474,7 @@ extern "C" { #define meshtastic_ModuleConfig_PaxcounterConfig_init_default {0, 0, 0, 0} #define meshtastic_ModuleConfig_SerialConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0} #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_StoreForwardConfig_init_default {0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_RangeTestConfig_init_default {0, 0, 0} #define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} @@ -494,7 +490,7 @@ extern "C" { #define meshtastic_ModuleConfig_PaxcounterConfig_init_zero {0, 0, 0, 0} #define meshtastic_ModuleConfig_SerialConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Baud_MIN, 0, _meshtastic_ModuleConfig_SerialConfig_Serial_Mode_MIN, 0} #define meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0, 0} +#define meshtastic_ModuleConfig_StoreForwardConfig_init_zero {0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_RangeTestConfig_init_zero {0, 0, 0} #define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0} @@ -564,7 +560,6 @@ extern "C" { #define meshtastic_ModuleConfig_StoreForwardConfig_records_tag 3 #define meshtastic_ModuleConfig_StoreForwardConfig_history_return_max_tag 4 #define meshtastic_ModuleConfig_StoreForwardConfig_history_return_window_tag 5 -#define meshtastic_ModuleConfig_StoreForwardConfig_is_server_tag 6 #define meshtastic_ModuleConfig_RangeTestConfig_enabled_tag 1 #define meshtastic_ModuleConfig_RangeTestConfig_sender_tag 2 #define meshtastic_ModuleConfig_RangeTestConfig_save_tag 3 @@ -748,8 +743,7 @@ X(a, STATIC, SINGULAR, BOOL, enabled, 1) \ X(a, STATIC, SINGULAR, BOOL, heartbeat, 2) \ X(a, STATIC, SINGULAR, UINT32, records, 3) \ X(a, STATIC, SINGULAR, UINT32, history_return_max, 4) \ -X(a, STATIC, SINGULAR, UINT32, history_return_window, 5) \ -X(a, STATIC, SINGULAR, BOOL, is_server, 6) +X(a, STATIC, SINGULAR, UINT32, history_return_window, 5) #define meshtastic_ModuleConfig_StoreForwardConfig_CALLBACK NULL #define meshtastic_ModuleConfig_StoreForwardConfig_DEFAULT NULL @@ -854,7 +848,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg; #define meshtastic_ModuleConfig_RangeTestConfig_size 10 #define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96 #define meshtastic_ModuleConfig_SerialConfig_size 28 -#define meshtastic_ModuleConfig_StoreForwardConfig_size 24 +#define meshtastic_ModuleConfig_StoreForwardConfig_size 22 #define meshtastic_ModuleConfig_TelemetryConfig_size 36 #define meshtastic_ModuleConfig_size 257 #define meshtastic_RemoteHardwarePin_size 21 diff --git a/src/mesh/generated/meshtastic/portnums.pb.h b/src/mesh/generated/meshtastic/portnums.pb.h index 6cc82352ab..233e8d6534 100644 --- a/src/mesh/generated/meshtastic/portnums.pb.h +++ b/src/mesh/generated/meshtastic/portnums.pb.h @@ -124,8 +124,6 @@ typedef enum _meshtastic_PortNum { meshtastic_PortNum_ATAK_PLUGIN = 72, /* Provides unencrypted information about a node for consumption by a map via MQTT */ meshtastic_PortNum_MAP_REPORT_APP = 73, - /* PowerStress based monitoring support (for automated power consumption testing) */ - meshtastic_PortNum_POWERSTRESS_APP = 74, /* Private applications should use portnums >= 256. To simplify initial development and testing you can use "PRIVATE_APP" in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh)) */ diff --git a/src/mesh/generated/meshtastic/powermon.pb.cpp b/src/mesh/generated/meshtastic/powermon.pb.cpp deleted file mode 100644 index ce41ea0217..0000000000 --- a/src/mesh/generated/meshtastic/powermon.pb.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.8 */ - -#include "meshtastic/powermon.pb.h" -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -PB_BIND(meshtastic_PowerMon, meshtastic_PowerMon, AUTO) - - -PB_BIND(meshtastic_PowerStressMessage, meshtastic_PowerStressMessage, AUTO) - - - - - diff --git a/src/mesh/generated/meshtastic/powermon.pb.h b/src/mesh/generated/meshtastic/powermon.pb.h deleted file mode 100644 index 7de0618e9b..0000000000 --- a/src/mesh/generated/meshtastic/powermon.pb.h +++ /dev/null @@ -1,138 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.8 */ - -#ifndef PB_MESHTASTIC_MESHTASTIC_POWERMON_PB_H_INCLUDED -#define PB_MESHTASTIC_MESHTASTIC_POWERMON_PB_H_INCLUDED -#include - -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -/* Enum definitions */ -/* Any significant power changing event in meshtastic should be tagged with a powermon state transition. -If you are making new meshtastic features feel free to add new entries at the end of this definition. */ -typedef enum _meshtastic_PowerMon_State { - meshtastic_PowerMon_State_None = 0, - meshtastic_PowerMon_State_CPU_DeepSleep = 1, - meshtastic_PowerMon_State_CPU_LightSleep = 2, - /* The external Vext1 power is on. Many boards have auxillary power rails that the CPU turns on only -occasionally. In cases where that rail has multiple devices on it we usually want to have logging on -the state of that rail as an independent record. -For instance on the Heltec Tracker 1.1 board, this rail is the power source for the GPS and screen. - -The log messages will be short and complete (see PowerMon.Event in the protobufs for details). -something like "S:PM:C,0x00001234,REASON" where the hex number is the bitmask of all current states. -(We use a bitmask for states so that if a log message gets lost it won't be fatal) */ - meshtastic_PowerMon_State_Vext1_On = 4, - meshtastic_PowerMon_State_Lora_RXOn = 8, - meshtastic_PowerMon_State_Lora_TXOn = 16, - meshtastic_PowerMon_State_Lora_RXActive = 32, - meshtastic_PowerMon_State_BT_On = 64, - meshtastic_PowerMon_State_LED_On = 128, - meshtastic_PowerMon_State_Screen_On = 256, - meshtastic_PowerMon_State_Screen_Drawing = 512, - meshtastic_PowerMon_State_Wifi_On = 1024, - /* GPS is actively trying to find our location -See GPSPowerState for more details */ - meshtastic_PowerMon_State_GPS_Active = 2048 -} meshtastic_PowerMon_State; - -/* What operation would we like the UUT to perform. -note: senders should probably set want_response in their request packets, so that they can know when the state -machine has started processing their request */ -typedef enum _meshtastic_PowerStressMessage_Opcode { - /* Unset/unused */ - meshtastic_PowerStressMessage_Opcode_UNSET = 0, - meshtastic_PowerStressMessage_Opcode_PRINT_INFO = 1, /* Print board version slog and send an ack that we are alive and ready to process commands */ - meshtastic_PowerStressMessage_Opcode_FORCE_QUIET = 2, /* Try to turn off all automatic processing of packets, screen, sleeping, etc (to make it easier to measure in isolation) */ - meshtastic_PowerStressMessage_Opcode_END_QUIET = 3, /* Stop powerstress processing - probably by just rebooting the board */ - meshtastic_PowerStressMessage_Opcode_SCREEN_ON = 16, /* Turn the screen on */ - meshtastic_PowerStressMessage_Opcode_SCREEN_OFF = 17, /* Turn the screen off */ - meshtastic_PowerStressMessage_Opcode_CPU_IDLE = 32, /* Let the CPU run but we assume mostly idling for num_seconds */ - meshtastic_PowerStressMessage_Opcode_CPU_DEEPSLEEP = 33, /* Force deep sleep for FIXME seconds */ - meshtastic_PowerStressMessage_Opcode_CPU_FULLON = 34, /* Spin the CPU as fast as possible for num_seconds */ - meshtastic_PowerStressMessage_Opcode_LED_ON = 48, /* Turn the LED on for num_seconds (and leave it on - for baseline power measurement purposes) */ - meshtastic_PowerStressMessage_Opcode_LED_OFF = 49, /* Force the LED off for num_seconds */ - meshtastic_PowerStressMessage_Opcode_LORA_OFF = 64, /* Completely turn off the LORA radio for num_seconds */ - meshtastic_PowerStressMessage_Opcode_LORA_TX = 65, /* Send Lora packets for num_seconds */ - meshtastic_PowerStressMessage_Opcode_LORA_RX = 66, /* Receive Lora packets for num_seconds (node will be mostly just listening, unless an external agent is helping stress this by sending packets on the current channel) */ - meshtastic_PowerStressMessage_Opcode_BT_OFF = 80, /* Turn off the BT radio for num_seconds */ - meshtastic_PowerStressMessage_Opcode_BT_ON = 81, /* Turn on the BT radio for num_seconds */ - meshtastic_PowerStressMessage_Opcode_WIFI_OFF = 96, /* Turn off the WIFI radio for num_seconds */ - meshtastic_PowerStressMessage_Opcode_WIFI_ON = 97, /* Turn on the WIFI radio for num_seconds */ - meshtastic_PowerStressMessage_Opcode_GPS_OFF = 112, /* Turn off the GPS radio for num_seconds */ - meshtastic_PowerStressMessage_Opcode_GPS_ON = 113 /* Turn on the GPS radio for num_seconds */ -} meshtastic_PowerStressMessage_Opcode; - -/* Struct definitions */ -/* Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs). -But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us) */ -typedef struct _meshtastic_PowerMon { - char dummy_field; -} meshtastic_PowerMon; - -/* PowerStress testing support via the C++ PowerStress module */ -typedef struct _meshtastic_PowerStressMessage { - /* What type of HardwareMessage is this? */ - meshtastic_PowerStressMessage_Opcode cmd; - float num_seconds; -} meshtastic_PowerStressMessage; - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Helper constants for enums */ -#define _meshtastic_PowerMon_State_MIN meshtastic_PowerMon_State_None -#define _meshtastic_PowerMon_State_MAX meshtastic_PowerMon_State_GPS_Active -#define _meshtastic_PowerMon_State_ARRAYSIZE ((meshtastic_PowerMon_State)(meshtastic_PowerMon_State_GPS_Active+1)) - -#define _meshtastic_PowerStressMessage_Opcode_MIN meshtastic_PowerStressMessage_Opcode_UNSET -#define _meshtastic_PowerStressMessage_Opcode_MAX meshtastic_PowerStressMessage_Opcode_GPS_ON -#define _meshtastic_PowerStressMessage_Opcode_ARRAYSIZE ((meshtastic_PowerStressMessage_Opcode)(meshtastic_PowerStressMessage_Opcode_GPS_ON+1)) - - -#define meshtastic_PowerStressMessage_cmd_ENUMTYPE meshtastic_PowerStressMessage_Opcode - - -/* Initializer values for message structs */ -#define meshtastic_PowerMon_init_default {0} -#define meshtastic_PowerStressMessage_init_default {_meshtastic_PowerStressMessage_Opcode_MIN, 0} -#define meshtastic_PowerMon_init_zero {0} -#define meshtastic_PowerStressMessage_init_zero {_meshtastic_PowerStressMessage_Opcode_MIN, 0} - -/* Field tags (for use in manual encoding/decoding) */ -#define meshtastic_PowerStressMessage_cmd_tag 1 -#define meshtastic_PowerStressMessage_num_seconds_tag 2 - -/* Struct field encoding specification for nanopb */ -#define meshtastic_PowerMon_FIELDLIST(X, a) \ - -#define meshtastic_PowerMon_CALLBACK NULL -#define meshtastic_PowerMon_DEFAULT NULL - -#define meshtastic_PowerStressMessage_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, cmd, 1) \ -X(a, STATIC, SINGULAR, FLOAT, num_seconds, 2) -#define meshtastic_PowerStressMessage_CALLBACK NULL -#define meshtastic_PowerStressMessage_DEFAULT NULL - -extern const pb_msgdesc_t meshtastic_PowerMon_msg; -extern const pb_msgdesc_t meshtastic_PowerStressMessage_msg; - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define meshtastic_PowerMon_fields &meshtastic_PowerMon_msg -#define meshtastic_PowerStressMessage_fields &meshtastic_PowerStressMessage_msg - -/* Maximum encoded size of messages (where known) */ -#define MESHTASTIC_MESHTASTIC_POWERMON_PB_H_MAX_SIZE meshtastic_PowerStressMessage_size -#define meshtastic_PowerMon_size 0 -#define meshtastic_PowerStressMessage_size 7 - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 82cd0a55d9..28d3687548 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -115,10 +115,6 @@ typedef struct _meshtastic_EnvironmentMetrics { float wind_speed; /* Weight in KG */ float weight; - /* Wind gust in m/s */ - float wind_gust; - /* Wind lull in m/s */ - float wind_lull; } meshtastic_EnvironmentMetrics; /* Power Metrics (voltage / current / etc) */ @@ -209,13 +205,13 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_DeviceMetrics_init_default {0, 0, 0, 0, 0} -#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_EnvironmentMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_default {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}} #define meshtastic_Nau7802Config_init_default {0, 0} #define meshtastic_DeviceMetrics_init_zero {0, 0, 0, 0, 0} -#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +#define meshtastic_EnvironmentMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_PowerMetrics_init_zero {0, 0, 0, 0, 0, 0} #define meshtastic_AirQualityMetrics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}} @@ -242,8 +238,6 @@ extern "C" { #define meshtastic_EnvironmentMetrics_wind_direction_tag 13 #define meshtastic_EnvironmentMetrics_wind_speed_tag 14 #define meshtastic_EnvironmentMetrics_weight_tag 15 -#define meshtastic_EnvironmentMetrics_wind_gust_tag 16 -#define meshtastic_EnvironmentMetrics_wind_lull_tag 17 #define meshtastic_PowerMetrics_ch1_voltage_tag 1 #define meshtastic_PowerMetrics_ch1_current_tag 2 #define meshtastic_PowerMetrics_ch2_voltage_tag 3 @@ -295,9 +289,7 @@ X(a, STATIC, SINGULAR, FLOAT, ir_lux, 11) \ X(a, STATIC, SINGULAR, FLOAT, uv_lux, 12) \ X(a, STATIC, SINGULAR, UINT32, wind_direction, 13) \ X(a, STATIC, SINGULAR, FLOAT, wind_speed, 14) \ -X(a, STATIC, SINGULAR, FLOAT, weight, 15) \ -X(a, STATIC, SINGULAR, FLOAT, wind_gust, 16) \ -X(a, STATIC, SINGULAR, FLOAT, wind_lull, 17) +X(a, STATIC, SINGULAR, FLOAT, weight, 15) #define meshtastic_EnvironmentMetrics_CALLBACK NULL #define meshtastic_EnvironmentMetrics_DEFAULT NULL @@ -365,10 +357,10 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; #define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size #define meshtastic_AirQualityMetrics_size 72 #define meshtastic_DeviceMetrics_size 27 -#define meshtastic_EnvironmentMetrics_size 85 +#define meshtastic_EnvironmentMetrics_size 73 #define meshtastic_Nau7802Config_size 16 #define meshtastic_PowerMetrics_size 30 -#define meshtastic_Telemetry_size 92 +#define meshtastic_Telemetry_size 80 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index b309484e23..7f9df058dd 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -6,7 +6,7 @@ #include "main.h" #include "mesh/http/ContentHelper.h" #include "mesh/http/WebServer.h" -#if HAS_WIFI +#if !MESHTASTIC_EXCLUDE_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "mqtt/JSON.h" diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index e733d18011..ffb16bd3e5 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -1,5 +1,5 @@ #include "configuration.h" -#if HAS_WIFI +#if !MESHTASTIC_EXCLUDE_WIFI #include "NodeDB.h" #include "RTC.h" #include "concurrency/Periodic.h" diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index cab63e5594..0915864623 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -137,7 +137,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta #if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH if (BleOta::getOtaAppVersion().isEmpty()) { LOG_INFO("No OTA firmware available, scheduling regular reboot in %d seconds\n", s); - screen->startAlert("Rebooting..."); + screen->startRebootScreen(); } else { screen->startFirmwareUpdateScreen(); BleOta::switchToOtaApp(); @@ -145,7 +145,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta } #else LOG_INFO("Not on ESP32, scheduling regular reboot in %d seconds\n", s); - screen->startAlert("Rebooting..."); + screen->startRebootScreen(); #endif rebootAtMsec = (s < 0) ? 0 : (millis() + s * 1000); break; @@ -200,7 +200,6 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta case meshtastic_AdminMessage_remove_by_nodenum_tag: { LOG_INFO("Client is receiving a remove_nodenum command.\n"); nodeDB->removeNodeByNum(r->remove_by_nodenum); - this->notifyObservers(r); // Observed by screen break; } case meshtastic_AdminMessage_set_favorite_node_tag: { @@ -233,9 +232,9 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta #if !MESHTASTIC_EXCLUDE_GPS if (gps != nullptr) gps->enable(); +#endif // Send our new fixed position to the mesh for good measure positionModule->sendOurPosition(); -#endif } break; } @@ -300,8 +299,8 @@ void AdminModule::handleGetModuleConfigResponse(const meshtastic_MeshPacket &mp, { // Skip if it's disabled or no pins are exposed if (!r->get_module_config_response.payload_variant.remote_hardware.enabled || - r->get_module_config_response.payload_variant.remote_hardware.available_pins_count == 0) { - LOG_DEBUG("Remote hardware module disabled or no available_pins. Skipping...\n"); + !r->get_module_config_response.payload_variant.remote_hardware.available_pins) { + LOG_DEBUG("Remote hardware module disabled or no vailable_pins. Skipping...\n"); return; } for (uint8_t i = 0; i < devicestate.node_remote_hardware_pins_count; i++) { @@ -389,10 +388,6 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) LOG_DEBUG("Tried to set node_info_broadcast_secs too low, setting to %d\n", min_node_info_broadcast_secs); config.device.node_info_broadcast_secs = min_node_info_broadcast_secs; } - // Router Client is deprecated; Set it to client - if (c.payload_variant.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT) { - config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT; - } break; case meshtastic_Config_position_tag: LOG_INFO("Setting config: Position\n"); @@ -816,7 +811,7 @@ void AdminModule::handleGetChannel(const meshtastic_MeshPacket &req, uint32_t ch void AdminModule::reboot(int32_t seconds) { LOG_INFO("Rebooting in %d seconds\n", seconds); - screen->startAlert("Rebooting..."); + screen->startRebootScreen(); rebootAtMsec = (seconds < 0) ? 0 : (millis() + seconds * 1000); } diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h index a5ffeb7d60..32b32c253a 100644 --- a/src/modules/AdminModule.h +++ b/src/modules/AdminModule.h @@ -1,13 +1,13 @@ #pragma once #include "ProtobufModule.h" -#if HAS_WIFI +#if HAS_WIFI && !MESHTASTIC_EXCLUDE_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif /** * Admin module for admin messages */ -class AdminModule : public ProtobufModule, public Observable +class AdminModule : public ProtobufModule { public: /** Constructor diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index 84b5a3260e..f513e045f4 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -148,9 +148,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) if (this->currentMessageIndex == 0) { this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT; - requestFocus(); // Tell Screen::setFrames to move to our module's frame, next time it runs - UIFrameEvent e; - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + UIFrameEvent e = {false, true}; + e.frameChanged = true; this->notifyObservers(&e); return 0; @@ -167,8 +166,8 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } } if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL)) { - UIFrameEvent e; - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + UIFrameEvent e = {false, true}; + e.frameChanged = true; this->currentMessageIndex = -1; #if !defined(T_WATCH_S3) && !defined(RAK14014) @@ -354,8 +353,6 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } if (validEvent) { - requestFocus(); // Tell Screen::setFrames to move to our module's frame, next time it runs - // Let runOnce to be called immediately. if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) { setIntervalFromNow(0); // on fast keypresses, this isn't fast enough. @@ -381,11 +378,6 @@ void CannedMessageModule::sendText(NodeNum dest, ChannelIndex channel, const cha p->decoded.payload.size++; } - // Only receive routing messages when expecting ACK for a canned message - // Prevents the canned message module from regenerating the screen's frameset at unexpected times, - // or raising a UIFrameEvent before another module has the chance - this->waitingForAck = true; - LOG_INFO("Sending message id=%d, dest=%x, msg=%.*s\n", p->id, p->to, p->decoded.payload.size, p->decoded.payload.bytes); service.sendToMesh( @@ -401,13 +393,13 @@ int32_t CannedMessageModule::runOnce() return INT32_MAX; } // LOG_DEBUG("Check status\n"); - UIFrameEvent e; + UIFrameEvent e = {false, true}; if ((this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) || (this->runState == CANNED_MESSAGE_RUN_STATE_MESSAGE)) { // TODO: might have some feedback of sending state this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; temporaryMessage = ""; - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + e.frameChanged = true; this->currentMessageIndex = -1; this->freetext = ""; // clear freetext this->cursor = 0; @@ -420,7 +412,7 @@ int32_t CannedMessageModule::runOnce() } else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) && ((millis() - this->lastTouchMillis) > INACTIVATE_AFTER_MS)) { // Reset module - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + e.frameChanged = true; this->currentMessageIndex = -1; this->freetext = ""; // clear freetext this->cursor = 0; @@ -457,7 +449,7 @@ int32_t CannedMessageModule::runOnce() this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; } } - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + e.frameChanged = true; this->currentMessageIndex = -1; this->freetext = ""; // clear freetext this->cursor = 0; @@ -471,7 +463,7 @@ int32_t CannedMessageModule::runOnce() } else if ((this->runState != CANNED_MESSAGE_RUN_STATE_FREETEXT) && (this->currentMessageIndex == -1)) { this->currentMessageIndex = 0; LOG_DEBUG("First touch (%d):%s\n", this->currentMessageIndex, this->getCurrentMessage()); - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + e.frameChanged = true; this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE; } else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_UP) { if (this->messagesCount > 0) { @@ -575,7 +567,7 @@ int32_t CannedMessageModule::runOnce() break; } if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + e.frameChanged = true; switch (this->payload) { // code below all trigger the freetext window (where you type to send a message) or reset the // display back to the default window case 0x08: // backspace @@ -605,14 +597,14 @@ int32_t CannedMessageModule::runOnce() // handle fn+s for shutdown case 0x9b: if (screen) - screen->startAlert("Shutting down..."); + screen->startShutdownScreen(); shutdownAtMsec = millis() + DEFAULT_SHUTDOWN_SECONDS * 1000; runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; break; // and fn+r for reboot case 0x90: if (screen) - screen->startAlert("Rebooting..."); + screen->startRebootScreen(); rebootAtMsec = millis() + DEFAULT_REBOOT_SECONDS * 1000; runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; break; @@ -714,8 +706,8 @@ int CannedMessageModule::getPrevIndex() void CannedMessageModule::showTemporaryMessage(const String &message) { temporaryMessage = message; - UIFrameEvent e; - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + UIFrameEvent e = {false, true}; + e.frameChanged = true; notifyObservers(&e); runState = CANNED_MESSAGE_RUN_STATE_MESSAGE; // run this loop again in 2 seconds, next iteration will clear the display @@ -922,13 +914,11 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st char buffer[50]; if (temporaryMessage.length() != 0) { - requestFocus(); // Tell Screen::setFrames to move to our module's frame LOG_DEBUG("Drawing temporary message: %s", temporaryMessage.c_str()); display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(FONT_MEDIUM); display->drawString(display->getWidth() / 2 + x, 0 + y + 12, temporaryMessage); } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) { - requestFocus(); // Tell Screen::setFrames to move to our module's frame display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(FONT_MEDIUM); String displayString; @@ -950,7 +940,6 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st display->drawStringf(display->getWidth() / 2 + x, y + 130, buffer, rssiString, this->lastRxRssi); } } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) { - requestFocus(); // Tell Screen::setFrames to move to our module's frame display->setTextAlignment(TEXT_ALIGN_CENTER); display->setFont(FONT_MEDIUM); display->drawString(display->getWidth() / 2 + x, 0 + y + 12, "Sending..."); @@ -959,7 +948,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st display->setFont(FONT_SMALL); display->drawString(10 + x, 0 + y + FONT_HEIGHT_SMALL, "Canned Message\nModule disabled."); } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { - requestFocus(); // Tell Screen::setFrames to move to our module's frame + #if defined(T_WATCH_S3) || defined(RAK14014) drawKeyboard(display, state, 0, 0); #else @@ -1041,18 +1030,16 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st ProcessMessage CannedMessageModule::handleReceived(const meshtastic_MeshPacket &mp) { - if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP && waitingForAck) { + if (mp.decoded.portnum == meshtastic_PortNum_ROUTING_APP) { // look for a request_id if (mp.decoded.request_id != 0) { - UIFrameEvent e; - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen - requestFocus(); // Tell Screen::setFrames that our module's frame should be shown, even if not "first" in the frameset + UIFrameEvent e = {false, true}; + e.frameChanged = true; this->runState = CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED; this->incoming = service.getNodenumFromRequestId(mp.decoded.request_id); meshtastic_Routing decoded = meshtastic_Routing_init_default; pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_Routing_fields, &decoded); this->ack = decoded.error_reason == meshtastic_Routing_Error_NONE; - waitingForAck = false; // No longer want routing packets this->notifyObservers(&e); // run the next time 2 seconds later setIntervalFromNow(2000); diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h index 797b9f7cff..00e8c2bf9a 100644 --- a/src/modules/CannedMessageModule.h +++ b/src/modules/CannedMessageModule.h @@ -81,8 +81,9 @@ class CannedMessageModule : public SinglePortModule, public Observabledecoded.portnum) { + case meshtastic_PortNum_TEXT_MESSAGE_APP: case meshtastic_PortNum_ROUTING_APP: - return waitingForAck; + return true; default: return false; } @@ -139,8 +140,7 @@ class CannedMessageModule : public SinglePortModule, public Observable, private concurrency::OSThread -{ - meshtastic_PowerStressMessage currentMessage = meshtastic_PowerStressMessage_init_default; - bool isRunningCommand = false; - - public: - /** Constructor - * name is for debugging output - */ - PowerStressModule(); - - protected: - /** Called to handle a particular incoming message - - @return true if you've guaranteed you've handled this message and no other handlers should be considered for it - */ - virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_PowerStressMessage *p) override; - - /** - * Periodically read the gpios we have been asked to WATCH, if they have changed, - * broadcast a message with the change information. - * - * The method that will be called each time our thread gets a chance to run - * - * Returns desired period for next invocation (or RUN_SAME for no change) - */ - virtual int32_t runOnce() override; -}; - -extern PowerStressModule powerStressModule; \ No newline at end of file diff --git a/src/modules/Telemetry/AirQualityTelemetry.cpp b/src/modules/Telemetry/AirQualityTelemetry.cpp index 43b0ac46c3..4f5fbcd131 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.cpp +++ b/src/modules/Telemetry/AirQualityTelemetry.cpp @@ -47,8 +47,7 @@ int32_t AirQualityTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval, - default_telemetry_broadcast_interval_secs))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.air_quality_interval))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); @@ -86,90 +85,53 @@ bool AirQualityTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPack return false; // Let others look at this message also if they want } -bool AirQualityTelemetryModule::getAirQualityTelemetry(meshtastic_Telemetry *m) +bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) { if (!aqi.read(&data)) { LOG_WARN("Skipping send measurements. Could not read AQIn\n"); return false; } - m->time = getTime(); - m->which_variant = meshtastic_Telemetry_air_quality_metrics_tag; - m->variant.air_quality_metrics.pm10_standard = data.pm10_standard; - m->variant.air_quality_metrics.pm25_standard = data.pm25_standard; - m->variant.air_quality_metrics.pm100_standard = data.pm100_standard; + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; + m.time = getTime(); + m.which_variant = meshtastic_Telemetry_air_quality_metrics_tag; + m.variant.air_quality_metrics.pm10_standard = data.pm10_standard; + m.variant.air_quality_metrics.pm25_standard = data.pm25_standard; + m.variant.air_quality_metrics.pm100_standard = data.pm100_standard; - m->variant.air_quality_metrics.pm10_environmental = data.pm10_env; - m->variant.air_quality_metrics.pm25_environmental = data.pm25_env; - m->variant.air_quality_metrics.pm100_environmental = data.pm100_env; + m.variant.air_quality_metrics.pm10_environmental = data.pm10_env; + m.variant.air_quality_metrics.pm25_environmental = data.pm25_env; + m.variant.air_quality_metrics.pm100_environmental = data.pm100_env; LOG_INFO("(Sending): PM1.0(Standard)=%i, PM2.5(Standard)=%i, PM10.0(Standard)=%i\n", - m->variant.air_quality_metrics.pm10_standard, m->variant.air_quality_metrics.pm25_standard, - m->variant.air_quality_metrics.pm100_standard); + m.variant.air_quality_metrics.pm10_standard, m.variant.air_quality_metrics.pm25_standard, + m.variant.air_quality_metrics.pm100_standard); LOG_INFO(" | PM1.0(Environmental)=%i, PM2.5(Environmental)=%i, PM10.0(Environmental)=%i\n", - m->variant.air_quality_metrics.pm10_environmental, m->variant.air_quality_metrics.pm25_environmental, - m->variant.air_quality_metrics.pm100_environmental); - - return true; -} - -meshtastic_MeshPacket *AirQualityTelemetryModule::allocReply() -{ - if (currentRequest) { - auto req = *currentRequest; - const auto &p = req.decoded; - meshtastic_Telemetry scratch; - meshtastic_Telemetry *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { - decoded = &scratch; - } else { - LOG_ERROR("Error decoding AirQualityTelemetry module!\n"); - return NULL; - } - // Check for a request for air quality metrics - if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) { - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; - if (getAirQualityTelemetry(&m)) { - LOG_INFO("Air quality telemetry replying to request\n"); - return allocDataProtobuf(m); - } else { - return NULL; - } - } - } - return NULL; -} - -bool AirQualityTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) -{ - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; - if (getAirQualityTelemetry(&m)) { - meshtastic_MeshPacket *p = allocDataProtobuf(m); - p->to = dest; - p->decoded.want_response = false; - if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) - p->priority = meshtastic_MeshPacket_Priority_RELIABLE; - else - p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; - - // release previous packet before occupying a new spot - if (lastMeasurementPacket != nullptr) - packetPool.release(lastMeasurementPacket); - - lastMeasurementPacket = packetPool.allocCopy(*p); - if (phoneOnly) { - LOG_INFO("Sending packet to phone\n"); - service.sendToPhone(p); - } else { - LOG_INFO("Sending packet to mesh\n"); - service.sendToMesh(p, RX_SRC_LOCAL, true); - } - return true; + m.variant.air_quality_metrics.pm10_environmental, m.variant.air_quality_metrics.pm25_environmental, + m.variant.air_quality_metrics.pm100_environmental); + + meshtastic_MeshPacket *p = allocDataProtobuf(m); + p->to = dest; + p->decoded.want_response = false; + if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) + p->priority = meshtastic_MeshPacket_Priority_RELIABLE; + else + p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; + + // release previous packet before occupying a new spot + if (lastMeasurementPacket != nullptr) + packetPool.release(lastMeasurementPacket); + + lastMeasurementPacket = packetPool.allocCopy(*p); + if (phoneOnly) { + LOG_INFO("Sending packet to phone\n"); + service.sendToPhone(p); + } else { + LOG_INFO("Sending packet to mesh\n"); + service.sendToMesh(p, RX_SRC_LOCAL, true); } - - return false; + return true; } #endif \ No newline at end of file diff --git a/src/modules/Telemetry/AirQualityTelemetry.h b/src/modules/Telemetry/AirQualityTelemetry.h index 9d09078b11..eb0355001e 100644 --- a/src/modules/Telemetry/AirQualityTelemetry.h +++ b/src/modules/Telemetry/AirQualityTelemetry.h @@ -26,11 +26,6 @@ class AirQualityTelemetryModule : private concurrency::OSThread, public Protobuf */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override; virtual int32_t runOnce() override; - /** Called to get current Air Quality data - @return true if it contains valid data - */ - bool getAirQualityTelemetry(meshtastic_Telemetry *m); - virtual meshtastic_MeshPacket *allocReply() override; /** * Send our Telemetry into the mesh */ diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 9fe679b41f..b64e8d1130 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -17,8 +17,7 @@ int32_t DeviceTelemetryModule::runOnce() { refreshUptime(); if (((lastSentToMesh == 0) || - ((uptimeLastMs - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval, - default_telemetry_broadcast_interval_secs))) && + ((uptimeLastMs - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.device_update_interval))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil() && config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER && config.device.role != meshtastic_Config_DeviceConfig_Role_CLIENT_HIDDEN) { @@ -53,27 +52,14 @@ bool DeviceTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket & meshtastic_MeshPacket *DeviceTelemetryModule::allocReply() { - if (currentRequest) { - auto req = *currentRequest; - const auto &p = req.decoded; - meshtastic_Telemetry scratch; - meshtastic_Telemetry *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { - decoded = &scratch; - } else { - LOG_ERROR("Error decoding DeviceTelemetry module!\n"); - return NULL; - } - // Check for a request for device metrics - if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) { - LOG_INFO("Device telemetry replying to request\n"); - - meshtastic_Telemetry telemetry = getDeviceTelemetry(); - return allocDataProtobuf(telemetry); - } + if (ignoreRequest) { + return NULL; } - return NULL; + + LOG_INFO("Device telemetry replying to request\n"); + + meshtastic_Telemetry telemetry = getDeviceTelemetry(); + return allocDataProtobuf(telemetry); } meshtastic_Telemetry DeviceTelemetryModule::getDeviceTelemetry() @@ -118,4 +104,4 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) service.sendToMesh(p, RX_SRC_LOCAL, true); } return true; -} \ No newline at end of file +} diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 9f0dc7b79c..b1149799b5 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -69,8 +69,7 @@ int32_t EnvironmentTelemetryModule::runOnce() { if (sleepOnNextExecution == true) { sleepOnNextExecution = false; - uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval, - default_telemetry_broadcast_interval_secs); + uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval); LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs); doDeepSleep(nightyNightMs, true); } @@ -125,8 +124,6 @@ int32_t EnvironmentTelemetryModule::runOnce() result = ina219Sensor.runOnce(); if (ina260Sensor.hasSensor()) result = ina260Sensor.runOnce(); - if (ina3221Sensor.hasSensor()) - result = ina3221Sensor.runOnce(); if (veml7700Sensor.hasSensor()) result = veml7700Sensor.runOnce(); if (tsl2591Sensor.hasSensor()) @@ -155,8 +152,7 @@ int32_t EnvironmentTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval, - default_telemetry_broadcast_interval_secs))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval))) && airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); @@ -202,7 +198,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt if (lastMeasurementPacket == nullptr) { // If there's no valid packet, display "Environment" display->drawString(x, y, "Environment"); - display->drawString(x, y += _fontHeight(FONT_SMALL), "No measurement"); + display->drawString(x, y += fontHeight(FONT_SMALL), "No measurement"); return; } @@ -227,31 +223,31 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt } // Continue with the remaining details - display->drawString(x, y += _fontHeight(FONT_SMALL), + display->drawString(x, y += fontHeight(FONT_SMALL), "Temp/Hum: " + last_temp + " / " + String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%"); if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0) { - display->drawString(x, y += _fontHeight(FONT_SMALL), + display->drawString(x, y += fontHeight(FONT_SMALL), "Press: " + String(lastMeasurement.variant.environment_metrics.barometric_pressure, 0) + "hPA"); } if (lastMeasurement.variant.environment_metrics.voltage != 0) { - display->drawString(x, y += _fontHeight(FONT_SMALL), + display->drawString(x, y += fontHeight(FONT_SMALL), "Volt/Cur: " + String(lastMeasurement.variant.environment_metrics.voltage, 0) + "V / " + String(lastMeasurement.variant.environment_metrics.current, 0) + "mA"); } if (lastMeasurement.variant.environment_metrics.iaq != 0) { - display->drawString(x, y += _fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq)); + display->drawString(x, y += fontHeight(FONT_SMALL), "IAQ: " + String(lastMeasurement.variant.environment_metrics.iaq)); } if (lastMeasurement.variant.environment_metrics.distance != 0) - display->drawString(x, y += _fontHeight(FONT_SMALL), + display->drawString(x, y += fontHeight(FONT_SMALL), "Water Level: " + String(lastMeasurement.variant.environment_metrics.distance, 0) + "mm"); if (lastMeasurement.variant.environment_metrics.weight != 0) - display->drawString(x, y += _fontHeight(FONT_SMALL), + display->drawString(x, y += fontHeight(FONT_SMALL), "Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg"); } @@ -284,142 +280,102 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac return false; // Let others look at this message also if they want } -bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m) +bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) { + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; bool valid = true; bool hasSensor = false; - m->time = getTime(); - m->which_variant = meshtastic_Telemetry_environment_metrics_tag; + m.time = getTime(); + m.which_variant = meshtastic_Telemetry_environment_metrics_tag; #ifdef T1000X_SENSOR_EN // add by WayenWeng valid = valid && t1000xSensor.getMetrics(&m); hasSensor = true; #else if (dfRobotLarkSensor.hasSensor()) { - valid = valid && dfRobotLarkSensor.getMetrics(m); + valid = valid && dfRobotLarkSensor.getMetrics(&m); hasSensor = true; } if (sht31Sensor.hasSensor()) { - valid = valid && sht31Sensor.getMetrics(m); - hasSensor = true; - } - if (sht4xSensor.hasSensor()) { - valid = valid && sht4xSensor.getMetrics(m); + valid = valid && sht31Sensor.getMetrics(&m); hasSensor = true; } if (lps22hbSensor.hasSensor()) { - valid = valid && lps22hbSensor.getMetrics(m); + valid = valid && lps22hbSensor.getMetrics(&m); hasSensor = true; } if (shtc3Sensor.hasSensor()) { - valid = valid && shtc3Sensor.getMetrics(m); + valid = valid && shtc3Sensor.getMetrics(&m); hasSensor = true; } if (bmp085Sensor.hasSensor()) { - valid = valid && bmp085Sensor.getMetrics(m); + valid = valid && bmp085Sensor.getMetrics(&m); hasSensor = true; } if (bmp280Sensor.hasSensor()) { - valid = valid && bmp280Sensor.getMetrics(m); + valid = valid && bmp280Sensor.getMetrics(&m); hasSensor = true; } if (bme280Sensor.hasSensor()) { - valid = valid && bme280Sensor.getMetrics(m); + valid = valid && bme280Sensor.getMetrics(&m); hasSensor = true; } if (bme680Sensor.hasSensor()) { - valid = valid && bme680Sensor.getMetrics(m); + valid = valid && bme680Sensor.getMetrics(&m); hasSensor = true; } if (mcp9808Sensor.hasSensor()) { - valid = valid && mcp9808Sensor.getMetrics(m); + valid = valid && mcp9808Sensor.getMetrics(&m); hasSensor = true; } if (ina219Sensor.hasSensor()) { - valid = valid && ina219Sensor.getMetrics(m); + valid = valid && ina219Sensor.getMetrics(&m); hasSensor = true; } if (ina260Sensor.hasSensor()) { - valid = valid && ina260Sensor.getMetrics(m); - hasSensor = true; - } - if (ina3221Sensor.hasSensor()) { - valid = valid && ina3221Sensor.getMetrics(m); + valid = valid && ina260Sensor.getMetrics(&m); hasSensor = true; } if (veml7700Sensor.hasSensor()) { - valid = valid && veml7700Sensor.getMetrics(m); + valid = valid && veml7700Sensor.getMetrics(&m); hasSensor = true; } if (tsl2591Sensor.hasSensor()) { - valid = valid && tsl2591Sensor.getMetrics(m); + valid = valid && tsl2591Sensor.getMetrics(&m); hasSensor = true; } if (opt3001Sensor.hasSensor()) { - valid = valid && opt3001Sensor.getMetrics(m); + valid = valid && opt3001Sensor.getMetrics(&m); hasSensor = true; } if (mlx90632Sensor.hasSensor()) { - valid = valid && mlx90632Sensor.getMetrics(m); + valid = valid && mlx90632Sensor.getMetrics(&m); hasSensor = true; } if (rcwl9620Sensor.hasSensor()) { - valid = valid && rcwl9620Sensor.getMetrics(m); + valid = valid && rcwl9620Sensor.getMetrics(&m); hasSensor = true; } if (nau7802Sensor.hasSensor()) { - valid = valid && nau7802Sensor.getMetrics(m); + valid = valid && nau7802Sensor.getMetrics(&m); hasSensor = true; } if (aht10Sensor.hasSensor()) { if (!bmp280Sensor.hasSensor()) { - valid = valid && aht10Sensor.getMetrics(m); + valid = valid && aht10Sensor.getMetrics(&m); hasSensor = true; } else { // prefer bmp280 temp if both sensors are present, fetch only humidity meshtastic_Telemetry m_ahtx = meshtastic_Telemetry_init_zero; LOG_INFO("AHTX0+BMP280 module detected: using temp from BMP280 and humy from AHTX0\n"); aht10Sensor.getMetrics(&m_ahtx); - m->variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity; + m.variant.environment_metrics.relative_humidity = m_ahtx.variant.environment_metrics.relative_humidity; } } #endif + valid = valid && hasSensor; - return valid && hasSensor; -} - -meshtastic_MeshPacket *EnvironmentTelemetryModule::allocReply() -{ - if (currentRequest) { - auto req = *currentRequest; - const auto &p = req.decoded; - meshtastic_Telemetry scratch; - meshtastic_Telemetry *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { - decoded = &scratch; - } else { - LOG_ERROR("Error decoding EnvironmentTelemetry module!\n"); - return NULL; - } - // Check for a request for environment metrics - if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) { - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; - if (getEnvironmentTelemetry(&m)) { - LOG_INFO("Environment telemetry replying to request\n"); - return allocDataProtobuf(m); - } else { - return NULL; - } - } - } - return NULL; -} - -bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) -{ - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; - if (getEnvironmentTelemetry(&m)) { + if (valid) { LOG_INFO("(Sending): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f\n", m.variant.environment_metrics.barometric_pressure, m.variant.environment_metrics.current, m.variant.environment_metrics.gas_resistance, m.variant.environment_metrics.relative_humidity, @@ -457,9 +413,8 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) setIntervalFromNow(5000); } } - return true; } - return false; + return valid; } AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule(const meshtastic_MeshPacket &mp, @@ -522,11 +477,6 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule if (result != AdminMessageHandleResult::NOT_HANDLED) return result; } - if (ina3221Sensor.hasSensor()) { - result = ina3221Sensor.handleAdminMessage(mp, request, response); - if (result != AdminMessageHandleResult::NOT_HANDLED) - return result; - } if (veml7700Sensor.hasSensor()) { result = veml7700Sensor.handleAdminMessage(mp, request, response); if (result != AdminMessageHandleResult::NOT_HANDLED) @@ -565,4 +515,4 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule return result; } -#endif +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/EnvironmentTelemetry.h b/src/modules/Telemetry/EnvironmentTelemetry.h index ced617c2fc..ca150347e7 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.h +++ b/src/modules/Telemetry/EnvironmentTelemetry.h @@ -32,11 +32,6 @@ class EnvironmentTelemetryModule : private concurrency::OSThread, public Protobu */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override; virtual int32_t runOnce() override; - /** Called to get current Environment telemetry data - @return true if it contains valid data - */ - bool getEnvironmentTelemetry(meshtastic_Telemetry *m); - virtual meshtastic_MeshPacket *allocReply() override; /** * Send our Telemetry into the mesh */ diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index 6915d67e3d..826de8a4ab 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -24,8 +24,7 @@ int32_t PowerTelemetryModule::runOnce() { if (sleepOnNextExecution == true) { sleepOnNextExecution = false; - uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval, - default_telemetry_broadcast_interval_secs); + uint32_t nightyNightMs = Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval); LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs); doDeepSleep(nightyNightMs, true); } @@ -71,8 +70,7 @@ int32_t PowerTelemetryModule::runOnce() uint32_t now = millis(); if (((lastSentToMesh == 0) || - ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval, - default_telemetry_broadcast_interval_secs))) && + ((now - lastSentToMesh) >= Default::getConfiguredOrDefaultMs(moduleConfig.telemetry.power_update_interval))) && airTime->isTxAllowedAirUtil()) { sendTelemetry(); lastSentToMesh = now; @@ -110,7 +108,7 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s display->drawString(x, y, "Power Telemetry"); if (lastMeasurementPacket == nullptr) { display->setFont(FONT_SMALL); - display->drawString(x, y += _fontHeight(FONT_MEDIUM), "No measurement"); + display->drawString(x, y += fontHeight(FONT_MEDIUM), "No measurement"); return; } @@ -122,22 +120,22 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s auto &p = lastMeasurementPacket->decoded; if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &lastMeasurement)) { display->setFont(FONT_SMALL); - display->drawString(x, y += _fontHeight(FONT_MEDIUM), "Measurement Error"); + display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error"); LOG_ERROR("Unable to decode last packet"); return; } display->setFont(FONT_SMALL); String last_temp = String(lastMeasurement.variant.environment_metrics.temperature, 0) + "°C"; - display->drawString(x, y += _fontHeight(FONT_MEDIUM) - 2, "From: " + String(lastSender) + "(" + String(agoSecs) + "s)"); + display->drawString(x, y += fontHeight(FONT_MEDIUM) - 2, "From: " + String(lastSender) + "(" + String(agoSecs) + "s)"); if (lastMeasurement.variant.power_metrics.ch1_voltage != 0) { - display->drawString(x, y += _fontHeight(FONT_SMALL), + display->drawString(x, y += fontHeight(FONT_SMALL), "Ch 1 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch1_voltage, 0) + "V / " + String(lastMeasurement.variant.power_metrics.ch1_current, 0) + "mA"); - display->drawString(x, y += _fontHeight(FONT_SMALL), + display->drawString(x, y += fontHeight(FONT_SMALL), "Ch 2 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch2_voltage, 0) + "V / " + String(lastMeasurement.variant.power_metrics.ch2_current, 0) + "mA"); - display->drawString(x, y += _fontHeight(FONT_SMALL), + display->drawString(x, y += fontHeight(FONT_SMALL), "Ch 3 Volt/Cur: " + String(lastMeasurement.variant.power_metrics.ch3_voltage, 0) + "V / " + String(lastMeasurement.variant.power_metrics.ch3_current, 0) + "mA"); } @@ -165,63 +163,29 @@ bool PowerTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &m return false; // Let others look at this message also if they want } -bool PowerTelemetryModule::getPowerTelemetry(meshtastic_Telemetry *m) +bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) { + meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; bool valid = false; - m->time = getTime(); - m->which_variant = meshtastic_Telemetry_power_metrics_tag; - - m->variant.power_metrics.ch1_voltage = 0; - m->variant.power_metrics.ch1_current = 0; - m->variant.power_metrics.ch2_voltage = 0; - m->variant.power_metrics.ch2_current = 0; - m->variant.power_metrics.ch3_voltage = 0; - m->variant.power_metrics.ch3_current = 0; + m.time = getTime(); + m.which_variant = meshtastic_Telemetry_power_metrics_tag; + + m.variant.power_metrics.ch1_voltage = 0; + m.variant.power_metrics.ch1_current = 0; + m.variant.power_metrics.ch2_voltage = 0; + m.variant.power_metrics.ch2_current = 0; + m.variant.power_metrics.ch3_voltage = 0; + m.variant.power_metrics.ch3_current = 0; #if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) if (ina219Sensor.hasSensor()) - valid = ina219Sensor.getMetrics(m); + valid = ina219Sensor.getMetrics(&m); if (ina260Sensor.hasSensor()) - valid = ina260Sensor.getMetrics(m); + valid = ina260Sensor.getMetrics(&m); if (ina3221Sensor.hasSensor()) - valid = ina3221Sensor.getMetrics(m); + valid = ina3221Sensor.getMetrics(&m); #endif - return valid; -} - -meshtastic_MeshPacket *PowerTelemetryModule::allocReply() -{ - if (currentRequest) { - auto req = *currentRequest; - const auto &p = req.decoded; - meshtastic_Telemetry scratch; - meshtastic_Telemetry *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &meshtastic_Telemetry_msg, &scratch)) { - decoded = &scratch; - } else { - LOG_ERROR("Error decoding PowerTelemetry module!\n"); - return NULL; - } - // Check for a request for power metrics - if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) { - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; - if (getPowerTelemetry(&m)) { - LOG_INFO("Power telemetry replying to request\n"); - return allocDataProtobuf(m); - } else { - return NULL; - } - } - } - - return NULL; -} - -bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) -{ - meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; - if (getPowerTelemetry(&m)) { + if (valid) { LOG_INFO("(Sending): ch1_voltage=%f, ch1_current=%f, ch2_voltage=%f, ch2_current=%f, " "ch3_voltage=%f, ch3_current=%f\n", m.variant.power_metrics.ch1_voltage, m.variant.power_metrics.ch1_current, m.variant.power_metrics.ch2_voltage, @@ -254,9 +218,8 @@ bool PowerTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) setIntervalFromNow(5000); } } - return true; } - return false; + return valid; } #endif \ No newline at end of file diff --git a/src/modules/Telemetry/PowerTelemetry.h b/src/modules/Telemetry/PowerTelemetry.h index 1b68847dba..3d6b686f22 100644 --- a/src/modules/Telemetry/PowerTelemetry.h +++ b/src/modules/Telemetry/PowerTelemetry.h @@ -33,11 +33,6 @@ class PowerTelemetryModule : private concurrency::OSThread, public ProtobufModul */ virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *p) override; virtual int32_t runOnce() override; - /** Called to get current Power telemetry data - @return true if it contains valid data - */ - bool getPowerTelemetry(meshtastic_Telemetry *m); - virtual meshtastic_MeshPacket *allocReply() override; /** * Send our Telemetry into the mesh */ diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp index dec99c551c..ea2cb4ea8c 100644 --- a/src/modules/Telemetry/Sensor/INA3221Sensor.cpp +++ b/src/modules/Telemetry/Sensor/INA3221Sensor.cpp @@ -16,7 +16,8 @@ int32_t INA3221Sensor::runOnce() return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; } if (!status) { - ina3221.begin(nodeTelemetrySensorsMap[sensorType].second); + ina3221.setAddr(INA3221_ADDR42_SDA); // i2c address 0x42 + ina3221.begin(); ina3221.setShuntRes(100, 100, 100); // 0.1 Ohm shunt resistors status = true; } else { @@ -27,69 +28,22 @@ int32_t INA3221Sensor::runOnce() void INA3221Sensor::setup() {} -struct _INA3221Measurement INA3221Sensor::getMeasurement(ina3221_ch_t ch) -{ - struct _INA3221Measurement measurement; - - measurement.voltage = ina3221.getVoltage(ch); - measurement.current = ina3221.getCurrent(ch); - - return measurement; -} - -struct _INA3221Measurements INA3221Sensor::getMeasurements() -{ - struct _INA3221Measurements measurements; - - // INA3221 has 3 channels starting from 0 - for (int i = 0; i < 3; i++) { - measurements.measurements[i] = getMeasurement((ina3221_ch_t)i); - } - - return measurements; -} - bool INA3221Sensor::getMetrics(meshtastic_Telemetry *measurement) { - switch (measurement->which_variant) { - case meshtastic_Telemetry_environment_metrics_tag: - return getEnvironmentMetrics(measurement); - - case meshtastic_Telemetry_power_metrics_tag: - return getPowerMetrics(measurement); - } - - // unsupported metric - return false; -} - -bool INA3221Sensor::getEnvironmentMetrics(meshtastic_Telemetry *measurement) -{ - struct _INA3221Measurement m = getMeasurement(ENV_CH); - - measurement->variant.environment_metrics.voltage = m.voltage; - measurement->variant.environment_metrics.current = m.current; - - return true; -} - -bool INA3221Sensor::getPowerMetrics(meshtastic_Telemetry *measurement) -{ - struct _INA3221Measurements m = getMeasurements(); - - measurement->variant.power_metrics.ch1_voltage = m.measurements[INA3221_CH1].voltage; - measurement->variant.power_metrics.ch1_current = m.measurements[INA3221_CH1].current; - measurement->variant.power_metrics.ch2_voltage = m.measurements[INA3221_CH2].voltage; - measurement->variant.power_metrics.ch2_current = m.measurements[INA3221_CH2].current; - measurement->variant.power_metrics.ch3_voltage = m.measurements[INA3221_CH3].voltage; - measurement->variant.power_metrics.ch3_current = m.measurements[INA3221_CH3].current; - + measurement->variant.environment_metrics.voltage = ina3221.getVoltage(INA3221_CH1); + measurement->variant.environment_metrics.current = ina3221.getCurrent(INA3221_CH1); + measurement->variant.power_metrics.ch1_voltage = ina3221.getVoltage(INA3221_CH1); + measurement->variant.power_metrics.ch1_current = ina3221.getCurrent(INA3221_CH1); + measurement->variant.power_metrics.ch2_voltage = ina3221.getVoltage(INA3221_CH2); + measurement->variant.power_metrics.ch2_current = ina3221.getCurrent(INA3221_CH2); + measurement->variant.power_metrics.ch3_voltage = ina3221.getVoltage(INA3221_CH3); + measurement->variant.power_metrics.ch3_current = ina3221.getCurrent(INA3221_CH3); return true; } uint16_t INA3221Sensor::getBusVoltageMv() { - return lround(ina3221.getVoltage(BAT_CH) * 1000); + return lround(ina3221.getVoltage(INA3221_CH1) * 1000); } #endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/INA3221Sensor.h b/src/modules/Telemetry/Sensor/INA3221Sensor.h index d5121aab60..3b8e382eea 100644 --- a/src/modules/Telemetry/Sensor/INA3221Sensor.h +++ b/src/modules/Telemetry/Sensor/INA3221Sensor.h @@ -12,21 +12,6 @@ class INA3221Sensor : public TelemetrySensor, VoltageSensor private: INA3221 ina3221 = INA3221(INA3221_ADDR42_SDA); - // channel to report voltage/current for environment metrics - ina3221_ch_t ENV_CH = INA3221_CH1; - - // channel to report battery voltage for device_battery_ina_address - ina3221_ch_t BAT_CH = INA3221_CH1; - - // get a single measurement for a channel - struct _INA3221Measurement getMeasurement(ina3221_ch_t ch); - - // get all measurements for all channels - struct _INA3221Measurements getMeasurements(); - - bool getEnvironmentMetrics(meshtastic_Telemetry *measurement); - bool getPowerMetrics(meshtastic_Telemetry *measurement); - protected: void setup() override; @@ -37,14 +22,4 @@ class INA3221Sensor : public TelemetrySensor, VoltageSensor virtual uint16_t getBusVoltageMv() override; }; -struct _INA3221Measurement { - float voltage; - float current; -}; - -struct _INA3221Measurements { - // INA3221 has 3 channels - struct _INA3221Measurement measurements[3]; -}; - #endif \ No newline at end of file diff --git a/src/modules/WaypointModule.cpp b/src/modules/WaypointModule.cpp index e1974db730..83485c8eee 100644 --- a/src/modules/WaypointModule.cpp +++ b/src/modules/WaypointModule.cpp @@ -2,11 +2,6 @@ #include "NodeDB.h" #include "PowerFSM.h" #include "configuration.h" -#if HAS_SCREEN -#include "gps/RTC.h" -#include "graphics/Screen.h" -#include "main.h" -#endif WaypointModule *waypointModule; @@ -16,171 +11,14 @@ ProcessMessage WaypointModule::handleReceived(const meshtastic_MeshPacket &mp) auto &p = mp.decoded; LOG_INFO("Received waypoint msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes); #endif + // We only store/display messages destined for us. // Keep a copy of the most recent text message. devicestate.rx_waypoint = mp; devicestate.has_rx_waypoint = true; powerFSM.trigger(EVENT_RECEIVED_MSG); - -#if HAS_SCREEN - - UIFrameEvent e; - - // New or updated waypoint: focus on this frame next time Screen::setFrames runs - if (shouldDraw()) { - requestFocus(); - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; - } - - // Deleting an old waypoint: remove the frame quietly, don't change frame position if possible - else - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET_BACKGROUND; - - notifyObservers(&e); - -#endif + notifyObservers(&mp); return ProcessMessage::CONTINUE; // Let others look at this message also if they want } - -#if HAS_SCREEN -bool WaypointModule::shouldDraw() -{ -#if !MESHTASTIC_EXCLUDE_WAYPOINT - // If no waypoint to show - if (!devicestate.has_rx_waypoint) - return false; - - // Decode the message, to find the expiration time (is waypoint still valid) - // This handles "deletion" as well as expiration - meshtastic_Waypoint wp; - memset(&wp, 0, sizeof(wp)); - if (pb_decode_from_bytes(devicestate.rx_waypoint.decoded.payload.bytes, devicestate.rx_waypoint.decoded.payload.size, - &meshtastic_Waypoint_msg, &wp)) { - // Valid waypoint - if (wp.expire > getTime()) - return devicestate.has_rx_waypoint = true; - - // Expired, or deleted - else - return devicestate.has_rx_waypoint = false; - } - - // If decoding failed - LOG_ERROR("Failed to decode waypoint\n"); - devicestate.has_rx_waypoint = false; - return false; -#else - return false; -#endif -} - -/// Draw the last waypoint we received -void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -{ - // Prepare to draw - display->setFont(FONT_SMALL); - display->setTextAlignment(TEXT_ALIGN_LEFT); - - // Handle inverted display - // Unsure of expected behavior: for now, copy drawNodeInfo - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) - display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL); - - // Decode the waypoint - meshtastic_MeshPacket &mp = devicestate.rx_waypoint; - meshtastic_Waypoint wp; - memset(&wp, 0, sizeof(wp)); - if (!pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_Waypoint_msg, &wp)) { - // This *should* be caught by shouldDrawWaypoint, but we'll short-circuit here just in case - display->drawStringMaxWidth(0 + x, 0 + y, x + display->getWidth(), "Couldn't decode waypoint"); - devicestate.has_rx_waypoint = false; - return; - } - - // Get timestamp info. Will pass as a field to drawColumns - static char lastStr[20]; - screen->getTimeAgoStr(sinceReceived(&mp), lastStr, sizeof(lastStr)); - - // Will contain distance information, passed as a field to drawColumns - static char distStr[20]; - - // Get our node, to use our own position - meshtastic_NodeInfoLite *ourNode = nodeDB->getMeshNode(nodeDB->getNodeNum()); - - // Text fields to draw (left of compass) - // Last element must be NULL. This signals the end of the char*[] to drawColumns - const char *fields[] = {"Waypoint", lastStr, wp.name, distStr, NULL}; - - // Dimensions / co-ordinates for the compass/circle - int16_t compassX = 0, compassY = 0; - uint16_t compassDiam = graphics::Screen::getCompassDiam(display->getWidth(), display->getHeight()); - - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) { - compassX = x + display->getWidth() - compassDiam / 2 - 5; - compassY = y + display->getHeight() / 2; - } else { - compassX = x + display->getWidth() - compassDiam / 2 - 5; - compassY = y + FONT_HEIGHT_SMALL + (display->getHeight() - FONT_HEIGHT_SMALL) / 2; - } - - // If our node has a position: - if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) { - const meshtastic_PositionLite &op = ourNode->position; - float myHeading; - if (screen->hasHeading()) - myHeading = (screen->getHeading()) * PI / 180; // gotta convert compass degrees to Radians - else - myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); - screen->drawCompassNorth(display, compassX, compassY, myHeading); - - // Distance to Waypoint - float d = GeoCoord::latLongToMeter(DegD(wp.latitude_i), DegD(wp.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i)); - if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) { - if (d < (2 * MILES_TO_FEET)) - snprintf(distStr, sizeof(distStr), "%.0f ft", d * METERS_TO_FEET); - else - snprintf(distStr, sizeof(distStr), "%.1f mi", d * METERS_TO_FEET / MILES_TO_FEET); - } else { - if (d < 2000) - snprintf(distStr, sizeof(distStr), "%.0f m", d); - else - snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000); - } - - // Compass bearing to waypoint - float bearingToOther = - GeoCoord::bearing(DegD(op.latitude_i), DegD(op.longitude_i), DegD(wp.latitude_i), DegD(wp.longitude_i)); - // If the top of the compass is a static north then bearingToOther can be drawn on the compass directly - // If the top of the compass is not a static north we need adjust bearingToOther based on heading - if (!config.display.compass_north_top) - bearingToOther -= myHeading; - screen->drawNodeHeading(display, compassX, compassY, compassDiam, bearingToOther); - } - - // If our node doesn't have position - else { - // ? in the compass - display->drawString(compassX - FONT_HEIGHT_SMALL / 4, compassY - FONT_HEIGHT_SMALL / 2, "?"); - - // ? in the distance field - if (config.display.units == meshtastic_Config_DisplayConfig_DisplayUnits_IMPERIAL) - strncpy(distStr, "? mi", sizeof(distStr)); - else - strncpy(distStr, "? km", sizeof(distStr)); - } - - // Undo color-inversion, if set prior to drawing header - // Unsure of expected behavior? For now: copy drawNodeInfo - if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) { - display->setColor(BLACK); - } - - // Draw compass circle - display->drawCircle(compassX, compassY, compassDiam / 2); - - // Must be after distStr is populated - screen->drawColumns(display, x, y, fields); -} -#endif \ No newline at end of file diff --git a/src/modules/WaypointModule.h b/src/modules/WaypointModule.h index 4c9c7b86b0..ddbabf4deb 100644 --- a/src/modules/WaypointModule.h +++ b/src/modules/WaypointModule.h @@ -5,29 +5,21 @@ /** * Waypoint message handling for meshtastic */ -class WaypointModule : public SinglePortModule, public Observable +class WaypointModule : public SinglePortModule, public Observable { public: /** Constructor * name is for debugging output */ WaypointModule() : SinglePortModule("waypoint", meshtastic_PortNum_WAYPOINT_APP) {} -#if HAS_SCREEN - bool shouldDraw(); -#endif + protected: /** Called to handle a particular incoming message @return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it */ - - virtual Observable *getUIFrameObservable() override { return this; } -#if HAS_SCREEN - virtual bool wantUIFrame() override { return this->shouldDraw(); } - virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) override; -#endif virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override; }; -extern WaypointModule *waypointModule; \ No newline at end of file +extern WaypointModule *waypointModule; diff --git a/src/modules/esp32/AudioModule.cpp b/src/modules/esp32/AudioModule.cpp index 2e2e4f5287..4a7b1c2c60 100644 --- a/src/modules/esp32/AudioModule.cpp +++ b/src/modules/esp32/AudioModule.cpp @@ -190,13 +190,13 @@ int32_t AudioModule::runOnce() firstTime = false; } else { - UIFrameEvent e; + UIFrameEvent e = {false, true}; // Check if PTT is pressed. TODO hook that into Onebutton/Interrupt drive. if (digitalRead(moduleConfig.audio.ptt_pin ? moduleConfig.audio.ptt_pin : PTT_PIN) == HIGH) { if (radio_state == RadioState::rx) { LOG_INFO("PTT pressed, switching to TX\n"); radio_state = RadioState::tx; - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + e.frameChanged = true; this->notifyObservers(&e); } } else { @@ -209,7 +209,7 @@ int32_t AudioModule::runOnce() } tx_encode_frame_index = sizeof(tx_header); radio_state = RadioState::rx; - e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen + e.frameChanged = true; this->notifyObservers(&e); } } diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index 34d6fb1d09..e6712871d0 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -66,6 +66,10 @@ bool PaxcounterModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, m meshtastic_MeshPacket *PaxcounterModule::allocReply() { + if (ignoreRequest) { + return NULL; + } + meshtastic_Paxcount pl = meshtastic_Paxcount_init_default; pl.wifi = count_from_libpax.wifi_count; pl.ble = count_from_libpax.ble_count; @@ -101,7 +105,7 @@ int32_t PaxcounterModule::runOnce() sendInfo(NODENUM_BROADCAST); } return Default::getConfiguredOrDefaultMs(moduleConfig.paxcounter.paxcounter_update_interval, - default_telemetry_broadcast_interval_secs); + default_broadcast_interval_secs); } else { return disable(); } @@ -127,4 +131,4 @@ void PaxcounterModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state } #endif // HAS_SCREEN -#endif \ No newline at end of file +#endif diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp index dc8650ad0b..12cddc5202 100644 --- a/src/modules/esp32/StoreForwardModule.cpp +++ b/src/modules/esp32/StoreForwardModule.cpp @@ -319,8 +319,8 @@ ProcessMessage StoreForwardModule::handleReceived(const meshtastic_MeshPacket &m #ifdef ARCH_ESP32 if (moduleConfig.store_forward.enabled) { - // The router node should not be sending messages as a client - if ((getFrom(&mp) != nodeDB->getNodeNum())) { + // The router node should not be sending messages as a client. Unless he is a ROUTER_CLIENT + if ((getFrom(&mp) != nodeDB->getNodeNum()) || (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_CLIENT)) { if ((mp.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) && is_server) { auto &p = mp.decoded; diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index a64720c78c..9f9ac5c243 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -14,7 +14,7 @@ #endif #include "mesh/generated/meshtastic/remote_hardware.pb.h" #include "sleep.h" -#if HAS_WIFI +#if HAS_WIFI && !MESHTASTIC_EXCLUDE_WIFI #include "mesh/wifi/WiFiAPClient.h" #include #endif @@ -175,7 +175,7 @@ void mqttInit() new MQTT(); } -#if HAS_NETWORKING +#ifdef HAS_NETWORKING MQTT::MQTT() : concurrency::OSThread("mqtt"), pubSub(mqttClient), mqttQueue(MAX_MQTT_QUEUE) #else MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) @@ -206,7 +206,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) moduleConfig.mqtt.map_report_settings.publish_interval_secs, default_map_publish_interval_secs); } -#if HAS_NETWORKING +#ifdef HAS_NETWORKING if (!moduleConfig.mqtt.proxy_to_client_enabled) pubSub.setCallback(mqttCallback); #endif @@ -226,7 +226,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE) bool MQTT::isConnectedDirectly() { -#if HAS_NETWORKING +#ifdef HAS_NETWORKING return pubSub.connected(); #else return false; @@ -244,7 +244,7 @@ bool MQTT::publish(const char *topic, const char *payload, bool retained) service.sendMqttMessageToClientProxy(msg); return true; } -#if HAS_NETWORKING +#ifdef HAS_NETWORKING else if (isConnectedDirectly()) { return pubSub.publish(topic, payload, retained); } @@ -264,7 +264,7 @@ bool MQTT::publish(const char *topic, const uint8_t *payload, size_t length, boo service.sendMqttMessageToClientProxy(msg); return true; } -#if HAS_NETWORKING +#ifdef HAS_NETWORKING else if (isConnectedDirectly()) { return pubSub.publish(topic, payload, length, retained); } @@ -284,7 +284,7 @@ void MQTT::reconnect() publishStatus(); return; // Don't try to connect directly to the server } -#if HAS_NETWORKING +#ifdef HAS_NETWORKING // Defaults int serverPort = 1883; const char *serverAddr = default_mqtt_address; @@ -357,7 +357,7 @@ void MQTT::reconnect() void MQTT::sendSubscriptions() { -#if HAS_NETWORKING +#ifdef HAS_NETWORKING size_t numChan = channels.getNumChannels(); for (size_t i = 0; i < numChan; i++) { const auto &ch = channels.getByIndex(i); @@ -396,7 +396,7 @@ bool MQTT::wantsLink() const int32_t MQTT::runOnce() { -#if HAS_NETWORKING +#ifdef HAS_NETWORKING if (!moduleConfig.mqtt.enabled || !(moduleConfig.mqtt.map_reporting_enabled || channels.anyMqttEnabled())) return disable(); @@ -482,12 +482,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket & auto &ch = channels.getByIndex(chIndex); - if (mp_decoded.which_payload_variant != meshtastic_MeshPacket_decoded_tag) { - LOG_CRIT("MQTT::onSend(): mp_decoded isn't actually decoded\n"); - return; - } - - if (strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0 && + if (&mp_decoded.decoded && strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0 && (mp_decoded.decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP || mp_decoded.decoded.portnum == meshtastic_PortNum_DETECTION_SENSOR_APP)) { LOG_DEBUG("MQTT onSend - Ignoring range test or detection sensor message on public mqtt\n"); diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index 1ebba4afe9..f2eb6b1204 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -8,15 +8,17 @@ #include "mqtt/JSON.h" #if HAS_WIFI #include +#define HAS_NETWORKING 1 #if !defined(ARCH_PORTDUINO) #include #endif #endif #if HAS_ETHERNET #include +#define HAS_NETWORKING 1 #endif -#if HAS_NETWORKING +#ifdef HAS_NETWORKING #include #endif @@ -41,7 +43,7 @@ class MQTT : private concurrency::OSThread #endif public: -#if HAS_NETWORKING +#ifdef HAS_NETWORKING PubSubClient pubSub; #endif MQTT(); diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index d959553a4b..68aa9b4653 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -12,7 +12,6 @@ NimBLECharacteristic *fromNumCharacteristic; NimBLECharacteristic *BatteryCharacteristic; -NimBLECharacteristic *logRadioCharacteristic; NimBLEServer *bleServer; static bool passkeyShowing; @@ -59,6 +58,7 @@ class NimbleBluetoothFromRadioCallback : public NimBLECharacteristicCallbacks { virtual void onRead(NimBLECharacteristic *pCharacteristic) { + LOG_INFO("From Radio onread\n"); uint8_t fromRadioBytes[meshtastic_FromRadio_size]; size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); @@ -82,33 +82,7 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks LOG_INFO("*** Enter passkey %d on the peer side ***\n", passkey); powerFSM.trigger(EVENT_BLUETOOTH_PAIR); -#if HAS_SCREEN - screen->startAlert([passkey](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { - char btPIN[16] = "888888"; - snprintf(btPIN, sizeof(btPIN), "%06u", passkey); - int x_offset = display->width() / 2; - int y_offset = display->height() <= 80 ? 0 : 32; - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->setFont(FONT_MEDIUM); - display->drawString(x_offset + x, y_offset + y, "Bluetooth"); - - display->setFont(FONT_SMALL); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5; - display->drawString(x_offset + x, y_offset + y, "Enter this code"); - - display->setFont(FONT_LARGE); - String displayPin(btPIN); - String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5; - display->drawString(x_offset + x, y_offset + y, pin); - - display->setFont(FONT_SMALL); - String deviceName = "Name: "; - deviceName.concat(getDeviceName()); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; - display->drawString(x_offset + x, y_offset + y, deviceName); - }); -#endif + screen->startBluetoothPinScreen(passkey); passkeyShowing = true; return passkey; @@ -120,7 +94,7 @@ class NimbleBluetoothServerCallback : public NimBLEServerCallbacks if (passkeyShowing) { passkeyShowing = false; - screen->endAlert(); + screen->stopBluetoothPinScreen(); } } @@ -206,8 +180,6 @@ void NimbleBluetooth::setupService() ToRadioCharacteristic = bleService->createCharacteristic(TORADIO_UUID, NIMBLE_PROPERTY::WRITE); FromRadioCharacteristic = bleService->createCharacteristic(FROMRADIO_UUID, NIMBLE_PROPERTY::READ); fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ); - logRadioCharacteristic = - bleService->createCharacteristic(LOGRADIO_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ, 512U); } else { ToRadioCharacteristic = bleService->createCharacteristic( TORADIO_UUID, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_AUTHEN | NIMBLE_PROPERTY::WRITE_ENC); @@ -216,9 +188,6 @@ void NimbleBluetooth::setupService() fromNumCharacteristic = bleService->createCharacteristic(FROMNUM_UUID, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC); - logRadioCharacteristic = bleService->createCharacteristic( - LOGRADIO_UUID, - NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_AUTHEN | NIMBLE_PROPERTY::READ_ENC, 512U); } bluetoothPhoneAPI = new BluetoothPhoneAPI(); @@ -267,14 +236,6 @@ void NimbleBluetooth::clearBonds() NimBLEDevice::deleteAllBonds(); } -void NimbleBluetooth::sendLog(const uint8_t *logMessage, size_t length) -{ - if (!bleServer || !isConnected() || length > 512) { - return; - } - logRadioCharacteristic->notify(logMessage, length, true); -} - void clearNVS() { NimBLEDevice::deleteAllBonds(); diff --git a/src/nimble/NimbleBluetooth.h b/src/nimble/NimbleBluetooth.h index 45602e0887..d1e347830a 100644 --- a/src/nimble/NimbleBluetooth.h +++ b/src/nimble/NimbleBluetooth.h @@ -11,7 +11,6 @@ class NimbleBluetooth : BluetoothApi bool isActive(); bool isConnected(); int getRssi(); - void sendLog(const uint8_t *logMessage, size_t length); private: void setupService(); diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h index fd3f92a9c3..5565b64686 100644 --- a/src/platform/esp32/architecture.h +++ b/src/platform/esp32/architecture.h @@ -151,14 +151,6 @@ #define HW_VENDOR meshtastic_HardwareModel_RADIOMASTER_900_BANDIT_NANO #elif defined(HELTEC_CAPSULE_SENSOR_V3) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_CAPSULE_SENSOR_V3 -#elif defined(HELTEC_VISION_MASTER_T190) -#define HW_VENDOR meshtastic_HardwareModel_HELTEC_VISION_MASTER_T190 -#elif defined(HELTEC_VISION_MASTER_E213) -#define HW_VENDOR meshtastic_HardwareModel_HELTEC_VISION_MASTER_E213 -#elif defined(HELTEC_VISION_MASTER_E290) -#define HW_VENDOR meshtastic_HardwareModel_HELTEC_VISION_MASTER_E290 -#elif defined(HELTEC_MESH_NODE_T114) -#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 #endif // ----------------------------------------------------------------------------- diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index aa51e810a8..1dd7a389af 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -8,7 +8,7 @@ #include "nimble/NimbleBluetooth.h" #endif -#if HAS_WIFI +#if !MESHTASTIC_EXCLUDE_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif @@ -24,22 +24,23 @@ #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !MESHTASTIC_EXCLUDE_BLUETOOTH void setBluetoothEnable(bool enable) { -#if HAS_WIFI +#ifndef MESHTASTIC_EXCLUDE_WIFI if (!isWifiAvailable() && config.bluetooth.enabled == true) -#else - if (config.bluetooth.enabled == true) #endif - { - if (!nimbleBluetooth) { - nimbleBluetooth = new NimbleBluetooth(); - } - if (enable && !nimbleBluetooth->isActive()) { - nimbleBluetooth->setup(); +#ifdef MESHTASTIC_EXCLUDE_WIFI + if (config.bluetooth.enabled == true) +#endif + { + if (!nimbleBluetooth) { + nimbleBluetooth = new NimbleBluetooth(); + } + if (enable && !nimbleBluetooth->isActive()) { + nimbleBluetooth->setup(); + } + // For ESP32, no way to recover from bluetooth shutdown without reboot + // BLE advertising automatically stops when MCU enters light-sleep(?) + // For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse } - // For ESP32, no way to recover from bluetooth shutdown without reboot - // BLE advertising automatically stops when MCU enters light-sleep(?) - // For deep-sleep, shutdown hardware with nimbleBluetooth->deinit(). Requires reboot to reverse - } } #else void setBluetoothEnable(bool enable) {} diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 6138e2aefc..8b817f51b4 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -8,18 +8,17 @@ #include "mesh/mesh-pb-constants.h" #include #include + static BLEService meshBleService = BLEService(BLEUuid(MESH_SERVICE_UUID_16)); static BLECharacteristic fromNum = BLECharacteristic(BLEUuid(FROMNUM_UUID_16)); static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16)); static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16)); -static BLECharacteristic logRadio = BLECharacteristic(BLEUuid(LOGRADIO_UUID_16)); static BLEDis bledis; // DIS (Device Information Service) helper class instance static BLEBas blebas; // BAS (Battery Service) helper class instance static BLEDfu bledfu; // DFU software update helper service static BLEDfuSecure bledfusecure; // DFU software update helper service -static BLEDfu bledfu; // DFU software update helper service // This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in // process at once // static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)]; @@ -53,14 +52,16 @@ static BluetoothPhoneAPI *bluetoothPhoneAPI; void onConnect(uint16_t conn_handle) { - // Get the reference to current connection BLEConnection *connection = Bluefruit.Connection(conn_handle); connectionHandle = conn_handle; + char central_name[32] = {0}; connection->getPeerName(central_name, sizeof(central_name)); + LOG_INFO("BLE Connected to %s\n", central_name); } + /** * Callback invoked when a connection is dropped * @param conn_handle connection where this event happens @@ -71,36 +72,37 @@ void onDisconnect(uint16_t conn_handle, uint8_t reason) // FIXME - we currently assume only one active connection LOG_INFO("BLE Disconnected, reason = 0x%x\n", reason); } + void onCccd(uint16_t conn_hdl, BLECharacteristic *chr, uint16_t cccd_value) { // Display the raw request packet LOG_INFO("CCCD Updated: %u\n", cccd_value); + // Check the characteristic this CCCD update is associated with in case // this handler is used for multiple CCCD records. - - // According to the GATT spec: cccd value = 0x0001 means notifications are enabled - // and cccd value = 0x0002 means indications are enabled - - if (chr->uuid == fromNum.uuid || chr->uuid == logRadio.uuid) { - auto result = cccd_value == 2 ? chr->indicateEnabled(conn_hdl) : chr->notifyEnabled(conn_hdl); - if (result) { - LOG_INFO("Notify/Indicate enabled\n"); + if (chr->uuid == fromNum.uuid) { + if (chr->notifyEnabled(conn_hdl)) { + LOG_INFO("fromNum 'Notify' enabled\n"); } else { - LOG_INFO("Notify/Indicate disabled\n"); + LOG_INFO("fromNum 'Notify' disabled\n"); } } } + void startAdv(void) { // Advertising packet Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + // IncludeService UUID // Bluefruit.ScanResponse.addService(meshBleService); Bluefruit.ScanResponse.addTxPower(); Bluefruit.ScanResponse.addName(); + // Include Name // Bluefruit.Advertising.addName(); Bluefruit.Advertising.addService(meshBleService); + /* Start Advertising * - Enable auto advertising if disconnected * - Interval: fast mode = 20 ms, slow mode = 152.5 ms @@ -115,6 +117,7 @@ void startAdv(void) Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X } + // Just ack that the caller is allowed to read static void authorizeRead(uint16_t conn_hdl) { @@ -122,6 +125,7 @@ static void authorizeRead(uint16_t conn_hdl) reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; sd_ble_gatts_rw_authorize_reply(conn_hdl, &reply); } + /** * client is starting read, pull the bytes from our API class */ @@ -130,6 +134,7 @@ void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e if (request->offset == 0) { // If the read is long, we will get multiple authorize invocations - we only populate data on the first size_t numBytes = bluetoothPhoneAPI->getFromRadio(fromRadioBytes); + // Someone is going to read our value as soon as this callback returns. So fill it with the next message in the queue // or make empty if the queue is empty fromRadio.write(fromRadioBytes, numBytes); @@ -138,22 +143,37 @@ void onFromRadioAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_e } authorizeRead(conn_hdl); } + void onToRadioWrite(uint16_t conn_hdl, BLECharacteristic *chr, uint8_t *data, uint16_t len) { LOG_INFO("toRadioWriteCb data %p, len %u\n", data, len); + bluetoothPhoneAPI->handleToRadio(data, len); } +/** + * client is starting read, pull the bytes from our API class + */ +void onFromNumAuthorize(uint16_t conn_hdl, BLECharacteristic *chr, ble_gatts_evt_read_t *request) +{ + LOG_INFO("fromNumAuthorizeCb\n"); + + authorizeRead(conn_hdl); +} + void setupMeshService(void) { bluetoothPhoneAPI = new BluetoothPhoneAPI(); + meshBleService.begin(); + // Note: You must call .begin() on the BLEService before calling .begin() on // any characteristic(s) within that service definition.. Calling .begin() on // a BLECharacteristic will cause it to be added to the last BLEService that // was 'begin()'ed! auto secMode = config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN ? SECMODE_OPEN : SECMODE_ENC_NO_MITM; + fromNum.setProperties(CHR_PROPS_NOTIFY | CHR_PROPS_READ); fromNum.setPermission(secMode, SECMODE_NO_ACCESS); // FIXME, secure this!!! fromNum.setFixedLen( @@ -183,15 +203,10 @@ void setupMeshService(void) // We don't call this callback via the adafruit queue, because we can safely run in the BLE context toRadio.setWriteCallback(onToRadioWrite, false); toRadio.begin(); - - logRadio.setProperties(CHR_PROPS_INDICATE | CHR_PROPS_NOTIFY | CHR_PROPS_READ); - logRadio.setPermission(secMode, SECMODE_NO_ACCESS); - logRadio.setMaxLen(512); - logRadio.setCccdWriteCallback(onCccd); - logRadio.write32(0); - logRadio.begin(); } + static uint32_t configuredPasskey; + void NRF52Bluetooth::shutdown() { // Shutdown bluetooth for minimum power draw @@ -201,23 +216,29 @@ void NRF52Bluetooth::shutdown() } Bluefruit.Advertising.stop(); } + void NRF52Bluetooth::startDisabled() { // Setup Bluetooth nrf52Bluetooth->setup(); + // Shutdown bluetooth for minimum power draw Bluefruit.Advertising.stop(); Bluefruit.setTxPower(-40); // Minimum power + LOG_INFO("Disabling NRF52 Bluetooth. (Workaround: tx power min, advertising stopped)\n"); } + bool NRF52Bluetooth::isConnected() { return Bluefruit.connected(connectionHandle); } + int NRF52Bluetooth::getRssi() { return 0; // FIXME figure out where to source this } + void NRF52Bluetooth::setup() { // Initialise the Bluefruit module @@ -225,10 +246,12 @@ void NRF52Bluetooth::setup() Bluefruit.autoConnLed(false); Bluefruit.configPrphBandwidth(BANDWIDTH_MAX); Bluefruit.begin(); + // Clear existing data. Bluefruit.Advertising.stop(); Bluefruit.Advertising.clearData(); Bluefruit.ScanResponse.clearData(); + if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) { configuredPasskey = config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN ? config.bluetooth.fixed_pin @@ -247,6 +270,7 @@ void NRF52Bluetooth::setup() } // Set the advertised device name (keep it short!) Bluefruit.setName(getDeviceName()); + // Set the connect/disconnect callback handlers Bluefruit.Periph.setConnectCallback(onConnect); Bluefruit.Periph.setDisconnectCallback(onDisconnect); @@ -263,19 +287,24 @@ void NRF52Bluetooth::setup() bledis.setModel(optstr(HW_VERSION)); bledis.setFirmwareRev(optstr(APP_VERSION)); bledis.begin(); + // Start the BLE Battery Service and set it to 100% LOG_INFO("Configuring the Battery Service\n"); blebas.begin(); blebas.write(0); // Unknown battery level for now + // Setup the Heart Rate Monitor service using // BLEService and BLECharacteristic classes LOG_INFO("Configuring the Mesh bluetooth service\n"); setupMeshService(); + // Setup the advertising packet(s) LOG_INFO("Setting up the advertising payload(s)\n"); startAdv(); + LOG_INFO("Advertising\n"); } + void NRF52Bluetooth::resumeAdvertising() { Bluefruit.Advertising.restartOnDisconnect(true); @@ -283,52 +312,34 @@ void NRF52Bluetooth::resumeAdvertising() Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode Bluefruit.Advertising.start(0); } + /// Given a level between 0-100, update the BLE attribute void updateBatteryLevel(uint8_t level) { blebas.write(level); } + void NRF52Bluetooth::clearBonds() { LOG_INFO("Clearing bluetooth bonds!\n"); bond_print_list(BLE_GAP_ROLE_PERIPH); bond_print_list(BLE_GAP_ROLE_CENTRAL); + Bluefruit.Periph.clearBonds(); Bluefruit.Central.clearBonds(); } + void NRF52Bluetooth::onConnectionSecured(uint16_t conn_handle) { LOG_INFO("BLE connection secured\n"); } + bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request) { LOG_INFO("BLE pairing process started with passkey %.3s %.3s\n", passkey, passkey + 3); powerFSM.trigger(EVENT_BLUETOOTH_PAIR); - screen->startAlert([](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { - char btPIN[16] = "888888"; - snprintf(btPIN, sizeof(btPIN), "%06u", configuredPasskey); - int x_offset = display->width() / 2; - int y_offset = display->height() <= 80 ? 0 : 32; - display->setTextAlignment(TEXT_ALIGN_CENTER); - display->setFont(FONT_MEDIUM); - display->drawString(x_offset + x, y_offset + y, "Bluetooth"); - - display->setFont(FONT_SMALL); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_MEDIUM - 4 : y_offset + FONT_HEIGHT_MEDIUM + 5; - display->drawString(x_offset + x, y_offset + y, "Enter this code"); - - display->setFont(FONT_LARGE); - String displayPin(btPIN); - String pin = displayPin.substring(0, 3) + " " + displayPin.substring(3, 6); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_SMALL - 5 : y_offset + FONT_HEIGHT_SMALL + 5; - display->drawString(x_offset + x, y_offset + y, pin); - - display->setFont(FONT_SMALL); - String deviceName = "Name: "; - deviceName.concat(getDeviceName()); - y_offset = display->height() == 64 ? y_offset + FONT_HEIGHT_LARGE - 6 : y_offset + FONT_HEIGHT_LARGE + 5; - display->drawString(x_offset + x, y_offset + y, deviceName); - }); + screen->startBluetoothPinScreen(configuredPasskey); + if (match_request) { uint32_t start_time = millis(); while (millis() < start_time + 30000) { @@ -339,21 +350,13 @@ bool NRF52Bluetooth::onPairingPasskey(uint16_t conn_handle, uint8_t const passke LOG_INFO("BLE passkey pairing: match_request=%i\n", match_request); return true; } + void NRF52Bluetooth::onPairingCompleted(uint16_t conn_handle, uint8_t auth_status) { if (auth_status == BLE_GAP_SEC_STATUS_SUCCESS) LOG_INFO("BLE pairing success\n"); else LOG_INFO("BLE pairing failed\n"); - screen->endAlert(); -} -void NRF52Bluetooth::sendLog(const uint8_t *logMessage, size_t length) -{ - if (!isConnected() || length > 512) - return; - if (logRadio.indicateEnabled()) - logRadio.indicate(logMessage, (uint16_t)length); - else - logRadio.notify(logMessage, (uint16_t)length); -} + screen->stopBluetoothPinScreen(); +} \ No newline at end of file diff --git a/src/platform/nrf52/NRF52Bluetooth.h b/src/platform/nrf52/NRF52Bluetooth.h index 2229163f81..450af47f91 100644 --- a/src/platform/nrf52/NRF52Bluetooth.h +++ b/src/platform/nrf52/NRF52Bluetooth.h @@ -13,10 +13,10 @@ class NRF52Bluetooth : BluetoothApi void clearBonds(); bool isConnected(); int getRssi(); - void sendLog(const uint8_t *logMessage, size_t length); private: static void onConnectionSecured(uint16_t conn_handle); + void convertToUint8(uint8_t target[4], uint32_t source); static bool onPairingPasskey(uint16_t conn_handle, uint8_t const passkey[6], bool match_request); static void onPairingCompleted(uint16_t conn_handle, uint8_t auth_status); }; \ No newline at end of file diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp index 7334f3a041..1f2c6867d5 100644 --- a/src/platform/nrf52/main-nrf52.cpp +++ b/src/platform/nrf52/main-nrf52.cpp @@ -63,8 +63,7 @@ static void initBrownout() // We don't bother with setting up brownout if soft device is disabled - because during production we always use softdevice } -// This is a public global so that the debugger can set it to false automatically from our gdbinit -bool useSoftDevice = true; // Set to false for easier debugging +static const bool useSoftDevice = true; // Set to false for easier debugging #if !MESHTASTIC_EXCLUDE_BLUETOOTH void setBluetoothEnable(bool enable) @@ -150,43 +149,13 @@ void nrf52Loop() checkSDEvents(); } -#ifdef USE_SEMIHOSTING -#include - -/** - * Note: this variable is in BSS and therfore false by default. But the gdbinit - * file will be installing a temporary breakpoint that changes wantSemihost to true. - */ -bool wantSemihost; - -/** - * Turn on semihosting if the ICE debugger wants it. - */ -void nrf52InitSemiHosting() -{ - if (wantSemihost) { - static SemihostingStream semiStream; - // We must dynamically alloc because the constructor does semihost operations which - // would crash any load not talking to a debugger - semiStream.open(); - semiStream.println("Semihosting starts!"); - // Redirect our serial output to instead go via the ICE port - console->setDestination(&semiStream); - } -} -#endif - void nrf52Setup() { - uint32_t why = NRF_POWER->RESETREAS; + auto why = NRF_POWER->RESETREAS; // per // https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpower.html LOG_DEBUG("Reset reason: 0x%x\n", why); -#ifdef USE_SEMIHOSTING - nrf52InitSemiHosting(); -#endif - // Per // https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/monitor-mode-debugging-with-j-link-and-gdbeclipse // This is the recommended setting for Monitor Mode Debugging @@ -234,18 +203,6 @@ void cpuDeepSleep(uint32_t msecToWake) // RAK-12039 set pin for Air quality sensor digitalWrite(AQ_SET_PIN, LOW); #endif -#ifdef RAK14014 - // GPIO restores input status, otherwise there will be leakage current - nrf_gpio_cfg_default(TFT_BL); - nrf_gpio_cfg_default(TFT_DC); - nrf_gpio_cfg_default(TFT_CS); - nrf_gpio_cfg_default(TFT_SCLK); - nrf_gpio_cfg_default(TFT_MOSI); - nrf_gpio_cfg_default(TFT_MISO); - nrf_gpio_cfg_default(SCREEN_TOUCH_INT); - nrf_gpio_cfg_default(WB_I2C1_SCL); - nrf_gpio_cfg_default(WB_I2C1_SDA); -#endif #endif // Sleepy trackers or sensors can low power "sleep" // Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event @@ -286,10 +243,5 @@ void clearBonds() void enterDfuMode() { -// SDK kit does not have native USB like almost all other NRF52 boards -#ifdef NRF_USE_SERIAL_DFU - enterSerialDfu(); -#else enterUf2Dfu(); -#endif } \ No newline at end of file diff --git a/src/platform/nrf52/softdevice/nrf_sdm.h b/src/platform/nrf52/softdevice/nrf_sdm.h index 33b6cc3421..2786a86a45 100644 --- a/src/platform/nrf52/softdevice/nrf_sdm.h +++ b/src/platform/nrf52/softdevice/nrf_sdm.h @@ -141,7 +141,7 @@ the start of the SoftDevice (without MBR)*/ * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed * just above the MBR (the usual case). */ -#define SD_FLASH_SIZE 0x27000 +#define SD_FLASH_SIZE 0x26000 /** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual diff --git a/src/shutdown.h b/src/shutdown.h index 3f191eea88..54fb3071b7 100644 --- a/src/shutdown.h +++ b/src/shutdown.h @@ -38,7 +38,7 @@ void powerCommandsCheck() #if defined(ARCH_ESP32) || defined(ARCH_NRF52) if (shutdownAtMsec) { - screen->startAlert("Shutting down..."); + screen->startShutdownScreen(); } #endif diff --git a/src/sleep.cpp b/src/sleep.cpp index ed02ba44ab..55e70e7b87 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -8,7 +8,6 @@ #include "MeshRadio.h" #include "MeshService.h" #include "NodeDB.h" -#include "PowerMon.h" #include "detect/LoRaRadioType.h" #include "error.h" #include "main.h" @@ -18,7 +17,7 @@ #ifdef ARCH_ESP32 #include "esp32/pm.h" #include "esp_pm.h" -#if HAS_WIFI +#if !MESHTASTIC_EXCLUDE_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif #include "rom/rtc.h" @@ -37,7 +36,10 @@ Observable preflightSleep; /// Called to tell observers we are now entering sleep and you should prepare. Must return 0 /// notifySleep will be called for light or deep sleep, notifyDeepSleep is only called for deep sleep +/// notifyGPSSleep will be called when config.position.gps_enabled is set to 0 or from buttonthread when GPS_POWER_TOGGLE is +/// enabled. Observable notifySleep, notifyDeepSleep; +Observable notifyGPSSleep; // deep sleep support RTC_DATA_ATTR int bootCount = 0; @@ -54,20 +56,20 @@ RTC_DATA_ATTR int bootCount = 0; */ void setCPUFast(bool on) { -#if defined(ARCH_ESP32) && HAS_WIFI +#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_WIFI if (isWifiAvailable()) { /* * * There's a newly introduced bug in the espressif framework where WiFi is - * unstable when the frequency is less than 240MHz. + * unstable when the frequency is less than 240mhz. * * This mostly impacts WiFi AP mode but we'll bump the frequency for * all WiFi use cases. * (Added: Dec 23, 2021 by Jm Casler) */ #ifndef CONFIG_IDF_TARGET_ESP32C3 - LOG_DEBUG("Setting CPU to 240MHz because WiFi is in use.\n"); + LOG_DEBUG("Setting CPU to 240mhz because WiFi is in use.\n"); setCpuFrequencyMhz(240); #endif return; @@ -83,11 +85,6 @@ void setCPUFast(bool on) void setLed(bool ledOn) { - if (ledOn) - powerMon->setState(meshtastic_PowerMon_State_LED_On); - else - powerMon->clearState(meshtastic_PowerMon_State_LED_On); - #ifdef LED_PIN // toggle the led so we can get some rough sense of how often loop is pausing digitalWrite(LED_PIN, ledOn ^ LED_INVERTED); @@ -238,7 +235,6 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) pinMode(PIN_POWER_EN, INPUT); // power off peripherals // pinMode(PIN_POWER_EN1, INPUT_PULLDOWN); #endif - #if HAS_GPS // Kill GPS power completely (even if previously we just had it in sleep mode) if (gps) @@ -273,8 +269,6 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) #elif defined(VEXT_ENABLE_V05) digitalWrite(VEXT_ENABLE_V05, 0); // turn off the lora amplifier power digitalWrite(ST7735_BL_V05, 0); // turn off the display power -#elif defined(VEXT_ENABLE) && defined(VEXT_ON_VALUE) - digitalWrite(VEXT_ENABLE, !VEXT_ON_VALUE); // turn on the display power #elif defined(VEXT_ENABLE) digitalWrite(VEXT_ENABLE, 1); // turn off the display power #endif diff --git a/src/sleep.h b/src/sleep.h index f154b8d445..8d5b9a94f3 100644 --- a/src/sleep.h +++ b/src/sleep.h @@ -41,6 +41,8 @@ extern Observable notifySleep; /// Called to tell observers we are now entering (deep) sleep and you should prepare. Must return 0 extern Observable notifyDeepSleep; +/// Called to tell GPS thread to enter deep sleep independently of LoRa/MCU sleep, prior to full poweroff. Must return 0 +extern Observable notifyGPSSleep; void enableModemSleep(); #ifdef ARCH_ESP32 void enableLoraInterrupt(); diff --git a/variants/heltec_capsule_sensor_v3/variant.h b/variants/heltec_capsule_sensor_v3/variant.h index 51c3cb6adc..0d5ab73cfb 100644 --- a/variants/heltec_capsule_sensor_v3/variant.h +++ b/variants/heltec_capsule_sensor_v3/variant.h @@ -1,5 +1,5 @@ #define LED_PIN 33 -#define LED_PIN2 34 +#define LED_PIN2 34 #define EXT_PWR_DETECT 35 #define BUTTON_PIN 18 diff --git a/variants/heltec_mesh_node_t114/platformio.ini b/variants/heltec_mesh_node_t114/platformio.ini deleted file mode 100644 index 99bdf77a72..0000000000 --- a/variants/heltec_mesh_node_t114/platformio.ini +++ /dev/null @@ -1,15 +0,0 @@ -; First prototype nrf52840/sx1262 device -[env:heltec-mesh-node-t114] -extends = nrf52840_base -board = heltec_mesh_node_t114 -debug_tool = jlink - -# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling. -build_flags = ${nrf52840_base.build_flags} -Ivariants/heltec_mesh_node_t114 - -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" - -build_src_filter = ${nrf52_base.build_src_filter} +<../variants/heltec_mesh_node_t114> -lib_deps = - ${nrf52840_base.lib_deps} - lewisxhe/PCF8563_Library@^1.0.1 - https://github.com/Bei-Ji-Quan/st7789#b8e7e076714b670764139289d3829b0beff67edb \ No newline at end of file diff --git a/variants/heltec_mesh_node_t114/variant.cpp b/variants/heltec_mesh_node_t114/variant.cpp deleted file mode 100644 index cae079b749..0000000000 --- a/variants/heltec_mesh_node_t114/variant.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright (c) 2014-2015 Arduino LLC. All right reserved. - Copyright (c) 2016 Sandeep Mistry All right reserved. - Copyright (c) 2018, Adafruit Industries (adafruit.com) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "variant.h" -#include "nrf.h" -#include "wiring_constants.h" -#include "wiring_digital.h" - -const uint32_t g_ADigitalPinMap[] = { - // P0 - pins 0 and 1 are hardwired for xtal and should never be enabled - 0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - - // P1 - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; - -void initVariant() -{ - // LED1 & LED2 - pinMode(PIN_LED1, OUTPUT); - ledOff(PIN_LED1); - - pinMode(PIN_LED2, OUTPUT); - ledOff(PIN_LED2); - - pinMode(PIN_LED3, OUTPUT); - ledOff(PIN_LED3); -} diff --git a/variants/heltec_mesh_node_t114/variant.h b/variants/heltec_mesh_node_t114/variant.h deleted file mode 100644 index b233069c63..0000000000 --- a/variants/heltec_mesh_node_t114/variant.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - Copyright (c) 2014-2015 Arduino LLC. All right reserved. - Copyright (c) 2016 Sandeep Mistry All right reserved. - Copyright (c) 2018, Adafruit Industries (adafruit.com) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _VARIANT_HELTEC_NRF_ -#define _VARIANT_HELTEC_NRF_ -/** Master clock frequency */ -#define VARIANT_MCK (64000000ul) - -#define USE_LFXO // Board uses 32khz crystal for LF - -/*---------------------------------------------------------------------------- - * Headers - *----------------------------------------------------------------------------*/ - -#include "WVariant.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -#define HELTEC_MESH_NODE_T114 - -#define USE_ST7789 - -#define ST7789_NSS 11 -#define ST7789_RS 12 // DC -#define ST7789_SDA 41 // MOSI -#define ST7789_SCK 40 -#define ST7789_RESET 2 -#define ST7789_MISO -1 -#define ST7789_BUSY -1 -#define VTFT_CTRL 3 -#define VTFT_LEDA 15 -// #define ST7789_BL (32+6) -#define TFT_BACKLIGHT_ON LOW -#define ST7789_SPI_HOST SPI1_HOST -// #define ST7789_BACKLIGHT_EN (32+6) -#define SPI_FREQUENCY 40000000 -#define SPI_READ_FREQUENCY 16000000 -#define TFT_HEIGHT 135 -#define TFT_WIDTH 240 -#define TFT_OFFSET_X 0 -#define TFT_OFFSET_Y 0 -// #define TFT_OFFSET_ROTATION 0 -// #define SCREEN_ROTATE -// #define SCREEN_TRANSITION_FRAMERATE 5 - -// Number of pins defined in PinDescription array -#define PINS_COUNT (48) -#define NUM_DIGITAL_PINS (48) -#define NUM_ANALOG_INPUTS (1) -#define NUM_ANALOG_OUTPUTS (0) - -// LEDs -#define PIN_LED1 (32 + 3) // 13 red (confirmed on 1.0 board) -// Unused(by firmware) LEDs: -#define PIN_LED2 (1 + 1) // 14 blue -#define PIN_LED3 (1 + 11) // 15 green - -#define LED_RED PIN_LED3 -#define LED_BLUE PIN_LED1 -#define LED_GREEN PIN_LED2 - -#define LED_BUILTIN LED_BLUE -#define LED_CONN PIN_GREEN - -#define LED_STATE_ON 0 // State when LED is lit -#define LED_INVERTED 1 - -/* - * Buttons - */ -#define PIN_BUTTON1 (32 + 10) -// #define PIN_BUTTON2 (0 + 18) // 0.18 is labeled on the board as RESET but we configure it in the bootloader as a regular -// GPIO - -/* -No longer populated on PCB -*/ -#define PIN_SERIAL2_RX (0 + 9) -#define PIN_SERIAL2_TX (0 + 10) -// #define PIN_SERIAL2_EN (0 + 17) - -/** - Wire Interfaces - */ -#define WIRE_INTERFACES_COUNT 1 - -#define PIN_WIRE_SDA (26) -#define PIN_WIRE_SCL (27) - -// QSPI Pins -#define PIN_QSPI_SCK (32 + 14) -#define PIN_QSPI_CS (32 + 15) -#define PIN_QSPI_IO0 (32 + 12) // MOSI if using two bit interface -#define PIN_QSPI_IO1 (32 + 13) // MISO if using two bit interface -#define PIN_QSPI_IO2 (0 + 7) // WP if using two bit interface (i.e. not used) -#define PIN_QSPI_IO3 (0 + 5) // HOLD if using two bit interface (i.e. not used) - -// On-board QSPI Flash -#define EXTERNAL_FLASH_DEVICES MX25R1635F -#define EXTERNAL_FLASH_USE_QSPI - -/* - * Lora radio - */ - -#define USE_SX1262 -// #define USE_SX1268 -#define SX126X_CS (0 + 24) // FIXME - we really should define LORA_CS instead -#define LORA_CS (0 + 24) -#define SX126X_DIO1 (0 + 20) -// Note DIO2 is attached internally to the module to an analog switch for TX/RX switching -// #define SX1262_DIO3 \ -// (0 + 21) // This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the -// main -// CPU? -#define SX126X_BUSY (0 + 17) -#define SX126X_RESET (0 + 25) -// Not really an E22 but TTGO seems to be trying to clone that -#define SX126X_DIO2_AS_RF_SWITCH -#define SX126X_DIO3_TCXO_VOLTAGE 1.8 - -#define PIN_SPI1_MISO \ - ST7789_MISO // FIXME not really needed, but for now the SPI code requires something to be defined, pick an used GPIO -#define PIN_SPI1_MOSI ST7789_SDA -#define PIN_SPI1_SCK ST7789_SCK - -/* - * GPS pins - */ - -#define GPS_L76K - -#define PIN_GPS_RESET (32 + 6) // An output to reset L76K GPS. As per datasheet, low for > 100ms will reset the L76K -#define GPS_RESET_MODE LOW -#define PIN_GPS_EN (21) -#define GPS_EN_ACTIVE HIGH -#define PIN_GPS_STANDBY (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake -#define PIN_GPS_PPS (32 + 4) -// Seems to be missing on this new board -// #define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS -#define GPS_TX_PIN (32 + 5) // This is for bits going TOWARDS the CPU -#define GPS_RX_PIN (32 + 7) // This is for bits going TOWARDS the GPS - -#define GPS_THREAD_INTERVAL 50 - -#define PIN_SERIAL1_RX GPS_TX_PIN -#define PIN_SERIAL1_TX GPS_RX_PIN - -// PCF8563 RTC Module -#define PCF8563_RTC 0x51 - -/* - * SPI Interfaces - */ -#define SPI_INTERFACES_COUNT 2 - -// For LORA, spi 0 -#define PIN_SPI_MISO (0 + 23) -#define PIN_SPI_MOSI (0 + 22) -#define PIN_SPI_SCK (0 + 19) - -// #define PIN_PWR_EN (0 + 6) - -// To debug via the segger JLINK console rather than the CDC-ACM serial device -// #define USE_SEGGER - -// Battery -// The battery sense is hooked to pin A0 (4) -// it is defined in the anlaolgue pin section of this file -// and has 12 bit resolution - -#define ADC_CTRL 6 -#define ADC_CTRL_ENABLED HIGH -#define BATTERY_PIN 4 -#define ADC_RESOLUTION 14 - -#define BATTERY_SENSE_RESOLUTION_BITS 12 -#define BATTERY_SENSE_RESOLUTION 4096.0 -#undef AREF_VOLTAGE -#define AREF_VOLTAGE 3.0 -#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 -#define ADC_MULTIPLIER (4.90F) - -#define HAS_RTC 0 -#ifdef __cplusplus -} -#endif - -/*---------------------------------------------------------------------------- - * Arduino objects - C++ only - *----------------------------------------------------------------------------*/ - -#endif \ No newline at end of file diff --git a/variants/heltec_vision_master_e213/pins_arduino.h b/variants/heltec_vision_master_e213/pins_arduino.h deleted file mode 100644 index 01c16c496b..0000000000 --- a/variants/heltec_vision_master_e213/pins_arduino.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef Pins_Arduino_h -#define Pins_Arduino_h - -#include - -#define HELTEC_VISION_MASTER_E213 true - -static const uint8_t LED_BUILTIN = 35; -#define BUILTIN_LED LED_BUILTIN // backward compatibility -#define LED_BUILTIN LED_BUILTIN - -static const uint8_t TX = 43; -static const uint8_t RX = 44; - -static const uint8_t SDA = 41; -static const uint8_t SCL = 42; - -static const uint8_t SS = 8; -static const uint8_t MOSI = 10; -static const uint8_t MISO = 11; -static const uint8_t SCK = 9; - -static const uint8_t A0 = 1; -static const uint8_t A1 = 2; -static const uint8_t A2 = 3; -static const uint8_t A3 = 4; -static const uint8_t A4 = 5; -static const uint8_t A5 = 6; -static const uint8_t A6 = 7; -static const uint8_t A7 = 8; -static const uint8_t A8 = 9; -static const uint8_t A9 = 10; -static const uint8_t A10 = 11; -static const uint8_t A11 = 12; -static const uint8_t A12 = 13; -static const uint8_t A13 = 14; -static const uint8_t A14 = 15; -static const uint8_t A15 = 16; -static const uint8_t A16 = 17; -static const uint8_t A17 = 18; -static const uint8_t A18 = 19; -static const uint8_t A19 = 20; - -static const uint8_t T1 = 1; -static const uint8_t T2 = 2; -static const uint8_t T3 = 3; -static const uint8_t T4 = 4; -static const uint8_t T5 = 5; -static const uint8_t T6 = 6; -static const uint8_t T7 = 7; -static const uint8_t T8 = 8; -static const uint8_t T9 = 9; -static const uint8_t T10 = 10; -static const uint8_t T11 = 11; -static const uint8_t T12 = 12; -static const uint8_t T13 = 13; -static const uint8_t T14 = 14; - -static const uint8_t RST_LoRa = 12; -static const uint8_t BUSY_LoRa = 13; -static const uint8_t DIO0 = 14; - -#endif /* Pins_Arduino_h */ diff --git a/variants/heltec_vision_master_e213/platformio.ini b/variants/heltec_vision_master_e213/platformio.ini deleted file mode 100644 index 77cc659834..0000000000 --- a/variants/heltec_vision_master_e213/platformio.ini +++ /dev/null @@ -1,23 +0,0 @@ -[env:heltec-vision-master-e213] -extends = esp32s3_base -board = heltec_wifi_lora_32_V3 -build_flags = - ${esp32s3_base.build_flags} - -Ivariants/heltec_vision_master_e213 - -DHELTEC_VISION_MASTER_E213 - -DEINK_DISPLAY_MODEL=GxEPD2_213_FC1 - -DEINK_WIDTH=250 - -DEINK_HEIGHT=122 - -DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk - -DEINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted - -DEINK_LIMIT_RATE_BACKGROUND_SEC=30 ; Minimum interval between BACKGROUND updates - -DEINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates -; -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated - -DEINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. - -DEINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" - -DEINK_HASQUIRK_WEAKFASTREFRESH ; Pixels set with fast-refresh are easy to clear, disrupted by sunlight -lib_deps = - ${esp32s3_base.lib_deps} - https://github.com/meshtastic/GxEPD2#b202ebfec6a4821e098cf7a625ba0f6f2400292d - lewisxhe/PCF8563_Library@^1.0.1 -upload_speed = 115200 \ No newline at end of file diff --git a/variants/heltec_vision_master_e213/variant.h b/variants/heltec_vision_master_e213/variant.h deleted file mode 100644 index 169602a0d7..0000000000 --- a/variants/heltec_vision_master_e213/variant.h +++ /dev/null @@ -1,58 +0,0 @@ -// #define LED_PIN 18 - -// Enable bus for external periherals -#define I2C_SDA SDA -#define I2C_SCL SCL - -#define USE_EINK - -/* - * eink display pins - */ -#define PIN_EINK_CS 5 -#define PIN_EINK_BUSY 1 -#define PIN_EINK_DC 2 -#define PIN_EINK_RES 3 -#define PIN_EINK_SCLK 4 -#define PIN_EINK_MOSI 6 - -/* - * SPI interfaces - */ -#define SPI_INTERFACES_COUNT 2 - -#define PIN_SPI_MISO 10 // MISO P0.17 -#define PIN_SPI_MOSI 11 // MOSI P0.15 -#define PIN_SPI_SCK 9 // SCK P0.13 - -#define VEXT_ENABLE 18 // powers the oled display and the lora antenna boost -#define VEXT_ON_VALUE 1 -#define BUTTON_PIN 21 - -#define ADC_CTRL 46 -#define ADC_CTRL_ENABLED HIGH -#define BATTERY_PIN 7 -#define ADC_CHANNEL ADC1_GPIO7_CHANNEL -#define ADC_MULTIPLIER 4.9 * 1.03 // Voltage divider is roughly 1:1 -#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high - -#define USE_SX1262 - -#define LORA_DIO0 -1 // a No connect on the SX1262 module -#define LORA_RESET 12 -#define LORA_DIO1 14 // SX1262 IRQ -#define LORA_DIO2 13 // SX1262 BUSY -#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled - -#define LORA_SCK 9 -#define LORA_MISO 11 -#define LORA_MOSI 10 -#define LORA_CS 8 - -#define SX126X_CS LORA_CS -#define SX126X_DIO1 LORA_DIO1 -#define SX126X_BUSY LORA_DIO2 -#define SX126X_RESET LORA_RESET - -#define SX126X_DIO2_AS_RF_SWITCH -#define SX126X_DIO3_TCXO_VOLTAGE 1.8 \ No newline at end of file diff --git a/variants/heltec_vision_master_e290/pins_arduino.h b/variants/heltec_vision_master_e290/pins_arduino.h deleted file mode 100644 index e5d5078463..0000000000 --- a/variants/heltec_vision_master_e290/pins_arduino.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef Pins_Arduino_h -#define Pins_Arduino_h - -#include - -static const uint8_t LED_BUILTIN = 35; -#define BUILTIN_LED LED_BUILTIN // backward compatibility -#define LED_BUILTIN LED_BUILTIN - -static const uint8_t TX = 43; -static const uint8_t RX = 44; - -static const uint8_t SDA = 41; -static const uint8_t SCL = 42; - -static const uint8_t SS = 8; -static const uint8_t MOSI = 10; -static const uint8_t MISO = 11; -static const uint8_t SCK = 9; - -static const uint8_t A0 = 1; -static const uint8_t A1 = 2; -static const uint8_t A2 = 3; -static const uint8_t A3 = 4; -static const uint8_t A4 = 5; -static const uint8_t A5 = 6; -static const uint8_t A6 = 7; -static const uint8_t A7 = 8; -static const uint8_t A8 = 9; -static const uint8_t A9 = 10; -static const uint8_t A10 = 11; -static const uint8_t A11 = 12; -static const uint8_t A12 = 13; -static const uint8_t A13 = 14; -static const uint8_t A14 = 15; -static const uint8_t A15 = 16; -static const uint8_t A16 = 17; -static const uint8_t A17 = 18; -static const uint8_t A18 = 19; -static const uint8_t A19 = 20; - -static const uint8_t T1 = 1; -static const uint8_t T2 = 2; -static const uint8_t T3 = 3; -static const uint8_t T4 = 4; -static const uint8_t T5 = 5; -static const uint8_t T6 = 6; -static const uint8_t T7 = 7; -static const uint8_t T8 = 8; -static const uint8_t T9 = 9; -static const uint8_t T10 = 10; -static const uint8_t T11 = 11; -static const uint8_t T12 = 12; -static const uint8_t T13 = 13; -static const uint8_t T14 = 14; - -static const uint8_t RST_LoRa = 12; -static const uint8_t BUSY_LoRa = 13; -static const uint8_t DIO0 = 14; - -#endif /* Pins_Arduino_h */ diff --git a/variants/heltec_vision_master_e290/platformio.ini b/variants/heltec_vision_master_e290/platformio.ini deleted file mode 100644 index 60ff60036a..0000000000 --- a/variants/heltec_vision_master_e290/platformio.ini +++ /dev/null @@ -1,25 +0,0 @@ -[env:heltec-vision-master-e290] -board_level = extra -extends = esp32s3_base -board = heltec_wifi_lora_32_V3 -build_flags = - ${esp32s3_base.build_flags} - -Ivariants/heltec_vision_master_e290 - -DHELTEC_VISION_MASTER_E290 - -DEINK_DISPLAY_MODEL=GxEPD2_290_BS - -DEINK_WIDTH=296 - -DEINK_HEIGHT=128 -; -D USE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk -; -D EINK_LIMIT_FASTREFRESH=10 ; How many consecutive fast-refreshes are permitted -; -D EINK_LIMIT_RATE_BACKGROUND_SEC=1 ; Minimum interval between BACKGROUND updates -; -D EINK_LIMIT_RATE_RESPONSIVE_SEC=1 ; Minimum interval between RESPONSIVE updates -; -D EINK_LIMIT_GHOSTING_PX=2000 ; (Optional) How much image ghosting is tolerated -; -D EINK_BACKGROUND_USES_FAST ; (Optional) Use FAST refresh for both BACKGROUND and RESPONSIVE, until a limit is reached. -; -D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting" -; -D EINK_HASQUIRK_WEAKFASTREFRESH ; Pixels set with fast-refresh are easy to clear, disrupted by sunlight - -lib_deps = - ${esp32s3_base.lib_deps} - https://github.com/meshtastic/GxEPD2#b202ebfec6a4821e098cf7a625ba0f6f2400292d - lewisxhe/PCF8563_Library@^1.0.1 -upload_speed = 115200 \ No newline at end of file diff --git a/variants/heltec_vision_master_e290/variant.h b/variants/heltec_vision_master_e290/variant.h deleted file mode 100644 index a122a7e0fa..0000000000 --- a/variants/heltec_vision_master_e290/variant.h +++ /dev/null @@ -1,58 +0,0 @@ -// #define LED_PIN 18 - -// Enable bus for external periherals -#define I2C_SDA SDA -#define I2C_SCL SCL - -#define USE_EINK - -/* - * eink display pins - */ -#define PIN_EINK_CS 3 -#define PIN_EINK_BUSY 5 -#define PIN_EINK_DC 4 -#define PIN_EINK_RES 5 -#define PIN_EINK_SCLK 2 -#define PIN_EINK_MOSI 1 - -/* - * SPI interfaces - */ -#define SPI_INTERFACES_COUNT 2 - -#define PIN_SPI_MISO 10 // MISO -#define PIN_SPI_MOSI 11 // MOSI -#define PIN_SPI_SCK 9 // SCK - -#define VEXT_ENABLE 18 // powers the e-ink display -#define VEXT_ON_VALUE 1 -#define BUTTON_PIN 21 - -#define ADC_CTRL 46 -#define ADC_CTRL_ENABLED HIGH -#define BATTERY_PIN 7 -#define ADC_CHANNEL ADC1_GPIO7_CHANNEL -#define ADC_MULTIPLIER 4.9 * 1.03 -#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high - -#define USE_SX1262 - -#define LORA_DIO0 -1 // a No connect on the SX1262 module -#define LORA_RESET 12 -#define LORA_DIO1 14 // SX1262 IRQ -#define LORA_DIO2 13 // SX1262 BUSY -#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled - -#define LORA_SCK 9 -#define LORA_MISO 11 -#define LORA_MOSI 10 -#define LORA_CS 8 - -#define SX126X_CS LORA_CS -#define SX126X_DIO1 LORA_DIO1 -#define SX126X_BUSY LORA_DIO2 -#define SX126X_RESET LORA_RESET - -#define SX126X_DIO2_AS_RF_SWITCH -#define SX126X_DIO3_TCXO_VOLTAGE 1.8 \ No newline at end of file diff --git a/variants/heltec_vision_master_t190/pins_arduino.h b/variants/heltec_vision_master_t190/pins_arduino.h deleted file mode 100644 index e5d5078463..0000000000 --- a/variants/heltec_vision_master_t190/pins_arduino.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef Pins_Arduino_h -#define Pins_Arduino_h - -#include - -static const uint8_t LED_BUILTIN = 35; -#define BUILTIN_LED LED_BUILTIN // backward compatibility -#define LED_BUILTIN LED_BUILTIN - -static const uint8_t TX = 43; -static const uint8_t RX = 44; - -static const uint8_t SDA = 41; -static const uint8_t SCL = 42; - -static const uint8_t SS = 8; -static const uint8_t MOSI = 10; -static const uint8_t MISO = 11; -static const uint8_t SCK = 9; - -static const uint8_t A0 = 1; -static const uint8_t A1 = 2; -static const uint8_t A2 = 3; -static const uint8_t A3 = 4; -static const uint8_t A4 = 5; -static const uint8_t A5 = 6; -static const uint8_t A6 = 7; -static const uint8_t A7 = 8; -static const uint8_t A8 = 9; -static const uint8_t A9 = 10; -static const uint8_t A10 = 11; -static const uint8_t A11 = 12; -static const uint8_t A12 = 13; -static const uint8_t A13 = 14; -static const uint8_t A14 = 15; -static const uint8_t A15 = 16; -static const uint8_t A16 = 17; -static const uint8_t A17 = 18; -static const uint8_t A18 = 19; -static const uint8_t A19 = 20; - -static const uint8_t T1 = 1; -static const uint8_t T2 = 2; -static const uint8_t T3 = 3; -static const uint8_t T4 = 4; -static const uint8_t T5 = 5; -static const uint8_t T6 = 6; -static const uint8_t T7 = 7; -static const uint8_t T8 = 8; -static const uint8_t T9 = 9; -static const uint8_t T10 = 10; -static const uint8_t T11 = 11; -static const uint8_t T12 = 12; -static const uint8_t T13 = 13; -static const uint8_t T14 = 14; - -static const uint8_t RST_LoRa = 12; -static const uint8_t BUSY_LoRa = 13; -static const uint8_t DIO0 = 14; - -#endif /* Pins_Arduino_h */ diff --git a/variants/heltec_vision_master_t190/platformio.ini b/variants/heltec_vision_master_t190/platformio.ini deleted file mode 100644 index bbaa0075c5..0000000000 --- a/variants/heltec_vision_master_t190/platformio.ini +++ /dev/null @@ -1,13 +0,0 @@ -[env:heltec-vision-master-t190] -extends = esp32s3_base -board = heltec_wifi_lora_32_V3 -build_flags = - ${esp32s3_base.build_flags} - -Ivariants/heltec_vision_master_t190 - -DHELTEC_VISION_MASTER_T190 - ; -D PRIVATE_HW -lib_deps = - ${esp32s3_base.lib_deps} - lewisxhe/PCF8563_Library@^1.0.1 - https://github.com/Bei-Ji-Quan/st7789#b8e7e076714b670764139289d3829b0beff67edb -upload_speed = 921600 \ No newline at end of file diff --git a/variants/heltec_vision_master_t190/variant.h b/variants/heltec_vision_master_t190/variant.h deleted file mode 100644 index 97500d357e..0000000000 --- a/variants/heltec_vision_master_t190/variant.h +++ /dev/null @@ -1,76 +0,0 @@ -// #define LED_PIN 18 - -// Enable bus for external periherals -#define I2C_SDA 1 -#define I2C_SCL 2 -#define USE_ST7789 - -#define ST7789_NSS 39 -// #define ST7789_CS 39 -#define ST7789_RS 47 // DC -#define ST7789_SDA 48 // MOSI -#define ST7789_SCK 38 -#define ST7789_RESET 40 -#define ST7789_MISO 4 -#define ST7789_BUSY -1 -#define VTFT_CTRL 7 -// #define TFT_BL 3 -#define VTFT_LEDA 17 -#define TFT_BACKLIGHT_ON HIGH -// #define TFT_BL 17 -// #define TFT_BACKLIGHT_ON HIGH -// #define ST7789_BL 3 -#define ST7789_SPI_HOST SPI2_HOST -// #define ST7789_BACKLIGHT_EN 17 -#define SPI_FREQUENCY 10000000 -#define SPI_READ_FREQUENCY 10000000 -#define TFT_HEIGHT 170 -#define TFT_WIDTH 320 -#define TFT_OFFSET_X 0 -#define TFT_OFFSET_Y 0 -// #define TFT_OFFSET_ROTATION 0 -// #define SCREEN_ROTATE -// #define SCREEN_TRANSITION_FRAMERATE 5 -#define BRIGHTNESS_DEFAULT 100 // Medium Low Brightnes - -// #define SLEEP_TIME 120 - -/* - * SPI interfaces - */ -#define SPI_INTERFACES_COUNT 2 - -#define PIN_SPI_MISO 10 // MISO P0.17 -#define PIN_SPI_MOSI 11 // MOSI P0.15 -#define PIN_SPI_SCK 9 // SCK P0.13 - -// #define VEXT_ENABLE 7 // active low, powers the oled display and the lora antenna boost -#define BUTTON_PIN 0 - -#define ADC_CTRL 46 -#define ADC_CTRL_ENABLED HIGH -#define BATTERY_PIN 6 -#define ADC_CHANNEL ADC1_GPIO6_CHANNEL -#define ADC_MULTIPLIER 4.9 * 1.03 // Voltage divider is roughly 1:1 -#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // Voltage divider output is quite high - -#define USE_SX1262 - -#define LORA_DIO0 -1 // a No connect on the SX1262 module -#define LORA_RESET 12 -#define LORA_DIO1 14 // SX1262 IRQ -#define LORA_DIO2 13 // SX1262 BUSY -#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled - -#define LORA_SCK 9 -#define LORA_MISO 11 -#define LORA_MOSI 10 -#define LORA_CS 8 - -#define SX126X_CS LORA_CS -#define SX126X_DIO1 LORA_DIO1 -#define SX126X_BUSY LORA_DIO2 -#define SX126X_RESET LORA_RESET - -#define SX126X_DIO2_AS_RF_SWITCH -#define SX126X_DIO3_TCXO_VOLTAGE 1.8 \ No newline at end of file diff --git a/variants/heltec_wireless_paper/pins_arduino.h b/variants/heltec_wireless_paper/pins_arduino.h index 3e36d98f56..9e1d8a9a01 100644 --- a/variants/heltec_wireless_paper/pins_arduino.h +++ b/variants/heltec_wireless_paper/pins_arduino.h @@ -3,10 +3,16 @@ #include -static const uint8_t LED_BUILTIN = 18; +#define WIFI_Kit_32 true +#define DISPLAY_HEIGHT 64 +#define DISPLAY_WIDTH 128 + +static const uint8_t LED_BUILTIN = 35; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN +static const uint8_t KEY_BUILTIN = 0; + static const uint8_t TX = 43; static const uint8_t RX = 44; @@ -54,8 +60,11 @@ static const uint8_t T12 = 12; static const uint8_t T13 = 13; static const uint8_t T14 = 14; +static const uint8_t Vext = 45; +static const uint8_t LED = 18; + static const uint8_t RST_LoRa = 12; static const uint8_t BUSY_LoRa = 13; -static const uint8_t DIO1 = 14; +static const uint8_t DIO0 = 14; #endif /* Pins_Arduino_h */ diff --git a/variants/heltec_wireless_paper/variant.h b/variants/heltec_wireless_paper/variant.h index c41d6d9dfe..29b8bbbd14 100644 --- a/variants/heltec_wireless_paper/variant.h +++ b/variants/heltec_wireless_paper/variant.h @@ -1,12 +1,14 @@ #define LED_PIN 18 -#define BUTTON_PIN 0 -// I2C +// Enable bus for external periherals #define I2C_SDA SDA #define I2C_SCL SCL -// Display (E-Ink) #define USE_EINK + +/* + * eink display pins + */ #define PIN_EINK_CS 4 #define PIN_EINK_BUSY 7 #define PIN_EINK_DC 5 @@ -14,28 +16,32 @@ #define PIN_EINK_SCLK 3 #define PIN_EINK_MOSI 2 -// SPI +/* + * SPI interfaces + */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO 10 // MISO -#define PIN_SPI_MOSI 11 // MOSI -#define PIN_SPI_SCK 9 // SCK -// Power -#define VEXT_ENABLE 45 // Active low, powers the E-Ink display +#define PIN_SPI_MISO 10 // MISO P0.17 +#define PIN_SPI_MOSI 11 // MOSI P0.15 +#define PIN_SPI_SCK 9 // SCK P0.13 + +#define VEXT_ENABLE 45 // active low, powers the oled display and the lora antenna boost +#define BUTTON_PIN 0 + #define ADC_CTRL 19 #define BATTERY_PIN 20 #define ADC_CHANNEL ADC2_GPIO20_CHANNEL #define ADC_MULTIPLIER 2 // Voltage divider is roughly 1:1 #define BAT_MEASURE_ADC_UNIT 2 // Use ADC2 -#define ADC_ATTENUATION ADC_ATTEN_DB_12 // Voltage divider output is quite high +#define ADC_ATTENUATION ADC_ATTEN_DB_11 // Voltage divider output is quite high -// LoRa #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module #define LORA_RESET 12 #define LORA_DIO1 14 // SX1262 IRQ #define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled #define LORA_SCK 9 #define LORA_MISO 11 diff --git a/variants/heltec_wireless_paper_v1/pins_arduino.h b/variants/heltec_wireless_paper_v1/pins_arduino.h index 2bb44161ab..9e1d8a9a01 100644 --- a/variants/heltec_wireless_paper_v1/pins_arduino.h +++ b/variants/heltec_wireless_paper_v1/pins_arduino.h @@ -3,7 +3,11 @@ #include -static const uint8_t LED_BUILTIN = 18; +#define WIFI_Kit_32 true +#define DISPLAY_HEIGHT 64 +#define DISPLAY_WIDTH 128 + +static const uint8_t LED_BUILTIN = 35; #define BUILTIN_LED LED_BUILTIN // backward compatibility #define LED_BUILTIN LED_BUILTIN @@ -61,6 +65,6 @@ static const uint8_t LED = 18; static const uint8_t RST_LoRa = 12; static const uint8_t BUSY_LoRa = 13; -static const uint8_t DIO1 = 14; +static const uint8_t DIO0 = 14; #endif /* Pins_Arduino_h */ diff --git a/variants/heltec_wireless_paper_v1/variant.h b/variants/heltec_wireless_paper_v1/variant.h index c41d6d9dfe..29b8bbbd14 100644 --- a/variants/heltec_wireless_paper_v1/variant.h +++ b/variants/heltec_wireless_paper_v1/variant.h @@ -1,12 +1,14 @@ #define LED_PIN 18 -#define BUTTON_PIN 0 -// I2C +// Enable bus for external periherals #define I2C_SDA SDA #define I2C_SCL SCL -// Display (E-Ink) #define USE_EINK + +/* + * eink display pins + */ #define PIN_EINK_CS 4 #define PIN_EINK_BUSY 7 #define PIN_EINK_DC 5 @@ -14,28 +16,32 @@ #define PIN_EINK_SCLK 3 #define PIN_EINK_MOSI 2 -// SPI +/* + * SPI interfaces + */ #define SPI_INTERFACES_COUNT 2 -#define PIN_SPI_MISO 10 // MISO -#define PIN_SPI_MOSI 11 // MOSI -#define PIN_SPI_SCK 9 // SCK -// Power -#define VEXT_ENABLE 45 // Active low, powers the E-Ink display +#define PIN_SPI_MISO 10 // MISO P0.17 +#define PIN_SPI_MOSI 11 // MOSI P0.15 +#define PIN_SPI_SCK 9 // SCK P0.13 + +#define VEXT_ENABLE 45 // active low, powers the oled display and the lora antenna boost +#define BUTTON_PIN 0 + #define ADC_CTRL 19 #define BATTERY_PIN 20 #define ADC_CHANNEL ADC2_GPIO20_CHANNEL #define ADC_MULTIPLIER 2 // Voltage divider is roughly 1:1 #define BAT_MEASURE_ADC_UNIT 2 // Use ADC2 -#define ADC_ATTENUATION ADC_ATTEN_DB_12 // Voltage divider output is quite high +#define ADC_ATTENUATION ADC_ATTEN_DB_11 // Voltage divider output is quite high -// LoRa #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module #define LORA_RESET 12 #define LORA_DIO1 14 // SX1262 IRQ #define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled #define LORA_SCK 9 #define LORA_MISO 11 diff --git a/variants/heltec_wireless_tracker/platformio.ini b/variants/heltec_wireless_tracker/platformio.ini index c7ecce8eab..3259d563c3 100644 --- a/variants/heltec_wireless_tracker/platformio.ini +++ b/variants/heltec_wireless_tracker/platformio.ini @@ -1,7 +1,7 @@ [env:heltec-wireless-tracker] extends = esp32s3_base board = heltec_wireless_tracker -upload_protocol = esptool +upload_protocol = esp-builtin build_flags = ${esp32s3_base.build_flags} -I variants/heltec_wireless_tracker @@ -11,4 +11,4 @@ build_flags = lib_deps = ${esp32s3_base.lib_deps} - lovyan03/LovyanGFX@^1.1.8 + lovyan03/LovyanGFX@^1.1.8 \ No newline at end of file diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 6a67b00835..ef3e5a6458 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -20,7 +20,6 @@ lib_deps = debug_tool = jlink - ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds ;upload_protocol = jlink @@ -28,93 +27,26 @@ debug_tool = jlink ; Allows programming and debug via the RAK NanoDAP as the default debugger tool for the RAK4631 (it is only $10!) ; programming time is about the same as the bootloader version. ; For information on this see the meshtastic developers documentation for "Development on the NRF52" -[env:rak4631_dbg] +[env:rak4631_dap] extends = env:rak4631 board_level = extra - -; if the builtin version of openocd has a buggy version of semihosting, so use the external version -; platform_packages = platformio/tool-openocd@^3.1200.0 - -build_flags = - ${env:rak4631.build_flags} - -D USE_SEMIHOSTING - -lib_deps = - ${env:rak4631.lib_deps} - https://github.com/geeksville/Armduino-Semihosting.git#35b538fdf208c3530c1434cd099a08e486672ee4 - -; NOTE: the pyocd support for semihosting is buggy. So I switched to using the builtin platformio support for the stlink adapter which worked much better. -; However the built in openocd version in platformio has buggy support for TCP to semihosting. -; -; So I'm now trying the external openocd - but the openocd scripts for nrf52.cfg assume you are using a DAP adapter not an STLINK adapter. -; In theory I could change those scripts. But for now I'm trying going back to a DAP adapter but with the external openocd. - -upload_protocol = stlink +; pyocd pack --i nrf52840 ; eventually use platformio/tool-pyocd@^2.3600.0 instad -;upload_protocol = custom -;upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE - -; We want the initial breakpoint at setup() instead of main(). Also we want to enable semihosting at that point so instead of -; debug_init_break = tbreak setup -; we just turn off the platformio tbreak and do it in .gdbinit (where we have more flexibility for scripting) -; also we use a permanent breakpoint so it gets reused each time we restart the debugging session? -debug_init_break = tbreak setup - -; Note: add "monitor arm semihosting_redirect tcp 4444 all" if you want the stdout from the device to go to that port number instead -; (for use by meshtastic command line) -; monitor arm semihosting disable -; monitor debug_level 3 -; -; IMPORTANT: fileio must be disabled before using port 5555 - openocd ver 0.12 has a bug where if enabled it never properly parses the special :tt name -; for stdio access. -; monitor arm semihosting_redirect tcp 5555 stdio - -; Also note: it is _impossible_ to do non blocking reads on the semihost console port (an oversight when ARM specified the semihost API). -; So we'll neve be able to general purpose bi-directional communication with the device over semihosting. -debug_extra_cmds = - echo Running .gdbinit script - monitor arm semihosting enable - monitor arm semihosting_fileio enable - monitor arm semihosting_redirect disable - commands 1 - echo Breakpoint at setup() has semihosting console, connect to it with "telnet localhost 5555" - set wantSemihost = true - set useSoftDevice = false - end - +upload_protocol = custom +upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE ; Only reprogram the board if the code has changed debug_load_mode = modified ;debug_load_mode = manual -debug_tool = stlink -;debug_tool = custom -; debug_server = -; openocd -; -f -; /usr/local/share/openocd/scripts/interface/stlink.cfg -; -f -; /usr/local/share/openocd/scripts/target/nrf52.cfg -; $PLATFORMIO_CORE_DIR/packages/tool-openocd/openocd/scripts/interface/cmsis-dap.cfg - -; Allows programming and debug via the RAK NanoDAP as the default debugger tool for the RAK4631 (it is only $10!) -; programming time is about the same as the bootloader version. -; For information on this see the meshtastic developers documentation for "Development on the NRF52" +debug_tool = custom ; We manually pass in the elf file so that pyocd can reverse engineer FreeRTOS data (running threads, etc...) -;debug_server = -; pyocd -; gdbserver -; -j -; ${platformio.workspace_dir}/.. -; -t -; nrf52840 -; --semihosting -; --elf -; ${platformio.build_dir}/${this.__env__}/firmware.elf - -; If you want to debug the semihosting support you can turn on extra logging in pyocd with -; -L -; pyocd.debug.semihost.trace=debug - +debug_server = + pyocd + gdbserver + -t + nrf52840 + --elf + ${platformio.build_dir}/${this.__env__}/firmware.elf ; The following is not needed because it automatically tries do this ;debug_server_ready_pattern = -.*GDB server started on port \d+.* ;debug_port = localhost:3333 \ No newline at end of file diff --git a/variants/tlora_t3s3_v1/platformio.ini b/variants/tlora_t3s3_v1/platformio.ini index 0a57972803..002b2f224a 100644 --- a/variants/tlora_t3s3_v1/platformio.ini +++ b/variants/tlora_t3s3_v1/platformio.ini @@ -2,7 +2,7 @@ extends = esp32s3_base board = tlora-t3s3-v1 board_check = true -upload_protocol = esptool +upload_protocol = esp-builtin build_flags = ${esp32_base.build_flags} -D TLORA_T3S3_V1 -I variants/tlora_t3s3_v1 diff --git a/variants/wio-sdk-wm1110/platformio.ini b/variants/wio-sdk-wm1110/platformio.ini index 7667174289..cd3a76d02f 100644 --- a/variants/wio-sdk-wm1110/platformio.ini +++ b/variants/wio-sdk-wm1110/platformio.ini @@ -6,7 +6,7 @@ board = wio-sdk-wm1110 # Remove adafruit USB serial from the build (it is incompatible with using the ch340 serial chip on this board) build_unflags = ${nrf52840_base:build_unflags} -DUSBCON -DUSE_TINYUSB -; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e +board_level = extra build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-sdk-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. @@ -15,19 +15,5 @@ build_src_filter = ${nrf52_base.build_src_filter} +<../variants/wio-sdk-wm1110> lib_deps = ${nrf52840_base.lib_deps} debug_tool = jlink -;debug_tool = stlink -;debug_speed = 4000 -; No need to reflash if the binary hasn't changed -debug_load_mode = modified ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -upload_protocol = nrfutil -;upload_protocol = stlink -; we prefer to stop in setup() because we are an 'ardiuno' app -debug_init_break = tbreak setup - -; we need to turn off BLE/soft device if we are debugging otherwise it will watchdog reset us. -debug_extra_cmds = - echo Running .gdbinit script - commands 1 - set useSoftDevice = false - end +upload_protocol = jlink diff --git a/variants/wio-sdk-wm1110/softdevice/ble.h b/variants/wio-sdk-wm1110/softdevice/ble.h deleted file mode 100644 index 177b436ad8..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble.h +++ /dev/null @@ -1,652 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON BLE SoftDevice Common - @{ - @defgroup ble_api Events, type definitions and API calls - @{ - - @brief Module independent events, type definitions and API calls for the BLE SoftDevice. - - */ - -#ifndef BLE_H__ -#define BLE_H__ - -#include "ble_err.h" -#include "ble_gap.h" -#include "ble_gatt.h" -#include "ble_gattc.h" -#include "ble_gatts.h" -#include "ble_l2cap.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_COMMON_ENUMERATIONS Enumerations - * @{ */ - -/** - * @brief Common API SVC numbers. - */ -enum BLE_COMMON_SVCS { - SD_BLE_ENABLE = BLE_SVC_BASE, /**< Enable and initialize the BLE stack */ - SD_BLE_EVT_GET, /**< Get an event from the pending events queue. */ - SD_BLE_UUID_VS_ADD, /**< Add a Vendor Specific base UUID. */ - SD_BLE_UUID_DECODE, /**< Decode UUID bytes. */ - SD_BLE_UUID_ENCODE, /**< Encode UUID bytes. */ - SD_BLE_VERSION_GET, /**< Get the local version information (company ID, Link Layer Version, Link Layer Subversion). */ - SD_BLE_USER_MEM_REPLY, /**< User Memory Reply. */ - SD_BLE_OPT_SET, /**< Set a BLE option. */ - SD_BLE_OPT_GET, /**< Get a BLE option. */ - SD_BLE_CFG_SET, /**< Add a configuration to the BLE stack. */ - SD_BLE_UUID_VS_REMOVE, /**< Remove a Vendor Specific base UUID. */ -}; - -/** - * @brief BLE Module Independent Event IDs. - */ -enum BLE_COMMON_EVTS { - BLE_EVT_USER_MEM_REQUEST = BLE_EVT_BASE + 0, /**< User Memory request. See @ref ble_evt_user_mem_request_t - \n Reply with @ref sd_ble_user_mem_reply. */ - BLE_EVT_USER_MEM_RELEASE = BLE_EVT_BASE + 1, /**< User Memory release. See @ref ble_evt_user_mem_release_t */ -}; - -/**@brief BLE Connection Configuration IDs. - * - * IDs that uniquely identify a connection configuration. - */ -enum BLE_CONN_CFGS { - BLE_CONN_CFG_GAP = BLE_CONN_CFG_BASE + 0, /**< BLE GAP specific connection configuration. */ - BLE_CONN_CFG_GATTC = BLE_CONN_CFG_BASE + 1, /**< BLE GATTC specific connection configuration. */ - BLE_CONN_CFG_GATTS = BLE_CONN_CFG_BASE + 2, /**< BLE GATTS specific connection configuration. */ - BLE_CONN_CFG_GATT = BLE_CONN_CFG_BASE + 3, /**< BLE GATT specific connection configuration. */ - BLE_CONN_CFG_L2CAP = BLE_CONN_CFG_BASE + 4, /**< BLE L2CAP specific connection configuration. */ -}; - -/**@brief BLE Common Configuration IDs. - * - * IDs that uniquely identify a common configuration. - */ -enum BLE_COMMON_CFGS { - BLE_COMMON_CFG_VS_UUID = BLE_CFG_BASE, /**< Vendor specific base UUID configuration */ -}; - -/**@brief Common Option IDs. - * IDs that uniquely identify a common option. - */ -enum BLE_COMMON_OPTS { - BLE_COMMON_OPT_PA_LNA = BLE_OPT_BASE + 0, /**< PA and LNA options */ - BLE_COMMON_OPT_CONN_EVT_EXT = BLE_OPT_BASE + 1, /**< Extended connection events option */ - BLE_COMMON_OPT_EXTENDED_RC_CAL = BLE_OPT_BASE + 2, /**< Extended RC calibration option */ -}; - -/** @} */ - -/** @addtogroup BLE_COMMON_DEFINES Defines - * @{ */ - -/** @brief Required pointer alignment for BLE Events. - */ -#define BLE_EVT_PTR_ALIGNMENT 4 - -/** @brief Leaves the maximum of the two arguments. - */ -#define BLE_MAX(a, b) ((a) < (b) ? (b) : (a)) - -/** @brief Maximum possible length for BLE Events. - * @note The highest value used for @ref ble_gatt_conn_cfg_t::att_mtu in any connection configuration shall be used as a - * parameter. If that value has not been configured for any connections then @ref BLE_GATT_ATT_MTU_DEFAULT must be used instead. - */ -#define BLE_EVT_LEN_MAX(ATT_MTU) \ - (offsetof(ble_evt_t, evt.gattc_evt.params.prim_srvc_disc_rsp.services) + ((ATT_MTU)-1) / 4 * sizeof(ble_gattc_service_t)) - -/** @defgroup BLE_USER_MEM_TYPES User Memory Types - * @{ */ -#define BLE_USER_MEM_TYPE_INVALID 0x00 /**< Invalid User Memory Types. */ -#define BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES 0x01 /**< User Memory for GATTS queued writes. */ -/** @} */ - -/** @defgroup BLE_UUID_VS_COUNTS Vendor Specific base UUID counts - * @{ - */ -#define BLE_UUID_VS_COUNT_DEFAULT 10 /**< Default VS UUID count. */ -#define BLE_UUID_VS_COUNT_MAX 254 /**< Maximum VS UUID count. */ -/** @} */ - -/** @defgroup BLE_COMMON_CFG_DEFAULTS Configuration defaults. - * @{ - */ -#define BLE_CONN_CFG_TAG_DEFAULT 0 /**< Default configuration tag, SoftDevice default connection configuration. */ - -/** @} */ - -/** @} */ - -/** @addtogroup BLE_COMMON_STRUCTURES Structures - * @{ */ - -/**@brief User Memory Block. */ -typedef struct { - uint8_t *p_mem; /**< Pointer to the start of the user memory block. */ - uint16_t len; /**< Length in bytes of the user memory block. */ -} ble_user_mem_block_t; - -/**@brief Event structure for @ref BLE_EVT_USER_MEM_REQUEST. */ -typedef struct { - uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ -} ble_evt_user_mem_request_t; - -/**@brief Event structure for @ref BLE_EVT_USER_MEM_RELEASE. */ -typedef struct { - uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */ - ble_user_mem_block_t mem_block; /**< User memory block */ -} ble_evt_user_mem_release_t; - -/**@brief Event structure for events not associated with a specific function module. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which this event occurred. */ - union { - ble_evt_user_mem_request_t user_mem_request; /**< User Memory Request Event Parameters. */ - ble_evt_user_mem_release_t user_mem_release; /**< User Memory Release Event Parameters. */ - } params; /**< Event parameter union. */ -} ble_common_evt_t; - -/**@brief BLE Event header. */ -typedef struct { - uint16_t evt_id; /**< Value from a BLE__EVT series. */ - uint16_t evt_len; /**< Length in octets including this header. */ -} ble_evt_hdr_t; - -/**@brief Common BLE Event type, wrapping the module specific event reports. */ -typedef struct { - ble_evt_hdr_t header; /**< Event header. */ - union { - ble_common_evt_t common_evt; /**< Common Event, evt_id in BLE_EVT_* series. */ - ble_gap_evt_t gap_evt; /**< GAP originated event, evt_id in BLE_GAP_EVT_* series. */ - ble_gattc_evt_t gattc_evt; /**< GATT client originated event, evt_id in BLE_GATTC_EVT* series. */ - ble_gatts_evt_t gatts_evt; /**< GATT server originated event, evt_id in BLE_GATTS_EVT* series. */ - ble_l2cap_evt_t l2cap_evt; /**< L2CAP originated event, evt_id in BLE_L2CAP_EVT* series. */ - } evt; /**< Event union. */ -} ble_evt_t; - -/** - * @brief Version Information. - */ -typedef struct { - uint8_t version_number; /**< Link Layer Version number. See - https://www.bluetooth.org/en-us/specification/assigned-numbers/link-layer for assigned values. */ - uint16_t company_id; /**< Company ID, Nordic Semiconductor's company ID is 89 (0x0059) - (https://www.bluetooth.org/apps/content/Default.aspx?doc_id=49708). */ - uint16_t - subversion_number; /**< Link Layer Sub Version number, corresponds to the SoftDevice Config ID or Firmware ID (FWID). */ -} ble_version_t; - -/** - * @brief Configuration parameters for the PA and LNA. - */ -typedef struct { - uint8_t enable : 1; /**< Enable toggling for this amplifier */ - uint8_t active_high : 1; /**< Set the pin to be active high */ - uint8_t gpio_pin : 6; /**< The GPIO pin to toggle for this amplifier */ -} ble_pa_lna_cfg_t; - -/** - * @brief PA & LNA GPIO toggle configuration - * - * This option configures the SoftDevice to toggle pins when the radio is active for use with a power amplifier and/or - * a low noise amplifier. - * - * Toggling the pins is achieved by using two PPI channels and a GPIOTE channel. The hardware channel IDs are provided - * by the application and should be regarded as reserved as long as any PA/LNA toggling is enabled. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * @note Setting this option while the radio is in use (i.e. any of the roles are active) may have undefined consequences - * and must be avoided by the application. - */ -typedef struct { - ble_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */ - ble_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */ - - uint8_t ppi_ch_id_set; /**< PPI channel used for radio pin setting */ - uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */ - uint8_t gpiote_ch_id; /**< GPIOTE channel used for radio pin toggling */ -} ble_common_opt_pa_lna_t; - -/** - * @brief Configuration of extended BLE connection events. - * - * When enabled the SoftDevice will dynamically extend the connection event when possible. - * - * The connection event length is controlled by the connection configuration as set by @ref ble_gap_conn_cfg_t::event_length. - * The connection event can be extended if there is time to send another packet pair before the start of the next connection - * interval, and if there are no conflicts with other BLE roles requesting radio time. - * - * @note @ref sd_ble_opt_get is not supported for this option. - */ -typedef struct { - uint8_t enable : 1; /**< Enable extended BLE connection events, disabled by default. */ -} ble_common_opt_conn_evt_ext_t; - -/** - * @brief Enable/disable extended RC calibration. - * - * If extended RC calibration is enabled and the internal RC oscillator (@ref NRF_CLOCK_LF_SRC_RC) is used as the SoftDevice - * LFCLK source, the SoftDevice as a peripheral will by default try to increase the receive window if two consecutive packets - * are not received. If it turns out that the packets were not received due to clock drift, the RC calibration is started. - * This calibration comes in addition to the periodic calibration that is configured by @ref sd_softdevice_enable(). When - * using only peripheral connections, the periodic calibration can therefore be configured with a much longer interval as the - * peripheral will be able to detect and adjust automatically to clock drift, and calibrate on demand. - * - * If extended RC calibration is disabled and the internal RC oscillator is used as the SoftDevice LFCLK source, the - * RC oscillator is calibrated periodically as configured by @ref sd_softdevice_enable(). - * - * @note @ref sd_ble_opt_get is not supported for this option. - */ -typedef struct { - uint8_t enable : 1; /**< Enable extended RC calibration, enabled by default. */ -} ble_common_opt_extended_rc_cal_t; - -/**@brief Option structure for common options. */ -typedef union { - ble_common_opt_pa_lna_t pa_lna; /**< Parameters for controlling PA and LNA pin toggling. */ - ble_common_opt_conn_evt_ext_t conn_evt_ext; /**< Parameters for enabling extended connection events. */ - ble_common_opt_extended_rc_cal_t extended_rc_cal; /**< Parameters for enabling extended RC calibration. */ -} ble_common_opt_t; - -/**@brief Common BLE Option type, wrapping the module specific options. */ -typedef union { - ble_common_opt_t common_opt; /**< COMMON options, opt_id in @ref BLE_COMMON_OPTS series. */ - ble_gap_opt_t gap_opt; /**< GAP option, opt_id in @ref BLE_GAP_OPTS series. */ - ble_gattc_opt_t gattc_opt; /**< GATTC option, opt_id in @ref BLE_GATTC_OPTS series. */ -} ble_opt_t; - -/**@brief BLE connection configuration type, wrapping the module specific configurations, set with - * @ref sd_ble_cfg_set. - * - * @note Connection configurations don't have to be set. - * In the case that no configurations has been set, or fewer connection configurations has been set than enabled connections, - * the default connection configuration will be automatically added for the remaining connections. - * When creating connections with the default configuration, @ref BLE_CONN_CFG_TAG_DEFAULT should be used in - * place of @ref ble_conn_cfg_t::conn_cfg_tag. - * - * @sa sd_ble_gap_adv_start() - * @sa sd_ble_gap_connect() - * - * @mscs - * @mmsc{@ref BLE_CONN_CFG} - * @endmscs - - */ -typedef struct { - uint8_t conn_cfg_tag; /**< The application chosen tag it can use with the - @ref sd_ble_gap_adv_start() and @ref sd_ble_gap_connect() calls - to select this configuration when creating a connection. - Must be different for all connection configurations added and not @ref BLE_CONN_CFG_TAG_DEFAULT. */ - union { - ble_gap_conn_cfg_t gap_conn_cfg; /**< GAP connection configuration, cfg_id is @ref BLE_CONN_CFG_GAP. */ - ble_gattc_conn_cfg_t gattc_conn_cfg; /**< GATTC connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTC. */ - ble_gatts_conn_cfg_t gatts_conn_cfg; /**< GATTS connection configuration, cfg_id is @ref BLE_CONN_CFG_GATTS. */ - ble_gatt_conn_cfg_t gatt_conn_cfg; /**< GATT connection configuration, cfg_id is @ref BLE_CONN_CFG_GATT. */ - ble_l2cap_conn_cfg_t l2cap_conn_cfg; /**< L2CAP connection configuration, cfg_id is @ref BLE_CONN_CFG_L2CAP. */ - } params; /**< Connection configuration union. */ -} ble_conn_cfg_t; - -/** - * @brief Configuration of Vendor Specific base UUIDs, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_PARAM Too many UUIDs configured. - */ -typedef struct { - uint8_t vs_uuid_count; /**< Number of 128-bit Vendor Specific base UUID bases to allocate memory for. - Default value is @ref BLE_UUID_VS_COUNT_DEFAULT. Maximum value is - @ref BLE_UUID_VS_COUNT_MAX. */ -} ble_common_cfg_vs_uuid_t; - -/**@brief Common BLE Configuration type, wrapping the common configurations. */ -typedef union { - ble_common_cfg_vs_uuid_t vs_uuid_cfg; /**< Vendor Specific base UUID configuration, cfg_id is @ref BLE_COMMON_CFG_VS_UUID. */ -} ble_common_cfg_t; - -/**@brief BLE Configuration type, wrapping the module specific configurations. */ -typedef union { - ble_conn_cfg_t conn_cfg; /**< Connection specific configurations, cfg_id in @ref BLE_CONN_CFGS series. */ - ble_common_cfg_t common_cfg; /**< Global common configurations, cfg_id in @ref BLE_COMMON_CFGS series. */ - ble_gap_cfg_t gap_cfg; /**< Global GAP configurations, cfg_id in @ref BLE_GAP_CFGS series. */ - ble_gatts_cfg_t gatts_cfg; /**< Global GATTS configuration, cfg_id in @ref BLE_GATTS_CFGS series. */ -} ble_cfg_t; - -/** @} */ - -/** @addtogroup BLE_COMMON_FUNCTIONS Functions - * @{ */ - -/**@brief Enable the BLE stack - * - * @param[in, out] p_app_ram_base Pointer to a variable containing the start address of the - * application RAM region (APP_RAM_BASE). On return, this will - * contain the minimum start address of the application RAM region - * required by the SoftDevice for this configuration. - * @warning After this call, the SoftDevice may generate several events. The list of events provided - * below require the application to initiate a SoftDevice API call. The corresponding API call - * is referenced in the event documentation. - * If the application fails to do so, the BLE connection may timeout, or the SoftDevice may stop - * communicating with the peer device. - * - @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST - * - @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST - * - @ref BLE_GAP_EVT_SEC_INFO_REQUEST - * - @ref BLE_GAP_EVT_SEC_REQUEST - * - @ref BLE_GAP_EVT_AUTH_KEY_REQUEST - * - @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST - * - @ref BLE_EVT_USER_MEM_REQUEST - * - @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST - * - * @note The memory requirement for a specific configuration will not increase between SoftDevices - * with the same major version number. - * - * @note At runtime the IC's RAM is split into 2 regions: The SoftDevice RAM region is located - * between 0x20000000 and APP_RAM_BASE-1 and the application's RAM region is located between - * APP_RAM_BASE and the start of the call stack. - * - * @details This call initializes the BLE stack, no BLE related function other than @ref - * sd_ble_cfg_set can be called before this one. - * - * @mscs - * @mmsc{@ref BLE_COMMON_ENABLE} - * @endmscs - * - * @retval ::NRF_SUCCESS The BLE stack has been initialized successfully. - * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized and cannot be reinitialized. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_NO_MEM One or more of the following is true: - * - The amount of memory assigned to the SoftDevice by *p_app_ram_base is not - * large enough to fit this configuration's memory requirement. Check *p_app_ram_base - * and set the start address of the application RAM region accordingly. - * - Dynamic part of the SoftDevice RAM region is larger then 64 kB which - * is currently not supported. - * @retval ::NRF_ERROR_RESOURCES The total number of L2CAP Channels configured using @ref sd_ble_cfg_set is too large. - */ -SVCALL(SD_BLE_ENABLE, uint32_t, sd_ble_enable(uint32_t *p_app_ram_base)); - -/**@brief Add configurations for the BLE stack - * - * @param[in] cfg_id Config ID, see @ref BLE_CONN_CFGS, @ref BLE_COMMON_CFGS, @ref - * BLE_GAP_CFGS or @ref BLE_GATTS_CFGS. - * @param[in] p_cfg Pointer to a ble_cfg_t structure containing the configuration value. - * @param[in] app_ram_base The start address of the application RAM region (APP_RAM_BASE). - * See @ref sd_ble_enable for details about APP_RAM_BASE. - * - * @note The memory requirement for a specific configuration will not increase between SoftDevices - * with the same major version number. - * - * @note If a configuration is set more than once, the last one set is the one that takes effect on - * @ref sd_ble_enable. - * - * @note Any part of the BLE stack that is NOT configured with @ref sd_ble_cfg_set will have default - * configuration. - * - * @note @ref sd_ble_cfg_set may be called at any time when the SoftDevice is enabled (see @ref - * sd_softdevice_enable) while the BLE part of the SoftDevice is not enabled (see @ref - * sd_ble_enable). - * - * @note Error codes for the configurations are described in the configuration structs. - * - * @mscs - * @mmsc{@ref BLE_COMMON_ENABLE} - * @endmscs - * - * @retval ::NRF_SUCCESS The configuration has been added successfully. - * @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid cfg_id supplied. - * @retval ::NRF_ERROR_NO_MEM The amount of memory assigned to the SoftDevice by app_ram_base is not - * large enough to fit this configuration's memory requirement. - */ -SVCALL(SD_BLE_CFG_SET, uint32_t, sd_ble_cfg_set(uint32_t cfg_id, ble_cfg_t const *p_cfg, uint32_t app_ram_base)); - -/**@brief Get an event from the pending events queue. - * - * @param[out] p_dest Pointer to buffer to be filled in with an event, or NULL to retrieve the event length. - * This buffer must be aligned to the extend defined by @ref BLE_EVT_PTR_ALIGNMENT. - * The buffer should be interpreted as a @ref ble_evt_t struct. - * @param[in, out] p_len Pointer the length of the buffer, on return it is filled with the event length. - * - * @details This call allows the application to pull a BLE event from the BLE stack. The application is signaled that - * an event is available from the BLE stack by the triggering of the SD_EVT_IRQn interrupt. - * The application is free to choose whether to call this function from thread mode (main context) or directly from the - * Interrupt Service Routine that maps to SD_EVT_IRQn. In any case however, and because the BLE stack runs at a higher - * priority than the application, this function should be called in a loop (until @ref NRF_ERROR_NOT_FOUND is returned) - * every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the BLE stack. Failure to do so - * could potentially leave events in the internal queue without the application being aware of this fact. - * - * Sizing the p_dest buffer is equally important, since the application needs to provide all the memory necessary for the event to - * be copied into application memory. If the buffer provided is not large enough to fit the entire contents of the event, - * @ref NRF_ERROR_DATA_SIZE will be returned and the application can then call again with a larger buffer size. - * The maximum possible event length is defined by @ref BLE_EVT_LEN_MAX. The application may also "peek" the event length - * by providing p_dest as a NULL pointer and inspecting the value of *p_len upon return: - * - * \code - * uint16_t len; - * errcode = sd_ble_evt_get(NULL, &len); - * \endcode - * - * @mscs - * @mmsc{@ref BLE_COMMON_IRQ_EVT_MSC} - * @mmsc{@ref BLE_COMMON_THREAD_EVT_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Event pulled and stored into the supplied buffer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied. - * @retval ::NRF_ERROR_NOT_FOUND No events ready to be pulled. - * @retval ::NRF_ERROR_DATA_SIZE Event ready but could not fit into the supplied buffer. - */ -SVCALL(SD_BLE_EVT_GET, uint32_t, sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len)); - -/**@brief Add a Vendor Specific base UUID. - * - * @details This call enables the application to add a Vendor Specific base UUID to the BLE stack's table, for later - * use with all other modules and APIs. This then allows the application to use the shorter, 24-bit @ref ble_uuid_t - * format when dealing with both 16-bit and 128-bit UUIDs without having to check for lengths and having split code - * paths. This is accomplished by extending the grouping mechanism that the Bluetooth SIG standard base UUID uses - * for all other 128-bit UUIDs. The type field in the @ref ble_uuid_t structure is an index (relative to - * @ref BLE_UUID_TYPE_VENDOR_BEGIN) to the table populated by multiple calls to this function, and the UUID field - * in the same structure contains the 2 bytes at indexes 12 and 13. The number of possible 128-bit UUIDs available to - * the application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536, - * although restricted to modifying bytes 12 and 13 for each of the entries in the supplied array. - * - * @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by - * the 16-bit uuid field in @ref ble_uuid_t. - * - * @note If a UUID is already present in the BLE stack's internal table, the corresponding index will be returned in - * p_uuid_type along with an @ref NRF_SUCCESS error code. - * - * @param[in] p_vs_uuid Pointer to a 16-octet (128-bit) little endian Vendor Specific base UUID disregarding - * bytes 12 and 13. - * @param[out] p_uuid_type Pointer to a uint8_t where the type field in @ref ble_uuid_t corresponding to this UUID will be - * stored. - * - * @retval ::NRF_SUCCESS Successfully added the Vendor Specific base UUID. - * @retval ::NRF_ERROR_INVALID_ADDR If p_vs_uuid or p_uuid_type is NULL or invalid. - * @retval ::NRF_ERROR_NO_MEM If there are no more free slots for VS UUIDs. - */ -SVCALL(SD_BLE_UUID_VS_ADD, uint32_t, sd_ble_uuid_vs_add(ble_uuid128_t const *p_vs_uuid, uint8_t *p_uuid_type)); - -/**@brief Remove a Vendor Specific base UUID. - * - * @details This call removes a Vendor Specific base UUID. This function allows - * the application to reuse memory allocated for Vendor Specific base UUIDs. - * - * @note Currently this function can only be called with a p_uuid_type set to @ref BLE_UUID_TYPE_UNKNOWN or the last added UUID - * type. - * - * @param[inout] p_uuid_type Pointer to a uint8_t where its value matches the UUID type in @ref ble_uuid_t::type to be removed. - * If the type is set to @ref BLE_UUID_TYPE_UNKNOWN, or the pointer is NULL, the last Vendor Specific - * base UUID will be removed. If the function returns successfully, the UUID type that was removed will - * be written back to @p p_uuid_type. If function returns with a failure, it contains the last type that - * is in use by the ATT Server. - * - * @retval ::NRF_SUCCESS Successfully removed the Vendor Specific base UUID. - * @retval ::NRF_ERROR_INVALID_ADDR If p_uuid_type is invalid. - * @retval ::NRF_ERROR_INVALID_PARAM If p_uuid_type points to a non-valid UUID type. - * @retval ::NRF_ERROR_FORBIDDEN If the Vendor Specific base UUID is in use by the ATT Server. - */ -SVCALL(SD_BLE_UUID_VS_REMOVE, uint32_t, sd_ble_uuid_vs_remove(uint8_t *p_uuid_type)); - -/** @brief Decode little endian raw UUID bytes (16-bit or 128-bit) into a 24 bit @ref ble_uuid_t structure. - * - * @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared - * to the corresponding ones in each entry of the table of Vendor Specific base UUIDs - * to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index - * relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type. - * - * @note If the UUID length supplied is 2, then the type set by this call will always be @ref BLE_UUID_TYPE_BLE. - * - * @param[in] uuid_le_len Length in bytes of the buffer pointed to by p_uuid_le (must be 2 or 16 bytes). - * @param[in] p_uuid_le Pointer pointing to little endian raw UUID bytes. - * @param[out] p_uuid Pointer to a @ref ble_uuid_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Successfully decoded into the @ref ble_uuid_t structure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid UUID length. - * @retval ::NRF_ERROR_NOT_FOUND For a 128-bit UUID, no match in the populated table of UUIDs. - */ -SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uint8_t const *p_uuid_le, ble_uuid_t *p_uuid)); - -/** @brief Encode a @ref ble_uuid_t structure into little endian raw UUID bytes (16-bit or 128-bit). - * - * @note The pointer to the destination buffer p_uuid_le may be NULL, in which case only the validity and size of p_uuid is - * computed. - * - * @param[in] p_uuid Pointer to a @ref ble_uuid_t structure that will be encoded into bytes. - * @param[out] p_uuid_le_len Pointer to a uint8_t that will be filled with the encoded length (2 or 16 bytes). - * @param[out] p_uuid_le Pointer to a buffer where the little endian raw UUID bytes (2 or 16) will be stored. - * - * @retval ::NRF_SUCCESS Successfully encoded into the buffer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid UUID type. - */ -SVCALL(SD_BLE_UUID_ENCODE, uint32_t, sd_ble_uuid_encode(ble_uuid_t const *p_uuid, uint8_t *p_uuid_le_len, uint8_t *p_uuid_le)); - -/**@brief Get Version Information. - * - * @details This call allows the application to get the BLE stack version information. - * - * @param[out] p_version Pointer to a ble_version_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Version information stored successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy (typically doing a locally-initiated disconnection procedure). - */ -SVCALL(SD_BLE_VERSION_GET, uint32_t, sd_ble_version_get(ble_version_t *p_version)); - -/**@brief Provide a user memory block. - * - * @note This call can only be used as a response to a @ref BLE_EVT_USER_MEM_REQUEST event issued to the application. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_block Pointer to a user memory block structure or NULL if memory is managed by the application. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully queued a response to the peer. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid user memory block length supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection state or no user memory request pending. - */ -SVCALL(SD_BLE_USER_MEM_REPLY, uint32_t, sd_ble_user_mem_reply(uint16_t conn_handle, ble_user_mem_block_t const *p_block)); - -/**@brief Set a BLE option. - * - * @details This call allows the application to set the value of an option. - * - * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS, @ref BLE_GAP_OPTS, and @ref BLE_GATTC_OPTS. - * @param[in] p_opt Pointer to a @ref ble_opt_t structure containing the option value. - * - * @retval ::NRF_SUCCESS Option set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Unable to set the parameter at this time. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. - */ -SVCALL(SD_BLE_OPT_SET, uint32_t, sd_ble_opt_set(uint32_t opt_id, ble_opt_t const *p_opt)); - -/**@brief Get a BLE option. - * - * @details This call allows the application to retrieve the value of an option. - * - * @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS and @ref BLE_GAP_OPTS. - * @param[out] p_opt Pointer to a ble_opt_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Option retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Unable to retrieve the parameter at this time. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed. - * @retval ::NRF_ERROR_NOT_SUPPORTED This option is not supported. - * - */ -SVCALL(SD_BLE_OPT_GET, uint32_t, sd_ble_opt_get(uint32_t opt_id, ble_opt_t *p_opt)); - -/** @} */ -#ifdef __cplusplus -} -#endif -#endif /* BLE_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_err.h b/variants/wio-sdk-wm1110/softdevice/ble_err.h deleted file mode 100644 index d20f6d1416..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_err.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @addtogroup nrf_error - @{ - @ingroup BLE_COMMON - @} - - @defgroup ble_err General error codes - @{ - - @brief General error code definitions for the BLE API. - - @ingroup BLE_COMMON -*/ -#ifndef NRF_BLE_ERR_H__ -#define NRF_BLE_ERR_H__ - -#include "nrf_error.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* @defgroup BLE_ERRORS Error Codes - * @{ */ -#define BLE_ERROR_NOT_ENABLED (NRF_ERROR_STK_BASE_NUM + 0x001) /**< @ref sd_ble_enable has not been called. */ -#define BLE_ERROR_INVALID_CONN_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x002) /**< Invalid connection handle. */ -#define BLE_ERROR_INVALID_ATTR_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x003) /**< Invalid attribute handle. */ -#define BLE_ERROR_INVALID_ADV_HANDLE (NRF_ERROR_STK_BASE_NUM + 0x004) /**< Invalid advertising handle. */ -#define BLE_ERROR_INVALID_ROLE (NRF_ERROR_STK_BASE_NUM + 0x005) /**< Invalid role. */ -#define BLE_ERROR_BLOCKED_BY_OTHER_LINKS \ - (NRF_ERROR_STK_BASE_NUM + 0x006) /**< The attempt to change link settings failed due to the scheduling of other links. */ -/** @} */ - -/** @defgroup BLE_ERROR_SUBRANGES Module specific error code subranges - * @brief Assignment of subranges for module specific error codes. - * @note For specific error codes, see ble_.h or ble_error_.h. - * @{ */ -#define NRF_L2CAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x100) /**< L2CAP specific errors. */ -#define NRF_GAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x200) /**< GAP specific errors. */ -#define NRF_GATTC_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x300) /**< GATT client specific errors. */ -#define NRF_GATTS_ERR_BASE (NRF_ERROR_STK_BASE_NUM + 0x400) /**< GATT server specific errors. */ -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif - -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gap.h b/variants/wio-sdk-wm1110/softdevice/ble_gap.h deleted file mode 100644 index 8ebdfa82b0..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_gap.h +++ /dev/null @@ -1,2895 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GAP Generic Access Profile (GAP) - @{ - @brief Definitions and prototypes for the GAP interface. - */ - -#ifndef BLE_GAP_H__ -#define BLE_GAP_H__ - -#include "ble_err.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup BLE_GAP_ENUMERATIONS Enumerations - * @{ */ - -/**@brief GAP API SVC numbers. - */ -enum BLE_GAP_SVCS { - SD_BLE_GAP_ADDR_SET = BLE_GAP_SVC_BASE, /**< Set own Bluetooth Address. */ - SD_BLE_GAP_ADDR_GET = BLE_GAP_SVC_BASE + 1, /**< Get own Bluetooth Address. */ - SD_BLE_GAP_WHITELIST_SET = BLE_GAP_SVC_BASE + 2, /**< Set active whitelist. */ - SD_BLE_GAP_DEVICE_IDENTITIES_SET = BLE_GAP_SVC_BASE + 3, /**< Set device identity list. */ - SD_BLE_GAP_PRIVACY_SET = BLE_GAP_SVC_BASE + 4, /**< Set Privacy settings*/ - SD_BLE_GAP_PRIVACY_GET = BLE_GAP_SVC_BASE + 5, /**< Get Privacy settings*/ - SD_BLE_GAP_ADV_SET_CONFIGURE = BLE_GAP_SVC_BASE + 6, /**< Configure an advertising set. */ - SD_BLE_GAP_ADV_START = BLE_GAP_SVC_BASE + 7, /**< Start Advertising. */ - SD_BLE_GAP_ADV_STOP = BLE_GAP_SVC_BASE + 8, /**< Stop Advertising. */ - SD_BLE_GAP_CONN_PARAM_UPDATE = BLE_GAP_SVC_BASE + 9, /**< Connection Parameter Update. */ - SD_BLE_GAP_DISCONNECT = BLE_GAP_SVC_BASE + 10, /**< Disconnect. */ - SD_BLE_GAP_TX_POWER_SET = BLE_GAP_SVC_BASE + 11, /**< Set TX Power. */ - SD_BLE_GAP_APPEARANCE_SET = BLE_GAP_SVC_BASE + 12, /**< Set Appearance. */ - SD_BLE_GAP_APPEARANCE_GET = BLE_GAP_SVC_BASE + 13, /**< Get Appearance. */ - SD_BLE_GAP_PPCP_SET = BLE_GAP_SVC_BASE + 14, /**< Set PPCP. */ - SD_BLE_GAP_PPCP_GET = BLE_GAP_SVC_BASE + 15, /**< Get PPCP. */ - SD_BLE_GAP_DEVICE_NAME_SET = BLE_GAP_SVC_BASE + 16, /**< Set Device Name. */ - SD_BLE_GAP_DEVICE_NAME_GET = BLE_GAP_SVC_BASE + 17, /**< Get Device Name. */ - SD_BLE_GAP_AUTHENTICATE = BLE_GAP_SVC_BASE + 18, /**< Initiate Pairing/Bonding. */ - SD_BLE_GAP_SEC_PARAMS_REPLY = BLE_GAP_SVC_BASE + 19, /**< Reply with Security Parameters. */ - SD_BLE_GAP_AUTH_KEY_REPLY = BLE_GAP_SVC_BASE + 20, /**< Reply with an authentication key. */ - SD_BLE_GAP_LESC_DHKEY_REPLY = BLE_GAP_SVC_BASE + 21, /**< Reply with an LE Secure Connections DHKey. */ - SD_BLE_GAP_KEYPRESS_NOTIFY = BLE_GAP_SVC_BASE + 22, /**< Notify of a keypress during an authentication procedure. */ - SD_BLE_GAP_LESC_OOB_DATA_GET = BLE_GAP_SVC_BASE + 23, /**< Get the local LE Secure Connections OOB data. */ - SD_BLE_GAP_LESC_OOB_DATA_SET = BLE_GAP_SVC_BASE + 24, /**< Set the remote LE Secure Connections OOB data. */ - SD_BLE_GAP_ENCRYPT = BLE_GAP_SVC_BASE + 25, /**< Initiate encryption procedure. */ - SD_BLE_GAP_SEC_INFO_REPLY = BLE_GAP_SVC_BASE + 26, /**< Reply with Security Information. */ - SD_BLE_GAP_CONN_SEC_GET = BLE_GAP_SVC_BASE + 27, /**< Obtain connection security level. */ - SD_BLE_GAP_RSSI_START = BLE_GAP_SVC_BASE + 28, /**< Start reporting of changes in RSSI. */ - SD_BLE_GAP_RSSI_STOP = BLE_GAP_SVC_BASE + 29, /**< Stop reporting of changes in RSSI. */ - SD_BLE_GAP_SCAN_START = BLE_GAP_SVC_BASE + 30, /**< Start Scanning. */ - SD_BLE_GAP_SCAN_STOP = BLE_GAP_SVC_BASE + 31, /**< Stop Scanning. */ - SD_BLE_GAP_CONNECT = BLE_GAP_SVC_BASE + 32, /**< Connect. */ - SD_BLE_GAP_CONNECT_CANCEL = BLE_GAP_SVC_BASE + 33, /**< Cancel ongoing connection procedure. */ - SD_BLE_GAP_RSSI_GET = BLE_GAP_SVC_BASE + 34, /**< Get the last RSSI sample. */ - SD_BLE_GAP_PHY_UPDATE = BLE_GAP_SVC_BASE + 35, /**< Initiate or respond to a PHY Update Procedure. */ - SD_BLE_GAP_DATA_LENGTH_UPDATE = BLE_GAP_SVC_BASE + 36, /**< Initiate or respond to a Data Length Update Procedure. */ - SD_BLE_GAP_QOS_CHANNEL_SURVEY_START = BLE_GAP_SVC_BASE + 37, /**< Start Quality of Service (QoS) channel survey module. */ - SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP = BLE_GAP_SVC_BASE + 38, /**< Stop Quality of Service (QoS) channel survey module. */ - SD_BLE_GAP_ADV_ADDR_GET = BLE_GAP_SVC_BASE + 39, /**< Get the Address used on air while Advertising. */ - SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET = BLE_GAP_SVC_BASE + 40, /**< Get the next connection event counter. */ - SD_BLE_GAP_CONN_EVT_TRIGGER_START = BLE_GAP_SVC_BASE + 41, /** Start triggering a given task on connection event start. */ - SD_BLE_GAP_CONN_EVT_TRIGGER_STOP = - BLE_GAP_SVC_BASE + 42, /** Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. */ -}; - -/**@brief GAP Event IDs. - * IDs that uniquely identify an event coming from the stack to the application. - */ -enum BLE_GAP_EVTS { - BLE_GAP_EVT_CONNECTED = - BLE_GAP_EVT_BASE, /**< Connected to peer. \n See @ref ble_gap_evt_connected_t */ - BLE_GAP_EVT_DISCONNECTED = - BLE_GAP_EVT_BASE + 1, /**< Disconnected from peer. \n See @ref ble_gap_evt_disconnected_t. */ - BLE_GAP_EVT_CONN_PARAM_UPDATE = - BLE_GAP_EVT_BASE + 2, /**< Connection Parameters updated. \n See @ref ble_gap_evt_conn_param_update_t. */ - BLE_GAP_EVT_SEC_PARAMS_REQUEST = - BLE_GAP_EVT_BASE + 3, /**< Request to provide security parameters. \n Reply with @ref sd_ble_gap_sec_params_reply. - \n See @ref ble_gap_evt_sec_params_request_t. */ - BLE_GAP_EVT_SEC_INFO_REQUEST = - BLE_GAP_EVT_BASE + 4, /**< Request to provide security information. \n Reply with @ref sd_ble_gap_sec_info_reply. - \n See @ref ble_gap_evt_sec_info_request_t. */ - BLE_GAP_EVT_PASSKEY_DISPLAY = - BLE_GAP_EVT_BASE + 5, /**< Request to display a passkey to the user. \n In LESC Numeric Comparison, reply with @ref - sd_ble_gap_auth_key_reply. \n See @ref ble_gap_evt_passkey_display_t. */ - BLE_GAP_EVT_KEY_PRESSED = - BLE_GAP_EVT_BASE + 6, /**< Notification of a keypress on the remote device.\n See @ref ble_gap_evt_key_pressed_t */ - BLE_GAP_EVT_AUTH_KEY_REQUEST = - BLE_GAP_EVT_BASE + 7, /**< Request to provide an authentication key. \n Reply with @ref sd_ble_gap_auth_key_reply. - \n See @ref ble_gap_evt_auth_key_request_t. */ - BLE_GAP_EVT_LESC_DHKEY_REQUEST = - BLE_GAP_EVT_BASE + 8, /**< Request to calculate an LE Secure Connections DHKey. \n Reply with @ref - sd_ble_gap_lesc_dhkey_reply. \n See @ref ble_gap_evt_lesc_dhkey_request_t */ - BLE_GAP_EVT_AUTH_STATUS = - BLE_GAP_EVT_BASE + 9, /**< Authentication procedure completed with status. \n See @ref ble_gap_evt_auth_status_t. */ - BLE_GAP_EVT_CONN_SEC_UPDATE = - BLE_GAP_EVT_BASE + 10, /**< Connection security updated. \n See @ref ble_gap_evt_conn_sec_update_t. */ - BLE_GAP_EVT_TIMEOUT = - BLE_GAP_EVT_BASE + 11, /**< Timeout expired. \n See @ref ble_gap_evt_timeout_t. */ - BLE_GAP_EVT_RSSI_CHANGED = - BLE_GAP_EVT_BASE + 12, /**< RSSI report. \n See @ref ble_gap_evt_rssi_changed_t. */ - BLE_GAP_EVT_ADV_REPORT = - BLE_GAP_EVT_BASE + 13, /**< Advertising report. \n See @ref ble_gap_evt_adv_report_t. */ - BLE_GAP_EVT_SEC_REQUEST = - BLE_GAP_EVT_BASE + 14, /**< Security Request. \n Reply with @ref sd_ble_gap_authenticate -\n or with @ref sd_ble_gap_encrypt if required security information is available -. \n See @ref ble_gap_evt_sec_request_t. */ - BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 15, /**< Connection Parameter Update Request. \n Reply with @ref - sd_ble_gap_conn_param_update. \n See @ref ble_gap_evt_conn_param_update_request_t. */ - BLE_GAP_EVT_SCAN_REQ_REPORT = - BLE_GAP_EVT_BASE + 16, /**< Scan request report. \n See @ref ble_gap_evt_scan_req_report_t. */ - BLE_GAP_EVT_PHY_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 17, /**< PHY Update Request. \n Reply with @ref sd_ble_gap_phy_update. \n - See @ref ble_gap_evt_phy_update_request_t. */ - BLE_GAP_EVT_PHY_UPDATE = - BLE_GAP_EVT_BASE + 18, /**< PHY Update Procedure is complete. \n See @ref ble_gap_evt_phy_update_t. */ - BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST = - BLE_GAP_EVT_BASE + 19, /**< Data Length Update Request. \n Reply with @ref - sd_ble_gap_data_length_update. \n See @ref ble_gap_evt_data_length_update_request_t. */ - BLE_GAP_EVT_DATA_LENGTH_UPDATE = - BLE_GAP_EVT_BASE + - 20, /**< LL Data Channel PDU payload length updated. \n See @ref ble_gap_evt_data_length_update_t. */ - BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT = - BLE_GAP_EVT_BASE + - 21, /**< Channel survey report. \n See @ref ble_gap_evt_qos_channel_survey_report_t. */ - BLE_GAP_EVT_ADV_SET_TERMINATED = - BLE_GAP_EVT_BASE + - 22, /**< Advertising set terminated. \n See @ref ble_gap_evt_adv_set_terminated_t. */ -}; - -/**@brief GAP Option IDs. - * IDs that uniquely identify a GAP option. - */ -enum BLE_GAP_OPTS { - BLE_GAP_OPT_CH_MAP = BLE_GAP_OPT_BASE, /**< Channel Map. @ref ble_gap_opt_ch_map_t */ - BLE_GAP_OPT_LOCAL_CONN_LATENCY = BLE_GAP_OPT_BASE + 1, /**< Local connection latency. @ref ble_gap_opt_local_conn_latency_t */ - BLE_GAP_OPT_PASSKEY = BLE_GAP_OPT_BASE + 2, /**< Set passkey. @ref ble_gap_opt_passkey_t */ - BLE_GAP_OPT_COMPAT_MODE_1 = BLE_GAP_OPT_BASE + 3, /**< Compatibility mode. @ref ble_gap_opt_compat_mode_1_t */ - BLE_GAP_OPT_AUTH_PAYLOAD_TIMEOUT = - BLE_GAP_OPT_BASE + 4, /**< Set Authenticated payload timeout. @ref ble_gap_opt_auth_payload_timeout_t */ - BLE_GAP_OPT_SLAVE_LATENCY_DISABLE = - BLE_GAP_OPT_BASE + 5, /**< Disable slave latency. @ref ble_gap_opt_slave_latency_disable_t */ -}; - -/**@brief GAP Configuration IDs. - * - * IDs that uniquely identify a GAP configuration. - */ -enum BLE_GAP_CFGS { - BLE_GAP_CFG_ROLE_COUNT = BLE_GAP_CFG_BASE, /**< Role count configuration. */ - BLE_GAP_CFG_DEVICE_NAME = BLE_GAP_CFG_BASE + 1, /**< Device name configuration. */ - BLE_GAP_CFG_PPCP_INCL_CONFIG = BLE_GAP_CFG_BASE + 2, /**< Peripheral Preferred Connection Parameters characteristic - inclusion configuration. */ - BLE_GAP_CFG_CAR_INCL_CONFIG = BLE_GAP_CFG_BASE + 3, /**< Central Address Resolution characteristic - inclusion configuration. */ -}; - -/**@brief GAP TX Power roles. - */ -enum BLE_GAP_TX_POWER_ROLES { - BLE_GAP_TX_POWER_ROLE_ADV = 1, /**< Advertiser role. */ - BLE_GAP_TX_POWER_ROLE_SCAN_INIT = 2, /**< Scanner and initiator role. */ - BLE_GAP_TX_POWER_ROLE_CONN = 3, /**< Connection role. */ -}; - -/** @} */ - -/**@addtogroup BLE_GAP_DEFINES Defines - * @{ */ - -/**@defgroup BLE_ERRORS_GAP SVC return values specific to GAP - * @{ */ -#define BLE_ERROR_GAP_UUID_LIST_MISMATCH \ - (NRF_GAP_ERR_BASE + 0x000) /**< UUID list does not contain an integral number of UUIDs. */ -#define BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST \ - (NRF_GAP_ERR_BASE + 0x001) /**< Use of Whitelist not permitted with discoverable advertising. */ -#define BLE_ERROR_GAP_INVALID_BLE_ADDR \ - (NRF_GAP_ERR_BASE + 0x002) /**< The upper two bits of the address do not correspond to the specified address type. */ -#define BLE_ERROR_GAP_WHITELIST_IN_USE \ - (NRF_GAP_ERR_BASE + 0x003) /**< Attempt to modify the whitelist while already in use by another operation. */ -#define BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE \ - (NRF_GAP_ERR_BASE + 0x004) /**< Attempt to modify the device identity list while already in use by another operation. */ -#define BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE \ - (NRF_GAP_ERR_BASE + 0x005) /**< The device identity list contains entries with duplicate identity addresses. */ -/**@} */ - -/**@defgroup BLE_GAP_ROLES GAP Roles - * @{ */ -#define BLE_GAP_ROLE_INVALID 0x0 /**< Invalid Role. */ -#define BLE_GAP_ROLE_PERIPH 0x1 /**< Peripheral Role. */ -#define BLE_GAP_ROLE_CENTRAL 0x2 /**< Central Role. */ -/**@} */ - -/**@defgroup BLE_GAP_TIMEOUT_SOURCES GAP Timeout sources - * @{ */ -#define BLE_GAP_TIMEOUT_SRC_SCAN 0x01 /**< Scanning timeout. */ -#define BLE_GAP_TIMEOUT_SRC_CONN 0x02 /**< Connection timeout. */ -#define BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD 0x03 /**< Authenticated payload timeout. */ -/**@} */ - -/**@defgroup BLE_GAP_ADDR_TYPES GAP Address types - * @{ */ -#define BLE_GAP_ADDR_TYPE_PUBLIC 0x00 /**< Public (identity) address.*/ -#define BLE_GAP_ADDR_TYPE_RANDOM_STATIC 0x01 /**< Random static (identity) address. */ -#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE 0x02 /**< Random private resolvable address. */ -#define BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE 0x03 /**< Random private non-resolvable address. */ -#define BLE_GAP_ADDR_TYPE_ANONYMOUS \ - 0x7F /**< An advertiser may advertise without its address. \ - This type of advertising is called anonymous. */ -/**@} */ - -/**@brief The default interval in seconds at which a private address is refreshed. */ -#define BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S (900) /* 15 minutes. */ -/**@brief The maximum interval in seconds at which a private address can be refreshed. */ -#define BLE_GAP_MAX_PRIVATE_ADDR_CYCLE_INTERVAL_S (41400) /* 11 hours 30 minutes. */ - -/** @brief BLE address length. */ -#define BLE_GAP_ADDR_LEN (6) - -/**@defgroup BLE_GAP_PRIVACY_MODES Privacy modes - * @{ */ -#define BLE_GAP_PRIVACY_MODE_OFF 0x00 /**< Device will send and accept its identity address for its own address. */ -#define BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY 0x01 /**< Device will send and accept only private addresses for its own address. */ -#define BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY \ - 0x02 /**< Device will send and accept only private addresses for its own address, \ - and will not accept a peer using identity address as sender address when \ - the peer IRK is exchanged, non-zero and added to the identity list. */ -/**@} */ - -/** @brief Invalid power level. */ -#define BLE_GAP_POWER_LEVEL_INVALID 127 - -/** @brief Advertising set handle not set. */ -#define BLE_GAP_ADV_SET_HANDLE_NOT_SET (0xFF) - -/** @brief The default number of advertising sets. */ -#define BLE_GAP_ADV_SET_COUNT_DEFAULT (1) - -/** @brief The maximum number of advertising sets supported by this SoftDevice. */ -#define BLE_GAP_ADV_SET_COUNT_MAX (1) - -/**@defgroup BLE_GAP_ADV_SET_DATA_SIZES Advertising data sizes. - * @{ */ -#define BLE_GAP_ADV_SET_DATA_SIZE_MAX \ - (31) /**< Maximum data length for an advertising set. \ - If more advertising data is required, use extended advertising instead. */ -#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED \ - (255) /**< Maximum supported data length for an extended advertising set. */ - -#define BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_CONNECTABLE_MAX_SUPPORTED \ - (238) /**< Maximum supported data length for an extended connectable advertising set. */ -/**@}. */ - -/** @brief Set ID not available in advertising report. */ -#define BLE_GAP_ADV_REPORT_SET_ID_NOT_AVAILABLE 0xFF - -/**@defgroup BLE_GAP_EVT_ADV_SET_TERMINATED_REASON GAP Advertising Set Terminated reasons - * @{ */ -#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_TIMEOUT 0x01 /**< Timeout value reached. */ -#define BLE_GAP_EVT_ADV_SET_TERMINATED_REASON_LIMIT_REACHED 0x02 /**< @ref ble_gap_adv_params_t::max_adv_evts was reached. */ -/**@} */ - -/**@defgroup BLE_GAP_AD_TYPE_DEFINITIONS GAP Advertising and Scan Response Data format - * @note Found at https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm - * @{ */ -#define BLE_GAP_AD_TYPE_FLAGS 0x01 /**< Flags for discoverability. */ -#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 /**< Partial list of 16 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 /**< Complete list of 16 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 /**< Partial list of 32 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 /**< Complete list of 32 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 /**< Partial list of 128 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 /**< Complete list of 128 bit service UUIDs. */ -#define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 /**< Short local device name. */ -#define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 /**< Complete local device name. */ -#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A /**< Transmit power level. */ -#define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D /**< Class of device. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E /**< Simple Pairing Hash C. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F /**< Simple Pairing Randomizer R. */ -#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 /**< Security Manager TK Value. */ -#define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 /**< Security Manager Out Of Band Flags. */ -#define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 /**< Slave Connection Interval Range. */ -#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 /**< List of 16-bit Service Solicitation UUIDs. */ -#define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 /**< List of 128-bit Service Solicitation UUIDs. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 /**< Service Data - 16-bit UUID. */ -#define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 /**< Public Target Address. */ -#define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 /**< Random Target Address. */ -#define BLE_GAP_AD_TYPE_APPEARANCE 0x19 /**< Appearance. */ -#define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A /**< Advertising Interval. */ -#define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B /**< LE Bluetooth Device Address. */ -#define BLE_GAP_AD_TYPE_LE_ROLE 0x1C /**< LE Role. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D /**< Simple Pairing Hash C-256. */ -#define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E /**< Simple Pairing Randomizer R-256. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 /**< Service Data - 32-bit UUID. */ -#define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 /**< Service Data - 128-bit UUID. */ -#define BLE_GAP_AD_TYPE_LESC_CONFIRMATION_VALUE 0x22 /**< LE Secure Connections Confirmation Value */ -#define BLE_GAP_AD_TYPE_LESC_RANDOM_VALUE 0x23 /**< LE Secure Connections Random Value */ -#define BLE_GAP_AD_TYPE_URI 0x24 /**< URI */ -#define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D /**< 3D Information Data. */ -#define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF /**< Manufacturer Specific Data. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_FLAGS GAP Advertisement Flags - * @{ */ -#define BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE (0x01) /**< LE Limited Discoverable Mode. */ -#define BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE (0x02) /**< LE General Discoverable Mode. */ -#define BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED (0x04) /**< BR/EDR not supported. */ -#define BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER (0x08) /**< Simultaneous LE and BR/EDR, Controller. */ -#define BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST (0x10) /**< Simultaneous LE and BR/EDR, Host. */ -#define BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE \ - (BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE | \ - BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE Limited Discoverable Mode, BR/EDR not supported. */ -#define BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE \ - (BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE | \ - BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) /**< LE General Discoverable Mode, BR/EDR not supported. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_INTERVALS GAP Advertising interval max and min - * @{ */ -#define BLE_GAP_ADV_INTERVAL_MIN 0x000020 /**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */ -#define BLE_GAP_ADV_INTERVAL_MAX 0x004000 /**< Maximum Advertising interval in 625 us units, i.e. 10.24 s. */ - /**@} */ - -/**@defgroup BLE_GAP_SCAN_INTERVALS GAP Scan interval max and min - * @{ */ -#define BLE_GAP_SCAN_INTERVAL_MIN 0x0004 /**< Minimum Scan interval in 625 us units, i.e. 2.5 ms. */ -#define BLE_GAP_SCAN_INTERVAL_MAX 0xFFFF /**< Maximum Scan interval in 625 us units, i.e. 40,959.375 s. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_WINDOW GAP Scan window max and min - * @{ */ -#define BLE_GAP_SCAN_WINDOW_MIN 0x0004 /**< Minimum Scan window in 625 us units, i.e. 2.5 ms. */ -#define BLE_GAP_SCAN_WINDOW_MAX 0xFFFF /**< Maximum Scan window in 625 us units, i.e. 40,959.375 s. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_TIMEOUT GAP Scan timeout max and min - * @{ */ -#define BLE_GAP_SCAN_TIMEOUT_MIN 0x0001 /**< Minimum Scan timeout in 10 ms units, i.e 10 ms. */ -#define BLE_GAP_SCAN_TIMEOUT_UNLIMITED 0x0000 /**< Continue to scan forever. */ - /** @} */ - -/**@defgroup BLE_GAP_SCAN_BUFFER_SIZE GAP Minimum scanner buffer size - * - * Scan buffers are used for storing advertising data received from an advertiser. - * If ble_gap_scan_params_t::extended is set to 0, @ref BLE_GAP_SCAN_BUFFER_MIN is the minimum scan buffer length. - * else the minimum scan buffer size is @ref BLE_GAP_SCAN_BUFFER_EXTENDED_MIN. - * @{ */ -#define BLE_GAP_SCAN_BUFFER_MIN \ - (31) /**< Minimum data length for an \ - advertising set. */ -#define BLE_GAP_SCAN_BUFFER_MAX \ - (31) /**< Maximum data length for an \ - advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MIN \ - (255) /**< Minimum data length for an \ - extended advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX \ - (1650) /**< Maximum data length for an \ - extended advertising set. */ -#define BLE_GAP_SCAN_BUFFER_EXTENDED_MAX_SUPPORTED \ - (255) /**< Maximum supported data length for \ - an extended advertising set. */ -/** @} */ - -/**@defgroup BLE_GAP_ADV_TYPES GAP Advertising types - * - * Advertising types defined in Bluetooth Core Specification v5.0, Vol 6, Part B, Section 4.4.2. - * - * The maximum advertising data length is defined by @ref BLE_GAP_ADV_SET_DATA_SIZE_MAX. - * The maximum supported data length for an extended advertiser is defined by - * @ref BLE_GAP_ADV_SET_DATA_SIZE_EXTENDED_MAX_SUPPORTED - * Note that some of the advertising types do not support advertising data. Non-scannable types do not support - * scan response data. - * - * @{ */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x01 /**< Connectable and scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE \ - 0x02 /**< Connectable non-scannable directed advertising \ - events. Advertising interval is less that 3.75 ms. \ - Use this type for fast reconnections. \ - @note Advertising data is not supported. */ -#define BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x03 /**< Connectable non-scannable directed advertising \ - events. \ - @note Advertising data is not supported. */ -#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x04 /**< Non-connectable scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x05 /**< Non-connectable non-scannable undirected \ - advertising events. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x06 /**< Connectable non-scannable undirected advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_CONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x07 /**< Connectable non-scannable directed advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_UNDIRECTED \ - 0x08 /**< Non-connectable scannable undirected advertising \ - events using extended advertising PDUs. \ - @note Only scan response data is supported. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_SCANNABLE_DIRECTED \ - 0x09 /**< Non-connectable scannable directed advertising \ - events using extended advertising PDUs. \ - @note Only scan response data is supported. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED \ - 0x0A /**< Non-connectable non-scannable undirected advertising \ - events using extended advertising PDUs. */ -#define BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED \ - 0x0B /**< Non-connectable non-scannable directed advertising \ - events using extended advertising PDUs. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_FILTER_POLICIES GAP Advertising filter policies - * @{ */ -#define BLE_GAP_ADV_FP_ANY 0x00 /**< Allow scan requests and connect requests from any device. */ -#define BLE_GAP_ADV_FP_FILTER_SCANREQ 0x01 /**< Filter scan requests with whitelist. */ -#define BLE_GAP_ADV_FP_FILTER_CONNREQ 0x02 /**< Filter connect requests with whitelist. */ -#define BLE_GAP_ADV_FP_FILTER_BOTH 0x03 /**< Filter both scan and connect requests with whitelist. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_DATA_STATUS GAP Advertising data status - * @{ */ -#define BLE_GAP_ADV_DATA_STATUS_COMPLETE 0x00 /**< All data in the advertising event have been received. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA \ - 0x01 /**< More data to be received. \ - @note This value will only be used if \ - @ref ble_gap_scan_params_t::report_incomplete_evts and \ - @ref ble_gap_adv_report_type_t::extended_pdu are set to true. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED \ - 0x02 /**< Incomplete data. Buffer size insufficient to receive more. \ - @note This value will only be used if \ - @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ -#define BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MISSED \ - 0x03 /**< Failed to receive the remaining data. \ - @note This value will only be used if \ - @ref ble_gap_adv_report_type_t::extended_pdu is set to true. */ -/**@} */ - -/**@defgroup BLE_GAP_SCAN_FILTER_POLICIES GAP Scanner filter policies - * @{ */ -#define BLE_GAP_SCAN_FP_ACCEPT_ALL \ - 0x00 /**< Accept all advertising packets except directed advertising packets \ - not addressed to this device. */ -#define BLE_GAP_SCAN_FP_WHITELIST \ - 0x01 /**< Accept advertising packets from devices in the whitelist except directed \ - packets not addressed to this device. */ -#define BLE_GAP_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED \ - 0x02 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL. \ - In addition, accept directed advertising packets, where the advertiser's \ - address is a resolvable private address that cannot be resolved. */ -#define BLE_GAP_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED \ - 0x03 /**< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST. \ - In addition, accept directed advertising packets, where the advertiser's \ - address is a resolvable private address that cannot be resolved. */ -/**@} */ - -/**@defgroup BLE_GAP_ADV_TIMEOUT_VALUES GAP Advertising timeout values in 10 ms units - * @{ */ -#define BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX \ - (128) /**< Maximum high duty advertising time in 10 ms units. Corresponds to 1.28 s. \ - */ -#define BLE_GAP_ADV_TIMEOUT_LIMITED_MAX \ - (18000) /**< Maximum advertising time in 10 ms units corresponding to TGAP(lim_adv_timeout) = 180 s in limited discoverable \ - mode. */ -#define BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED \ - (0) /**< Unlimited advertising in general discoverable mode. \ - For high duty cycle advertising, this corresponds to @ref BLE_GAP_ADV_TIMEOUT_HIGH_DUTY_MAX. */ -/**@} */ - -/**@defgroup BLE_GAP_DISC_MODES GAP Discovery modes - * @{ */ -#define BLE_GAP_DISC_MODE_NOT_DISCOVERABLE 0x00 /**< Not discoverable discovery Mode. */ -#define BLE_GAP_DISC_MODE_LIMITED 0x01 /**< Limited Discovery Mode. */ -#define BLE_GAP_DISC_MODE_GENERAL 0x02 /**< General Discovery Mode. */ -/**@} */ - -/**@defgroup BLE_GAP_IO_CAPS GAP IO Capabilities - * @{ */ -#define BLE_GAP_IO_CAPS_DISPLAY_ONLY 0x00 /**< Display Only. */ -#define BLE_GAP_IO_CAPS_DISPLAY_YESNO 0x01 /**< Display and Yes/No entry. */ -#define BLE_GAP_IO_CAPS_KEYBOARD_ONLY 0x02 /**< Keyboard Only. */ -#define BLE_GAP_IO_CAPS_NONE 0x03 /**< No I/O capabilities. */ -#define BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY 0x04 /**< Keyboard and Display. */ -/**@} */ - -/**@defgroup BLE_GAP_AUTH_KEY_TYPES GAP Authentication Key Types - * @{ */ -#define BLE_GAP_AUTH_KEY_TYPE_NONE 0x00 /**< No key (may be used to reject). */ -#define BLE_GAP_AUTH_KEY_TYPE_PASSKEY 0x01 /**< 6-digit Passkey. */ -#define BLE_GAP_AUTH_KEY_TYPE_OOB 0x02 /**< Out Of Band data. */ -/**@} */ - -/**@defgroup BLE_GAP_KP_NOT_TYPES GAP Keypress Notification Types - * @{ */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_START 0x00 /**< Passkey entry started. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_IN 0x01 /**< Passkey digit entered. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_DIGIT_OUT 0x02 /**< Passkey digit erased. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_CLEAR 0x03 /**< Passkey cleared. */ -#define BLE_GAP_KP_NOT_TYPE_PASSKEY_END 0x04 /**< Passkey entry completed. */ -/**@} */ - -/**@defgroup BLE_GAP_SEC_STATUS GAP Security status - * @{ */ -#define BLE_GAP_SEC_STATUS_SUCCESS 0x00 /**< Procedure completed with success. */ -#define BLE_GAP_SEC_STATUS_TIMEOUT 0x01 /**< Procedure timed out. */ -#define BLE_GAP_SEC_STATUS_PDU_INVALID 0x02 /**< Invalid PDU received. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE1_BEGIN 0x03 /**< Reserved for Future Use range #1 begin. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE1_END 0x80 /**< Reserved for Future Use range #1 end. */ -#define BLE_GAP_SEC_STATUS_PASSKEY_ENTRY_FAILED 0x81 /**< Passkey entry failed (user canceled or other). */ -#define BLE_GAP_SEC_STATUS_OOB_NOT_AVAILABLE 0x82 /**< Out of Band Key not available. */ -#define BLE_GAP_SEC_STATUS_AUTH_REQ 0x83 /**< Authentication requirements not met. */ -#define BLE_GAP_SEC_STATUS_CONFIRM_VALUE 0x84 /**< Confirm value failed. */ -#define BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP 0x85 /**< Pairing not supported. */ -#define BLE_GAP_SEC_STATUS_ENC_KEY_SIZE 0x86 /**< Encryption key size. */ -#define BLE_GAP_SEC_STATUS_SMP_CMD_UNSUPPORTED 0x87 /**< Unsupported SMP command. */ -#define BLE_GAP_SEC_STATUS_UNSPECIFIED 0x88 /**< Unspecified reason. */ -#define BLE_GAP_SEC_STATUS_REPEATED_ATTEMPTS 0x89 /**< Too little time elapsed since last attempt. */ -#define BLE_GAP_SEC_STATUS_INVALID_PARAMS 0x8A /**< Invalid parameters. */ -#define BLE_GAP_SEC_STATUS_DHKEY_FAILURE 0x8B /**< DHKey check failure. */ -#define BLE_GAP_SEC_STATUS_NUM_COMP_FAILURE 0x8C /**< Numeric Comparison failure. */ -#define BLE_GAP_SEC_STATUS_BR_EDR_IN_PROG 0x8D /**< BR/EDR pairing in progress. */ -#define BLE_GAP_SEC_STATUS_X_TRANS_KEY_DISALLOWED 0x8E /**< BR/EDR Link Key cannot be used for LE keys. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE2_BEGIN 0x8F /**< Reserved for Future Use range #2 begin. */ -#define BLE_GAP_SEC_STATUS_RFU_RANGE2_END 0xFF /**< Reserved for Future Use range #2 end. */ -/**@} */ - -/**@defgroup BLE_GAP_SEC_STATUS_SOURCES GAP Security status sources - * @{ */ -#define BLE_GAP_SEC_STATUS_SOURCE_LOCAL 0x00 /**< Local failure. */ -#define BLE_GAP_SEC_STATUS_SOURCE_REMOTE 0x01 /**< Remote failure. */ -/**@} */ - -/**@defgroup BLE_GAP_CP_LIMITS GAP Connection Parameters Limits - * @{ */ -#define BLE_GAP_CP_MIN_CONN_INTVL_NONE 0xFFFF /**< No new minimum connection interval specified in connect parameters. */ -#define BLE_GAP_CP_MIN_CONN_INTVL_MIN \ - 0x0006 /**< Lowest minimum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ -#define BLE_GAP_CP_MIN_CONN_INTVL_MAX \ - 0x0C80 /**< Highest minimum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ - */ -#define BLE_GAP_CP_MAX_CONN_INTVL_NONE 0xFFFF /**< No new maximum connection interval specified in connect parameters. */ -#define BLE_GAP_CP_MAX_CONN_INTVL_MIN \ - 0x0006 /**< Lowest maximum connection interval permitted, in units of 1.25 ms, i.e. 7.5 ms. */ -#define BLE_GAP_CP_MAX_CONN_INTVL_MAX \ - 0x0C80 /**< Highest maximum connection interval permitted, in units of 1.25 ms, i.e. 4 s. \ - */ -#define BLE_GAP_CP_SLAVE_LATENCY_MAX 0x01F3 /**< Highest slave latency permitted, in connection events. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_NONE 0xFFFF /**< No new supervision timeout specified in connect parameters. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MIN 0x000A /**< Lowest supervision timeout permitted, in units of 10 ms, i.e. 100 ms. */ -#define BLE_GAP_CP_CONN_SUP_TIMEOUT_MAX 0x0C80 /**< Highest supervision timeout permitted, in units of 10 ms, i.e. 32 s. */ -/**@} */ - -/**@defgroup BLE_GAP_DEVNAME GAP device name defines. - * @{ */ -#define BLE_GAP_DEVNAME_DEFAULT "nRF5x" /**< Default device name value. */ -#define BLE_GAP_DEVNAME_DEFAULT_LEN 31 /**< Default number of octets in device name. */ -#define BLE_GAP_DEVNAME_MAX_LEN 248 /**< Maximum number of octets in device name. */ -/**@} */ - -/**@brief Disable RSSI events for connections */ -#define BLE_GAP_RSSI_THRESHOLD_INVALID 0xFF - -/**@defgroup BLE_GAP_PHYS GAP PHYs - * @{ */ -#define BLE_GAP_PHY_AUTO 0x00 /**< Automatic PHY selection. Refer @ref sd_ble_gap_phy_update for more information.*/ -#define BLE_GAP_PHY_1MBPS 0x01 /**< 1 Mbps PHY. */ -#define BLE_GAP_PHY_2MBPS 0x02 /**< 2 Mbps PHY. */ -#define BLE_GAP_PHY_CODED 0x04 /**< Coded PHY. */ -#define BLE_GAP_PHY_NOT_SET 0xFF /**< PHY is not configured. */ - -/**@brief Supported PHYs in connections, for scanning, and for advertising. */ -#define BLE_GAP_PHYS_SUPPORTED (BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS | BLE_GAP_PHY_CODED) /**< All PHYs are supported. */ - -/**@} */ - -/**@defgroup BLE_GAP_CONN_SEC_MODE_SET_MACROS GAP attribute security requirement setters - * - * See @ref ble_gap_conn_sec_mode_t. - * @{ */ -/**@brief Set sec_mode pointed to by ptr to have no access rights.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(ptr) \ - do { \ - (ptr)->sm = 0; \ - (ptr)->lv = 0; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require no protection, open link.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_OPEN(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 1; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require encryption, but no MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 2; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require encryption and MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 3; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require LESC encryption and MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 1; \ - (ptr)->lv = 4; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require signing or encryption, no MITM protection needed.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(ptr) \ - do { \ - (ptr)->sm = 2; \ - (ptr)->lv = 1; \ - } while (0) -/**@brief Set sec_mode pointed to by ptr to require signing or encryption with MITM protection.*/ -#define BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(ptr) \ - do { \ - (ptr)->sm = 2; \ - (ptr)->lv = 2; \ - } while (0) -/**@} */ - -/**@brief GAP Security Random Number Length. */ -#define BLE_GAP_SEC_RAND_LEN 8 - -/**@brief GAP Security Key Length. */ -#define BLE_GAP_SEC_KEY_LEN 16 - -/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key Length. */ -#define BLE_GAP_LESC_P256_PK_LEN 64 - -/**@brief GAP LE Secure Connections Elliptic Curve Diffie-Hellman DHKey Length. */ -#define BLE_GAP_LESC_DHKEY_LEN 32 - -/**@brief GAP Passkey Length. */ -#define BLE_GAP_PASSKEY_LEN 6 - -/**@brief Maximum amount of addresses in the whitelist. */ -#define BLE_GAP_WHITELIST_ADDR_MAX_COUNT (8) - -/**@brief Maximum amount of identities in the device identities list. */ -#define BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT (8) - -/**@brief Default connection count for a configuration. */ -#define BLE_GAP_CONN_COUNT_DEFAULT (1) - -/**@defgroup BLE_GAP_EVENT_LENGTH GAP event length defines. - * @{ */ -#define BLE_GAP_EVENT_LENGTH_MIN (2) /**< Minimum event length, in 1.25 ms units. */ -#define BLE_GAP_EVENT_LENGTH_CODED_PHY_MIN (6) /**< The shortest event length in 1.25 ms units supporting LE Coded PHY. */ -#define BLE_GAP_EVENT_LENGTH_DEFAULT (3) /**< Default event length, in 1.25 ms units. */ -/**@} */ - -/**@defgroup BLE_GAP_ROLE_COUNT GAP concurrent connection count defines. - * @{ */ -#define BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT (1) /**< Default maximum number of connections concurrently acting as peripherals. */ -#define BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT (3) /**< Default maximum number of connections concurrently acting as centrals. */ -#define BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT \ - (1) /**< Default number of SMP instances shared between all connections acting as centrals. */ -#define BLE_GAP_ROLE_COUNT_COMBINED_MAX \ - (20) /**< Maximum supported number of concurrent connections in the peripheral and central roles combined. */ - -/**@} */ - -/**@brief Automatic data length parameter. */ -#define BLE_GAP_DATA_LENGTH_AUTO 0 - -/**@defgroup BLE_GAP_AUTH_PAYLOAD_TIMEOUT Authenticated payload timeout defines. - * @{ */ -#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX (48000) /**< Maximum authenticated payload timeout in 10 ms units, i.e. 8 minutes. */ -#define BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MIN (1) /**< Minimum authenticated payload timeout in 10 ms units, i.e. 10 ms. */ -/**@} */ - -/**@defgroup GAP_SEC_MODES GAP Security Modes - * @{ */ -#define BLE_GAP_SEC_MODE 0x00 /**< No key (may be used to reject). */ -/**@} */ - -/**@brief The total number of channels in Bluetooth Low Energy. */ -#define BLE_GAP_CHANNEL_COUNT (40) - -/**@defgroup BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS Quality of Service (QoS) Channel survey interval defines - * @{ */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS (0) /**< Continuous channel survey. */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MIN_US (7500) /**< Minimum channel survey interval in microseconds (7.5 ms). */ -#define BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_MAX_US (4000000) /**< Maximum channel survey interval in microseconds (4 s). */ - /**@} */ - -/** @} */ - -/** @defgroup BLE_GAP_CHAR_INCL_CONFIG GAP Characteristic inclusion configurations - * @{ - */ -#define BLE_GAP_CHAR_INCL_CONFIG_INCLUDE (0) /**< Include the characteristic in the Attribute Table */ -#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITH_SPACE \ - (1) /**< Do not include the characteristic in the Attribute table. \ - The SoftDevice will reserve the attribute handles \ - which are otherwise used for this characteristic. \ - By reserving the attribute handles it will be possible \ - to upgrade the SoftDevice without changing handle of the \ - Service Changed characteristic. */ -#define BLE_GAP_CHAR_INCL_CONFIG_EXCLUDE_WITHOUT_SPACE \ - (2) /**< Do not include the characteristic in the Attribute table. \ - The SoftDevice will not reserve the attribute handles \ - which are otherwise used for this characteristic. */ -/**@} */ - -/** @defgroup BLE_GAP_CHAR_INCL_CONFIG_DEFAULTS Characteristic inclusion default values - * @{ */ -#define BLE_GAP_PPCP_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ -#define BLE_GAP_CAR_INCL_CONFIG_DEFAULT (BLE_GAP_CHAR_INCL_CONFIG_INCLUDE) /**< Included by default. */ -/**@} */ - -/** @defgroup BLE_GAP_SLAVE_LATENCY Slave latency configuration options - * @{ */ -#define BLE_GAP_SLAVE_LATENCY_ENABLE \ - (0) /**< Slave latency is enabled. When slave latency is enabled, \ - the slave will wake up every time it has data to send, \ - and/or every slave latency number of connection events. */ -#define BLE_GAP_SLAVE_LATENCY_DISABLE \ - (1) /**< Disable slave latency. The slave will wake up every connection event \ - regardless of the requested slave latency. \ - This option consumes the most power. */ -#define BLE_GAP_SLAVE_LATENCY_WAIT_FOR_ACK \ - (2) /**< The slave will wake up every connection event if it has not received \ - an ACK from the master for at least slave latency events. This \ - configuration may increase the power consumption in environments \ - with a lot of radio activity. */ -/**@} */ - -/**@addtogroup BLE_GAP_STRUCTURES Structures - * @{ */ - -/**@brief Advertising event properties. */ -typedef struct { - uint8_t type; /**< Advertising type. See @ref BLE_GAP_ADV_TYPES. */ - uint8_t anonymous : 1; /**< Omit advertiser's address from all PDUs. - @note Anonymous advertising is only available for - @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_UNDIRECTED and - @ref BLE_GAP_ADV_TYPE_EXTENDED_NONCONNECTABLE_NONSCANNABLE_DIRECTED. */ - uint8_t include_tx_power : 1; /**< This feature is not supported on this SoftDevice. */ -} ble_gap_adv_properties_t; - -/**@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 Advertising Auxiliary Pointer. */ -typedef struct { - uint16_t aux_offset; /**< Time offset from the beginning of advertising packet to the auxiliary packet in 100 us units. */ - uint8_t aux_phy; /**< Indicates the PHY on which the auxiliary advertising packet is sent. See @ref BLE_GAP_PHYS. */ -} ble_gap_aux_pointer_t; - -/**@brief Bluetooth Low Energy address. */ -typedef struct { - uint8_t - addr_id_peer : 1; /**< Only valid for peer addresses. - This bit is set by the SoftDevice to indicate whether the address has been resolved from - a Resolvable Private Address (when the peer is using privacy). - If set to 1, @ref addr and @ref addr_type refer to the identity address of the resolved address. - - This bit is ignored when a variable of type @ref ble_gap_addr_t is used as input to API functions. - */ - uint8_t addr_type : 7; /**< See @ref BLE_GAP_ADDR_TYPES. */ - uint8_t addr[BLE_GAP_ADDR_LEN]; /**< 48-bit address, LSB format. - @ref addr is not used if @ref addr_type is @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. */ -} ble_gap_addr_t; - -/**@brief GAP connection parameters. - * - * @note When ble_conn_params_t is received in an event, both min_conn_interval and - * max_conn_interval will be equal to the connection interval set by the central. - * - * @note If both conn_sup_timeout and max_conn_interval are specified, then the following constraint applies: - * conn_sup_timeout * 4 > (1 + slave_latency) * max_conn_interval - * that corresponds to the following Bluetooth Spec requirement: - * The Supervision_Timeout in milliseconds shall be larger than - * (1 + Conn_Latency) * Conn_Interval_Max * 2, where Conn_Interval_Max is given in milliseconds. - */ -typedef struct { - uint16_t min_conn_interval; /**< Minimum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t max_conn_interval; /**< Maximum Connection Interval in 1.25 ms units, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t slave_latency; /**< Slave Latency in number of connection events, see @ref BLE_GAP_CP_LIMITS.*/ - uint16_t conn_sup_timeout; /**< Connection Supervision Timeout in 10 ms units, see @ref BLE_GAP_CP_LIMITS.*/ -} ble_gap_conn_params_t; - -/**@brief GAP connection security modes. - * - * Security Mode 0 Level 0: No access permissions at all (this level is not defined by the Bluetooth Core specification).\n - * Security Mode 1 Level 1: No security is needed (aka open link).\n - * Security Mode 1 Level 2: Encrypted link required, MITM protection not necessary.\n - * Security Mode 1 Level 3: MITM protected encrypted link required.\n - * Security Mode 1 Level 4: LESC MITM protected encrypted link using a 128-bit strength encryption key required.\n - * Security Mode 2 Level 1: Signing or encryption required, MITM protection not necessary.\n - * Security Mode 2 Level 2: MITM protected signing required, unless link is MITM protected encrypted.\n - */ -typedef struct { - uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ - uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */ - -} ble_gap_conn_sec_mode_t; - -/**@brief GAP connection security status.*/ -typedef struct { - ble_gap_conn_sec_mode_t sec_mode; /**< Currently active security mode for this connection.*/ - uint8_t - encr_key_size; /**< Length of currently active encryption key, 7 to 16 octets (only applicable for bonding procedures). */ -} ble_gap_conn_sec_t; - -/**@brief Identity Resolving Key. */ -typedef struct { - uint8_t irk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing IRK. */ -} ble_gap_irk_t; - -/**@brief Channel mask (40 bits). - * Every channel is represented with a bit positioned as per channel index defined in Bluetooth Core Specification v5.0, - * Vol 6, Part B, Section 1.4.1. The LSB contained in array element 0 represents channel index 0, and bit 39 represents - * channel index 39. If a bit is set to 1, the channel is not used. - */ -typedef uint8_t ble_gap_ch_mask_t[5]; - -/**@brief GAP advertising parameters. */ -typedef struct { - ble_gap_adv_properties_t properties; /**< The properties of the advertising events. */ - ble_gap_addr_t const *p_peer_addr; /**< Address of a known peer. - @note ble_gap_addr_t::addr_type cannot be - @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. - - When privacy is enabled and the local device uses - @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE addresses, - the device identity list is searched for a matching entry. If - the local IRK for that device identity is set, the local IRK - for that device will be used to generate the advertiser address - field in the advertising packet. - - If @ref ble_gap_adv_properties_t::type is directed, this must be - set to the targeted scanner or initiator. If the peer address is - in the device identity list, the peer IRK for that device will be - used to generate @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE - target addresses used in the advertising event PDUs. */ - uint32_t interval; /**< Advertising interval in 625 us units. @sa BLE_GAP_ADV_INTERVALS. - @note If @ref ble_gap_adv_properties_t::type is set to - @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE - advertising, this parameter is ignored. */ - uint16_t duration; /**< Advertising duration in 10 ms units. When timeout is reached, - an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. - @sa BLE_GAP_ADV_TIMEOUT_VALUES. - @note The SoftDevice will always complete at least one advertising - event even if the duration is set too low. */ - uint8_t max_adv_evts; /**< Maximum advertising events that shall be sent prior to disabling - advertising. Setting the value to 0 disables the limitation. When - the count of advertising events specified by this parameter - (if not 0) is reached, advertising will be automatically stopped - and an event of type @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised - @note If @ref ble_gap_adv_properties_t::type is set to - @ref BLE_GAP_ADV_TYPE_CONNECTABLE_NONSCANNABLE_DIRECTED_HIGH_DUTY_CYCLE, - this parameter is ignored. */ - ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. - At least one of the primary channels, that is channel index 37-39, must be used. - Masking away secondary advertising channels is not supported. */ - uint8_t filter_policy; /**< Filter Policy. @sa BLE_GAP_ADV_FILTER_POLICIES. */ - uint8_t primary_phy; /**< Indicates the PHY on which the primary advertising channel packets - are transmitted. If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS - will be used. - Valid values are @ref BLE_GAP_PHY_1MBPS and @ref BLE_GAP_PHY_CODED. - @note The primary_phy shall indicate @ref BLE_GAP_PHY_1MBPS if - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t secondary_phy; /**< Indicates the PHY on which the secondary advertising channel packets - are transmitted. - If set to @ref BLE_GAP_PHY_AUTO, @ref BLE_GAP_PHY_1MBPS will be used. - Valid values are - @ref BLE_GAP_PHY_1MBPS, @ref BLE_GAP_PHY_2MBPS, and @ref BLE_GAP_PHY_CODED. - If @ref ble_gap_adv_properties_t::type is an extended advertising type - and connectable, this is the PHY that will be used to establish a - connection and send AUX_ADV_IND packets on. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t set_id : 4; /**< The advertising set identifier distinguishes this advertising set from other - advertising sets transmitted by this and other devices. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is not an extended advertising type. */ - uint8_t scan_req_notification : 1; /**< Enable scan request notifications for this advertising set. When a - scan request is received and the scanner address is allowed - by the filter policy, @ref BLE_GAP_EVT_SCAN_REQ_REPORT is raised. - @note This parameter will be ignored when - @ref ble_gap_adv_properties_t::type is a non-scannable - advertising type. */ -} ble_gap_adv_params_t; - -/**@brief GAP advertising data buffers. - * - * The application must provide the buffers for advertisement. The memory shall reside in application RAM, and - * shall never be modified while advertising. The data shall be kept alive until either: - * - @ref BLE_GAP_EVT_ADV_SET_TERMINATED is raised. - * - @ref BLE_GAP_EVT_CONNECTED is raised with @ref ble_gap_evt_connected_t::adv_handle set to the corresponding - * advertising handle. - * - Advertising is stopped. - * - Advertising data is changed. - * To update advertising data while advertising, provide new buffers to @ref sd_ble_gap_adv_set_configure. */ -typedef struct { - ble_data_t adv_data; /**< Advertising data. - @note - Advertising data can only be specified for a @ref ble_gap_adv_properties_t::type - that is allowed to contain advertising data. */ - ble_data_t scan_rsp_data; /**< Scan response data. - @note - Scan response data can only be specified for a @ref ble_gap_adv_properties_t::type - that is scannable. */ -} ble_gap_adv_data_t; - -/**@brief GAP scanning parameters. */ -typedef struct { - uint8_t extended : 1; /**< If 1, the scanner will accept extended advertising packets. - If set to 0, the scanner will not receive advertising packets - on secondary advertising channels, and will not be able - to receive long advertising PDUs. */ - uint8_t report_incomplete_evts : 1; /**< If 1, events of type @ref ble_gap_evt_adv_report_t may have - @ref ble_gap_adv_report_type_t::status set to - @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. - This parameter is ignored when used with @ref sd_ble_gap_connect - @note This may be used to abort receiving more packets from an extended - advertising event, and is only available for extended - scanning, see @ref sd_ble_gap_scan_start. - @note This feature is not supported by this SoftDevice. */ - uint8_t active : 1; /**< If 1, perform active scanning by sending scan requests. - This parameter is ignored when used with @ref sd_ble_gap_connect. */ - uint8_t filter_policy : 2; /**< Scanning filter policy. @sa BLE_GAP_SCAN_FILTER_POLICIES. - @note Only @ref BLE_GAP_SCAN_FP_ACCEPT_ALL and - @ref BLE_GAP_SCAN_FP_WHITELIST are valid when used with - @ref sd_ble_gap_connect */ - uint8_t scan_phys; /**< Bitfield of PHYs to scan on. If set to @ref BLE_GAP_PHY_AUTO, - scan_phys will default to @ref BLE_GAP_PHY_1MBPS. - - If @ref ble_gap_scan_params_t::extended is set to 0, the only - supported PHY is @ref BLE_GAP_PHY_1MBPS. - - When used with @ref sd_ble_gap_scan_start, - the bitfield indicates the PHYs the scanner will use for scanning - on primary advertising channels. The scanner will accept - @ref BLE_GAP_PHYS_SUPPORTED as secondary advertising channel PHYs. - - When used with @ref sd_ble_gap_connect, the bitfield indicates - the PHYs the initiator will use for scanning on primary advertising - channels. The initiator will accept connections initiated on either - of the @ref BLE_GAP_PHYS_SUPPORTED PHYs. - If scan_phys contains @ref BLE_GAP_PHY_1MBPS and/or @ref BLE_GAP_PHY_2MBPS, - the primary scan PHY is @ref BLE_GAP_PHY_1MBPS. - If scan_phys also contains @ref BLE_GAP_PHY_CODED, the primary scan - PHY will also contain @ref BLE_GAP_PHY_CODED. If the only scan PHY is - @ref BLE_GAP_PHY_CODED, the primary scan PHY is - @ref BLE_GAP_PHY_CODED only. */ - uint16_t interval; /**< Scan interval in 625 us units. @sa BLE_GAP_SCAN_INTERVALS. */ - uint16_t window; /**< Scan window in 625 us units. @sa BLE_GAP_SCAN_WINDOW. - If scan_phys contains both @ref BLE_GAP_PHY_1MBPS and - @ref BLE_GAP_PHY_CODED interval shall be larger than or - equal to twice the scan window. */ - uint16_t timeout; /**< Scan timeout in 10 ms units. @sa BLE_GAP_SCAN_TIMEOUT. */ - ble_gap_ch_mask_t channel_mask; /**< Channel mask for primary and secondary advertising channels. - At least one of the primary channels, that is channel index 37-39, must be - set to 0. - Masking away secondary channels is not supported. */ -} ble_gap_scan_params_t; - -/**@brief Privacy. - * - * The privacy feature provides a way for the device to avoid being tracked over a period of time. - * The privacy feature, when enabled, hides the local device identity and replaces it with a private address - * that is automatically refreshed at a specified interval. - * - * If a device still wants to be recognized by other peers, it needs to share it's Identity Resolving Key (IRK). - * With this key, a device can generate a random private address that can only be recognized by peers in possession of that - * key, and devices can establish connections without revealing their real identities. - * - * Both network privacy (@ref BLE_GAP_PRIVACY_MODE_NETWORK_PRIVACY) and device privacy (@ref - * BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY) are supported. - * - * @note If the device IRK is updated, the new IRK becomes the one to be distributed in all - * bonding procedures performed after @ref sd_ble_gap_privacy_set returns. - * The IRK distributed during bonding procedure is the device IRK that is active when @ref sd_ble_gap_sec_params_reply is - * called. - */ -typedef struct { - uint8_t privacy_mode; /**< Privacy mode, see @ref BLE_GAP_PRIVACY_MODES. Default is @ref BLE_GAP_PRIVACY_MODE_OFF. */ - uint8_t private_addr_type; /**< The private address type must be either @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE or - @ref BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE. */ - uint16_t private_addr_cycle_s; /**< Private address cycle interval in seconds. Providing an address cycle value of 0 will use - the default value defined by @ref BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S. */ - ble_gap_irk_t - *p_device_irk; /**< When used as input, pointer to IRK structure that will be used as the default IRK. If NULL, the device - default IRK will be used. When used as output, pointer to IRK structure where the current default IRK - will be written to. If NULL, this argument is ignored. By default, the default IRK is used to generate - random private resolvable addresses for the local device unless instructed otherwise. */ -} ble_gap_privacy_params_t; - -/**@brief PHY preferences for TX and RX - * @note tx_phys and rx_phys are bit fields. Multiple bits can be set in them to indicate multiple preferred PHYs for each - * direction. - * @code - * p_gap_phys->tx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; - * p_gap_phys->rx_phys = BLE_GAP_PHY_1MBPS | BLE_GAP_PHY_2MBPS; - * @endcode - * - */ -typedef struct { - uint8_t tx_phys; /**< Preferred transmit PHYs, see @ref BLE_GAP_PHYS. */ - uint8_t rx_phys; /**< Preferred receive PHYs, see @ref BLE_GAP_PHYS. */ -} ble_gap_phys_t; - -/** @brief Keys that can be exchanged during a bonding procedure. */ -typedef struct { - uint8_t enc : 1; /**< Long Term Key and Master Identification. */ - uint8_t id : 1; /**< Identity Resolving Key and Identity Address Information. */ - uint8_t sign : 1; /**< Connection Signature Resolving Key. */ - uint8_t link : 1; /**< Derive the Link Key from the LTK. */ -} ble_gap_sec_kdist_t; - -/**@brief GAP security parameters. */ -typedef struct { - uint8_t bond : 1; /**< Perform bonding. */ - uint8_t mitm : 1; /**< Enable Man In The Middle protection. */ - uint8_t lesc : 1; /**< Enable LE Secure Connection pairing. */ - uint8_t keypress : 1; /**< Enable generation of keypress notifications. */ - uint8_t io_caps : 3; /**< IO capabilities, see @ref BLE_GAP_IO_CAPS. */ - uint8_t oob : 1; /**< The OOB data flag. - - In LE legacy pairing, this flag is set if a device has out of band authentication data. - The OOB method is used if both of the devices have out of band authentication data. - - In LE Secure Connections pairing, this flag is set if a device has the peer device's out of band - authentication data. The OOB method is used if at least one device has the peer device's OOB data - available. */ - uint8_t - min_key_size; /**< Minimum encryption key size in octets between 7 and 16. If 0 then not applicable in this instance. */ - uint8_t max_key_size; /**< Maximum encryption key size in octets between min_key_size and 16. */ - ble_gap_sec_kdist_t kdist_own; /**< Key distribution bitmap: keys that the local device will distribute. */ - ble_gap_sec_kdist_t kdist_peer; /**< Key distribution bitmap: keys that the remote device will distribute. */ -} ble_gap_sec_params_t; - -/**@brief GAP Encryption Information. */ -typedef struct { - uint8_t ltk[BLE_GAP_SEC_KEY_LEN]; /**< Long Term Key. */ - uint8_t lesc : 1; /**< Key generated using LE Secure Connections. */ - uint8_t auth : 1; /**< Authenticated Key. */ - uint8_t ltk_len : 6; /**< LTK length in octets. */ -} ble_gap_enc_info_t; - -/**@brief GAP Master Identification. */ -typedef struct { - uint16_t ediv; /**< Encrypted Diversifier. */ - uint8_t rand[BLE_GAP_SEC_RAND_LEN]; /**< Random Number. */ -} ble_gap_master_id_t; - -/**@brief GAP Signing Information. */ -typedef struct { - uint8_t csrk[BLE_GAP_SEC_KEY_LEN]; /**< Connection Signature Resolving Key. */ -} ble_gap_sign_info_t; - -/**@brief GAP LE Secure Connections P-256 Public Key. */ -typedef struct { - uint8_t pk[BLE_GAP_LESC_P256_PK_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman P-256 Public Key. Stored in the - standard SMP protocol format: {X,Y} both in little-endian. */ -} ble_gap_lesc_p256_pk_t; - -/**@brief GAP LE Secure Connections DHKey. */ -typedef struct { - uint8_t key[BLE_GAP_LESC_DHKEY_LEN]; /**< LE Secure Connections Elliptic Curve Diffie-Hellman Key. Stored in little-endian. */ -} ble_gap_lesc_dhkey_t; - -/**@brief GAP LE Secure Connections OOB data. */ -typedef struct { - ble_gap_addr_t addr; /**< Bluetooth address of the device. */ - uint8_t r[BLE_GAP_SEC_KEY_LEN]; /**< Random Number. */ - uint8_t c[BLE_GAP_SEC_KEY_LEN]; /**< Confirm Value. */ -} ble_gap_lesc_oob_data_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONNECTED. */ -typedef struct { - ble_gap_addr_t - peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref - ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ - uint8_t role; /**< BLE role for this connection, see @ref BLE_GAP_ROLES */ - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ - uint8_t adv_handle; /**< Advertising handle in which advertising has ended. - This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ - ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated - advertising set. The advertising buffers provided in - @ref sd_ble_gap_adv_set_configure are now released. - This variable is only set if role is set to @ref BLE_GAP_ROLE_PERIPH. */ -} ble_gap_evt_connected_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DISCONNECTED. */ -typedef struct { - uint8_t reason; /**< HCI error code, see @ref BLE_HCI_STATUS_CODES. */ -} ble_gap_evt_disconnected_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE. */ -typedef struct { - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ -} ble_gap_evt_conn_param_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_PHY_UPDATE_REQUEST. */ -typedef struct { - ble_gap_phys_t peer_preferred_phys; /**< The PHYs the peer prefers to use. */ -} ble_gap_evt_phy_update_request_t; - -/**@brief Event Structure for @ref BLE_GAP_EVT_PHY_UPDATE. */ -typedef struct { - uint8_t status; /**< Status of the procedure, see @ref BLE_HCI_STATUS_CODES.*/ - uint8_t tx_phy; /**< TX PHY for this connection, see @ref BLE_GAP_PHYS. */ - uint8_t rx_phy; /**< RX PHY for this connection, see @ref BLE_GAP_PHYS. */ -} ble_gap_evt_phy_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. */ -typedef struct { - ble_gap_sec_params_t peer_params; /**< Initiator Security Parameters. */ -} ble_gap_evt_sec_params_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_INFO_REQUEST. */ -typedef struct { - ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. */ - ble_gap_master_id_t master_id; /**< Master Identification for LTK lookup. */ - uint8_t enc_info : 1; /**< If 1, Encryption Information required. */ - uint8_t id_info : 1; /**< If 1, Identity Information required. */ - uint8_t sign_info : 1; /**< If 1, Signing Information required. */ -} ble_gap_evt_sec_info_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_PASSKEY_DISPLAY. */ -typedef struct { - uint8_t passkey[BLE_GAP_PASSKEY_LEN]; /**< 6-digit passkey in ASCII ('0'-'9' digits only). */ - uint8_t match_request : 1; /**< If 1 requires the application to report the match using @ref sd_ble_gap_auth_key_reply - with either @ref BLE_GAP_AUTH_KEY_TYPE_NONE if there is no match or - @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY if there is a match. */ -} ble_gap_evt_passkey_display_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_KEY_PRESSED. */ -typedef struct { - uint8_t kp_not; /**< Keypress notification type, see @ref BLE_GAP_KP_NOT_TYPES. */ -} ble_gap_evt_key_pressed_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_KEY_REQUEST. */ -typedef struct { - uint8_t key_type; /**< See @ref BLE_GAP_AUTH_KEY_TYPES. */ -} ble_gap_evt_auth_key_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST. */ -typedef struct { - ble_gap_lesc_p256_pk_t - *p_pk_peer; /**< LE Secure Connections remote P-256 Public Key. This will point to the application-supplied memory - inside the keyset during the call to @ref sd_ble_gap_sec_params_reply. */ - uint8_t oobd_req : 1; /**< LESC OOB data required. A call to @ref sd_ble_gap_lesc_oob_data_set is required to complete the - procedure. */ -} ble_gap_evt_lesc_dhkey_request_t; - -/**@brief Security levels supported. - * @note See Bluetooth Specification Version 4.2 Volume 3, Part C, Chapter 10, Section 10.2.1. - */ -typedef struct { - uint8_t lv1 : 1; /**< If 1: Level 1 is supported. */ - uint8_t lv2 : 1; /**< If 1: Level 2 is supported. */ - uint8_t lv3 : 1; /**< If 1: Level 3 is supported. */ - uint8_t lv4 : 1; /**< If 1: Level 4 is supported. */ -} ble_gap_sec_levels_t; - -/**@brief Encryption Key. */ -typedef struct { - ble_gap_enc_info_t enc_info; /**< Encryption Information. */ - ble_gap_master_id_t master_id; /**< Master Identification. */ -} ble_gap_enc_key_t; - -/**@brief Identity Key. */ -typedef struct { - ble_gap_irk_t id_info; /**< Identity Resolving Key. */ - ble_gap_addr_t id_addr_info; /**< Identity Address. */ -} ble_gap_id_key_t; - -/**@brief Security Keys. */ -typedef struct { - ble_gap_enc_key_t *p_enc_key; /**< Encryption Key, or NULL. */ - ble_gap_id_key_t *p_id_key; /**< Identity Key, or NULL. */ - ble_gap_sign_info_t *p_sign_key; /**< Signing Key, or NULL. */ - ble_gap_lesc_p256_pk_t *p_pk; /**< LE Secure Connections P-256 Public Key. When in debug mode the application must use the - value defined in the Core Bluetooth Specification v4.2 Vol.3, Part H, Section 2.3.5.6.1 */ -} ble_gap_sec_keys_t; - -/**@brief Security key set for both local and peer keys. */ -typedef struct { - ble_gap_sec_keys_t keys_own; /**< Keys distributed by the local device. For LE Secure Connections the encryption key will be - generated locally and will always be stored if bonding. */ - ble_gap_sec_keys_t - keys_peer; /**< Keys distributed by the remote device. For LE Secure Connections, p_enc_key must always be NULL. */ -} ble_gap_sec_keyset_t; - -/**@brief Data Length Update Procedure parameters. */ -typedef struct { - uint16_t max_tx_octets; /**< Maximum number of payload octets that a Controller supports for transmission of a single Link - Layer Data Channel PDU. */ - uint16_t max_rx_octets; /**< Maximum number of payload octets that a Controller supports for reception of a single Link Layer - Data Channel PDU. */ - uint16_t max_tx_time_us; /**< Maximum time, in microseconds, that a Controller supports for transmission of a single Link - Layer Data Channel PDU. */ - uint16_t max_rx_time_us; /**< Maximum time, in microseconds, that a Controller supports for reception of a single Link Layer - Data Channel PDU. */ -} ble_gap_data_length_params_t; - -/**@brief Data Length Update Procedure local limitation. */ -typedef struct { - uint16_t tx_payload_limited_octets; /**< If > 0, the requested TX packet length is too long by this many octets. */ - uint16_t rx_payload_limited_octets; /**< If > 0, the requested RX packet length is too long by this many octets. */ - uint16_t tx_rx_time_limited_us; /**< If > 0, the requested combination of TX and RX packet lengths is too long by this many - microseconds. */ -} ble_gap_data_length_limitation_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_AUTH_STATUS. */ -typedef struct { - uint8_t auth_status; /**< Authentication status, see @ref BLE_GAP_SEC_STATUS. */ - uint8_t error_src : 2; /**< On error, source that caused the failure, see @ref BLE_GAP_SEC_STATUS_SOURCES. */ - uint8_t bonded : 1; /**< Procedure resulted in a bond. */ - uint8_t lesc : 1; /**< Procedure resulted in a LE Secure Connection. */ - ble_gap_sec_levels_t sm1_levels; /**< Levels supported in Security Mode 1. */ - ble_gap_sec_levels_t sm2_levels; /**< Levels supported in Security Mode 2. */ - ble_gap_sec_kdist_t kdist_own; /**< Bitmap stating which keys were exchanged (distributed) by the local device. If bonding - with LE Secure Connections, the enc bit will be always set. */ - ble_gap_sec_kdist_t kdist_peer; /**< Bitmap stating which keys were exchanged (distributed) by the remote device. If bonding - with LE Secure Connections, the enc bit will never be set. */ -} ble_gap_evt_auth_status_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_SEC_UPDATE. */ -typedef struct { - ble_gap_conn_sec_t conn_sec; /**< Connection security level. */ -} ble_gap_evt_conn_sec_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Source of timeout event, see @ref BLE_GAP_TIMEOUT_SOURCES. */ - union { - ble_data_t adv_report_buffer; /**< If source is set to @ref BLE_GAP_TIMEOUT_SRC_SCAN, the released - scan buffer is contained in this field. */ - } params; /**< Event Parameters. */ -} ble_gap_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_RSSI_CHANGED. */ -typedef struct { - int8_t rssi; /**< Received Signal Strength Indication in dBm. - @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature - measurement. */ - uint8_t ch_index; /**< Data Channel Index on which the Signal Strength is measured (0-36). */ -} ble_gap_evt_rssi_changed_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_ADV_SET_TERMINATED */ -typedef struct { - uint8_t reason; /**< Reason for why the advertising set terminated. See - @ref BLE_GAP_EVT_ADV_SET_TERMINATED_REASON. */ - uint8_t adv_handle; /**< Advertising handle in which advertising has ended. */ - uint8_t num_completed_adv_events; /**< If @ref ble_gap_adv_params_t::max_adv_evts was not set to 0, - this field indicates the number of completed advertising events. */ - ble_gap_adv_data_t adv_data; /**< Advertising buffers corresponding to the terminated - advertising set. The advertising buffers provided in - @ref sd_ble_gap_adv_set_configure are now released. */ -} ble_gap_evt_adv_set_terminated_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; - -/**@brief Event structure for @ref BLE_GAP_EVT_SEC_REQUEST. */ -typedef struct { - uint8_t bond : 1; /**< Perform bonding. */ - uint8_t mitm : 1; /**< Man In The Middle protection requested. */ - uint8_t lesc : 1; /**< LE Secure Connections requested. */ - uint8_t keypress : 1; /**< Generation of keypress notifications requested. */ -} ble_gap_evt_sec_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST. */ -typedef struct { - ble_gap_conn_params_t conn_params; /**< GAP Connection Parameters. */ -} ble_gap_evt_conn_param_update_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_SCAN_REQ_REPORT. */ -typedef struct { - uint8_t adv_handle; /**< Advertising handle for the advertising set which received the Scan Request */ - int8_t rssi; /**< Received Signal Strength Indication in dBm. - @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature - measurement. */ - ble_gap_addr_t peer_addr; /**< Bluetooth address of the peer device. If the peer_addr resolved: @ref - ble_gap_addr_t::addr_id_peer is set to 1 and the address is the device's identity address. */ -} ble_gap_evt_scan_req_report_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST. */ -typedef struct { - ble_gap_data_length_params_t peer_params; /**< Peer data length parameters. */ -} ble_gap_evt_data_length_update_request_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE. - * - * @note This event may also be raised after a PHY Update procedure. - */ -typedef struct { - ble_gap_data_length_params_t effective_params; /**< The effective data length parameters. */ -} ble_gap_evt_data_length_update_t; - -/**@brief Event structure for @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT. */ -typedef struct { - int8_t - channel_energy[BLE_GAP_CHANNEL_COUNT]; /**< The measured energy on the Bluetooth Low Energy - channels, in dBm, indexed by Channel Index. - If no measurement is available for the given channel, channel_energy is set to - @ref BLE_GAP_POWER_LEVEL_INVALID. */ -} ble_gap_evt_qos_channel_survey_report_t; - -/**@brief GAP event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which event occurred. */ - union /**< union alternative identified by evt_id in enclosing struct. */ - { - ble_gap_evt_connected_t connected; /**< Connected Event Parameters. */ - ble_gap_evt_disconnected_t disconnected; /**< Disconnected Event Parameters. */ - ble_gap_evt_conn_param_update_t conn_param_update; /**< Connection Parameter Update Parameters. */ - ble_gap_evt_sec_params_request_t sec_params_request; /**< Security Parameters Request Event Parameters. */ - ble_gap_evt_sec_info_request_t sec_info_request; /**< Security Information Request Event Parameters. */ - ble_gap_evt_passkey_display_t passkey_display; /**< Passkey Display Event Parameters. */ - ble_gap_evt_key_pressed_t key_pressed; /**< Key Pressed Event Parameters. */ - ble_gap_evt_auth_key_request_t auth_key_request; /**< Authentication Key Request Event Parameters. */ - ble_gap_evt_lesc_dhkey_request_t lesc_dhkey_request; /**< LE Secure Connections DHKey calculation request. */ - ble_gap_evt_auth_status_t auth_status; /**< Authentication Status Event Parameters. */ - ble_gap_evt_conn_sec_update_t conn_sec_update; /**< Connection Security Update Event Parameters. */ - ble_gap_evt_timeout_t timeout; /**< Timeout Event Parameters. */ - ble_gap_evt_rssi_changed_t rssi_changed; /**< RSSI Event Parameters. */ - ble_gap_evt_adv_report_t adv_report; /**< Advertising Report Event Parameters. */ - ble_gap_evt_adv_set_terminated_t adv_set_terminated; /**< Advertising Set Terminated Event Parameters. */ - ble_gap_evt_sec_request_t sec_request; /**< Security Request Event Parameters. */ - ble_gap_evt_conn_param_update_request_t conn_param_update_request; /**< Connection Parameter Update Parameters. */ - ble_gap_evt_scan_req_report_t scan_req_report; /**< Scan Request Report Parameters. */ - ble_gap_evt_phy_update_request_t phy_update_request; /**< PHY Update Request Event Parameters. */ - ble_gap_evt_phy_update_t phy_update; /**< PHY Update Parameters. */ - ble_gap_evt_data_length_update_request_t data_length_update_request; /**< Data Length Update Request Event Parameters. */ - ble_gap_evt_data_length_update_t data_length_update; /**< Data Length Update Event Parameters. */ - ble_gap_evt_qos_channel_survey_report_t - qos_channel_survey_report; /**< Quality of Service (QoS) Channel Survey Report Parameters. */ - } params; /**< Event Parameters. */ -} ble_gap_evt_t; - -/** - * @brief BLE GAP connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_CONN_COUNT The connection count for the connection configurations is zero. - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - The sum of conn_count for all connection configurations combined exceeds UINT8_MAX. - * - The event length is smaller than @ref BLE_GAP_EVENT_LENGTH_MIN. - */ -typedef struct { - uint8_t conn_count; /**< The number of concurrent connections the application can create with this configuration. - The default and minimum value is @ref BLE_GAP_CONN_COUNT_DEFAULT. */ - uint16_t event_length; /**< The time set aside for this connection on every connection interval in 1.25 ms units. - The default value is @ref BLE_GAP_EVENT_LENGTH_DEFAULT, the minimum value is @ref - BLE_GAP_EVENT_LENGTH_MIN. The event length and the connection interval are the primary parameters - for setting the throughput of a connection. - See the SoftDevice Specification for details on throughput. */ -} ble_gap_conn_cfg_t; - -/** - * @brief Configuration of maximum concurrent connections in the different connected roles, set with - * @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_CONN_COUNT The sum of periph_role_count and central_role_count is too - * large. The maximum supported sum of concurrent connections is - * @ref BLE_GAP_ROLE_COUNT_COMBINED_MAX. - * @retval ::NRF_ERROR_INVALID_PARAM central_sec_count is larger than central_role_count. - * @retval ::NRF_ERROR_RESOURCES The adv_set_count is too large. The maximum - * supported advertising handles is - * @ref BLE_GAP_ADV_SET_COUNT_MAX. - */ -typedef struct { - uint8_t adv_set_count; /**< Maximum number of advertising sets. Default value is @ref BLE_GAP_ADV_SET_COUNT_DEFAULT. */ - uint8_t periph_role_count; /**< Maximum number of connections concurrently acting as a peripheral. Default value is @ref - BLE_GAP_ROLE_COUNT_PERIPH_DEFAULT. */ - uint8_t central_role_count; /**< Maximum number of connections concurrently acting as a central. Default value is @ref - BLE_GAP_ROLE_COUNT_CENTRAL_DEFAULT. */ - uint8_t central_sec_count; /**< Number of SMP instances shared between all connections acting as a central. Default value is - @ref BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT. */ - uint8_t qos_channel_survey_role_available : 1; /**< If set, the Quality of Service (QoS) channel survey module is available to - the application using @ref sd_ble_gap_qos_channel_survey_start. */ -} ble_gap_cfg_role_count_t; - -/** - * @brief Device name and its properties, set with @ref sd_ble_cfg_set. - * - * @note If the device name is not configured, the default device name will be - * @ref BLE_GAP_DEVNAME_DEFAULT, the maximum device name length will be - * @ref BLE_GAP_DEVNAME_DEFAULT_LEN, vloc will be set to @ref BLE_GATTS_VLOC_STACK and the device name - * will have no write access. - * - * @note If @ref max_len is more than @ref BLE_GAP_DEVNAME_DEFAULT_LEN and vloc is set to @ref BLE_GATTS_VLOC_STACK, - * the attribute table size must be increased to have room for the longer device name (see - * @ref sd_ble_cfg_set and @ref ble_gatts_cfg_attr_tab_size_t). - * - * @note If vloc is @ref BLE_GATTS_VLOC_STACK : - * - p_value must point to non-volatile memory (flash) or be NULL. - * - If p_value is NULL, the device name will initially be empty. - * - * @note If vloc is @ref BLE_GATTS_VLOC_USER : - * - p_value cannot be NULL. - * - If the device name is writable, p_value must point to volatile memory (RAM). - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - Invalid device name location (vloc). - * - Invalid device name security mode. - * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: - * - The device name length is invalid (must be between 0 and @ref BLE_GAP_DEVNAME_MAX_LEN). - * - The device name length is too long for the given Attribute Table. - * @retval ::NRF_ERROR_NOT_SUPPORTED Device name security mode is not supported. - */ -typedef struct { - ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ - uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ - uint8_t *p_value; /**< Pointer to where the value (device name) is stored or will be stored. */ - uint16_t current_len; /**< Current length in bytes of the memory pointed to by p_value.*/ - uint16_t max_len; /**< Maximum length in bytes of the memory pointed to by p_value.*/ -} ble_gap_cfg_device_name_t; - -/**@brief Peripheral Preferred Connection Parameters include configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t include_cfg; /**< Inclusion configuration of the Peripheral Preferred Connection Parameters characteristic. - See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_PPCP_INCL_CONFIG_DEFAULT. */ -} ble_gap_cfg_ppcp_incl_cfg_t; - -/**@brief Central Address Resolution include configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t include_cfg; /**< Inclusion configuration of the Central Address Resolution characteristic. - See @ref BLE_GAP_CHAR_INCL_CONFIG. Default is @ref BLE_GAP_CAR_INCL_CONFIG_DEFAULT. */ -} ble_gap_cfg_car_incl_cfg_t; - -/**@brief Configuration structure for GAP configurations. */ -typedef union { - ble_gap_cfg_role_count_t role_count_cfg; /**< Role count configuration, cfg_id is @ref BLE_GAP_CFG_ROLE_COUNT. */ - ble_gap_cfg_device_name_t device_name_cfg; /**< Device name configuration, cfg_id is @ref BLE_GAP_CFG_DEVICE_NAME. */ - ble_gap_cfg_ppcp_incl_cfg_t ppcp_include_cfg; /**< Peripheral Preferred Connection Parameters characteristic include - configuration, cfg_id is @ref BLE_GAP_CFG_PPCP_INCL_CONFIG. */ - ble_gap_cfg_car_incl_cfg_t car_include_cfg; /**< Central Address Resolution characteristic include configuration, - cfg_id is @ref BLE_GAP_CFG_CAR_INCL_CONFIG. */ -} ble_gap_cfg_t; - -/**@brief Channel Map option. - * - * @details Used with @ref sd_ble_opt_get to get the current channel map - * or @ref sd_ble_opt_set to set a new channel map. When setting the - * channel map, it applies to all current and future connections. When getting the - * current channel map, it applies to a single connection and the connection handle - * must be supplied. - * - * @note Setting the channel map may take some time, depending on connection parameters. - * The time taken may be different for each connection and the get operation will - * return the previous channel map until the new one has taken effect. - * - * @note After setting the channel map, by spec it can not be set again until at least 1 s has passed. - * See Bluetooth Specification Version 4.1 Volume 2, Part E, Section 7.3.46. - * - * @retval ::NRF_SUCCESS Get or set successful. - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - Less then two bits in @ref ch_map are set. - * - Bits for primary advertising channels (37-39) are set. - * @retval ::NRF_ERROR_BUSY Channel map was set again before enough time had passed. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied for get. - * - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle (only applicable for get) */ - uint8_t ch_map[5]; /**< Channel Map (37-bit). */ -} ble_gap_opt_ch_map_t; - -/**@brief Local connection latency option. - * - * @details Local connection latency is a feature which enables the slave to improve - * current consumption by ignoring the slave latency set by the peer. The - * local connection latency can only be set to a multiple of the slave latency, - * and cannot be longer than half of the supervision timeout. - * - * @details Used with @ref sd_ble_opt_set to set the local connection latency. The - * @ref sd_ble_opt_get is not supported for this option, but the actual - * local connection latency (unless set to NULL) is set as a return parameter - * when setting the option. - * - * @note The latency set will be truncated down to the closest slave latency event - * multiple, or the nearest multiple before half of the supervision timeout. - * - * @note The local connection latency is disabled by default, and needs to be enabled for new - * connections and whenever the connection is updated. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint16_t requested_latency; /**< Requested local connection latency. */ - uint16_t *p_actual_latency; /**< Pointer to storage for the actual local connection latency (can be set to NULL to skip return - value). */ -} ble_gap_opt_local_conn_latency_t; - -/**@brief Disable slave latency - * - * @details Used with @ref sd_ble_opt_set to temporarily disable slave latency of a peripheral connection - * (see @ref ble_gap_conn_params_t::slave_latency). And to re-enable it again. When disabled, the - * peripheral will ignore the slave_latency set by the central. - * - * @note Shall only be called on peripheral links. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_NOT_SUPPORTED Get is not supported. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint8_t disable; /**< For allowed values see @ref BLE_GAP_SLAVE_LATENCY */ -} ble_gap_opt_slave_latency_disable_t; - -/**@brief Passkey Option. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} - * @endmscs - * - * @details Structure containing the passkey to be used during pairing. This can be used with @ref - * sd_ble_opt_set to make the SoftDevice use a preprogrammed passkey for authentication - * instead of generating a random one. - * - * @note Repeated pairing attempts using the same preprogrammed passkey makes pairing vulnerable to MITM attacks. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * - */ -typedef struct { - uint8_t const *p_passkey; /**< Pointer to 6-digit ASCII string (digit 0..9 only, no NULL termination) passkey to be used - during pairing. If this is NULL, the SoftDevice will generate a random passkey if required.*/ -} ble_gap_opt_passkey_t; - -/**@brief Compatibility mode 1 option. - * - * @details This can be used with @ref sd_ble_opt_set to enable and disable - * compatibility mode 1. Compatibility mode 1 is disabled by default. - * - * @note Compatibility mode 1 enables interoperability with devices that do not support a value of - * 0 for the WinOffset parameter in the Link Layer CONNECT_IND packet. This applies to a - * limited set of legacy peripheral devices from another vendor. Enabling this compatibility - * mode will only have an effect if the local device will act as a central device and - * initiate a connection to a peripheral device. In that case it may lead to the connection - * creation taking up to one connection interval longer to complete for all connections. - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_INVALID_STATE When connection creation is ongoing while mode 1 is set. - */ -typedef struct { - uint8_t enable : 1; /**< Enable compatibility mode 1.*/ -} ble_gap_opt_compat_mode_1_t; - -/**@brief Authenticated payload timeout option. - * - * @details This can be used with @ref sd_ble_opt_set to change the Authenticated payload timeout to a value other - * than the default of @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT_MAX. - * - * @note The authenticated payload timeout event ::BLE_GAP_TIMEOUT_SRC_AUTH_PAYLOAD will be generated - * if auth_payload_timeout time has elapsed without receiving a packet with a valid MIC on an encrypted - * link. - * - * @note The LE ping procedure will be initiated before the timer expires to give the peer a chance - * to reset the timer. In addition the stack will try to prioritize running of LE ping over other - * activities to increase chances of finishing LE ping before timer expires. To avoid side-effects - * on other activities, it is recommended to use high timeout values. - * Recommended timeout > 2*(connInterval * (6 + connSlaveLatency)). - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. auth_payload_timeout was outside of allowed range. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter. - */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle */ - uint16_t auth_payload_timeout; /**< Requested timeout in 10 ms unit, see @ref BLE_GAP_AUTH_PAYLOAD_TIMEOUT. */ -} ble_gap_opt_auth_payload_timeout_t; - -/**@brief Option structure for GAP options. */ -typedef union { - ble_gap_opt_ch_map_t ch_map; /**< Parameters for the Channel Map option. */ - ble_gap_opt_local_conn_latency_t local_conn_latency; /**< Parameters for the Local connection latency option */ - ble_gap_opt_passkey_t passkey; /**< Parameters for the Passkey option.*/ - ble_gap_opt_compat_mode_1_t compat_mode_1; /**< Parameters for the compatibility mode 1 option.*/ - ble_gap_opt_auth_payload_timeout_t auth_payload_timeout; /**< Parameters for the authenticated payload timeout option.*/ - ble_gap_opt_slave_latency_disable_t slave_latency_disable; /**< Parameters for the Disable slave latency option */ -} ble_gap_opt_t; - -/**@brief Connection event triggering parameters. */ -typedef struct { - uint8_t ppi_ch_id; /**< PPI channel to use. This channel should be regarded as reserved until - connection event PPI task triggering is stopped. - The PPI channel ID can not be one of the PPI channels reserved by - the SoftDevice. See @ref NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK. */ - uint32_t task_endpoint; /**< Task Endpoint to trigger. */ - uint16_t conn_evt_counter_start; /**< The connection event on which the task triggering should start. */ - uint16_t period_in_events; /**< Trigger period. Valid range is [1, 32767]. - If the device is in slave role and slave latency is enabled, - this parameter should be set to a multiple of (slave latency + 1) - to ensure low power operation. */ -} ble_gap_conn_event_trigger_t; -/**@} */ - -/**@addtogroup BLE_GAP_FUNCTIONS Functions - * @{ */ - -/**@brief Set the local Bluetooth identity address. - * - * The local Bluetooth identity address is the address that identifies this device to other peers. - * The address type must be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. - * - * @note The identity address cannot be changed while advertising, scanning or creating a connection. - * - * @note This address will be distributed to the peer during bonding. - * If the address changes, the address stored in the peer device will not be valid and the ability to - * reconnect using the old address will be lost. - * - * @note By default the SoftDevice will set an address of type @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC upon being - * enabled. The address is a random number populated during the IC manufacturing process and remains unchanged - * for the lifetime of each IC. - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @endmscs - * - * @param[in] p_addr Pointer to address structure. - * - * @retval ::NRF_SUCCESS Address successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_STATE The identity address cannot be changed while advertising, - * scanning or creating a connection. - */ -SVCALL(SD_BLE_GAP_ADDR_SET, uint32_t, sd_ble_gap_addr_set(ble_gap_addr_t const *p_addr)); - -/**@brief Get local Bluetooth identity address. - * - * @note This will always return the identity address irrespective of the privacy settings, - * i.e. the address type will always be either @ref BLE_GAP_ADDR_TYPE_PUBLIC or @ref BLE_GAP_ADDR_TYPE_RANDOM_STATIC. - * - * @param[out] p_addr Pointer to address structure to be filled in. - * - * @retval ::NRF_SUCCESS Address successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - */ -SVCALL(SD_BLE_GAP_ADDR_GET, uint32_t, sd_ble_gap_addr_get(ble_gap_addr_t *p_addr)); - -/**@brief Get the Bluetooth device address used by the advertiser. - * - * @note This function will return the local Bluetooth address used in advertising PDUs. When - * using privacy, the SoftDevice will generate a new private address every - * @ref ble_gap_privacy_params_t::private_addr_cycle_s configured using - * @ref sd_ble_gap_privacy_set. Hence depending on when the application calls this API, the - * address returned may not be the latest address that is used in the advertising PDUs. - * - * @param[in] adv_handle The advertising handle to get the address from. - * @param[out] p_addr Pointer to address structure to be filled in. - * - * @retval ::NRF_SUCCESS Address successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid or NULL pointer supplied. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. - * @retval ::NRF_ERROR_INVALID_STATE The advertising set is currently not advertising. - */ -SVCALL(SD_BLE_GAP_ADV_ADDR_GET, uint32_t, sd_ble_gap_adv_addr_get(uint8_t adv_handle, ble_gap_addr_t *p_addr)); - -/**@brief Set the active whitelist in the SoftDevice. - * - * @note Only one whitelist can be used at a time and the whitelist is shared between the BLE roles. - * The whitelist cannot be set if a BLE role is using the whitelist. - * - * @note If an address is resolved using the information in the device identity list, then the whitelist - * filter policy applies to the peer identity address and not the resolvable address sent on air. - * - * @mscs - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} - * @endmscs - * - * @param[in] pp_wl_addrs Pointer to a whitelist of peer addresses, if NULL the whitelist will be cleared. - * @param[in] len Length of the whitelist, maximum @ref BLE_GAP_WHITELIST_ADDR_MAX_COUNT. - * - * @retval ::NRF_SUCCESS The whitelist is successfully set/cleared. - * @retval ::NRF_ERROR_INVALID_ADDR The whitelist (or one of its entries) provided is invalid. - * @retval ::BLE_ERROR_GAP_WHITELIST_IN_USE The whitelist is in use by a BLE role and cannot be set or cleared. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_DATA_SIZE The given whitelist size is invalid (zero or too large); this can only return when - * pp_wl_addrs is not NULL. - */ -SVCALL(SD_BLE_GAP_WHITELIST_SET, uint32_t, sd_ble_gap_whitelist_set(ble_gap_addr_t const *const *pp_wl_addrs, uint8_t len)); - -/**@brief Set device identity list. - * - * @note Only one device identity list can be used at a time and the list is shared between the BLE roles. - * The device identity list cannot be set if a BLE role is using the list. - * - * @param[in] pp_id_keys Pointer to an array of peer identity addresses and peer IRKs, if NULL the device identity list will - * be cleared. - * @param[in] pp_local_irks Pointer to an array of local IRKs. Each entry in the array maps to the entry in pp_id_keys at the - * same index. To fill in the list with the currently set device IRK for all peers, set to NULL. - * @param[in] len Length of the device identity list, maximum @ref BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT. - * - * @mscs - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_PRIVATE_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS The device identity list successfully set/cleared. - * @retval ::NRF_ERROR_INVALID_ADDR The device identity list (or one of its entries) provided is invalid. - * This code may be returned if the local IRK list also has an invalid entry. - * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_IN_USE The device identity list is in use and cannot be set or cleared. - * @retval ::BLE_ERROR_GAP_DEVICE_IDENTITIES_DUPLICATE The device identity list contains multiple entries with the same identity - * address. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_DATA_SIZE The given device identity list size invalid (zero or too large); this can - * only return when pp_id_keys is not NULL. - */ -SVCALL(SD_BLE_GAP_DEVICE_IDENTITIES_SET, uint32_t, - sd_ble_gap_device_identities_set(ble_gap_id_key_t const *const *pp_id_keys, ble_gap_irk_t const *const *pp_local_irks, - uint8_t len)); - -/**@brief Set privacy settings. - * - * @note Privacy settings cannot be changed while advertising, scanning or creating a connection. - * - * @param[in] p_privacy_params Privacy settings. - * - * @mscs - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_SCAN_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Set successfully. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid address type is supplied. - * @retval ::NRF_ERROR_INVALID_ADDR The pointer to privacy settings is NULL or invalid. - * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. - * @retval ::NRF_ERROR_INVALID_PARAM Out of range parameters are provided. - * @retval ::NRF_ERROR_NOT_SUPPORTED The SoftDevice does not support privacy if the Central Address Resolution - characteristic is not configured to be included and the SoftDevice is configured - to support central roles. - See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - * @retval ::NRF_ERROR_INVALID_STATE Privacy settings cannot be changed while advertising, scanning - * or creating a connection. - */ -SVCALL(SD_BLE_GAP_PRIVACY_SET, uint32_t, sd_ble_gap_privacy_set(ble_gap_privacy_params_t const *p_privacy_params)); - -/**@brief Get privacy settings. - * - * @note ::ble_gap_privacy_params_t::p_device_irk must be initialized to NULL or a valid address before this function is called. - * If it is initialized to a valid address, the address pointed to will contain the current device IRK on return. - * - * @param[in,out] p_privacy_params Privacy settings. - * - * @retval ::NRF_SUCCESS Privacy settings read. - * @retval ::NRF_ERROR_INVALID_ADDR The pointer given for returning the privacy settings may be NULL or invalid. - * Otherwise, the p_device_irk pointer in privacy parameter is an invalid pointer. - */ -SVCALL(SD_BLE_GAP_PRIVACY_GET, uint32_t, sd_ble_gap_privacy_get(ble_gap_privacy_params_t *p_privacy_params)); - -/**@brief Configure an advertising set. Set, clear or update advertising and scan response data. - * - * @note The format of the advertising data will be checked by this call to ensure interoperability. - * Limitations imposed by this API call to the data provided include having a flags data type in the scan response data and - * duplicating the local name in the advertising data and scan response data. - * - * @note In order to update advertising data while advertising, new advertising buffers must be provided. - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in,out] p_adv_handle Provide a pointer to a handle containing @ref - * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising set. On success, a new handle is then returned through the - * pointer. Provide a pointer to an existing advertising handle to configure an existing advertising set. - * @param[in] p_adv_data Advertising data. If set to NULL, no advertising data will be used. See - * @ref ble_gap_adv_data_t. - * @param[in] p_adv_params Advertising parameters. When this function is used to update advertising - * data while advertising, this parameter must be NULL. See @ref ble_gap_adv_params_t. - * - * @retval ::NRF_SUCCESS Advertising set successfully configured. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: - * - Invalid advertising data configuration specified. See @ref - * ble_gap_adv_data_t. - * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. - * - Use of whitelist requested but whitelist has not been set, - * see @ref sd_ble_gap_whitelist_set. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR ble_gap_adv_params_t::p_peer_addr is invalid. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - It is invalid to provide non-NULL advertising set parameters while - * advertising. - * - It is invalid to provide the same data buffers while advertising. To - * update advertising data, provide new advertising buffers. - * @retval ::BLE_ERROR_GAP_DISCOVERABLE_WITH_WHITELIST Discoverable mode and whitelist incompatible. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE The provided advertising handle was not found. Use @ref - * BLE_GAP_ADV_SET_HANDLE_NOT_SET to configure a new advertising handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_FLAGS Invalid combination of advertising flags supplied. - * @retval ::NRF_ERROR_INVALID_DATA Invalid data type(s) supplied. Check the advertising data format - * specification given in Bluetooth Specification Version 5.0, Volume 3, Part C, Chapter 11. - * @retval ::NRF_ERROR_INVALID_LENGTH Invalid data length(s) supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported data length or advertising parameter configuration. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to configure a new advertising handle. Update an - * existing advertising handle instead. - * @retval ::BLE_ERROR_GAP_UUID_LIST_MISMATCH Invalid UUID list supplied. - */ -SVCALL(SD_BLE_GAP_ADV_SET_CONFIGURE, uint32_t, - sd_ble_gap_adv_set_configure(uint8_t *p_adv_handle, ble_gap_adv_data_t const *p_adv_data, - ble_gap_adv_params_t const *p_adv_params)); - -/**@brief Start advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). - * - * @note Only one advertiser may be active at any time. - * - * @note If privacy is enabled, the advertiser's private address will be refreshed when this function is called. - * See @ref sd_ble_gap_privacy_set(). - * - * @events - * @event{@ref BLE_GAP_EVT_CONNECTED, Generated after connection has been established through connectable advertising.} - * @event{@ref BLE_GAP_EVT_ADV_SET_TERMINATED, Advertising set has terminated.} - * @event{@ref BLE_GAP_EVT_SCAN_REQ_REPORT, A scan request was received.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_PRIVACY_ADV_DIR_PRIV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] adv_handle Advertising handle to advertise on, received from @ref sd_ble_gap_adv_set_configure. - * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or - * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. For non-connectable - * advertising, this is ignored. - * - * @retval ::NRF_SUCCESS The BLE stack has started advertising. - * @retval ::NRF_ERROR_INVALID_STATE adv_handle is not configured or already advertising. - * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration - * tag has been reached; connectable advertiser cannot be started. - * To increase the number of available connections, - * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. Configure a new adveriting handle with @ref - sd_ble_gap_adv_set_configure. - * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied: - * - Invalid configuration of p_adv_params. See @ref ble_gap_adv_params_t. - * - Use of whitelist requested but whitelist has not been set, see @ref - sd_ble_gap_whitelist_set. - * @retval ::NRF_ERROR_RESOURCES Either: - * - adv_handle is configured with connectable advertising, but the event_length parameter - * associated with conn_cfg_tag is too small to be able to establish a connection on - * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. - * - Not enough BLE role slots available. - Stop one or more currently active roles (Central, Peripheral, Broadcaster or Observer) - and try again. - * - p_adv_params is configured with connectable advertising, but the event_length - parameter - * associated with conn_cfg_tag is too small to be able to establish a connection on - * the selected advertising phys. Use @ref sd_ble_cfg_set to increase the event length. - */ -SVCALL(SD_BLE_GAP_ADV_START, uint32_t, sd_ble_gap_adv_start(uint8_t adv_handle, uint8_t conn_cfg_tag)); - -/**@brief Stop advertising (GAP Discoverable, Connectable modes, Broadcast Procedure). - * - * @mscs - * @mmsc{@ref BLE_GAP_ADV_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] adv_handle The advertising handle that should stop advertising. - * - * @retval ::NRF_SUCCESS The BLE stack has stopped advertising. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Invalid advertising handle. - * @retval ::NRF_ERROR_INVALID_STATE The advertising handle is not advertising. - */ -SVCALL(SD_BLE_GAP_ADV_STOP, uint32_t, sd_ble_gap_adv_stop(uint8_t adv_handle)); - -/**@brief Update connection parameters. - * - * @details In the central role this will initiate a Link Layer connection parameter update procedure, - * otherwise in the peripheral role, this will send the corresponding L2CAP request and wait for - * the central to perform the procedure. In both cases, and regardless of success or failure, the application - * will be informed of the result with a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE event. - * - * @details This function can be used as a central both to reply to a @ref BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST or to start the - * procedure unrequested. - * - * @events - * @event{@ref BLE_GAP_EVT_CONN_PARAM_UPDATE, Result of the connection parameter update procedure.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CPU_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CPU_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CPU_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_conn_params Pointer to desired connection parameters. If NULL is provided on a peripheral role, - * the parameters in the PPCP characteristic of the GAP service will be used instead. - * If NULL is provided on a central role and in response to a @ref - * BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST, the peripheral request will be rejected - * - * @retval ::NRF_SUCCESS The Connection Update procedure has been started successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints. - * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. - * @retval ::NRF_ERROR_BUSY Procedure already in progress, wait for pending procedures to complete and retry. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GAP_CONN_PARAM_UPDATE, uint32_t, - sd_ble_gap_conn_param_update(uint16_t conn_handle, ble_gap_conn_params_t const *p_conn_params)); - -/**@brief Disconnect (GAP Link Termination). - * - * @details This call initiates the disconnection procedure, and its completion will be communicated to the application - * with a @ref BLE_GAP_EVT_DISCONNECTED event. - * - * @events - * @event{@ref BLE_GAP_EVT_DISCONNECTED, Generated when disconnection procedure is complete.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CONN_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] hci_status_code HCI status code, see @ref BLE_HCI_STATUS_CODES (accepted values are @ref - * BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION and @ref BLE_HCI_CONN_INTERVAL_UNACCEPTABLE). - * - * @retval ::NRF_SUCCESS The disconnection procedure has been started successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE Disconnection in progress or link has not been established. - */ -SVCALL(SD_BLE_GAP_DISCONNECT, uint32_t, sd_ble_gap_disconnect(uint16_t conn_handle, uint8_t hci_status_code)); - -/**@brief Set the radio's transmit power. - * - * @param[in] role The role to set the transmit power for, see @ref BLE_GAP_TX_POWER_ROLES for - * possible roles. - * @param[in] handle The handle parameter is interpreted depending on role: - * - If role is @ref BLE_GAP_TX_POWER_ROLE_CONN, this value is the specific connection handle. - * - If role is @ref BLE_GAP_TX_POWER_ROLE_ADV, the advertising set identified with the advertising handle, - * will use the specified transmit power, and include it in the advertising packet headers if - * @ref ble_gap_adv_properties_t::include_tx_power set. - * - For all other roles handle is ignored. - * @param[in] tx_power Radio transmit power in dBm (see note for accepted values). - * - * @note Supported tx_power values: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm and +4dBm. - * In addition, on some chips following values are supported: +2dBm, +5dBm, +6dBm, +7dBm and +8dBm. - * Setting these values on a chip that does not support them will result in undefined behaviour. - * @note The initiator will have the same transmit power as the scanner. - * @note When a connection is created it will inherit the transmit power from the initiator or - * advertiser leading to the connection. - * - * @retval ::NRF_SUCCESS Successfully changed the transmit power. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ADV_HANDLE Advertising handle not found. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_TX_POWER_SET, uint32_t, sd_ble_gap_tx_power_set(uint8_t role, uint16_t handle, int8_t tx_power)); - -/**@brief Set GAP Appearance value. - * - * @param[in] appearance Appearance (16-bit), see @ref BLE_APPEARANCES. - * - * @retval ::NRF_SUCCESS Appearance value set successfully. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - */ -SVCALL(SD_BLE_GAP_APPEARANCE_SET, uint32_t, sd_ble_gap_appearance_set(uint16_t appearance)); - -/**@brief Get GAP Appearance value. - * - * @param[out] p_appearance Pointer to appearance (16-bit) to be filled in, see @ref BLE_APPEARANCES. - * - * @retval ::NRF_SUCCESS Appearance value retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GAP_APPEARANCE_GET, uint32_t, sd_ble_gap_appearance_get(uint16_t *p_appearance)); - -/**@brief Set GAP Peripheral Preferred Connection Parameters. - * - * @param[in] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure with the desired parameters. - * - * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, - see @ref ble_gap_cfg_ppcp_incl_cfg_t. - */ -SVCALL(SD_BLE_GAP_PPCP_SET, uint32_t, sd_ble_gap_ppcp_set(ble_gap_conn_params_t const *p_conn_params)); - -/**@brief Get GAP Peripheral Preferred Connection Parameters. - * - * @param[out] p_conn_params Pointer to a @ref ble_gap_conn_params_t structure where the parameters will be stored. - * - * @retval ::NRF_SUCCESS Peripheral Preferred Connection Parameters retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The characteristic is not included in the Attribute Table, - see @ref ble_gap_cfg_ppcp_incl_cfg_t. - */ -SVCALL(SD_BLE_GAP_PPCP_GET, uint32_t, sd_ble_gap_ppcp_get(ble_gap_conn_params_t *p_conn_params)); - -/**@brief Set GAP device name. - * - * @note If the device name is located in application flash memory (see @ref ble_gap_cfg_device_name_t), - * it cannot be changed. Then @ref NRF_ERROR_FORBIDDEN will be returned. - * - * @param[in] p_write_perm Write permissions for the Device Name characteristic, see @ref ble_gap_conn_sec_mode_t. - * @param[in] p_dev_name Pointer to a UTF-8 encoded, non NULL-terminated string. - * @param[in] len Length of the UTF-8, non NULL-terminated string pointed to by p_dev_name in octets (must be smaller or - * equal than @ref BLE_GAP_DEVNAME_MAX_LEN). - * - * @retval ::NRF_SUCCESS GAP device name and permissions set successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_FORBIDDEN Device name is not writable. - */ -SVCALL(SD_BLE_GAP_DEVICE_NAME_SET, uint32_t, - sd_ble_gap_device_name_set(ble_gap_conn_sec_mode_t const *p_write_perm, uint8_t const *p_dev_name, uint16_t len)); - -/**@brief Get GAP device name. - * - * @note If the device name is longer than the size of the supplied buffer, - * p_len will return the complete device name length, - * and not the number of bytes actually returned in p_dev_name. - * The application may use this information to allocate a suitable buffer size. - * - * @param[out] p_dev_name Pointer to an empty buffer where the UTF-8 non NULL-terminated string will be placed. Set to - * NULL to obtain the complete device name length. - * @param[in,out] p_len Length of the buffer pointed by p_dev_name, complete device name length on output. - * - * @retval ::NRF_SUCCESS GAP device name retrieved successfully. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - */ -SVCALL(SD_BLE_GAP_DEVICE_NAME_GET, uint32_t, sd_ble_gap_device_name_get(uint8_t *p_dev_name, uint16_t *p_len)); - -/**@brief Initiate the GAP Authentication procedure. - * - * @details In the central role, this function will send an SMP Pairing Request (or an SMP Pairing Failed if rejected), - * otherwise in the peripheral role, an SMP Security Request will be sent. - * - * @events - * @event{Depending on the security parameters set and the packet exchanges with the peer\, the following events may be - * generated:} - * @event{@ref BLE_GAP_EVT_SEC_PARAMS_REQUEST} - * @event{@ref BLE_GAP_EVT_SEC_INFO_REQUEST} - * @event{@ref BLE_GAP_EVT_PASSKEY_DISPLAY} - * @event{@ref BLE_GAP_EVT_KEY_PRESSED} - * @event{@ref BLE_GAP_EVT_AUTH_KEY_REQUEST} - * @event{@ref BLE_GAP_EVT_LESC_DHKEY_REQUEST} - * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE} - * @event{@ref BLE_GAP_EVT_AUTH_STATUS} - * @event{@ref BLE_GAP_EVT_TIMEOUT} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_SEC_REQ_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_sec_params Pointer to the @ref ble_gap_sec_params_t structure with the security parameters to be used during the - * pairing or bonding procedure. In the peripheral role, only the bond, mitm, lesc and keypress fields of this structure are used. - * In the central role, this pointer may be NULL to reject a Security Request. - * - * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - No link has been established. - * - An encryption is already executing or queued. - * @retval ::NRF_ERROR_NO_MEM The maximum number of authentication procedures that can run in parallel for the given role is - * reached. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. - * Distribution of own Identity Information is only supported if the Central - * Address Resolution characteristic is configured to be included or - * the Softdevice is configured to support peripheral roles only. - * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - * @retval ::NRF_ERROR_TIMEOUT A SMP timeout has occurred, and further SMP operations on this link is prohibited. - */ -SVCALL(SD_BLE_GAP_AUTHENTICATE, uint32_t, - sd_ble_gap_authenticate(uint16_t conn_handle, ble_gap_sec_params_t const *p_sec_params)); - -/**@brief Reply with GAP security parameters. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST, calling it at other times will result in - * an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_CONFIRM_FAIL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_KS_TOO_SMALL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_APP_ERROR_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_REMOTE_PAIRING_FAIL_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_PAIRING_TIMEOUT_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] sec_status Security status, see @ref BLE_GAP_SEC_STATUS. - * @param[in] p_sec_params Pointer to a @ref ble_gap_sec_params_t security parameters structure. In the central role this must be - * set to NULL, as the parameters have already been provided during a previous call to @ref sd_ble_gap_authenticate. - * @param[in,out] p_sec_keyset Pointer to a @ref ble_gap_sec_keyset_t security keyset structure. Any keys generated and/or - * distributed as a result of the ongoing security procedure will be stored into the memory referenced by the pointers inside this - * structure. The keys will be stored and available to the application upon reception of a @ref BLE_GAP_EVT_AUTH_STATUS event. - * Note that the SoftDevice expects the application to provide memory for storing the - * peer's keys. So it must be ensured that the relevant pointers inside this structure are not NULL. The - * pointers to the local key can, however, be NULL, in which case, the local key data will not be available to the application - * upon reception of the - * @ref BLE_GAP_EVT_AUTH_STATUS event. - * - * @retval ::NRF_SUCCESS Successfully accepted security parameter from the application. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Security parameters has not been requested. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED Setting of sign or link fields in @ref ble_gap_sec_kdist_t not supported. - * Distribution of own Identity Information is only supported if the Central - * Address Resolution characteristic is configured to be included or - * the Softdevice is configured to support peripheral roles only. - * See @ref ble_gap_cfg_car_incl_cfg_t and @ref ble_gap_cfg_role_count_t. - */ -SVCALL(SD_BLE_GAP_SEC_PARAMS_REPLY, uint32_t, - sd_ble_gap_sec_params_reply(uint16_t conn_handle, uint8_t sec_status, ble_gap_sec_params_t const *p_sec_params, - ble_gap_sec_keyset_t const *p_sec_keyset)); - -/**@brief Reply with an authentication key. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_AUTH_KEY_REQUEST or a @ref BLE_GAP_EVT_PASSKEY_DISPLAY, - * calling it at other times will result in an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_BONDING_PK_CENTRAL_OOB_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_BONDING_PK_PERIPH_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] key_type See @ref BLE_GAP_AUTH_KEY_TYPES. - * @param[in] p_key If key type is @ref BLE_GAP_AUTH_KEY_TYPE_NONE, then NULL. - * If key type is @ref BLE_GAP_AUTH_KEY_TYPE_PASSKEY, then a 6-byte ASCII string (digit 0..9 only, no NULL - * termination) or NULL when confirming LE Secure Connections Numeric Comparison. If key type is @ref BLE_GAP_AUTH_KEY_TYPE_OOB, - * then a 16-byte OOB key value in little-endian format. - * - * @retval ::NRF_SUCCESS Authentication key successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Authentication key has not been requested. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_AUTH_KEY_REPLY, uint32_t, - sd_ble_gap_auth_key_reply(uint16_t conn_handle, uint8_t key_type, uint8_t const *p_key)); - -/**@brief Reply with an LE Secure connections DHKey. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST, calling it at other times will result in - * an @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_PAIRING_JW_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_NC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_PD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_dhkey LE Secure Connections DHKey. - * - * @retval ::NRF_SUCCESS DHKey successfully set. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - The peer is not authenticated. - * - The application has not pulled a @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_DHKEY_REPLY, uint32_t, - sd_ble_gap_lesc_dhkey_reply(uint16_t conn_handle, ble_gap_lesc_dhkey_t const *p_dhkey)); - -/**@brief Notify the peer of a local keypress. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_PKE_CD_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_PKE_CD_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] kp_not See @ref BLE_GAP_KP_NOT_TYPES. - * - * @retval ::NRF_SUCCESS Keypress notification successfully queued for transmission. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Authentication key not requested. - * - Passkey has not been entered. - * - Keypresses have not been enabled by both peers. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_BUSY The BLE stack is busy. Retry at later time. - */ -SVCALL(SD_BLE_GAP_KEYPRESS_NOTIFY, uint32_t, sd_ble_gap_keypress_notify(uint16_t conn_handle, uint8_t kp_not)); - -/**@brief Generate a set of OOB data to send to a peer out of band. - * - * @note The @ref ble_gap_addr_t included in the OOB data returned will be the currently active one (or, if a connection has - * already been established, the one used during connection setup). The application may manually overwrite it with an updated - * value. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. Can be @ref BLE_CONN_HANDLE_INVALID if a BLE connection has not been established yet. - * @param[in] p_pk_own LE Secure Connections local P-256 Public Key. - * @param[out] p_oobd_own The OOB data to be sent out of band to a peer. - * - * @retval ::NRF_SUCCESS OOB data successfully generated. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_OOB_DATA_GET, uint32_t, - sd_ble_gap_lesc_oob_data_get(uint16_t conn_handle, ble_gap_lesc_p256_pk_t const *p_pk_own, - ble_gap_lesc_oob_data_t *p_oobd_own)); - -/**@brief Provide the OOB data sent/received out of band. - * - * @note An authentication procedure with OOB selected as an algorithm must be in progress when calling this function. - * @note A @ref BLE_GAP_EVT_LESC_DHKEY_REQUEST event with the oobd_req set to 1 must have been received prior to calling this - * function. - * - * @events - * @event{This function is used during authentication procedures\, see the list of events in the documentation of @ref - * sd_ble_gap_authenticate.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_LESC_BONDING_OOB_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_LESC_BONDING_OOB_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_oobd_own The OOB data sent out of band to a peer or NULL if the peer has not received OOB data. - * Must correspond to @ref ble_gap_sec_params_t::oob flag in @ref BLE_GAP_EVT_SEC_PARAMS_REQUEST. - * @param[in] p_oobd_peer The OOB data received out of band from a peer or NULL if none received. - * Must correspond to @ref ble_gap_sec_params_t::oob flag - * in @ref sd_ble_gap_authenticate in the central role or - * in @ref sd_ble_gap_sec_params_reply in the peripheral role. - * - * @retval ::NRF_SUCCESS OOB data accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Authentication key not requested - * - Not expecting LESC OOB data - * - Have not actually exchanged passkeys. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_LESC_OOB_DATA_SET, uint32_t, - sd_ble_gap_lesc_oob_data_set(uint16_t conn_handle, ble_gap_lesc_oob_data_t const *p_oobd_own, - ble_gap_lesc_oob_data_t const *p_oobd_peer)); - -/**@brief Initiate GAP Encryption procedure. - * - * @details In the central role, this function will initiate the encryption procedure using the encryption information provided. - * - * @events - * @event{@ref BLE_GAP_EVT_CONN_SEC_UPDATE, The connection security has been updated.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_AUTH_MUTEX_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_ENC_MSC} - * @mmsc{@ref BLE_GAP_MULTILINK_CTRL_PROC_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_SEC_REQ_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_master_id Pointer to a @ref ble_gap_master_id_t master identification structure. - * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. - * - * @retval ::NRF_SUCCESS Successfully initiated authentication procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::BLE_ERROR_INVALID_ROLE Operation is not supported in the Peripheral role. - * @retval ::NRF_ERROR_BUSY Procedure already in progress or not allowed at this time, wait for pending procedures to complete and - * retry. - */ -SVCALL(SD_BLE_GAP_ENCRYPT, uint32_t, - sd_ble_gap_encrypt(uint16_t conn_handle, ble_gap_master_id_t const *p_master_id, ble_gap_enc_info_t const *p_enc_info)); - -/**@brief Reply with GAP security information. - * - * @details This function is only used to reply to a @ref BLE_GAP_EVT_SEC_INFO_REQUEST, calling it at other times will result in - * @ref NRF_ERROR_INVALID_STATE. - * @note If the call returns an error code, the request is still pending, and the reply call may be repeated with corrected - * parameters. - * @note Data signing is not yet supported, and p_sign_info must therefore be NULL. - * - * @mscs - * @mmsc{@ref BLE_GAP_PERIPH_ENC_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_enc_info Pointer to a @ref ble_gap_enc_info_t encryption information structure. May be NULL to signal none is - * available. - * @param[in] p_id_info Pointer to a @ref ble_gap_irk_t identity information structure. May be NULL to signal none is available. - * @param[in] p_sign_info Pointer to a @ref ble_gap_sign_info_t signing information structure. May be NULL to signal none is - * available. - * - * @retval ::NRF_SUCCESS Successfully accepted security information. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - No link has been established. - * - No @ref BLE_GAP_EVT_SEC_INFO_REQUEST pending. - * - Encryption information provided by the app without being requested. See @ref - * ble_gap_evt_sec_info_request_t::enc_info. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_SEC_INFO_REPLY, uint32_t, - sd_ble_gap_sec_info_reply(uint16_t conn_handle, ble_gap_enc_info_t const *p_enc_info, ble_gap_irk_t const *p_id_info, - ble_gap_sign_info_t const *p_sign_info)); - -/**@brief Get the current connection security. - * - * @param[in] conn_handle Connection handle. - * @param[out] p_conn_sec Pointer to a @ref ble_gap_conn_sec_t structure to be filled in. - * - * @retval ::NRF_SUCCESS Current connection security successfully retrieved. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_CONN_SEC_GET, uint32_t, sd_ble_gap_conn_sec_get(uint16_t conn_handle, ble_gap_conn_sec_t *p_conn_sec)); - -/**@brief Start reporting the received signal strength to the application. - * - * A new event is reported whenever the RSSI value changes, until @ref sd_ble_gap_rssi_stop is called. - * - * @events - * @event{@ref BLE_GAP_EVT_RSSI_CHANGED, New RSSI data available. How often the event is generated is - * dependent on the settings of the threshold_dbm - * and skip_count input parameters.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] threshold_dbm Minimum change in dBm before triggering the @ref BLE_GAP_EVT_RSSI_CHANGED event. Events are - * disabled if threshold_dbm equals @ref BLE_GAP_RSSI_THRESHOLD_INVALID. - * @param[in] skip_count Number of RSSI samples with a change of threshold_dbm or more before sending a new @ref - * BLE_GAP_EVT_RSSI_CHANGED event. - * - * @retval ::NRF_SUCCESS Successfully activated RSSI reporting. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is already ongoing. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_RSSI_START, uint32_t, sd_ble_gap_rssi_start(uint16_t conn_handle, uint8_t threshold_dbm, uint8_t skip_count)); - -/**@brief Stop reporting the received signal strength. - * - * @note An RSSI change detected before the call but not yet received by the application - * may be reported after @ref sd_ble_gap_rssi_stop has been called. - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @mmsc{@ref BLE_GAP_RSSI_FILT_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * - * @retval ::NRF_SUCCESS Successfully deactivated RSSI reporting. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - */ -SVCALL(SD_BLE_GAP_RSSI_STOP, uint32_t, sd_ble_gap_rssi_stop(uint16_t conn_handle)); - -/**@brief Get the received signal strength for the last connection event. - * - * @ref sd_ble_gap_rssi_start must be called to start reporting RSSI before using this function. @ref NRF_ERROR_NOT_FOUND - * will be returned until RSSI was sampled for the first time after calling @ref sd_ble_gap_rssi_start. - * @note ERRATA-153 and ERRATA-225 require the rssi sample to be compensated based on a temperature measurement. - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_RSSI_READ_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[out] p_rssi Pointer to the location where the RSSI measurement shall be stored. - * @param[out] p_ch_index Pointer to the location where Channel Index for the RSSI measurement shall be stored. - * - * @retval ::NRF_SUCCESS Successfully read the RSSI. - * @retval ::NRF_ERROR_NOT_FOUND No sample is available. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE RSSI reporting is not ongoing. - */ -SVCALL(SD_BLE_GAP_RSSI_GET, uint32_t, sd_ble_gap_rssi_get(uint16_t conn_handle, int8_t *p_rssi, uint8_t *p_ch_index)); - -/**@brief Start or continue scanning (GAP Discovery procedure, Observer Procedure). - * - * @note A call to this function will require the application to keep the memory pointed by - * p_adv_report_buffer alive until the buffer is released. The buffer is released when the scanner is stopped - * or when this function is called with another buffer. - * - * @note The scanner will automatically stop in the following cases: - * - @ref sd_ble_gap_scan_stop is called. - * - @ref sd_ble_gap_connect is called. - * - A @ref BLE_GAP_EVT_TIMEOUT with source set to @ref BLE_GAP_TIMEOUT_SRC_SCAN is received. - * - When a @ref BLE_GAP_EVT_ADV_REPORT event is received and @ref ble_gap_adv_report_type_t::status is not set to - * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA. In this case scanning is only paused to let the application - * access received data. The application must call this function to continue scanning, or call @ref - * sd_ble_gap_scan_stop to stop scanning. - * - * @note If a @ref BLE_GAP_EVT_ADV_REPORT event is received with @ref ble_gap_adv_report_type_t::status set to - * @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_MORE_DATA, the scanner will continue scanning, and the application will - * receive more reports from this advertising event. The following reports will include the old and new received data. - * - * @events - * @event{@ref BLE_GAP_EVT_ADV_REPORT, An advertising or scan response packet has been received.} - * @event{@ref BLE_GAP_EVT_TIMEOUT, Scanner has timed out.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_SCAN_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @param[in] p_scan_params Pointer to scan parameters structure. When this function is used to continue - * scanning, this parameter must be NULL. - * @param[in] p_adv_report_buffer Pointer to buffer used to store incoming advertising data. - * The memory pointed to should be kept alive until the scanning is stopped. - * See @ref BLE_GAP_SCAN_BUFFER_SIZE for minimum and maximum buffer size. - * If the scanner receives advertising data larger than can be stored in the buffer, - * a @ref BLE_GAP_EVT_ADV_REPORT will be raised with @ref ble_gap_adv_report_type_t::status - * set to @ref BLE_GAP_ADV_DATA_STATUS_INCOMPLETE_TRUNCATED. - * - * @retval ::NRF_SUCCESS Successfully initiated scanning procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation. Either: - * - Scanning is already ongoing and p_scan_params was not NULL - * - Scanning is not running and p_scan_params was NULL. - * - The scanner has timed out when this function is called to continue scanning. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. See @ref ble_gap_scan_params_t. - * @retval ::NRF_ERROR_NOT_SUPPORTED Unsupported parameters supplied. See @ref ble_gap_scan_params_t. - * @retval ::NRF_ERROR_INVALID_LENGTH The provided buffer length is invalid. See @ref BLE_GAP_SCAN_BUFFER_MIN. - * @retval ::NRF_ERROR_RESOURCES Not enough BLE role slots available. - * Stop one or more currently active roles (Central, Peripheral or Broadcaster) and try again - */ -SVCALL(SD_BLE_GAP_SCAN_START, uint32_t, - sd_ble_gap_scan_start(ble_gap_scan_params_t const *p_scan_params, ble_data_t const *p_adv_report_buffer)); - -/**@brief Stop scanning (GAP Discovery procedure, Observer Procedure). - * - * @note The buffer provided in @ref sd_ble_gap_scan_start is released. - * - * @mscs - * @mmsc{@ref BLE_GAP_SCAN_MSC} - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully stopped scanning procedure. - * @retval ::NRF_ERROR_INVALID_STATE Not in the scanning state. - */ -SVCALL(SD_BLE_GAP_SCAN_STOP, uint32_t, sd_ble_gap_scan_stop(void)); - -/**@brief Create a connection (GAP Link Establishment). - * - * @note If a scanning procedure is currently in progress it will be automatically stopped when calling this function. - * The scanning procedure will be stopped even if the function returns an error. - * - * @events - * @event{@ref BLE_GAP_EVT_CONNECTED, A connection was established.} - * @event{@ref BLE_GAP_EVT_TIMEOUT, Failed to establish a connection.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_WL_SHARE_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_PRIV_MSC} - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} - * @endmscs - * - * @param[in] p_peer_addr Pointer to peer identity address. If @ref ble_gap_scan_params_t::filter_policy is set to use - * whitelist, then p_peer_addr is ignored. - * @param[in] p_scan_params Pointer to scan parameters structure. - * @param[in] p_conn_params Pointer to desired connection parameters. - * @param[in] conn_cfg_tag Tag identifying a configuration set by @ref sd_ble_cfg_set or - * @ref BLE_CONN_CFG_TAG_DEFAULT to use the default connection configuration. - * - * @retval ::NRF_SUCCESS Successfully initiated connection procedure. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid parameter(s) pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * - Invalid parameter(s) in p_scan_params or p_conn_params. - * - Use of whitelist requested but whitelist has not been set, see @ref - * sd_ble_gap_whitelist_set. - * - Peer address was not present in the device identity list, see @ref - * sd_ble_gap_device_identities_set. - * @retval ::NRF_ERROR_NOT_FOUND conn_cfg_tag not found. - * @retval ::NRF_ERROR_INVALID_STATE The SoftDevice is in an invalid state to perform this operation. This may be due to an - * existing locally initiated connect procedure, which must complete before initiating again. - * @retval ::BLE_ERROR_GAP_INVALID_BLE_ADDR Invalid Peer address. - * @retval ::NRF_ERROR_CONN_COUNT The limit of available connections for this connection configuration tag has been reached. - * To increase the number of available connections, - * use @ref sd_ble_cfg_set with @ref BLE_GAP_CFG_ROLE_COUNT or @ref BLE_CONN_CFG_GAP. - * @retval ::NRF_ERROR_RESOURCES Either: - * - Not enough BLE role slots available. - * Stop one or more currently active roles (Central, Peripheral or Observer) and try again. - * - The event_length parameter associated with conn_cfg_tag is too small to be able to - * establish a connection on the selected @ref ble_gap_scan_params_t::scan_phys. - * Use @ref sd_ble_cfg_set to increase the event length. - */ -SVCALL(SD_BLE_GAP_CONNECT, uint32_t, - sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params, - ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag)); - -/**@brief Cancel a connection establishment. - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_CONN_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully canceled an ongoing connection procedure. - * @retval ::NRF_ERROR_INVALID_STATE No locally initiated connect procedure started or connection - * completed occurred. - */ -SVCALL(SD_BLE_GAP_CONNECT_CANCEL, uint32_t, sd_ble_gap_connect_cancel(void)); - -/**@brief Initiate or respond to a PHY Update Procedure - * - * @details This function is used to initiate or respond to a PHY Update Procedure. It will always - * generate a @ref BLE_GAP_EVT_PHY_UPDATE event if successfully executed. - * If this function is used to initiate a PHY Update procedure and the only option - * provided in @ref ble_gap_phys_t::tx_phys and @ref ble_gap_phys_t::rx_phys is the - * currently active PHYs in the respective directions, the SoftDevice will generate a - * @ref BLE_GAP_EVT_PHY_UPDATE with the current PHYs set and will not initiate the - * procedure in the Link Layer. - * - * If @ref ble_gap_phys_t::tx_phys or @ref ble_gap_phys_t::rx_phys is @ref BLE_GAP_PHY_AUTO, - * then the stack will select PHYs based on the peer's PHY preferences and the local link - * configuration. The PHY Update procedure will for this case result in a PHY combination - * that respects the time constraints configured with @ref sd_ble_cfg_set and the current - * link layer data length. - * - * When acting as a central, the SoftDevice will select the fastest common PHY in each direction. - * - * If the peer does not support the PHY Update Procedure, then the resulting - * @ref BLE_GAP_EVT_PHY_UPDATE event will have a status set to - * @ref BLE_HCI_UNSUPPORTED_REMOTE_FEATURE. - * - * If the PHY Update procedure was rejected by the peer due to a procedure collision, the status - * will be @ref BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION or - * @ref BLE_HCI_DIFFERENT_TRANSACTION_COLLISION. - * If the peer responds to the PHY Update procedure with invalid parameters, the status - * will be @ref BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS. - * If the PHY Update procedure was rejected by the peer for a different reason, the status will - * contain the reason as specified by the peer. - * - * @events - * @event{@ref BLE_GAP_EVT_PHY_UPDATE, Result of the PHY Update Procedure.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GAP_CENTRAL_PHY_UPDATE} - * @mmsc{@ref BLE_GAP_PERIPHERAL_PHY_UPDATE} - * @endmscs - * - * @param[in] conn_handle Connection handle to indicate the connection for which the PHY Update is requested. - * @param[in] p_gap_phys Pointer to PHY structure. - * - * @retval ::NRF_SUCCESS Successfully requested a PHY Update. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the combination of - * @ref ble_gap_phys_t::tx_phys, @ref ble_gap_phys_t::rx_phys, and @ref - * ble_gap_data_length_params_t. The connection event length is configured with @ref BLE_CONN_CFG_GAP using @ref sd_ble_cfg_set. - * @retval ::NRF_ERROR_BUSY Procedure is already in progress or not allowed at this time. Process pending events and wait for the - * pending procedure to complete and retry. - * - */ -SVCALL(SD_BLE_GAP_PHY_UPDATE, uint32_t, sd_ble_gap_phy_update(uint16_t conn_handle, ble_gap_phys_t const *p_gap_phys)); - -/**@brief Initiate or respond to a Data Length Update Procedure. - * - * @note If the application uses @ref BLE_GAP_DATA_LENGTH_AUTO for one or more members of - * p_dl_params, the SoftDevice will choose the highest value supported in current - * configuration and connection parameters. - * @note If the link PHY is Coded, the SoftDevice will ensure that the MaxTxTime and/or MaxRxTime - * used in the Data Length Update procedure is at least 2704 us. Otherwise, MaxTxTime and - * MaxRxTime will be limited to maximum 2120 us. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_dl_params Pointer to local parameters to be used in Data Length Update - * Procedure. Set any member to @ref BLE_GAP_DATA_LENGTH_AUTO to let - * the SoftDevice automatically decide the value for that member. - * Set to NULL to use automatic values for all members. - * @param[out] p_dl_limitation Pointer to limitation to be written when local device does not - * have enough resources or does not support the requested Data Length - * Update parameters. Ignored if NULL. - * - * @mscs - * @mmsc{@ref BLE_GAP_DATA_LENGTH_UPDATE_PROCEDURE_MSC} - * @endmscs - * - * @retval ::NRF_SUCCESS Successfully set Data Length Extension initiation/response parameters. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. - * @retval ::NRF_ERROR_INVALID_STATE No link has been established. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. - * @retval ::NRF_ERROR_NOT_SUPPORTED The requested parameters are not supported by the SoftDevice. Inspect - * p_dl_limitation to see which parameter is not supported. - * @retval ::NRF_ERROR_RESOURCES The connection event length configured for this link is not sufficient for the requested - * parameters. Use @ref sd_ble_cfg_set with @ref BLE_CONN_CFG_GAP to increase the connection event length. Inspect p_dl_limitation - * to see where the limitation is. - * @retval ::NRF_ERROR_BUSY Peer has already initiated a Data Length Update Procedure. Process the - * pending @ref BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST event to respond. - */ -SVCALL(SD_BLE_GAP_DATA_LENGTH_UPDATE, uint32_t, - sd_ble_gap_data_length_update(uint16_t conn_handle, ble_gap_data_length_params_t const *p_dl_params, - ble_gap_data_length_limitation_t *p_dl_limitation)); - -/**@brief Start the Quality of Service (QoS) channel survey module. - * - * @details The channel survey module provides measurements of the energy levels on - * the Bluetooth Low Energy channels. When the module is enabled, @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT - * events will periodically report the measured energy levels for each channel. - * - * @note The measurements are scheduled with lower priority than other Bluetooth Low Energy roles, - * Radio Timeslot API events and Flash API events. - * - * @note The channel survey module will attempt to do measurements so that the average interval - * between measurements will be interval_us. However due to the channel survey module - * having the lowest priority of all roles and modules, this may not be possible. In that - * case fewer than expected channel survey reports may be given. - * - * @note In order to use the channel survey module, @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available - * must be set. This is done using @ref sd_ble_cfg_set. - * - * @param[in] interval_us Requested average interval for the measurements and reports. See - * @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVALS for valid ranges. If set - * to @ref BLE_GAP_QOS_CHANNEL_SURVEY_INTERVAL_CONTINUOUS, the channel - * survey role will be scheduled at every available opportunity. - * - * @retval ::NRF_SUCCESS The module is successfully started. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. interval_us is out of the - * allowed range. - * @retval ::NRF_ERROR_INVALID_STATE Trying to start the module when already running. - * @retval ::NRF_ERROR_RESOURCES The channel survey module is not available to the application. - * Set @ref ble_gap_cfg_role_count_t::qos_channel_survey_role_available using - * @ref sd_ble_cfg_set. - */ -SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_START, uint32_t, sd_ble_gap_qos_channel_survey_start(uint32_t interval_us)); - -/**@brief Stop the Quality of Service (QoS) channel survey module. - * - * @note The SoftDevice may generate one @ref BLE_GAP_EVT_QOS_CHANNEL_SURVEY_REPORT event after this - * function is called. - * - * @retval ::NRF_SUCCESS The module is successfully stopped. - * @retval ::NRF_ERROR_INVALID_STATE Trying to stop the module when it is not running. - */ -SVCALL(SD_BLE_GAP_QOS_CHANNEL_SURVEY_STOP, uint32_t, sd_ble_gap_qos_channel_survey_stop(void)); - -/**@brief Obtain the next connection event counter value. - * - * @details The connection event counter is initialized to zero on the first connection event. The value is incremented - * by one for each connection event. For more information see Bluetooth Core Specification v5.0, Vol 6, Part B, - * Section 4.5.1. - * - * @note The connection event counter obtained through this API will be outdated if this API is called - * at the same time as the connection event counter is incremented. - * - * @note This API will always return the last connection event counter + 1. - * The actual connection event may be multiple connection events later if: - * - Slave latency is enabled and there is no data to transmit or receive. - * - Another role is scheduled with a higher priority at the same time as the next connection event. - * - * @param[in] conn_handle Connection handle. - * @param[out] p_counter Pointer to the variable where the next connection event counter will be written. - * - * @retval ::NRF_SUCCESS The connection event counter was successfully retrieved. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle parameter supplied. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GAP_NEXT_CONN_EVT_COUNTER_GET, uint32_t, - sd_ble_gap_next_conn_evt_counter_get(uint16_t conn_handle, uint16_t *p_counter)); - -/**@brief Start triggering a given task on connection event start. - * - * @details When enabled, this feature will trigger a PPI task at the start of connection events. - * The application can configure the SoftDevice to trigger every N connection events starting from - * a given connection event counter. See also @ref ble_gap_conn_event_trigger_t. - * - * @param[in] conn_handle Connection handle. - * @param[in] p_params Connection event trigger parameters. - * - * @retval ::NRF_SUCCESS Success. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter supplied. See @ref ble_gap_conn_event_trigger_t. - * @retval ::NRF_ERROR_INVALID_STATE Either: - * - Trying to start connection event triggering when it is already ongoing. - * - @ref ble_gap_conn_event_trigger_t::conn_evt_counter_start is in the past. - * Use @ref sd_ble_gap_next_conn_evt_counter_get to find a new value - to be used as ble_gap_conn_event_trigger_t::conn_evt_counter_start. - */ -SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_START, uint32_t, - sd_ble_gap_conn_evt_trigger_start(uint16_t conn_handle, ble_gap_conn_event_trigger_t const *p_params)); - -/**@brief Stop triggering the task configured using @ref sd_ble_gap_conn_evt_trigger_start. - * - * @param[in] conn_handle Connection handle. - * - * @retval ::NRF_SUCCESS Success. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied. - * @retval ::NRF_ERROR_INVALID_STATE Trying to stop connection event triggering when it is not enabled. - */ -SVCALL(SD_BLE_GAP_CONN_EVT_TRIGGER_STOP, uint32_t, sd_ble_gap_conn_evt_trigger_stop(uint16_t conn_handle)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GAP_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gatt.h b/variants/wio-sdk-wm1110/softdevice/ble_gatt.h deleted file mode 100644 index df0d728fc8..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_gatt.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATT Generic Attribute Profile (GATT) Common - @{ - @brief Common definitions and prototypes for the GATT interfaces. - */ - -#ifndef BLE_GATT_H__ -#define BLE_GATT_H__ - -#include "ble_err.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATT_DEFINES Defines - * @{ */ - -/** @brief Default ATT MTU, in bytes. */ -#define BLE_GATT_ATT_MTU_DEFAULT 23 - -/**@brief Invalid Attribute Handle. */ -#define BLE_GATT_HANDLE_INVALID 0x0000 - -/**@brief First Attribute Handle. */ -#define BLE_GATT_HANDLE_START 0x0001 - -/**@brief Last Attribute Handle. */ -#define BLE_GATT_HANDLE_END 0xFFFF - -/** @defgroup BLE_GATT_TIMEOUT_SOURCES GATT Timeout sources - * @{ */ -#define BLE_GATT_TIMEOUT_SRC_PROTOCOL 0x00 /**< ATT Protocol timeout. */ -/** @} */ - -/** @defgroup BLE_GATT_WRITE_OPS GATT Write operations - * @{ */ -#define BLE_GATT_OP_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATT_OP_WRITE_REQ 0x01 /**< Write Request. */ -#define BLE_GATT_OP_WRITE_CMD 0x02 /**< Write Command. */ -#define BLE_GATT_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ -#define BLE_GATT_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ -#define BLE_GATT_OP_EXEC_WRITE_REQ 0x05 /**< Execute Write Request. */ -/** @} */ - -/** @defgroup BLE_GATT_EXEC_WRITE_FLAGS GATT Execute Write flags - * @{ */ -#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL 0x00 /**< Cancel prepared write. */ -#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE 0x01 /**< Execute prepared write. */ -/** @} */ - -/** @defgroup BLE_GATT_HVX_TYPES GATT Handle Value operations - * @{ */ -#define BLE_GATT_HVX_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATT_HVX_NOTIFICATION 0x01 /**< Handle Value Notification. */ -#define BLE_GATT_HVX_INDICATION 0x02 /**< Handle Value Indication. */ -/** @} */ - -/** @defgroup BLE_GATT_STATUS_CODES GATT Status Codes - * @{ */ -#define BLE_GATT_STATUS_SUCCESS 0x0000 /**< Success. */ -#define BLE_GATT_STATUS_UNKNOWN 0x0001 /**< Unknown or not applicable status. */ -#define BLE_GATT_STATUS_ATTERR_INVALID 0x0100 /**< ATT Error: Invalid Error Code. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_HANDLE 0x0101 /**< ATT Error: Invalid Attribute Handle. */ -#define BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED 0x0102 /**< ATT Error: Read not permitted. */ -#define BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED 0x0103 /**< ATT Error: Write not permitted. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_PDU 0x0104 /**< ATT Error: Used in ATT as Invalid PDU. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION 0x0105 /**< ATT Error: Authenticated link required. */ -#define BLE_GATT_STATUS_ATTERR_REQUEST_NOT_SUPPORTED 0x0106 /**< ATT Error: Used in ATT as Request Not Supported. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_OFFSET 0x0107 /**< ATT Error: Offset specified was past the end of the attribute. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION 0x0108 /**< ATT Error: Used in ATT as Insufficient Authorization. */ -#define BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL 0x0109 /**< ATT Error: Used in ATT as Prepare Queue Full. */ -#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND 0x010A /**< ATT Error: Used in ATT as Attribute not found. */ -#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_LONG \ - 0x010B /**< ATT Error: Attribute cannot be read or written using read/write blob requests. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_ENC_KEY_SIZE 0x010C /**< ATT Error: Encryption key size used is insufficient. */ -#define BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH 0x010D /**< ATT Error: Invalid value size. */ -#define BLE_GATT_STATUS_ATTERR_UNLIKELY_ERROR 0x010E /**< ATT Error: Very unlikely error. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION 0x010F /**< ATT Error: Encrypted link required. */ -#define BLE_GATT_STATUS_ATTERR_UNSUPPORTED_GROUP_TYPE \ - 0x0110 /**< ATT Error: Attribute type is not a supported grouping attribute. */ -#define BLE_GATT_STATUS_ATTERR_INSUF_RESOURCES 0x0111 /**< ATT Error: Insufficient resources. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_BEGIN 0x0112 /**< ATT Error: Reserved for Future Use range #1 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_END 0x017F /**< ATT Error: Reserved for Future Use range #1 end. */ -#define BLE_GATT_STATUS_ATTERR_APP_BEGIN 0x0180 /**< ATT Error: Application range begin. */ -#define BLE_GATT_STATUS_ATTERR_APP_END 0x019F /**< ATT Error: Application range end. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_BEGIN 0x01A0 /**< ATT Error: Reserved for Future Use range #2 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_END 0x01DF /**< ATT Error: Reserved for Future Use range #2 end. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_BEGIN 0x01E0 /**< ATT Error: Reserved for Future Use range #3 begin. */ -#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_END 0x01FC /**< ATT Error: Reserved for Future Use range #3 end. */ -#define BLE_GATT_STATUS_ATTERR_CPS_WRITE_REQ_REJECTED \ - 0x01FC /**< ATT Common Profile and Service Error: Write request rejected. \ - */ -#define BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR \ - 0x01FD /**< ATT Common Profile and Service Error: Client Characteristic Configuration Descriptor improperly configured. */ -#define BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG \ - 0x01FE /**< ATT Common Profile and Service Error: Procedure Already in Progress. */ -#define BLE_GATT_STATUS_ATTERR_CPS_OUT_OF_RANGE 0x01FF /**< ATT Common Profile and Service Error: Out Of Range. */ -/** @} */ - -/** @defgroup BLE_GATT_CPF_FORMATS Characteristic Presentation Formats - * @note Found at - * http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml - * @{ */ -#define BLE_GATT_CPF_FORMAT_RFU 0x00 /**< Reserved For Future Use. */ -#define BLE_GATT_CPF_FORMAT_BOOLEAN 0x01 /**< Boolean. */ -#define BLE_GATT_CPF_FORMAT_2BIT 0x02 /**< Unsigned 2-bit integer. */ -#define BLE_GATT_CPF_FORMAT_NIBBLE 0x03 /**< Unsigned 4-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT8 0x04 /**< Unsigned 8-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT12 0x05 /**< Unsigned 12-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT16 0x06 /**< Unsigned 16-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT24 0x07 /**< Unsigned 24-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT32 0x08 /**< Unsigned 32-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT48 0x09 /**< Unsigned 48-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT64 0x0A /**< Unsigned 64-bit integer. */ -#define BLE_GATT_CPF_FORMAT_UINT128 0x0B /**< Unsigned 128-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT8 0x0C /**< Signed 2-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT12 0x0D /**< Signed 12-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT16 0x0E /**< Signed 16-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT24 0x0F /**< Signed 24-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT32 0x10 /**< Signed 32-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT48 0x11 /**< Signed 48-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT64 0x12 /**< Signed 64-bit integer. */ -#define BLE_GATT_CPF_FORMAT_SINT128 0x13 /**< Signed 128-bit integer. */ -#define BLE_GATT_CPF_FORMAT_FLOAT32 0x14 /**< IEEE-754 32-bit floating point. */ -#define BLE_GATT_CPF_FORMAT_FLOAT64 0x15 /**< IEEE-754 64-bit floating point. */ -#define BLE_GATT_CPF_FORMAT_SFLOAT 0x16 /**< IEEE-11073 16-bit SFLOAT. */ -#define BLE_GATT_CPF_FORMAT_FLOAT 0x17 /**< IEEE-11073 32-bit FLOAT. */ -#define BLE_GATT_CPF_FORMAT_DUINT16 0x18 /**< IEEE-20601 format. */ -#define BLE_GATT_CPF_FORMAT_UTF8S 0x19 /**< UTF-8 string. */ -#define BLE_GATT_CPF_FORMAT_UTF16S 0x1A /**< UTF-16 string. */ -#define BLE_GATT_CPF_FORMAT_STRUCT 0x1B /**< Opaque Structure. */ -/** @} */ - -/** @defgroup BLE_GATT_CPF_NAMESPACES GATT Bluetooth Namespaces - * @{ - */ -#define BLE_GATT_CPF_NAMESPACE_BTSIG 0x01 /**< Bluetooth SIG defined Namespace. */ -#define BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN 0x0000 /**< Namespace Description Unknown. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATT_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATT connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_PARAM att_mtu is smaller than @ref BLE_GATT_ATT_MTU_DEFAULT. - */ -typedef struct { - uint16_t att_mtu; /**< Maximum size of ATT packet the SoftDevice can send or receive. - The default and minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - @mscs - @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} - @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} - @endmscs - */ -} ble_gatt_conn_cfg_t; - -/**@brief GATT Characteristic Properties. */ -typedef struct { - /* Standard properties */ - uint8_t broadcast : 1; /**< Broadcasting of the value permitted. */ - uint8_t read : 1; /**< Reading the value permitted. */ - uint8_t write_wo_resp : 1; /**< Writing the value with Write Command permitted. */ - uint8_t write : 1; /**< Writing the value with Write Request permitted. */ - uint8_t notify : 1; /**< Notification of the value permitted. */ - uint8_t indicate : 1; /**< Indications of the value permitted. */ - uint8_t auth_signed_wr : 1; /**< Writing the value with Signed Write Command permitted. */ -} ble_gatt_char_props_t; - -/**@brief GATT Characteristic Extended Properties. */ -typedef struct { - /* Extended properties */ - uint8_t reliable_wr : 1; /**< Writing the value with Queued Write operations permitted. */ - uint8_t wr_aux : 1; /**< Writing the Characteristic User Description descriptor permitted. */ -} ble_gatt_char_ext_props_t; - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GATT_H__ - -/** @} */ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gattc.h b/variants/wio-sdk-wm1110/softdevice/ble_gattc.h deleted file mode 100644 index f1df1782ca..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_gattc.h +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATTC Generic Attribute Profile (GATT) Client - @{ - @brief Definitions and prototypes for the GATT Client interface. - */ - -#ifndef BLE_GATTC_H__ -#define BLE_GATTC_H__ - -#include "ble_err.h" -#include "ble_gatt.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATTC_ENUMERATIONS Enumerations - * @{ */ - -/**@brief GATTC API SVC numbers. */ -enum BLE_GATTC_SVCS { - SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER = BLE_GATTC_SVC_BASE, /**< Primary Service Discovery. */ - SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, /**< Relationship Discovery. */ - SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, /**< Characteristic Discovery. */ - SD_BLE_GATTC_DESCRIPTORS_DISCOVER, /**< Characteristic Descriptor Discovery. */ - SD_BLE_GATTC_ATTR_INFO_DISCOVER, /**< Attribute Information Discovery. */ - SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, /**< Read Characteristic Value by UUID. */ - SD_BLE_GATTC_READ, /**< Generic read. */ - SD_BLE_GATTC_CHAR_VALUES_READ, /**< Read multiple Characteristic Values. */ - SD_BLE_GATTC_WRITE, /**< Generic write. */ - SD_BLE_GATTC_HV_CONFIRM, /**< Handle Value Confirmation. */ - SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. */ -}; - -/** - * @brief GATT Client Event IDs. - */ -enum BLE_GATTC_EVTS { - BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP = BLE_GATTC_EVT_BASE, /**< Primary Service Discovery Response event. \n See @ref - ble_gattc_evt_prim_srvc_disc_rsp_t. */ - BLE_GATTC_EVT_REL_DISC_RSP, /**< Relationship Discovery Response event. \n See @ref ble_gattc_evt_rel_disc_rsp_t. - */ - BLE_GATTC_EVT_CHAR_DISC_RSP, /**< Characteristic Discovery Response event. \n See @ref - ble_gattc_evt_char_disc_rsp_t. */ - BLE_GATTC_EVT_DESC_DISC_RSP, /**< Descriptor Discovery Response event. \n See @ref - ble_gattc_evt_desc_disc_rsp_t. */ - BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, /**< Attribute Information Response event. \n See @ref - ble_gattc_evt_attr_info_disc_rsp_t. */ - BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP, /**< Read By UUID Response event. \n See @ref - ble_gattc_evt_char_val_by_uuid_read_rsp_t. */ - BLE_GATTC_EVT_READ_RSP, /**< Read Response event. \n See @ref ble_gattc_evt_read_rsp_t. */ - BLE_GATTC_EVT_CHAR_VALS_READ_RSP, /**< Read multiple Response event. \n See @ref - ble_gattc_evt_char_vals_read_rsp_t. */ - BLE_GATTC_EVT_WRITE_RSP, /**< Write Response event. \n See @ref ble_gattc_evt_write_rsp_t. */ - BLE_GATTC_EVT_HVX, /**< Handle Value Notification or Indication event. \n Confirm indication with @ref - sd_ble_gattc_hv_confirm. \n See @ref ble_gattc_evt_hvx_t. */ - BLE_GATTC_EVT_EXCHANGE_MTU_RSP, /**< Exchange MTU Response event. \n See @ref - ble_gattc_evt_exchange_mtu_rsp_t. */ - BLE_GATTC_EVT_TIMEOUT, /**< Timeout event. \n See @ref ble_gattc_evt_timeout_t. */ - BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE /**< Write without Response transmission complete. \n See @ref - ble_gattc_evt_write_cmd_tx_complete_t. */ -}; - -/**@brief GATTC Option IDs. - * IDs that uniquely identify a GATTC option. - */ -enum BLE_GATTC_OPTS { - BLE_GATTC_OPT_UUID_DISC = BLE_GATTC_OPT_BASE, /**< UUID discovery. @ref ble_gattc_opt_uuid_disc_t */ -}; - -/** @} */ - -/** @addtogroup BLE_GATTC_DEFINES Defines - * @{ */ - -/** @defgroup BLE_ERRORS_GATTC SVC return values specific to GATTC - * @{ */ -#define BLE_ERROR_GATTC_PROC_NOT_PERMITTED (NRF_GATTC_ERR_BASE + 0x000) /**< Procedure not Permitted. */ -/** @} */ - -/** @defgroup BLE_GATTC_ATTR_INFO_FORMAT Attribute Information Formats - * @{ */ -#define BLE_GATTC_ATTR_INFO_FORMAT_16BIT 1 /**< 16-bit Attribute Information Format. */ -#define BLE_GATTC_ATTR_INFO_FORMAT_128BIT 2 /**< 128-bit Attribute Information Format. */ -/** @} */ - -/** @defgroup BLE_GATTC_DEFAULTS GATT Client defaults - * @{ */ -#define BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT \ - 1 /**< Default number of Write without Response that can be queued for transmission. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATTC_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATTC connection configuration parameters, set with @ref sd_ble_cfg_set. - */ -typedef struct { - uint8_t write_cmd_tx_queue_size; /**< The guaranteed minimum number of Write without Response that can be queued for - transmission. The default value is @ref BLE_GATTC_WRITE_CMD_TX_QUEUE_SIZE_DEFAULT */ -} ble_gattc_conn_cfg_t; - -/**@brief Operation Handle Range. */ -typedef struct { - uint16_t start_handle; /**< Start Handle. */ - uint16_t end_handle; /**< End Handle. */ -} ble_gattc_handle_range_t; - -/**@brief GATT service. */ -typedef struct { - ble_uuid_t uuid; /**< Service UUID. */ - ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */ -} ble_gattc_service_t; - -/**@brief GATT include. */ -typedef struct { - uint16_t handle; /**< Include Handle. */ - ble_gattc_service_t included_srvc; /**< Handle of the included service. */ -} ble_gattc_include_t; - -/**@brief GATT characteristic. */ -typedef struct { - ble_uuid_t uuid; /**< Characteristic UUID. */ - ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ - uint8_t char_ext_props : 1; /**< Extended properties present. */ - uint16_t handle_decl; /**< Handle of the Characteristic Declaration. */ - uint16_t handle_value; /**< Handle of the Characteristic Value. */ -} ble_gattc_char_t; - -/**@brief GATT descriptor. */ -typedef struct { - uint16_t handle; /**< Descriptor Handle. */ - ble_uuid_t uuid; /**< Descriptor UUID. */ -} ble_gattc_desc_t; - -/**@brief Write Parameters. */ -typedef struct { - uint8_t write_op; /**< Write Operation to be performed, see @ref BLE_GATT_WRITE_OPS. */ - uint8_t flags; /**< Flags, see @ref BLE_GATT_EXEC_WRITE_FLAGS. */ - uint16_t handle; /**< Handle to the attribute to be written. */ - uint16_t offset; /**< Offset in bytes. @note For WRITE_CMD and WRITE_REQ, offset must be 0. */ - uint16_t len; /**< Length of data in bytes. */ - uint8_t const *p_value; /**< Pointer to the value data. */ -} ble_gattc_write_params_t; - -/**@brief Attribute Information for 16-bit Attribute UUID. */ -typedef struct { - uint16_t handle; /**< Attribute handle. */ - ble_uuid_t uuid; /**< 16-bit Attribute UUID. */ -} ble_gattc_attr_info16_t; - -/**@brief Attribute Information for 128-bit Attribute UUID. */ -typedef struct { - uint16_t handle; /**< Attribute handle. */ - ble_uuid128_t uuid; /**< 128-bit Attribute UUID. */ -} ble_gattc_attr_info128_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Service count. */ - ble_gattc_service_t services[1]; /**< Service data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use - event structures with variable length array members. */ -} ble_gattc_evt_prim_srvc_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_REL_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Include count. */ - ble_gattc_include_t includes[1]; /**< Include data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use - event structures with variable length array members. */ -} ble_gattc_evt_rel_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Characteristic count. */ - ble_gattc_char_t chars[1]; /**< Characteristic data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event - structures with variable length array members. */ -} ble_gattc_evt_char_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_DESC_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Descriptor count. */ - ble_gattc_desc_t descs[1]; /**< Descriptor data. @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on how to use event - structures with variable length array members. */ -} ble_gattc_evt_desc_disc_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP. */ -typedef struct { - uint16_t count; /**< Attribute count. */ - uint8_t format; /**< Attribute information format, see @ref BLE_GATTC_ATTR_INFO_FORMAT. */ - union { - ble_gattc_attr_info16_t attr_info16[1]; /**< Attribute information for 16-bit Attribute UUID. - @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on - how to use event structures with variable length array members. */ - ble_gattc_attr_info128_t attr_info128[1]; /**< Attribute information for 128-bit Attribute UUID. - @note This is a variable length array. The size of 1 indicated is only a - placeholder for compilation. See @ref sd_ble_evt_get for more information on - how to use event structures with variable length array members. */ - } info; /**< Attribute information union. */ -} ble_gattc_evt_attr_info_disc_rsp_t; - -/**@brief GATT read by UUID handle value pair. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint8_t *p_value; /**< Pointer to the Attribute Value, length is available in @ref - ble_gattc_evt_char_val_by_uuid_read_rsp_t::value_len. */ -} ble_gattc_handle_value_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP. */ -typedef struct { - uint16_t count; /**< Handle-Value Pair Count. */ - uint16_t value_len; /**< Length of the value in Handle-Value(s) list. */ - uint8_t handle_value[1]; /**< Handle-Value(s) list. To iterate through the list use @ref - sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter. - @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with - variable length array members. */ -} ble_gattc_evt_char_val_by_uuid_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_READ_RSP. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint16_t offset; /**< Offset of the attribute data. */ - uint16_t len; /**< Attribute data length. */ - uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP. */ -typedef struct { - uint16_t len; /**< Concatenated Attribute values length. */ - uint8_t values[1]; /**< Attribute values. @note This is a variable length array. The size of 1 indicated is only a placeholder - for compilation. See @ref sd_ble_evt_get for more information on how to use event structures with - variable length array members. */ -} ble_gattc_evt_char_vals_read_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_RSP. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - uint8_t write_op; /**< Type of write operation, see @ref BLE_GATT_WRITE_OPS. */ - uint16_t offset; /**< Data offset. */ - uint16_t len; /**< Data length. */ - uint8_t data[1]; /**< Data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_write_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_HVX. */ -typedef struct { - uint16_t handle; /**< Handle to which the HVx operation applies. */ - uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ - uint16_t len; /**< Attribute data length. */ - uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gattc_evt_hvx_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. */ -typedef struct { - uint16_t server_rx_mtu; /**< Server RX MTU size. */ -} ble_gattc_evt_exchange_mtu_rsp_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ -} ble_gattc_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE. */ -typedef struct { - uint8_t count; /**< Number of write without response transmissions completed. */ -} ble_gattc_evt_write_cmd_tx_complete_t; - -/**@brief GATTC event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which event occurred. */ - uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ - uint16_t - error_handle; /**< In case of error: The handle causing the error. In all other cases @ref BLE_GATT_HANDLE_INVALID. */ - union { - ble_gattc_evt_prim_srvc_disc_rsp_t prim_srvc_disc_rsp; /**< Primary Service Discovery Response Event Parameters. */ - ble_gattc_evt_rel_disc_rsp_t rel_disc_rsp; /**< Relationship Discovery Response Event Parameters. */ - ble_gattc_evt_char_disc_rsp_t char_disc_rsp; /**< Characteristic Discovery Response Event Parameters. */ - ble_gattc_evt_desc_disc_rsp_t desc_disc_rsp; /**< Descriptor Discovery Response Event Parameters. */ - ble_gattc_evt_char_val_by_uuid_read_rsp_t - char_val_by_uuid_read_rsp; /**< Characteristic Value Read by UUID Response Event Parameters. */ - ble_gattc_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. */ - ble_gattc_evt_char_vals_read_rsp_t char_vals_read_rsp; /**< Characteristic Values Read Response Event Parameters. */ - ble_gattc_evt_write_rsp_t write_rsp; /**< Write Response Event Parameters. */ - ble_gattc_evt_hvx_t hvx; /**< Handle Value Notification/Indication Event Parameters. */ - ble_gattc_evt_exchange_mtu_rsp_t exchange_mtu_rsp; /**< Exchange MTU Response Event Parameters. */ - ble_gattc_evt_timeout_t timeout; /**< Timeout Event Parameters. */ - ble_gattc_evt_attr_info_disc_rsp_t attr_info_disc_rsp; /**< Attribute Information Discovery Event Parameters. */ - ble_gattc_evt_write_cmd_tx_complete_t - write_cmd_tx_complete; /**< Write without Response transmission complete Event Parameters. */ - } params; /**< Event Parameters. @note Only valid if @ref gatt_status == @ref BLE_GATT_STATUS_SUCCESS. */ -} ble_gattc_evt_t; - -/**@brief UUID discovery option. - * - * @details Used with @ref sd_ble_opt_set to enable and disable automatic insertion of discovered 128-bit UUIDs to the - * Vendor Specific UUID table. Disabled by default. - * - When disabled, if a procedure initiated by - * @ref sd_ble_gattc_primary_services_discover, - * @ref sd_ble_gattc_relationships_discover, - * @ref sd_ble_gattc_characteristics_discover, - * @ref sd_ble_gattc_descriptors_discover - * finds a 128-bit UUID which was not added by @ref sd_ble_uuid_vs_add, @ref ble_uuid_t::type will be set - * to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. - * - When enabled, all found 128-bit UUIDs will be automatically added. The application can use - * @ref sd_ble_uuid_encode to retrieve the 128-bit UUID from @ref ble_uuid_t received in the corresponding - * event. If the total number of Vendor Specific UUIDs exceeds the table capacity, @ref ble_uuid_t::type will - * be set to @ref BLE_UUID_TYPE_UNKNOWN in the corresponding event. - * See also @ref ble_common_cfg_vs_uuid_t, @ref sd_ble_uuid_vs_remove. - * - * @note @ref sd_ble_opt_get is not supported for this option. - * - * @retval ::NRF_SUCCESS Set successfully. - * - */ -typedef struct { - uint8_t auto_add_vs_enable : 1; /**< Set to 1 to enable (or 0 to disable) automatic insertion of discovered 128-bit UUIDs. */ -} ble_gattc_opt_uuid_disc_t; - -/**@brief Option structure for GATTC options. */ -typedef union { - ble_gattc_opt_uuid_disc_t uuid_disc; /**< Parameters for the UUID discovery option. */ -} ble_gattc_opt_t; - -/** @} */ - -/** @addtogroup BLE_GATTC_FUNCTIONS Functions - * @{ */ - -/**@brief Initiate or continue a GATT Primary Service Discovery procedure. - * - * @details This function initiates or resumes a Primary Service discovery procedure, starting from the supplied handle. - * If the last service has not been reached, this function must be called again with an updated start handle value to - * continue the search. See also @ref ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_PRIM_SRVC_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] start_handle Handle to start searching from. - * @param[in] p_srvc_uuid Pointer to the service UUID to be found. If it is NULL, all primary services will be returned. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Primary Service Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER, uint32_t, - sd_ble_gattc_primary_services_discover(uint16_t conn_handle, uint16_t start_handle, ble_uuid_t const *p_srvc_uuid)); - -/**@brief Initiate or continue a GATT Relationship Discovery procedure. - * - * @details This function initiates or resumes the Find Included Services sub-procedure. If the last included service has not been - * reached, this must be called again with an updated handle range to continue the search. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_REL_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_REL_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Relationship Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, uint32_t, - sd_ble_gattc_relationships_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Characteristic Discovery procedure. - * - * @details This function initiates or resumes a Characteristic discovery procedure. If the last Characteristic has not been - * reached, this must be called again with an updated handle range to continue the discovery. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_CHAR_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Characteristic Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, uint32_t, - sd_ble_gattc_characteristics_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Characteristic Descriptor Discovery procedure. - * - * @details This function initiates or resumes a Characteristic Descriptor discovery procedure. If the last Descriptor has not - * been reached, this must be called again with an updated handle range to continue the discovery. See also @ref - * ble_gattc_opt_uuid_disc_t. - * - * @events - * @event{@ref BLE_GATTC_EVT_DESC_DISC_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_DESC_DISC_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range A pointer to the range of handles of the Characteristic to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Descriptor Discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t, - sd_ble_gattc_descriptors_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Read using Characteristic UUID procedure. - * - * @details This function initiates or resumes a Read using Characteristic UUID procedure. If the last Characteristic has not been - * reached, this must be called again with an updated handle range to continue the discovery. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_READ_UUID_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_uuid Pointer to a Characteristic value UUID to read. - * @param[in] p_handle_range A pointer to the range of handles to perform this procedure on. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Read using Characteristic UUID procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, uint32_t, - sd_ble_gattc_char_value_by_uuid_read(uint16_t conn_handle, ble_uuid_t const *p_uuid, - ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Initiate or continue a GATT Read (Long) Characteristic or Descriptor procedure. - * - * @details This function initiates or resumes a GATT Read (Long) Characteristic or Descriptor procedure. If the Characteristic or - * Descriptor to be read is longer than ATT_MTU - 1, this function must be called multiple times with appropriate offset to read - * the complete value. - * - * @events - * @event{@ref BLE_GATTC_EVT_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_VALUE_READ_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] handle The handle of the attribute to be read. - * @param[in] offset Offset into the attribute value to be read. - * - * @retval ::NRF_SUCCESS Successfully started or resumed the Read (Long) procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_READ, uint32_t, sd_ble_gattc_read(uint16_t conn_handle, uint16_t handle, uint16_t offset)); - -/**@brief Initiate a GATT Read Multiple Characteristic Values procedure. - * - * @details This function initiates a GATT Read Multiple Characteristic Values procedure. - * - * @events - * @event{@ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_READ_MULT_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handles A pointer to the handle(s) of the attribute(s) to be read. - * @param[in] handle_count The number of handles in p_handles. - * - * @retval ::NRF_SUCCESS Successfully started the Read Multiple Characteristic Values procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t, - sd_ble_gattc_char_values_read(uint16_t conn_handle, uint16_t const *p_handles, uint16_t handle_count)); - -/**@brief Perform a Write (Characteristic Value or Descriptor, with or without response, signed or not, long or reliable) - * procedure. - * - * @details This function can perform all write procedures described in GATT. - * - * @note Only one write with response procedure can be ongoing per connection at a time. - * If the application tries to write with response while another write with response procedure is ongoing, - * the function call will return @ref NRF_ERROR_BUSY. - * A @ref BLE_GATTC_EVT_WRITE_RSP event will be issued as soon as the write response arrives from the peer. - * - * @note The number of Write without Response that can be queued is configured by @ref - * ble_gattc_conn_cfg_t::write_cmd_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. - * A @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event will be issued as soon as the transmission of the write without - * response is complete. - * - * @note The application can keep track of the available queue element count for writes without responses by following the - * procedure below: - * - Store initial queue element count in a variable. - * - Decrement the variable, which stores the currently available queue element count, by one when a call to this - * function returns @ref NRF_SUCCESS. - * - Increment the variable, which stores the current available queue element count, by the count variable in @ref - * BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event. - * - * @events - * @event{@ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE, Write without response transmission complete.} - * @event{@ref BLE_GATTC_EVT_WRITE_RSP, Write response received from the peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_VALUE_WRITE_WITHOUT_RESP_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_WRITE_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_LONG_WRITE_MSC} - * @mmsc{@ref BLE_GATTC_VALUE_RELIABLE_WRITE_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_write_params A pointer to a write parameters structure. - * - * @retval ::NRF_SUCCESS Successfully started the Write procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_BUSY For write with response, procedure already in progress. Wait for a @ref BLE_GATTC_EVT_WRITE_RSP event - * and retry. - * @retval ::NRF_ERROR_RESOURCES Too many writes without responses queued. - * Wait for a @ref BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE event and retry. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_WRITE, uint32_t, sd_ble_gattc_write(uint16_t conn_handle, ble_gattc_write_params_t const *p_write_params)); - -/**@brief Send a Handle Value Confirmation to the GATT Server. - * - * @mscs - * @mmsc{@ref BLE_GATTC_HVI_MSC} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] handle The handle of the attribute in the indication. - * - * @retval ::NRF_SUCCESS Successfully queued the Handle Value Confirmation for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no Indication pending to be confirmed. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_HV_CONFIRM, uint32_t, sd_ble_gattc_hv_confirm(uint16_t conn_handle, uint16_t handle)); - -/**@brief Discovers information about a range of attributes on a GATT server. - * - * @events - * @event{@ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, Generated when information about a range of attributes has been received.} - * @endevents - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] p_handle_range The range of handles to request information about. - * - * @retval ::NRF_SUCCESS Successfully started an attribute information discovery procedure. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t, - sd_ble_gattc_attr_info_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range)); - -/**@brief Start an ATT_MTU exchange by sending an Exchange MTU Request to the server. - * - * @details The SoftDevice sets ATT_MTU to the minimum of: - * - The Client RX MTU value, and - * - The Server RX MTU value from @ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP. - * - * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. - * - * @events - * @event{@ref BLE_GATTC_EVT_EXCHANGE_MTU_RSP} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTC_MTU_EXCHANGE} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] client_rx_mtu Client RX MTU size. - * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration - used for this connection. - * - The value must be equal to Server RX MTU size given in @ref sd_ble_gatts_exchange_mtu_reply - * if an ATT_MTU exchange has already been performed in the other direction. - * - * @retval ::NRF_SUCCESS Successfully sent request to the server. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid connection state or an ATT_MTU exchange was already requested once. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid Client RX MTU size supplied. - * @retval ::NRF_ERROR_BUSY Client procedure already in progress. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - reestablishing the connection. - */ -SVCALL(SD_BLE_GATTC_EXCHANGE_MTU_REQUEST, uint32_t, - sd_ble_gattc_exchange_mtu_request(uint16_t conn_handle, uint16_t client_rx_mtu)); - -/**@brief Iterate through Handle-Value(s) list in @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. - * - * @param[in] p_gattc_evt Pointer to event buffer containing @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP event. - * @note If the buffer contains different event, behavior is undefined. - * @param[in,out] p_iter Iterator, points to @ref ble_gattc_handle_value_t structure that will be filled in with - * the next Handle-Value pair in each iteration. If the function returns other than - * @ref NRF_SUCCESS, it will not be changed. - * - To start iteration, initialize the structure to zero. - * - To continue, pass the value from previous iteration. - * - * \code - * ble_gattc_handle_value_t iter; - * memset(&iter, 0, sizeof(ble_gattc_handle_value_t)); - * while (sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(&ble_evt.evt.gattc_evt, &iter) == NRF_SUCCESS) - * { - * app_handle = iter.handle; - * memcpy(app_value, iter.p_value, ble_evt.evt.gattc_evt.params.char_val_by_uuid_read_rsp.value_len); - * } - * \endcode - * - * @retval ::NRF_SUCCESS Successfully retrieved the next Handle-Value pair. - * @retval ::NRF_ERROR_NOT_FOUND No more Handle-Value pairs available in the list. - */ -__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, - ble_gattc_handle_value_t *p_iter); - -/** @} */ - -#ifndef SUPPRESS_INLINE_IMPLEMENTATION - -__STATIC_INLINE uint32_t sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(ble_gattc_evt_t *p_gattc_evt, - ble_gattc_handle_value_t *p_iter) -{ - uint32_t value_len = p_gattc_evt->params.char_val_by_uuid_read_rsp.value_len; - uint8_t *p_first = p_gattc_evt->params.char_val_by_uuid_read_rsp.handle_value; - uint8_t *p_next = p_iter->p_value ? p_iter->p_value + value_len : p_first; - - if ((p_next - p_first) / (sizeof(uint16_t) + value_len) < p_gattc_evt->params.char_val_by_uuid_read_rsp.count) { - p_iter->handle = (uint16_t)p_next[1] << 8 | p_next[0]; - p_iter->p_value = p_next + sizeof(uint16_t); - return NRF_SUCCESS; - } else { - return NRF_ERROR_NOT_FOUND; - } -} - -#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ - -#ifdef __cplusplus -} -#endif -#endif /* BLE_GATTC_H__ */ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_gatts.h b/variants/wio-sdk-wm1110/softdevice/ble_gatts.h deleted file mode 100644 index dc94957cd1..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_gatts.h +++ /dev/null @@ -1,904 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_GATTS Generic Attribute Profile (GATT) Server - @{ - @brief Definitions and prototypes for the GATTS interface. - */ - -#ifndef BLE_GATTS_H__ -#define BLE_GATTS_H__ - -#include "ble_err.h" -#include "ble_gap.h" -#include "ble_gatt.h" -#include "ble_hci.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_GATTS_ENUMERATIONS Enumerations - * @{ */ - -/** - * @brief GATTS API SVC numbers. - */ -enum BLE_GATTS_SVCS { - SD_BLE_GATTS_SERVICE_ADD = BLE_GATTS_SVC_BASE, /**< Add a service. */ - SD_BLE_GATTS_INCLUDE_ADD, /**< Add an included service. */ - SD_BLE_GATTS_CHARACTERISTIC_ADD, /**< Add a characteristic. */ - SD_BLE_GATTS_DESCRIPTOR_ADD, /**< Add a generic attribute. */ - SD_BLE_GATTS_VALUE_SET, /**< Set an attribute value. */ - SD_BLE_GATTS_VALUE_GET, /**< Get an attribute value. */ - SD_BLE_GATTS_HVX, /**< Handle Value Notification or Indication. */ - SD_BLE_GATTS_SERVICE_CHANGED, /**< Perform a Service Changed Indication to one or more peers. */ - SD_BLE_GATTS_RW_AUTHORIZE_REPLY, /**< Reply to an authorization request for a read or write operation on one or more - attributes. */ - SD_BLE_GATTS_SYS_ATTR_SET, /**< Set the persistent system attributes for a connection. */ - SD_BLE_GATTS_SYS_ATTR_GET, /**< Retrieve the persistent system attributes. */ - SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, /**< Retrieve the first valid user handle. */ - SD_BLE_GATTS_ATTR_GET, /**< Retrieve the UUID and/or metadata of an attribute. */ - SD_BLE_GATTS_EXCHANGE_MTU_REPLY /**< Reply to Exchange MTU Request. */ -}; - -/** - * @brief GATT Server Event IDs. - */ -enum BLE_GATTS_EVTS { - BLE_GATTS_EVT_WRITE = BLE_GATTS_EVT_BASE, /**< Write operation performed. \n See - @ref ble_gatts_evt_write_t. */ - BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST, /**< Read/Write Authorization request. \n Reply with - @ref sd_ble_gatts_rw_authorize_reply. \n See @ref ble_gatts_evt_rw_authorize_request_t. - */ - BLE_GATTS_EVT_SYS_ATTR_MISSING, /**< A persistent system attribute access is pending. \n Respond with @ref - sd_ble_gatts_sys_attr_set. \n See @ref ble_gatts_evt_sys_attr_missing_t. */ - BLE_GATTS_EVT_HVC, /**< Handle Value Confirmation. \n See @ref ble_gatts_evt_hvc_t. - */ - BLE_GATTS_EVT_SC_CONFIRM, /**< Service Changed Confirmation. \n No additional event - structure applies. */ - BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, /**< Exchange MTU Request. \n Reply with - @ref sd_ble_gatts_exchange_mtu_reply. \n See @ref ble_gatts_evt_exchange_mtu_request_t. - */ - BLE_GATTS_EVT_TIMEOUT, /**< Peer failed to respond to an ATT request in time. \n See @ref - ble_gatts_evt_timeout_t. */ - BLE_GATTS_EVT_HVN_TX_COMPLETE /**< Handle Value Notification transmission complete. \n See @ref - ble_gatts_evt_hvn_tx_complete_t. */ -}; - -/**@brief GATTS Configuration IDs. - * - * IDs that uniquely identify a GATTS configuration. - */ -enum BLE_GATTS_CFGS { - BLE_GATTS_CFG_SERVICE_CHANGED = BLE_GATTS_CFG_BASE, /**< Service changed configuration. */ - BLE_GATTS_CFG_ATTR_TAB_SIZE, /**< Attribute table size configuration. */ - BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM, /**< Service changed CCCD permission configuration. */ -}; - -/** @} */ - -/** @addtogroup BLE_GATTS_DEFINES Defines - * @{ */ - -/** @defgroup BLE_ERRORS_GATTS SVC return values specific to GATTS - * @{ */ -#define BLE_ERROR_GATTS_INVALID_ATTR_TYPE (NRF_GATTS_ERR_BASE + 0x000) /**< Invalid attribute type. */ -#define BLE_ERROR_GATTS_SYS_ATTR_MISSING (NRF_GATTS_ERR_BASE + 0x001) /**< System Attributes missing. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_LENS_MAX Maximum attribute lengths - * @{ */ -#define BLE_GATTS_FIX_ATTR_LEN_MAX (510) /**< Maximum length for fixed length Attribute Values. */ -#define BLE_GATTS_VAR_ATTR_LEN_MAX (512) /**< Maximum length for variable length Attribute Values. */ -/** @} */ - -/** @defgroup BLE_GATTS_SRVC_TYPES GATT Server Service Types - * @{ */ -#define BLE_GATTS_SRVC_TYPE_INVALID 0x00 /**< Invalid Service Type. */ -#define BLE_GATTS_SRVC_TYPE_PRIMARY 0x01 /**< Primary Service. */ -#define BLE_GATTS_SRVC_TYPE_SECONDARY 0x02 /**< Secondary Type. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_TYPES GATT Server Attribute Types - * @{ */ -#define BLE_GATTS_ATTR_TYPE_INVALID 0x00 /**< Invalid Attribute Type. */ -#define BLE_GATTS_ATTR_TYPE_PRIM_SRVC_DECL 0x01 /**< Primary Service Declaration. */ -#define BLE_GATTS_ATTR_TYPE_SEC_SRVC_DECL 0x02 /**< Secondary Service Declaration. */ -#define BLE_GATTS_ATTR_TYPE_INC_DECL 0x03 /**< Include Declaration. */ -#define BLE_GATTS_ATTR_TYPE_CHAR_DECL 0x04 /**< Characteristic Declaration. */ -#define BLE_GATTS_ATTR_TYPE_CHAR_VAL 0x05 /**< Characteristic Value. */ -#define BLE_GATTS_ATTR_TYPE_DESC 0x06 /**< Descriptor. */ -#define BLE_GATTS_ATTR_TYPE_OTHER 0x07 /**< Other, non-GATT specific type. */ -/** @} */ - -/** @defgroup BLE_GATTS_OPS GATT Server Operations - * @{ */ -#define BLE_GATTS_OP_INVALID 0x00 /**< Invalid Operation. */ -#define BLE_GATTS_OP_WRITE_REQ 0x01 /**< Write Request. */ -#define BLE_GATTS_OP_WRITE_CMD 0x02 /**< Write Command. */ -#define BLE_GATTS_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */ -#define BLE_GATTS_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */ -#define BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL 0x05 /**< Execute Write Request: Cancel all prepared writes. */ -#define BLE_GATTS_OP_EXEC_WRITE_REQ_NOW 0x06 /**< Execute Write Request: Immediately execute all prepared writes. */ -/** @} */ - -/** @defgroup BLE_GATTS_VLOCS GATT Value Locations - * @{ */ -#define BLE_GATTS_VLOC_INVALID 0x00 /**< Invalid Location. */ -#define BLE_GATTS_VLOC_STACK 0x01 /**< Attribute Value is located in stack memory, no user memory is required. */ -#define BLE_GATTS_VLOC_USER \ - 0x02 /**< Attribute Value is located in user memory. This requires the user to maintain a valid buffer through the lifetime \ - of the attribute, since the stack will read and write directly to the memory using the pointer provided in the APIs. \ - There are no alignment requirements for the buffer. */ -/** @} */ - -/** @defgroup BLE_GATTS_AUTHORIZE_TYPES GATT Server Authorization Types - * @{ */ -#define BLE_GATTS_AUTHORIZE_TYPE_INVALID 0x00 /**< Invalid Type. */ -#define BLE_GATTS_AUTHORIZE_TYPE_READ 0x01 /**< Authorize a Read Operation. */ -#define BLE_GATTS_AUTHORIZE_TYPE_WRITE 0x02 /**< Authorize a Write Request Operation. */ -/** @} */ - -/** @defgroup BLE_GATTS_SYS_ATTR_FLAGS System Attribute Flags - * @{ */ -#define BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS (1 << 0) /**< Restrict system attributes to system services only. */ -#define BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS (1 << 1) /**< Restrict system attributes to user services only. */ -/** @} */ - -/** @defgroup BLE_GATTS_SERVICE_CHANGED Service Changed Inclusion Values - * @{ - */ -#define BLE_GATTS_SERVICE_CHANGED_DEFAULT \ - (1) /**< Default is to include the Service Changed characteristic in the Attribute Table. */ -/** @} */ - -/** @defgroup BLE_GATTS_ATTR_TAB_SIZE Attribute Table size - * @{ - */ -#define BLE_GATTS_ATTR_TAB_SIZE_MIN (248) /**< Minimum Attribute Table size */ -#define BLE_GATTS_ATTR_TAB_SIZE_DEFAULT (1408) /**< Default Attribute Table size. */ -/** @} */ - -/** @defgroup BLE_GATTS_DEFAULTS GATT Server defaults - * @{ - */ -#define BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT \ - 1 /**< Default number of Handle Value Notifications that can be queued for transmission. */ -/** @} */ - -/** @} */ - -/** @addtogroup BLE_GATTS_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE GATTS connection configuration parameters, set with @ref sd_ble_cfg_set. - */ -typedef struct { - uint8_t hvn_tx_queue_size; /**< Minimum guaranteed number of Handle Value Notifications that can be queued for transmission. - The default value is @ref BLE_GATTS_HVN_TX_QUEUE_SIZE_DEFAULT */ -} ble_gatts_conn_cfg_t; - -/**@brief Attribute metadata. */ -typedef struct { - ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */ - ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */ - uint8_t vlen : 1; /**< Variable length attribute. */ - uint8_t vloc : 2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/ - uint8_t rd_auth : 1; /**< Read authorization and value will be requested from the application on every read operation. */ - uint8_t wr_auth : 1; /**< Write authorization will be requested from the application on every Write Request operation (but not - Write Command). */ -} ble_gatts_attr_md_t; - -/**@brief GATT Attribute. */ -typedef struct { - ble_uuid_t const *p_uuid; /**< Pointer to the attribute UUID. */ - ble_gatts_attr_md_t const *p_attr_md; /**< Pointer to the attribute metadata structure. */ - uint16_t init_len; /**< Initial attribute value length in bytes. */ - uint16_t init_offs; /**< Initial attribute value offset in bytes. If different from zero, the first init_offs bytes of the - attribute value will be left uninitialized. */ - uint16_t max_len; /**< Maximum attribute value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */ - uint8_t *p_value; /**< Pointer to the attribute data. Please note that if the @ref BLE_GATTS_VLOC_USER value location is - selected in the attribute metadata, this will have to point to a buffer that remains valid through the - lifetime of the attribute. This excludes usage of automatic variables that may go out of scope or any - other temporary location. The stack may access that memory directly without the application's - knowledge. For writable characteristics, this value must not be a location in flash memory.*/ -} ble_gatts_attr_t; - -/**@brief GATT Attribute Value. */ -typedef struct { - uint16_t len; /**< Length in bytes to be written or read. Length in bytes written or read after successful return.*/ - uint16_t offset; /**< Attribute value offset. */ - uint8_t *p_value; /**< Pointer to where value is stored or will be stored. - If value is stored in user memory, only the attribute length is updated when p_value == NULL. - Set to NULL when reading to obtain the complete length of the attribute value */ -} ble_gatts_value_t; - -/**@brief GATT Characteristic Presentation Format. */ -typedef struct { - uint8_t format; /**< Format of the value, see @ref BLE_GATT_CPF_FORMATS. */ - int8_t exponent; /**< Exponent for integer data types. */ - uint16_t unit; /**< Unit from Bluetooth Assigned Numbers. */ - uint8_t name_space; /**< Namespace from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ - uint16_t desc; /**< Namespace description from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */ -} ble_gatts_char_pf_t; - -/**@brief GATT Characteristic metadata. */ -typedef struct { - ble_gatt_char_props_t char_props; /**< Characteristic Properties. */ - ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic Extended Properties. */ - uint8_t const * - p_char_user_desc; /**< Pointer to a UTF-8 encoded string (non-NULL terminated), NULL if the descriptor is not required. */ - uint16_t char_user_desc_max_size; /**< The maximum size in bytes of the user description descriptor. */ - uint16_t char_user_desc_size; /**< The size of the user description, must be smaller or equal to char_user_desc_max_size. */ - ble_gatts_char_pf_t const - *p_char_pf; /**< Pointer to a presentation format structure or NULL if the CPF descriptor is not required. */ - ble_gatts_attr_md_t const - *p_user_desc_md; /**< Attribute metadata for the User Description descriptor, or NULL for default values. */ - ble_gatts_attr_md_t const - *p_cccd_md; /**< Attribute metadata for the Client Characteristic Configuration Descriptor, or NULL for default values. */ - ble_gatts_attr_md_t const - *p_sccd_md; /**< Attribute metadata for the Server Characteristic Configuration Descriptor, or NULL for default values. */ -} ble_gatts_char_md_t; - -/**@brief GATT Characteristic Definition Handles. */ -typedef struct { - uint16_t value_handle; /**< Handle to the characteristic value. */ - uint16_t user_desc_handle; /**< Handle to the User Description descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */ - uint16_t cccd_handle; /**< Handle to the Client Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if - not present. */ - uint16_t sccd_handle; /**< Handle to the Server Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if - not present. */ -} ble_gatts_char_handles_t; - -/**@brief GATT HVx parameters. */ -typedef struct { - uint16_t handle; /**< Characteristic Value Handle. */ - uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */ - uint16_t offset; /**< Offset within the attribute value. */ - uint16_t *p_len; /**< Length in bytes to be written, length in bytes written after return. */ - uint8_t const *p_data; /**< Actual data content, use NULL to use the current attribute value. */ -} ble_gatts_hvx_params_t; - -/**@brief GATT Authorization parameters. */ -typedef struct { - uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */ - uint8_t update : 1; /**< If set, data supplied in p_data will be used to update the attribute value. - Please note that for @ref BLE_GATTS_AUTHORIZE_TYPE_WRITE operations this bit must always be set, - as the data to be written needs to be stored and later provided by the application. */ - uint16_t offset; /**< Offset of the attribute value being updated. */ - uint16_t len; /**< Length in bytes of the value in p_data pointer, see @ref BLE_GATTS_ATTR_LENS_MAX. */ - uint8_t const *p_data; /**< Pointer to new value used to update the attribute value. */ -} ble_gatts_authorize_params_t; - -/**@brief GATT Read or Write Authorize Reply parameters. */ -typedef struct { - uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ - union { - ble_gatts_authorize_params_t read; /**< Read authorization parameters. */ - ble_gatts_authorize_params_t write; /**< Write authorization parameters. */ - } params; /**< Reply Parameters. */ -} ble_gatts_rw_authorize_reply_params_t; - -/**@brief Service Changed Inclusion configuration parameters, set with @ref sd_ble_cfg_set. */ -typedef struct { - uint8_t service_changed : 1; /**< If 1, include the Service Changed characteristic in the Attribute Table. Default is @ref - BLE_GATTS_SERVICE_CHANGED_DEFAULT. */ -} ble_gatts_cfg_service_changed_t; - -/**@brief Service Changed CCCD permission configuration parameters, set with @ref sd_ble_cfg_set. - * - * @note @ref ble_gatts_attr_md_t::vlen is ignored and should be set to 0. - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - @ref ble_gatts_attr_md_t::write_perm is out of range. - * - @ref ble_gatts_attr_md_t::write_perm is @ref BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS, that is - * not allowed by the Bluetooth Specification. - * - wrong @ref ble_gatts_attr_md_t::read_perm, only @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN is - * allowed by the Bluetooth Specification. - * - wrong @ref ble_gatts_attr_md_t::vloc, only @ref BLE_GATTS_VLOC_STACK is allowed. - * @retval ::NRF_ERROR_NOT_SUPPORTED Security Mode 2 not supported - */ -typedef struct { - ble_gatts_attr_md_t - perm; /**< Permission for Service Changed CCCD. Default is @ref BLE_GAP_CONN_SEC_MODE_SET_OPEN, no authorization. */ -} ble_gatts_cfg_service_changed_cccd_perm_t; - -/**@brief Attribute table size configuration parameters, set with @ref sd_ble_cfg_set. - * - * @retval ::NRF_ERROR_INVALID_LENGTH One or more of the following is true: - * - The specified Attribute Table size is too small. - * The minimum acceptable size is defined by @ref BLE_GATTS_ATTR_TAB_SIZE_MIN. - * - The specified Attribute Table size is not a multiple of 4. - */ -typedef struct { - uint32_t attr_tab_size; /**< Attribute table size. Default is @ref BLE_GATTS_ATTR_TAB_SIZE_DEFAULT, minimum is @ref - BLE_GATTS_ATTR_TAB_SIZE_MIN. */ -} ble_gatts_cfg_attr_tab_size_t; - -/**@brief Config structure for GATTS configurations. */ -typedef union { - ble_gatts_cfg_service_changed_t - service_changed; /**< Include service changed characteristic, cfg_id is @ref BLE_GATTS_CFG_SERVICE_CHANGED. */ - ble_gatts_cfg_service_changed_cccd_perm_t service_changed_cccd_perm; /**< Service changed CCCD permission, cfg_id is @ref - BLE_GATTS_CFG_SERVICE_CHANGED_CCCD_PERM. */ - ble_gatts_cfg_attr_tab_size_t attr_tab_size; /**< Attribute table size, cfg_id is @ref BLE_GATTS_CFG_ATTR_TAB_SIZE. */ -} ble_gatts_cfg_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_WRITE. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - ble_uuid_t uuid; /**< Attribute UUID. */ - uint8_t op; /**< Type of write operation, see @ref BLE_GATTS_OPS. */ - uint8_t auth_required; /**< Writing operation deferred due to authorization requirement. Application may use @ref - sd_ble_gatts_value_set to finalize the writing operation. */ - uint16_t offset; /**< Offset for the write operation. */ - uint16_t len; /**< Length of the received data. */ - uint8_t data[1]; /**< Received data. @note This is a variable length array. The size of 1 indicated is only a placeholder for - compilation. See @ref sd_ble_evt_get for more information on how to use event structures with variable - length array members. */ -} ble_gatts_evt_write_t; - -/**@brief Event substructure for authorized read requests, see @ref ble_gatts_evt_rw_authorize_request_t. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ - ble_uuid_t uuid; /**< Attribute UUID. */ - uint16_t offset; /**< Offset for the read operation. */ -} ble_gatts_evt_read_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST. */ -typedef struct { - uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */ - union { - ble_gatts_evt_read_t read; /**< Attribute Read Parameters. */ - ble_gatts_evt_write_t write; /**< Attribute Write Parameters. */ - } request; /**< Request Parameters. */ -} ble_gatts_evt_rw_authorize_request_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. */ -typedef struct { - uint8_t hint; /**< Hint (currently unused). */ -} ble_gatts_evt_sys_attr_missing_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_HVC. */ -typedef struct { - uint16_t handle; /**< Attribute Handle. */ -} ble_gatts_evt_hvc_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST. */ -typedef struct { - uint16_t client_rx_mtu; /**< Client RX MTU size. */ -} ble_gatts_evt_exchange_mtu_request_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_TIMEOUT. */ -typedef struct { - uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */ -} ble_gatts_evt_timeout_t; - -/**@brief Event structure for @ref BLE_GATTS_EVT_HVN_TX_COMPLETE. */ -typedef struct { - uint8_t count; /**< Number of notification transmissions completed. */ -} ble_gatts_evt_hvn_tx_complete_t; - -/**@brief GATTS event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which the event occurred. */ - union { - ble_gatts_evt_write_t write; /**< Write Event Parameters. */ - ble_gatts_evt_rw_authorize_request_t authorize_request; /**< Read or Write Authorize Request Parameters. */ - ble_gatts_evt_sys_attr_missing_t sys_attr_missing; /**< System attributes missing. */ - ble_gatts_evt_hvc_t hvc; /**< Handle Value Confirmation Event Parameters. */ - ble_gatts_evt_exchange_mtu_request_t exchange_mtu_request; /**< Exchange MTU Request Event Parameters. */ - ble_gatts_evt_timeout_t timeout; /**< Timeout Event. */ - ble_gatts_evt_hvn_tx_complete_t hvn_tx_complete; /**< Handle Value Notification transmission complete Event Parameters. */ - } params; /**< Event Parameters. */ -} ble_gatts_evt_t; - -/** @} */ - -/** @addtogroup BLE_GATTS_FUNCTIONS Functions - * @{ */ - -/**@brief Add a service declaration to the Attribute Table. - * - * @note Secondary Services are only relevant in the context of the entity that references them, it is therefore forbidden to - * add a secondary service declaration that is not referenced by another service later in the Attribute Table. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] type Toggles between primary and secondary services, see @ref BLE_GATTS_SRVC_TYPES. - * @param[in] p_uuid Pointer to service UUID. - * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a service declaration. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, Vendor Specific UUIDs need to be present in the table. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type, ble_uuid_t const *p_uuid, uint16_t *p_handle)); - -/**@brief Add an include declaration to the Attribute Table. - * - * @note It is currently only possible to add an include declaration to the last added service (i.e. only sequential population is - * supported at this time). - * - * @note The included service must already be present in the Attribute Table prior to this call. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] service_handle Handle of the service where the included service is to be placed, if @ref BLE_GATT_HANDLE_INVALID - * is used, it will be placed sequentially. - * @param[in] inc_srvc_handle Handle of the included service. - * @param[out] p_include_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added an include declaration. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, handle values need to match previously added services. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. - * @retval ::NRF_ERROR_NOT_SUPPORTED Feature is not supported, service_handle must be that of the last added service. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, self inclusions are not allowed. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - */ -SVCALL(SD_BLE_GATTS_INCLUDE_ADD, uint32_t, - sd_ble_gatts_include_add(uint16_t service_handle, uint16_t inc_srvc_handle, uint16_t *p_include_handle)); - -/**@brief Add a characteristic declaration, a characteristic value declaration and optional characteristic descriptor declarations - * to the Attribute Table. - * - * @note It is currently only possible to add a characteristic to the last added service (i.e. only sequential population is - * supported at this time). - * - * @note Several restrictions apply to the parameters, such as matching permissions between the user description descriptor and - * the writable auxiliaries bits, readable (no security) and writable (selectable) CCCDs and SCCDs and valid presentation format - * values. - * - * @note If no metadata is provided for the optional descriptors, their permissions will be derived from the characteristic - * permissions. - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] service_handle Handle of the service where the characteristic is to be placed, if @ref BLE_GATT_HANDLE_INVALID is - * used, it will be placed sequentially. - * @param[in] p_char_md Characteristic metadata. - * @param[in] p_attr_char_value Pointer to the attribute structure corresponding to the characteristic value. - * @param[out] p_handles Pointer to the structure where the assigned handles will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a characteristic. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, service handle, Vendor Specific UUIDs, lengths, and - * permissions need to adhere to the constraints. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - */ -SVCALL(SD_BLE_GATTS_CHARACTERISTIC_ADD, uint32_t, - sd_ble_gatts_characteristic_add(uint16_t service_handle, ble_gatts_char_md_t const *p_char_md, - ble_gatts_attr_t const *p_attr_char_value, ble_gatts_char_handles_t *p_handles)); - -/**@brief Add a descriptor to the Attribute Table. - * - * @note It is currently only possible to add a descriptor to the last added characteristic (i.e. only sequential population is - * supported at this time). - * - * @mscs - * @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC} - * @endmscs - * - * @param[in] char_handle Handle of the characteristic where the descriptor is to be placed, if @ref BLE_GATT_HANDLE_INVALID is - * used, it will be placed sequentially. - * @param[in] p_attr Pointer to the attribute structure. - * @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully added a descriptor. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, characteristic handle, Vendor Specific UUIDs, lengths, and - * permissions need to adhere to the constraints. - * @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a characteristic context is required. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - */ -SVCALL(SD_BLE_GATTS_DESCRIPTOR_ADD, uint32_t, - sd_ble_gatts_descriptor_add(uint16_t char_handle, ble_gatts_attr_t const *p_attr, uint16_t *p_handle)); - -/**@brief Set the value of a given attribute. - * - * @note Values other than system attributes can be set at any time, regardless of whether any active connections exist. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. - * @param[in] handle Attribute handle. - * @param[in,out] p_value Attribute value information. - * - * @retval ::NRF_SUCCESS Successfully set the value of the attribute. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_FORBIDDEN Forbidden handle supplied, certain attributes are not modifiable by the application. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. - */ -SVCALL(SD_BLE_GATTS_VALUE_SET, uint32_t, - sd_ble_gatts_value_set(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); - -/**@brief Get the value of a given attribute. - * - * @note If the attribute value is longer than the size of the supplied buffer, - * @ref ble_gatts_value_t::len will return the total attribute value length (excluding offset), - * and not the number of bytes actually returned in @ref ble_gatts_value_t::p_value. - * The application may use this information to allocate a suitable buffer size. - * - * @note When retrieving system attribute values with this function, the connection handle - * may refer to an already disconnected connection. Refer to the documentation of - * @ref sd_ble_gatts_sys_attr_get for further information. - * - * @param[in] conn_handle Connection handle. Ignored if the value does not belong to a system attribute. - * @param[in] handle Attribute handle. - * @param[in,out] p_value Attribute value information. - * - * @retval ::NRF_SUCCESS Successfully retrieved the value of the attribute. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid attribute offset supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied on a system attribute. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - */ -SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, - sd_ble_gatts_value_get(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value)); - -/**@brief Notify or Indicate an attribute value. - * - * @details This function checks for the relevant Client Characteristic Configuration descriptor value to verify that the relevant - * operation (notification or indication) has been enabled by the client. It is also able to update the attribute value before - * issuing the PDU, so that the application can atomically perform a value update and a server initiated transaction with a single - * API call. - * - * @note The local attribute value may be updated even if an outgoing packet is not sent to the peer due to an error during - * execution. The Attribute Table has been updated if one of the following error codes is returned: @ref NRF_ERROR_INVALID_STATE, - * @ref NRF_ERROR_BUSY, - * @ref NRF_ERROR_FORBIDDEN, @ref BLE_ERROR_GATTS_SYS_ATTR_MISSING and @ref NRF_ERROR_RESOURCES. - * The caller can check whether the value has been updated by looking at the contents of *(@ref - * ble_gatts_hvx_params_t::p_len). - * - * @note Only one indication procedure can be ongoing per connection at a time. - * If the application tries to indicate an attribute value while another indication procedure is ongoing, - * the function call will return @ref NRF_ERROR_BUSY. - * A @ref BLE_GATTS_EVT_HVC event will be issued as soon as the confirmation arrives from the peer. - * - * @note The number of Handle Value Notifications that can be queued is configured by @ref - * ble_gatts_conn_cfg_t::hvn_tx_queue_size When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES. A @ref - * BLE_GATTS_EVT_HVN_TX_COMPLETE event will be issued as soon as the transmission of the notification is complete. - * - * @note The application can keep track of the available queue element count for notifications by following the procedure - * below: - * - Store initial queue element count in a variable. - * - Decrement the variable, which stores the currently available queue element count, by one when a call to this - * function returns @ref NRF_SUCCESS. - * - Increment the variable, which stores the current available queue element count, by the count variable in @ref - * BLE_GATTS_EVT_HVN_TX_COMPLETE event. - * - * @events - * @event{@ref BLE_GATTS_EVT_HVN_TX_COMPLETE, Notification transmission complete.} - * @event{@ref BLE_GATTS_EVT_HVC, Confirmation received from the peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} - * @mmsc{@ref BLE_GATTS_HVN_MSC} - * @mmsc{@ref BLE_GATTS_HVI_MSC} - * @mmsc{@ref BLE_GATTS_HVX_DISABLED_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in,out] p_hvx_params Pointer to an HVx parameters structure. If @ref ble_gatts_hvx_params_t::p_data - * contains a non-NULL pointer the attribute value will be updated with the contents - * pointed by it before sending the notification or indication. If the attribute value - * is updated, @ref ble_gatts_hvx_params_t::p_len is updated by the SoftDevice to - * contain the number of actual bytes written, else it will be set to 0. - * - * @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute - * value. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: - * - Invalid Connection State - * - Notifications and/or indications not enabled in the CCCD - * - An ATT_MTU exchange is ongoing - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application - * are available to notify and indicate. - * @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and - * indicated. - * @retval ::NRF_ERROR_NOT_FOUND Attribute not found. - * @retval ::NRF_ERROR_FORBIDDEN The connection's current security level is lower than the one required by the write permissions - * of the CCCD associated with this characteristic. - * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied. - * @retval ::NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC - * event and retry. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - * @retval ::NRF_ERROR_RESOURCES Too many notifications queued. - * Wait for a @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event and retry. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_gatts_hvx_params_t const *p_hvx_params)); - -/**@brief Indicate the Service Changed attribute value. - * - * @details This call will send a Handle Value Indication to one or more peers connected to inform them that the Attribute - * Table layout has changed. As soon as the peer has confirmed the indication, a @ref BLE_GATTS_EVT_SC_CONFIRM event will - * be issued. - * - * @note Some of the restrictions and limitations that apply to @ref sd_ble_gatts_hvx also apply here. - * - * @events - * @event{@ref BLE_GATTS_EVT_SC_CONFIRM, Confirmation of attribute table change received from peer.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_GATTS_SC_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] start_handle Start of affected attribute handle range. - * @param[in] end_handle End of affected attribute handle range. - * - * @retval ::NRF_SUCCESS Successfully queued the Service Changed indication for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_NOT_SUPPORTED Service Changed not enabled at initialization. See @ref - * sd_ble_cfg_set and @ref ble_gatts_cfg_service_changed_t. - * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true: - * - Invalid Connection State - * - Notifications and/or indications not enabled in the CCCD - * - An ATT_MTU exchange is ongoing - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied, handles must be in the range populated by the - * application. - * @retval ::NRF_ERROR_BUSY Procedure already in progress. - * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known - * value. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t, - sd_ble_gatts_service_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle)); - -/**@brief Respond to a Read/Write authorization request. - * - * @note This call should only be used as a response to a @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event issued to the application. - * - * @mscs - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC} - * @mmsc{@ref BLE_GATTS_READ_REQ_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_WRITE_REQ_AUTH_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC} - * @mmsc{@ref BLE_GATTS_QUEUED_WRITE_PEER_CANCEL_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_rw_authorize_reply_params Pointer to a structure with the attribute provided by the application. - * - * @note @ref ble_gatts_authorize_params_t::p_data is ignored when this function is used to respond - * to a @ref BLE_GATTS_AUTHORIZE_TYPE_READ event if @ref ble_gatts_authorize_params_t::update - * is set to 0. - * - * @retval ::NRF_SUCCESS Successfully queued a response to the peer, and in the case of a write operation, Attribute - * Table updated. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no authorization request pending. - * @retval ::NRF_ERROR_INVALID_PARAM Authorization op invalid, - * handle supplied does not match requested handle, - * or invalid data to be written provided by the application. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_RW_AUTHORIZE_REPLY, uint32_t, - sd_ble_gatts_rw_authorize_reply(uint16_t conn_handle, - ble_gatts_rw_authorize_reply_params_t const *p_rw_authorize_reply_params)); - -/**@brief Update persistent system attribute information. - * - * @details Supply information about persistent system attributes to the stack, - * previously obtained using @ref sd_ble_gatts_sys_attr_get. - * This call is only allowed for active connections, and is usually - * made immediately after a connection is established with an known bonded device, - * often as a response to a @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. - * - * p_sysattrs may point directly to the application's stored copy of the system attributes - * obtained using @ref sd_ble_gatts_sys_attr_get. - * If the pointer is NULL, the system attribute info is initialized, assuming that - * the application does not have any previously saved system attribute data for this device. - * - * @note The state of persistent system attributes is reset upon connection establishment and then remembered for its duration. - * - * @note If this call returns with an error code different from @ref NRF_SUCCESS, the storage of persistent system attributes may - * have been completed only partially. This means that the state of the attribute table is undefined, and the application should - * either provide a new set of attributes using this same call or reset the SoftDevice to return to a known state. - * - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system - * services will be modified. - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user - * services will be modified. - * - * @mscs - * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC} - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_UNK_PEER_MSC} - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle. - * @param[in] p_sys_attr_data Pointer to a saved copy of system attributes supplied to the stack, or NULL. - * @param[in] len Size of data pointed by p_sys_attr_data, in octets. - * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS - * - * @retval ::NRF_SUCCESS Successfully set the system attribute information. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. - * @retval ::NRF_ERROR_INVALID_DATA Invalid data supplied, the data should be exactly the same as retrieved with @ref - * sd_ble_gatts_sys_attr_get. - * @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation. - */ -SVCALL(SD_BLE_GATTS_SYS_ATTR_SET, uint32_t, - sd_ble_gatts_sys_attr_set(uint16_t conn_handle, uint8_t const *p_sys_attr_data, uint16_t len, uint32_t flags)); - -/**@brief Retrieve persistent system attribute information from the stack. - * - * @details This call is used to retrieve information about values to be stored persistently by the application - * during the lifetime of a connection or after it has been terminated. When a new connection is established with the - * same bonded device, the system attribute information retrieved with this function should be restored using using @ref - * sd_ble_gatts_sys_attr_set. If retrieved after disconnection, the data should be read before a new connection established. The - * connection handle for the previous, now disconnected, connection will remain valid until a new one is created to allow this API - * call to refer to it. Connection handles belonging to active connections can be used as well, but care should be taken since the - * system attributes may be written to at any time by the peer during a connection's lifetime. - * - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system - * services will be returned. - * @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user - * services will be returned. - * - * @mscs - * @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC} - * @endmscs - * - * @param[in] conn_handle Connection handle of the recently terminated connection. - * @param[out] p_sys_attr_data Pointer to a buffer where updated information about system attributes will be filled in. The - * format of the data is described in @ref BLE_GATTS_SYS_ATTRS_FORMAT. NULL can be provided to obtain the length of the data. - * @param[in,out] p_len Size of application buffer if p_sys_attr_data is not NULL. Unconditionally updated to actual - * length of system attribute data. - * @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS - * - * @retval ::NRF_SUCCESS Successfully retrieved the system attribute information. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid flags supplied. - * @retval ::NRF_ERROR_DATA_SIZE The system attribute information did not fit into the provided buffer. - * @retval ::NRF_ERROR_NOT_FOUND No system attributes found. - */ -SVCALL(SD_BLE_GATTS_SYS_ATTR_GET, uint32_t, - sd_ble_gatts_sys_attr_get(uint16_t conn_handle, uint8_t *p_sys_attr_data, uint16_t *p_len, uint32_t flags)); - -/**@brief Retrieve the first valid user attribute handle. - * - * @param[out] p_handle Pointer to an integer where the handle will be stored. - * - * @retval ::NRF_SUCCESS Successfully retrieved the handle. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - */ -SVCALL(SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, uint32_t, sd_ble_gatts_initial_user_handle_get(uint16_t *p_handle)); - -/**@brief Retrieve the attribute UUID and/or metadata. - * - * @param[in] handle Attribute handle - * @param[out] p_uuid UUID of the attribute. Use NULL to omit this field. - * @param[out] p_md Metadata of the attribute. Use NULL to omit this field. - * - * @retval ::NRF_SUCCESS Successfully retrieved the attribute metadata, - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. Returned when both @c p_uuid and @c p_md are NULL. - * @retval ::NRF_ERROR_NOT_FOUND Attribute was not found. - */ -SVCALL(SD_BLE_GATTS_ATTR_GET, uint32_t, sd_ble_gatts_attr_get(uint16_t handle, ble_uuid_t *p_uuid, ble_gatts_attr_md_t *p_md)); - -/**@brief Reply to an ATT_MTU exchange request by sending an Exchange MTU Response to the client. - * - * @details This function is only used to reply to a @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST event. - * - * @details The SoftDevice sets ATT_MTU to the minimum of: - * - The Client RX MTU value from @ref BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST, and - * - The Server RX MTU value. - * - * However, the SoftDevice never sets ATT_MTU lower than @ref BLE_GATT_ATT_MTU_DEFAULT. - * - * @mscs - * @mmsc{@ref BLE_GATTS_MTU_EXCHANGE} - * @endmscs - * - * @param[in] conn_handle The connection handle identifying the connection to perform this procedure on. - * @param[in] server_rx_mtu Server RX MTU size. - * - The minimum value is @ref BLE_GATT_ATT_MTU_DEFAULT. - * - The maximum value is @ref ble_gatt_conn_cfg_t::att_mtu in the connection configuration - * used for this connection. - * - The value must be equal to Client RX MTU size given in @ref sd_ble_gattc_exchange_mtu_request - * if an ATT_MTU exchange has already been performed in the other direction. - * - * @retval ::NRF_SUCCESS Successfully sent response to the client. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no ATT_MTU exchange request pending. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid Server RX MTU size supplied. - * @retval ::NRF_ERROR_TIMEOUT There has been a GATT procedure timeout. No new GATT procedure can be performed without - * reestablishing the connection. - */ -SVCALL(SD_BLE_GATTS_EXCHANGE_MTU_REPLY, uint32_t, sd_ble_gatts_exchange_mtu_reply(uint16_t conn_handle, uint16_t server_rx_mtu)); -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_GATTS_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_hci.h b/variants/wio-sdk-wm1110/softdevice/ble_hci.h deleted file mode 100644 index 27f85d52ea..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_hci.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ -*/ - -#ifndef BLE_HCI_H__ -#define BLE_HCI_H__ -#ifdef __cplusplus -extern "C" { -#endif - -/** @defgroup BLE_HCI_STATUS_CODES Bluetooth status codes - * @{ */ - -#define BLE_HCI_STATUS_CODE_SUCCESS 0x00 /**< Success. */ -#define BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND 0x01 /**< Unknown BLE Command. */ -#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02 /**< Unknown Connection Identifier. */ -/*0x03 Hardware Failure -0x04 Page Timeout -*/ -#define BLE_HCI_AUTHENTICATION_FAILURE 0x05 /**< Authentication Failure. */ -#define BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING 0x06 /**< Pin or Key missing. */ -#define BLE_HCI_MEMORY_CAPACITY_EXCEEDED 0x07 /**< Memory Capacity Exceeded. */ -#define BLE_HCI_CONNECTION_TIMEOUT 0x08 /**< Connection Timeout. */ -/*0x09 Connection Limit Exceeded -0x0A Synchronous Connection Limit To A Device Exceeded -0x0B ACL Connection Already Exists*/ -#define BLE_HCI_STATUS_CODE_COMMAND_DISALLOWED 0x0C /**< Command Disallowed. */ -/*0x0D Connection Rejected due to Limited Resources -0x0E Connection Rejected Due To Security Reasons -0x0F Connection Rejected due to Unacceptable BD_ADDR -0x10 Connection Accept Timeout Exceeded -0x11 Unsupported Feature or Parameter Value*/ -#define BLE_HCI_STATUS_CODE_INVALID_BTLE_COMMAND_PARAMETERS 0x12 /**< Invalid BLE Command Parameters. */ -#define BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION 0x13 /**< Remote User Terminated Connection. */ -#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES \ - 0x14 /**< Remote Device Terminated Connection due to low \ - resources.*/ -#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF 0x15 /**< Remote Device Terminated Connection due to power off. */ -#define BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION 0x16 /**< Local Host Terminated Connection. */ -/* -0x17 Repeated Attempts -0x18 Pairing Not Allowed -0x19 Unknown LMP PDU -*/ -#define BLE_HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A /**< Unsupported Remote Feature. */ -/* -0x1B SCO Offset Rejected -0x1C SCO Interval Rejected -0x1D SCO Air Mode Rejected*/ -#define BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS 0x1E /**< Invalid LMP Parameters. */ -#define BLE_HCI_STATUS_CODE_UNSPECIFIED_ERROR 0x1F /**< Unspecified Error. */ -/*0x20 Unsupported LMP Parameter Value -0x21 Role Change Not Allowed -*/ -#define BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT 0x22 /**< LMP Response Timeout. */ -#define BLE_HCI_STATUS_CODE_LMP_ERROR_TRANSACTION_COLLISION 0x23 /**< LMP Error Transaction Collision/LL Procedure Collision. */ -#define BLE_HCI_STATUS_CODE_LMP_PDU_NOT_ALLOWED 0x24 /**< LMP PDU Not Allowed. */ -/*0x25 Encryption Mode Not Acceptable -0x26 Link Key Can Not be Changed -0x27 Requested QoS Not Supported -*/ -#define BLE_HCI_INSTANT_PASSED 0x28 /**< Instant Passed. */ -#define BLE_HCI_PAIRING_WITH_UNIT_KEY_UNSUPPORTED 0x29 /**< Pairing with Unit Key Unsupported. */ -#define BLE_HCI_DIFFERENT_TRANSACTION_COLLISION 0x2A /**< Different Transaction Collision. */ -/* -0x2B Reserved -0x2C QoS Unacceptable Parameter -0x2D QoS Rejected -0x2E Channel Classification Not Supported -0x2F Insufficient Security -*/ -#define BLE_HCI_PARAMETER_OUT_OF_MANDATORY_RANGE 0x30 /**< Parameter Out Of Mandatory Range. */ -/* -0x31 Reserved -0x32 Role Switch Pending -0x33 Reserved -0x34 Reserved Slot Violation -0x35 Role Switch Failed -0x36 Extended Inquiry Response Too Large -0x37 Secure Simple Pairing Not Supported By Host. -0x38 Host Busy - Pairing -0x39 Connection Rejected due to No Suitable Channel Found*/ -#define BLE_HCI_CONTROLLER_BUSY 0x3A /**< Controller Busy. */ -#define BLE_HCI_CONN_INTERVAL_UNACCEPTABLE 0x3B /**< Connection Interval Unacceptable. */ -#define BLE_HCI_DIRECTED_ADVERTISER_TIMEOUT 0x3C /**< Directed Advertisement Timeout. */ -#define BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE 0x3D /**< Connection Terminated due to MIC Failure. */ -#define BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED 0x3E /**< Connection Failed to be Established. */ - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_HCI_H__ - -/** @} */ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h b/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h deleted file mode 100644 index 5f4bd277d3..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_l2cap.h +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_L2CAP Logical Link Control and Adaptation Protocol (L2CAP) - @{ - @brief Definitions and prototypes for the L2CAP interface. - */ - -#ifndef BLE_L2CAP_H__ -#define BLE_L2CAP_H__ - -#include "ble_err.h" -#include "ble_ranges.h" -#include "ble_types.h" -#include "nrf_error.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup BLE_L2CAP_TERMINOLOGY Terminology - * @{ - * @details - * - * L2CAP SDU - * - A data unit that the application can send/receive to/from a peer. - * - * L2CAP PDU - * - A data unit that is exchanged between local and remote L2CAP entities. - * It consists of L2CAP protocol control information and payload fields. - * The payload field can contain an L2CAP SDU or a part of an L2CAP SDU. - * - * L2CAP MTU - * - The maximum length of an L2CAP SDU. - * - * L2CAP MPS - * - The maximum length of an L2CAP PDU payload field. - * - * Credits - * - A value indicating the number of L2CAP PDUs that the receiver of the credit can send to the peer. - * @} */ - -/**@addtogroup BLE_L2CAP_ENUMERATIONS Enumerations - * @{ */ - -/**@brief L2CAP API SVC numbers. */ -enum BLE_L2CAP_SVCS { - SD_BLE_L2CAP_CH_SETUP = BLE_L2CAP_SVC_BASE + 0, /**< Set up an L2CAP channel. */ - SD_BLE_L2CAP_CH_RELEASE = BLE_L2CAP_SVC_BASE + 1, /**< Release an L2CAP channel. */ - SD_BLE_L2CAP_CH_RX = BLE_L2CAP_SVC_BASE + 2, /**< Receive an SDU on an L2CAP channel. */ - SD_BLE_L2CAP_CH_TX = BLE_L2CAP_SVC_BASE + 3, /**< Transmit an SDU on an L2CAP channel. */ - SD_BLE_L2CAP_CH_FLOW_CONTROL = BLE_L2CAP_SVC_BASE + 4, /**< Advanced SDU reception flow control. */ -}; - -/**@brief L2CAP Event IDs. */ -enum BLE_L2CAP_EVTS { - BLE_L2CAP_EVT_CH_SETUP_REQUEST = BLE_L2CAP_EVT_BASE + 0, /**< L2CAP Channel Setup Request event. - \n Reply with @ref sd_ble_l2cap_ch_setup. - \n See @ref ble_l2cap_evt_ch_setup_request_t. */ - BLE_L2CAP_EVT_CH_SETUP_REFUSED = BLE_L2CAP_EVT_BASE + 1, /**< L2CAP Channel Setup Refused event. - \n See @ref ble_l2cap_evt_ch_setup_refused_t. */ - BLE_L2CAP_EVT_CH_SETUP = BLE_L2CAP_EVT_BASE + 2, /**< L2CAP Channel Setup Completed event. - \n See @ref ble_l2cap_evt_ch_setup_t. */ - BLE_L2CAP_EVT_CH_RELEASED = BLE_L2CAP_EVT_BASE + 3, /**< L2CAP Channel Released event. - \n No additional event structure applies. */ - BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED = BLE_L2CAP_EVT_BASE + 4, /**< L2CAP Channel SDU data buffer released event. - \n See @ref ble_l2cap_evt_ch_sdu_buf_released_t. */ - BLE_L2CAP_EVT_CH_CREDIT = BLE_L2CAP_EVT_BASE + 5, /**< L2CAP Channel Credit received. - \n See @ref ble_l2cap_evt_ch_credit_t. */ - BLE_L2CAP_EVT_CH_RX = BLE_L2CAP_EVT_BASE + 6, /**< L2CAP Channel SDU received. - \n See @ref ble_l2cap_evt_ch_rx_t. */ - BLE_L2CAP_EVT_CH_TX = BLE_L2CAP_EVT_BASE + 7, /**< L2CAP Channel SDU transmitted. - \n See @ref ble_l2cap_evt_ch_tx_t. */ -}; - -/** @} */ - -/**@addtogroup BLE_L2CAP_DEFINES Defines - * @{ */ - -/**@brief Maximum number of L2CAP channels per connection. */ -#define BLE_L2CAP_CH_COUNT_MAX (64) - -/**@brief Minimum L2CAP MTU, in bytes. */ -#define BLE_L2CAP_MTU_MIN (23) - -/**@brief Minimum L2CAP MPS, in bytes. */ -#define BLE_L2CAP_MPS_MIN (23) - -/**@brief Invalid CID. */ -#define BLE_L2CAP_CID_INVALID (0x0000) - -/**@brief Default number of credits for @ref sd_ble_l2cap_ch_flow_control. */ -#define BLE_L2CAP_CREDITS_DEFAULT (1) - -/**@defgroup BLE_L2CAP_CH_SETUP_REFUSED_SRCS L2CAP channel setup refused sources - * @{ */ -#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_LOCAL (0x01) /**< Local. */ -#define BLE_L2CAP_CH_SETUP_REFUSED_SRC_REMOTE (0x02) /**< Remote. */ - /** @} */ - -/** @defgroup BLE_L2CAP_CH_STATUS_CODES L2CAP channel status codes - * @{ */ -#define BLE_L2CAP_CH_STATUS_CODE_SUCCESS (0x0000) /**< Success. */ -#define BLE_L2CAP_CH_STATUS_CODE_LE_PSM_NOT_SUPPORTED (0x0002) /**< LE_PSM not supported. */ -#define BLE_L2CAP_CH_STATUS_CODE_NO_RESOURCES (0x0004) /**< No resources available. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHENTICATION (0x0005) /**< Insufficient authentication. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_AUTHORIZATION (0x0006) /**< Insufficient authorization. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC_KEY_SIZE (0x0007) /**< Insufficient encryption key size. */ -#define BLE_L2CAP_CH_STATUS_CODE_INSUFF_ENC (0x0008) /**< Insufficient encryption. */ -#define BLE_L2CAP_CH_STATUS_CODE_INVALID_SCID (0x0009) /**< Invalid Source CID. */ -#define BLE_L2CAP_CH_STATUS_CODE_SCID_ALLOCATED (0x000A) /**< Source CID already allocated. */ -#define BLE_L2CAP_CH_STATUS_CODE_UNACCEPTABLE_PARAMS (0x000B) /**< Unacceptable parameters. */ -#define BLE_L2CAP_CH_STATUS_CODE_NOT_UNDERSTOOD \ - (0x8000) /**< Command Reject received instead of LE Credit Based Connection Response. */ -#define BLE_L2CAP_CH_STATUS_CODE_TIMEOUT (0xC000) /**< Operation timed out. */ -/** @} */ - -/** @} */ - -/**@addtogroup BLE_L2CAP_STRUCTURES Structures - * @{ */ - -/** - * @brief BLE L2CAP connection configuration parameters, set with @ref sd_ble_cfg_set. - * - * @note These parameters are set per connection, so all L2CAP channels created on this connection - * will have the same parameters. - * - * @retval ::NRF_ERROR_INVALID_PARAM One or more of the following is true: - * - rx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. - * - tx_mps is smaller than @ref BLE_L2CAP_MPS_MIN. - * - ch_count is greater than @ref BLE_L2CAP_CH_COUNT_MAX. - * @retval ::NRF_ERROR_NO_MEM rx_mps or tx_mps is set too high. - */ -typedef struct { - uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall - be able to receive on L2CAP channels on connections with this - configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ - uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall - be able to transmit on L2CAP channels on connections with this - configuration. The minimum value is @ref BLE_L2CAP_MPS_MIN. */ - uint8_t rx_queue_size; /**< Number of SDU data buffers that can be queued for reception per - L2CAP channel. The minimum value is one. */ - uint8_t tx_queue_size; /**< Number of SDU data buffers that can be queued for transmission - per L2CAP channel. The minimum value is one. */ - uint8_t ch_count; /**< Number of L2CAP channels the application can create per connection - with this configuration. The default value is zero, the maximum - value is @ref BLE_L2CAP_CH_COUNT_MAX. - @note if this parameter is set to zero, all other parameters in - @ref ble_l2cap_conn_cfg_t are ignored. */ -} ble_l2cap_conn_cfg_t; - -/**@brief L2CAP channel RX parameters. */ -typedef struct { - uint16_t rx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP shall be able to - receive on this L2CAP channel. - - Must be equal to or greater than @ref BLE_L2CAP_MTU_MIN. */ - uint16_t rx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP shall be - able to receive on this L2CAP channel. - - Must be equal to or greater than @ref BLE_L2CAP_MPS_MIN. - - Must be equal to or less than @ref ble_l2cap_conn_cfg_t::rx_mps. */ - ble_data_t sdu_buf; /**< SDU data buffer for reception. - - If @ref ble_data_t::p_data is non-NULL, initial credits are - issued to the peer. - - If @ref ble_data_t::p_data is NULL, no initial credits are - issued to the peer. */ -} ble_l2cap_ch_rx_params_t; - -/**@brief L2CAP channel setup parameters. */ -typedef struct { - ble_l2cap_ch_rx_params_t rx_params; /**< L2CAP channel RX parameters. */ - uint16_t le_psm; /**< LE Protocol/Service Multiplexer. Used when requesting - setup of an L2CAP channel, ignored otherwise. */ - uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES. - Used when replying to a setup request of an L2CAP - channel, ignored otherwise. */ -} ble_l2cap_ch_setup_params_t; - -/**@brief L2CAP channel TX parameters. */ -typedef struct { - uint16_t tx_mtu; /**< The maximum L2CAP SDU size, in bytes, that L2CAP is able to - transmit on this L2CAP channel. */ - uint16_t peer_mps; /**< The maximum L2CAP PDU payload size, in bytes, that the peer is - able to receive on this L2CAP channel. */ - uint16_t tx_mps; /**< The maximum L2CAP PDU payload size, in bytes, that L2CAP is able - to transmit on this L2CAP channel. This is effective tx_mps, - selected by the SoftDevice as - MIN( @ref ble_l2cap_ch_tx_params_t::peer_mps, @ref ble_l2cap_conn_cfg_t::tx_mps ) */ - uint16_t credits; /**< Initial credits given by the peer. */ -} ble_l2cap_ch_tx_params_t; - -/**@brief L2CAP Channel Setup Request event. */ -typedef struct { - ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ - uint16_t le_psm; /**< LE Protocol/Service Multiplexer. */ -} ble_l2cap_evt_ch_setup_request_t; - -/**@brief L2CAP Channel Setup Refused event. */ -typedef struct { - uint8_t source; /**< Source, see @ref BLE_L2CAP_CH_SETUP_REFUSED_SRCS */ - uint16_t status; /**< Status code, see @ref BLE_L2CAP_CH_STATUS_CODES */ -} ble_l2cap_evt_ch_setup_refused_t; - -/**@brief L2CAP Channel Setup Completed event. */ -typedef struct { - ble_l2cap_ch_tx_params_t tx_params; /**< L2CAP channel TX parameters. */ -} ble_l2cap_evt_ch_setup_t; - -/**@brief L2CAP Channel SDU Data Buffer Released event. */ -typedef struct { - ble_data_t sdu_buf; /**< Returned reception or transmission SDU data buffer. The SoftDevice - returns SDU data buffers supplied by the application, which have - not yet been returned previously via a @ref BLE_L2CAP_EVT_CH_RX or - @ref BLE_L2CAP_EVT_CH_TX event. */ -} ble_l2cap_evt_ch_sdu_buf_released_t; - -/**@brief L2CAP Channel Credit received event. */ -typedef struct { - uint16_t credits; /**< Additional credits given by the peer. */ -} ble_l2cap_evt_ch_credit_t; - -/**@brief L2CAP Channel received SDU event. */ -typedef struct { - uint16_t sdu_len; /**< Total SDU length, in bytes. */ - ble_data_t sdu_buf; /**< SDU data buffer. - @note If there is not enough space in the buffer - (sdu_buf.len < sdu_len) then the rest of the SDU will be - silently discarded by the SoftDevice. */ -} ble_l2cap_evt_ch_rx_t; - -/**@brief L2CAP Channel transmitted SDU event. */ -typedef struct { - ble_data_t sdu_buf; /**< SDU data buffer. */ -} ble_l2cap_evt_ch_tx_t; - -/**@brief L2CAP event structure. */ -typedef struct { - uint16_t conn_handle; /**< Connection Handle on which the event occured. */ - uint16_t local_cid; /**< Local Channel ID of the L2CAP channel, or - @ref BLE_L2CAP_CID_INVALID if not present. */ - union { - ble_l2cap_evt_ch_setup_request_t ch_setup_request; /**< L2CAP Channel Setup Request Event Parameters. */ - ble_l2cap_evt_ch_setup_refused_t ch_setup_refused; /**< L2CAP Channel Setup Refused Event Parameters. */ - ble_l2cap_evt_ch_setup_t ch_setup; /**< L2CAP Channel Setup Completed Event Parameters. */ - ble_l2cap_evt_ch_sdu_buf_released_t ch_sdu_buf_released; /**< L2CAP Channel SDU Data Buffer Released Event Parameters. */ - ble_l2cap_evt_ch_credit_t credit; /**< L2CAP Channel Credit Received Event Parameters. */ - ble_l2cap_evt_ch_rx_t rx; /**< L2CAP Channel SDU Received Event Parameters. */ - ble_l2cap_evt_ch_tx_t tx; /**< L2CAP Channel SDU Transmitted Event Parameters. */ - } params; /**< Event Parameters. */ -} ble_l2cap_evt_t; - -/** @} */ - -/**@addtogroup BLE_L2CAP_FUNCTIONS Functions - * @{ */ - -/**@brief Set up an L2CAP channel. - * - * @details This function is used to: - * - Request setup of an L2CAP channel: sends an LE Credit Based Connection Request packet to a peer. - * - Reply to a setup request of an L2CAP channel (if called in response to a - * @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST event): sends an LE Credit Based Connection - * Response packet to a peer. - * - * @note A call to this function will require the application to keep the SDU data buffer alive - * until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX or - * @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_SETUP, Setup successful.} - * @event{@ref BLE_L2CAP_EVT_CH_SETUP_REFUSED, Setup failed.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_SETUP_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in,out] p_local_cid Pointer to a uint16_t containing Local Channel ID of the L2CAP channel: - * - As input: @ref BLE_L2CAP_CID_INVALID when requesting setup of an L2CAP - * channel or local_cid provided in the @ref BLE_L2CAP_EVT_CH_SETUP_REQUEST - * event when replying to a setup request of an L2CAP channel. - * - As output: local_cid for this channel. - * @param[in] p_params L2CAP channel parameters. - * - * @retval ::NRF_SUCCESS Successfully queued request or response for transmission. - * @retval ::NRF_ERROR_BUSY The stack is busy, process pending events and retry. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied. - * @retval ::NRF_ERROR_INVALID_LENGTH Supplied higher rx_mps than has been configured on this link. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (L2CAP channel already set up). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_RESOURCES The limit has been reached for available L2CAP channels, - * see @ref ble_l2cap_conn_cfg_t::ch_count. - */ -SVCALL(SD_BLE_L2CAP_CH_SETUP, uint32_t, - sd_ble_l2cap_ch_setup(uint16_t conn_handle, uint16_t *p_local_cid, ble_l2cap_ch_setup_params_t const *p_params)); - -/**@brief Release an L2CAP channel. - * - * @details This sends a Disconnection Request packet to a peer. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_RELEASED, Release complete.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_RELEASE_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * - * @retval ::NRF_SUCCESS Successfully queued request for transmission. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for the L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - */ -SVCALL(SD_BLE_L2CAP_CH_RELEASE, uint32_t, sd_ble_l2cap_ch_release(uint16_t conn_handle, uint16_t local_cid)); - -/**@brief Receive an SDU on an L2CAP channel. - * - * @details This may issue additional credits to the peer using an LE Flow Control Credit packet. - * - * @note A call to this function will require the application to keep the memory pointed by - * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_RX - * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::rx_queue_size SDU data buffers - * for reception per L2CAP channel. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_RX, The SDU is received.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_RX_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * @param[in] p_sdu_buf Pointer to the SDU data buffer. - * - * @retval ::NRF_SUCCESS Buffer accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for an L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_RESOURCES Too many SDU data buffers supplied. Wait for a - * @ref BLE_L2CAP_EVT_CH_RX event and retry. - */ -SVCALL(SD_BLE_L2CAP_CH_RX, uint32_t, sd_ble_l2cap_ch_rx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); - -/**@brief Transmit an SDU on an L2CAP channel. - * - * @note A call to this function will require the application to keep the memory pointed by - * @ref ble_data_t::p_data alive until the SDU data buffer is returned in @ref BLE_L2CAP_EVT_CH_TX - * or @ref BLE_L2CAP_EVT_CH_SDU_BUF_RELEASED event. - * - * @note The SoftDevice can queue up to @ref ble_l2cap_conn_cfg_t::tx_queue_size SDUs for - * transmission per L2CAP channel. - * - * @note The application can keep track of the available credits for transmission by following - * the procedure below: - * - Store initial credits given by the peer in a variable. - * (Initial credits are provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) - * - Decrement the variable, which stores the currently available credits, by - * ceiling((@ref ble_data_t::len + 2) / tx_mps) when a call to this function returns - * @ref NRF_SUCCESS. (tx_mps is provided in a @ref BLE_L2CAP_EVT_CH_SETUP event.) - * - Increment the variable, which stores the currently available credits, by additional - * credits given by the peer in a @ref BLE_L2CAP_EVT_CH_CREDIT event. - * - * @events - * @event{@ref BLE_L2CAP_EVT_CH_TX, The SDU is transmitted.} - * @endevents - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_TX_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel. - * @param[in] p_sdu_buf Pointer to the SDU data buffer. - * - * @retval ::NRF_SUCCESS Successfully queued L2CAP SDU for transmission. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for the L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - * @retval ::NRF_ERROR_DATA_SIZE Invalid SDU length supplied, must not be more than - * @ref ble_l2cap_ch_tx_params_t::tx_mtu provided in - * @ref BLE_L2CAP_EVT_CH_SETUP event. - * @retval ::NRF_ERROR_RESOURCES Too many SDUs queued for transmission. Wait for a - * @ref BLE_L2CAP_EVT_CH_TX event and retry. - */ -SVCALL(SD_BLE_L2CAP_CH_TX, uint32_t, sd_ble_l2cap_ch_tx(uint16_t conn_handle, uint16_t local_cid, ble_data_t const *p_sdu_buf)); - -/**@brief Advanced SDU reception flow control. - * - * @details Adjust the way the SoftDevice issues credits to the peer. - * This may issue additional credits to the peer using an LE Flow Control Credit packet. - * - * @mscs - * @mmsc{@ref BLE_L2CAP_CH_FLOW_CONTROL_MSC} - * @endmscs - * - * @param[in] conn_handle Connection Handle. - * @param[in] local_cid Local Channel ID of the L2CAP channel or @ref BLE_L2CAP_CID_INVALID to set - * the value that will be used for newly created channels. - * @param[in] credits Number of credits that the SoftDevice will make sure the peer has every - * time it starts using a new reception buffer. - * - @ref BLE_L2CAP_CREDITS_DEFAULT is the default value the SoftDevice will - * use if this function is not called. - * - If set to zero, the SoftDevice will stop issuing credits for new reception - * buffers the application provides or has provided. SDU reception that is - * currently ongoing will be allowed to complete. - * @param[out] p_credits NULL or pointer to a uint16_t. If a valid pointer is provided, it will be - * written by the SoftDevice with the number of credits that is or will be - * available to the peer. If the value written by the SoftDevice is 0 when - * credits parameter was set to 0, the peer will not be able to send more - * data until more credits are provided by calling this function again with - * credits > 0. This parameter is ignored when local_cid is set to - * @ref BLE_L2CAP_CID_INVALID. - * - * @note Application should take care when setting number of credits higher than default value. In - * this case the application must make sure that the SoftDevice always has reception buffers - * available (see @ref sd_ble_l2cap_ch_rx) for that channel. If the SoftDevice does not have - * such buffers available, packets may be NACKed on the Link Layer and all Bluetooth traffic - * on the connection handle may be stalled until the SoftDevice again has an available - * reception buffer. This applies even if the application has used this call to set the - * credits back to default, or zero. - * - * @retval ::NRF_SUCCESS Flow control parameters accepted. - * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied. - * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle. - * @retval ::NRF_ERROR_INVALID_STATE Invalid State to perform operation (Setup or release is - * in progress for an L2CAP channel). - * @retval ::NRF_ERROR_NOT_FOUND CID not found. - */ -SVCALL(SD_BLE_L2CAP_CH_FLOW_CONTROL, uint32_t, - sd_ble_l2cap_ch_flow_control(uint16_t conn_handle, uint16_t local_cid, uint16_t credits, uint16_t *p_credits)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // BLE_L2CAP_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_ranges.h b/variants/wio-sdk-wm1110/softdevice/ble_ranges.h deleted file mode 100644 index 2768e49967..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_ranges.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @defgroup ble_ranges Module specific SVC, event and option number subranges - @{ - - @brief Definition of SVC, event and option number subranges for each API module. - - @note - SVCs, event and option numbers are split into subranges for each API module. - Each module receives its entire allocated range of SVC calls, whether implemented or not, - but return BLE_ERROR_NOT_SUPPORTED for unimplemented or undefined calls in its range. - - Note that the symbols BLE__SVC_LAST is the end of the allocated SVC range, - rather than the last SVC function call actually defined and implemented. - - Specific SVC, event and option values are defined in each module's ble_.h file, - which defines names of each individual SVC code based on the range start value. -*/ - -#ifndef BLE_RANGES_H__ -#define BLE_RANGES_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#define BLE_SVC_BASE 0x60 /**< Common BLE SVC base. */ -#define BLE_SVC_LAST 0x6B /**< Common BLE SVC last. */ - -#define BLE_GAP_SVC_BASE 0x6C /**< GAP BLE SVC base. */ -#define BLE_GAP_SVC_LAST 0x9A /**< GAP BLE SVC last. */ - -#define BLE_GATTC_SVC_BASE 0x9B /**< GATTC BLE SVC base. */ -#define BLE_GATTC_SVC_LAST 0xA7 /**< GATTC BLE SVC last. */ - -#define BLE_GATTS_SVC_BASE 0xA8 /**< GATTS BLE SVC base. */ -#define BLE_GATTS_SVC_LAST 0xB7 /**< GATTS BLE SVC last. */ - -#define BLE_L2CAP_SVC_BASE 0xB8 /**< L2CAP BLE SVC base. */ -#define BLE_L2CAP_SVC_LAST 0xBF /**< L2CAP BLE SVC last. */ - -#define BLE_EVT_INVALID 0x00 /**< Invalid BLE Event. */ - -#define BLE_EVT_BASE 0x01 /**< Common BLE Event base. */ -#define BLE_EVT_LAST 0x0F /**< Common BLE Event last. */ - -#define BLE_GAP_EVT_BASE 0x10 /**< GAP BLE Event base. */ -#define BLE_GAP_EVT_LAST 0x2F /**< GAP BLE Event last. */ - -#define BLE_GATTC_EVT_BASE 0x30 /**< GATTC BLE Event base. */ -#define BLE_GATTC_EVT_LAST 0x4F /**< GATTC BLE Event last. */ - -#define BLE_GATTS_EVT_BASE 0x50 /**< GATTS BLE Event base. */ -#define BLE_GATTS_EVT_LAST 0x6F /**< GATTS BLE Event last. */ - -#define BLE_L2CAP_EVT_BASE 0x70 /**< L2CAP BLE Event base. */ -#define BLE_L2CAP_EVT_LAST 0x8F /**< L2CAP BLE Event last. */ - -#define BLE_OPT_INVALID 0x00 /**< Invalid BLE Option. */ - -#define BLE_OPT_BASE 0x01 /**< Common BLE Option base. */ -#define BLE_OPT_LAST 0x1F /**< Common BLE Option last. */ - -#define BLE_GAP_OPT_BASE 0x20 /**< GAP BLE Option base. */ -#define BLE_GAP_OPT_LAST 0x3F /**< GAP BLE Option last. */ - -#define BLE_GATT_OPT_BASE 0x40 /**< GATT BLE Option base. */ -#define BLE_GATT_OPT_LAST 0x5F /**< GATT BLE Option last. */ - -#define BLE_GATTC_OPT_BASE 0x60 /**< GATTC BLE Option base. */ -#define BLE_GATTC_OPT_LAST 0x7F /**< GATTC BLE Option last. */ - -#define BLE_GATTS_OPT_BASE 0x80 /**< GATTS BLE Option base. */ -#define BLE_GATTS_OPT_LAST 0x9F /**< GATTS BLE Option last. */ - -#define BLE_L2CAP_OPT_BASE 0xA0 /**< L2CAP BLE Option base. */ -#define BLE_L2CAP_OPT_LAST 0xBF /**< L2CAP BLE Option last. */ - -#define BLE_CFG_INVALID 0x00 /**< Invalid BLE configuration. */ - -#define BLE_CFG_BASE 0x01 /**< Common BLE configuration base. */ -#define BLE_CFG_LAST 0x1F /**< Common BLE configuration last. */ - -#define BLE_CONN_CFG_BASE 0x20 /**< BLE connection configuration base. */ -#define BLE_CONN_CFG_LAST 0x3F /**< BLE connection configuration last. */ - -#define BLE_GAP_CFG_BASE 0x40 /**< GAP BLE configuration base. */ -#define BLE_GAP_CFG_LAST 0x5F /**< GAP BLE configuration last. */ - -#define BLE_GATT_CFG_BASE 0x60 /**< GATT BLE configuration base. */ -#define BLE_GATT_CFG_LAST 0x7F /**< GATT BLE configuration last. */ - -#define BLE_GATTC_CFG_BASE 0x80 /**< GATTC BLE configuration base. */ -#define BLE_GATTC_CFG_LAST 0x9F /**< GATTC BLE configuration last. */ - -#define BLE_GATTS_CFG_BASE 0xA0 /**< GATTS BLE configuration base. */ -#define BLE_GATTS_CFG_LAST 0xBF /**< GATTS BLE configuration last. */ - -#define BLE_L2CAP_CFG_BASE 0xC0 /**< L2CAP BLE configuration base. */ -#define BLE_L2CAP_CFG_LAST 0xDF /**< L2CAP BLE configuration last. */ - -#ifdef __cplusplus -} -#endif -#endif /* BLE_RANGES_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/ble_types.h b/variants/wio-sdk-wm1110/softdevice/ble_types.h deleted file mode 100644 index db3656cfdd..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/ble_types.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup BLE_COMMON - @{ - @defgroup ble_types Common types and macro definitions - @{ - - @brief Common types and macro definitions for the BLE SoftDevice. - */ - -#ifndef BLE_TYPES_H__ -#define BLE_TYPES_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup BLE_TYPES_DEFINES Defines - * @{ */ - -/** @defgroup BLE_CONN_HANDLES BLE Connection Handles - * @{ */ -#define BLE_CONN_HANDLE_INVALID 0xFFFF /**< Invalid Connection Handle. */ -#define BLE_CONN_HANDLE_ALL 0xFFFE /**< Applies to all Connection Handles. */ -/** @} */ - -/** @defgroup BLE_UUID_VALUES Assigned Values for BLE UUIDs - * @{ */ -/* Generic UUIDs, applicable to all services */ -#define BLE_UUID_UNKNOWN 0x0000 /**< Reserved UUID. */ -#define BLE_UUID_SERVICE_PRIMARY 0x2800 /**< Primary Service. */ -#define BLE_UUID_SERVICE_SECONDARY 0x2801 /**< Secondary Service. */ -#define BLE_UUID_SERVICE_INCLUDE 0x2802 /**< Include. */ -#define BLE_UUID_CHARACTERISTIC 0x2803 /**< Characteristic. */ -#define BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP 0x2900 /**< Characteristic Extended Properties Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_USER_DESC 0x2901 /**< Characteristic User Description Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG 0x2902 /**< Client Characteristic Configuration Descriptor. */ -#define BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG 0x2903 /**< Server Characteristic Configuration Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT 0x2904 /**< Characteristic Presentation Format Descriptor. */ -#define BLE_UUID_DESCRIPTOR_CHAR_AGGREGATE_FORMAT 0x2905 /**< Characteristic Aggregate Format Descriptor. */ -/* GATT specific UUIDs */ -#define BLE_UUID_GATT 0x1801 /**< Generic Attribute Profile. */ -#define BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED 0x2A05 /**< Service Changed Characteristic. */ -/* GAP specific UUIDs */ -#define BLE_UUID_GAP 0x1800 /**< Generic Access Profile. */ -#define BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME 0x2A00 /**< Device Name Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_APPEARANCE 0x2A01 /**< Appearance Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_RECONN_ADDR 0x2A03 /**< Reconnection Address Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_PPCP 0x2A04 /**< Peripheral Preferred Connection Parameters Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_CAR 0x2AA6 /**< Central Address Resolution Characteristic. */ -#define BLE_UUID_GAP_CHARACTERISTIC_RPA_ONLY 0x2AC9 /**< Resolvable Private Address Only Characteristic. */ -/** @} */ - -/** @defgroup BLE_UUID_TYPES Types of UUID - * @{ */ -#define BLE_UUID_TYPE_UNKNOWN 0x00 /**< Invalid UUID type. */ -#define BLE_UUID_TYPE_BLE 0x01 /**< Bluetooth SIG UUID (16-bit). */ -#define BLE_UUID_TYPE_VENDOR_BEGIN 0x02 /**< Vendor UUID types start at this index (128-bit). */ -/** @} */ - -/** @defgroup BLE_APPEARANCES Bluetooth Appearance values - * @note Retrieved from - * http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml - * @{ */ -#define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */ -#define BLE_APPEARANCE_GENERIC_PHONE 64 /**< Generic Phone. */ -#define BLE_APPEARANCE_GENERIC_COMPUTER 128 /**< Generic Computer. */ -#define BLE_APPEARANCE_GENERIC_WATCH 192 /**< Generic Watch. */ -#define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /**< Watch: Sports Watch. */ -#define BLE_APPEARANCE_GENERIC_CLOCK 256 /**< Generic Clock. */ -#define BLE_APPEARANCE_GENERIC_DISPLAY 320 /**< Generic Display. */ -#define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /**< Generic Remote Control. */ -#define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /**< Generic Eye-glasses. */ -#define BLE_APPEARANCE_GENERIC_TAG 512 /**< Generic Tag. */ -#define BLE_APPEARANCE_GENERIC_KEYRING 576 /**< Generic Keyring. */ -#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /**< Generic Media Player. */ -#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /**< Generic Barcode Scanner. */ -#define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /**< Generic Thermometer. */ -#define BLE_APPEARANCE_THERMOMETER_EAR 769 /**< Thermometer: Ear. */ -#define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /**< Generic Heart rate Sensor. */ -#define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /**< Heart Rate Sensor: Heart Rate Belt. */ -#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /**< Generic Blood Pressure. */ -#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /**< Blood Pressure: Arm. */ -#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /**< Blood Pressure: Wrist. */ -#define BLE_APPEARANCE_GENERIC_HID 960 /**< Human Interface Device (HID). */ -#define BLE_APPEARANCE_HID_KEYBOARD 961 /**< Keyboard (HID Subtype). */ -#define BLE_APPEARANCE_HID_MOUSE 962 /**< Mouse (HID Subtype). */ -#define BLE_APPEARANCE_HID_JOYSTICK 963 /**< Joystick (HID Subtype). */ -#define BLE_APPEARANCE_HID_GAMEPAD 964 /**< Gamepad (HID Subtype). */ -#define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /**< Digitizer Tablet (HID Subtype). */ -#define BLE_APPEARANCE_HID_CARD_READER 966 /**< Card Reader (HID Subtype). */ -#define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /**< Digital Pen (HID Subtype). */ -#define BLE_APPEARANCE_HID_BARCODE 968 /**< Barcode Scanner (HID Subtype). */ -#define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /**< Generic Glucose Meter. */ -#define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /**< Generic Running Walking Sensor. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /**< Running Walking Sensor: In-Shoe. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /**< Running Walking Sensor: On-Shoe. */ -#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /**< Running Walking Sensor: On-Hip. */ -#define BLE_APPEARANCE_GENERIC_CYCLING 1152 /**< Generic Cycling. */ -#define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /**< Cycling: Cycling Computer. */ -#define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /**< Cycling: Speed Sensor. */ -#define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /**< Cycling: Cadence Sensor. */ -#define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /**< Cycling: Power Sensor. */ -#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /**< Cycling: Speed and Cadence Sensor. */ -#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /**< Generic Pulse Oximeter. */ -#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /**< Fingertip (Pulse Oximeter subtype). */ -#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /**< Wrist Worn(Pulse Oximeter subtype). */ -#define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /**< Generic Weight Scale. */ -#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /**< Generic Outdoor Sports Activity. */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /**< Location Display Device (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP \ - 5186 /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /**< Location Pod (Outdoor Sports Activity subtype). */ -#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD \ - 5188 /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */ -/** @} */ - -/** @brief Set .type and .uuid fields of ble_uuid_struct to specified UUID value. */ -#define BLE_UUID_BLE_ASSIGN(instance, value) \ - do { \ - instance.type = BLE_UUID_TYPE_BLE; \ - instance.uuid = value; \ - } while (0) - -/** @brief Copy type and uuid members from src to dst ble_uuid_t pointer. Both pointers must be valid/non-null. */ -#define BLE_UUID_COPY_PTR(dst, src) \ - do { \ - (dst)->type = (src)->type; \ - (dst)->uuid = (src)->uuid; \ - } while (0) - -/** @brief Copy type and uuid members from src to dst ble_uuid_t struct. */ -#define BLE_UUID_COPY_INST(dst, src) \ - do { \ - (dst).type = (src).type; \ - (dst).uuid = (src).uuid; \ - } while (0) - -/** @brief Compare for equality both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ -#define BLE_UUID_EQ(p_uuid1, p_uuid2) (((p_uuid1)->type == (p_uuid2)->type) && ((p_uuid1)->uuid == (p_uuid2)->uuid)) - -/** @brief Compare for difference both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */ -#define BLE_UUID_NEQ(p_uuid1, p_uuid2) (((p_uuid1)->type != (p_uuid2)->type) || ((p_uuid1)->uuid != (p_uuid2)->uuid)) - -/** @} */ - -/** @addtogroup BLE_TYPES_STRUCTURES Structures - * @{ */ - -/** @brief 128 bit UUID values. */ -typedef struct { - uint8_t uuid128[16]; /**< Little-Endian UUID bytes. */ -} ble_uuid128_t; - -/** @brief Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */ -typedef struct { - uint16_t uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */ - uint8_t - type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is @ref BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */ -} ble_uuid_t; - -/**@brief Data structure. */ -typedef struct { - uint8_t *p_data; /**< Pointer to the data buffer provided to/from the application. */ - uint16_t len; /**< Length of the data buffer, in bytes. */ -} ble_data_t; - -/** @} */ -#ifdef __cplusplus -} -#endif - -#endif /* BLE_TYPES_H__ */ - -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h b/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h deleted file mode 100644 index 4e0bd752ab..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf52/nrf_mbr.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2014 - 2017, Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_mbr_api Master Boot Record API - @{ - - @brief APIs for updating SoftDevice and BootLoader - -*/ - -#ifndef NRF_MBR_H__ -#define NRF_MBR_H__ - -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** @addtogroup NRF_MBR_DEFINES Defines - * @{ */ - -/**@brief MBR SVC Base number. */ -#define MBR_SVC_BASE (0x18) - -/**@brief Page size in words. */ -#define MBR_PAGE_SIZE_IN_WORDS (1024) - -/** @brief The size that must be reserved for the MBR when a SoftDevice is written to flash. -This is the offset where the first byte of the SoftDevice hex file is written. */ -#define MBR_SIZE (0x1000) - -/** @brief Location (in the flash memory) of the bootloader address. */ -#define MBR_BOOTLOADER_ADDR (0xFF8) - -/** @brief Location (in UICR) of the bootloader address. */ -#define MBR_UICR_BOOTLOADER_ADDR (&(NRF_UICR->NRFFW[0])) - -/** @brief Location (in the flash memory) of the address of the MBR parameter page. */ -#define MBR_PARAM_PAGE_ADDR (0xFFC) - -/** @brief Location (in UICR) of the address of the MBR parameter page. */ -#define MBR_UICR_PARAM_PAGE_ADDR (&(NRF_UICR->NRFFW[1])) - -/** @} */ - -/** @addtogroup NRF_MBR_ENUMS Enumerations - * @{ */ - -/**@brief nRF Master Boot Record API SVC numbers. */ -enum NRF_MBR_SVCS { - SD_MBR_COMMAND = MBR_SVC_BASE, /**< ::sd_mbr_command */ -}; - -/**@brief Possible values for ::sd_mbr_command_t.command */ -enum NRF_MBR_COMMANDS { - SD_MBR_COMMAND_COPY_BL, /**< Copy a new BootLoader. @see ::sd_mbr_command_copy_bl_t*/ - SD_MBR_COMMAND_COPY_SD, /**< Copy a new SoftDevice. @see ::sd_mbr_command_copy_sd_t*/ - SD_MBR_COMMAND_INIT_SD, /**< Initialize forwarding interrupts to SD, and run reset function in SD. Does not require any - parameters in ::sd_mbr_command_t params.*/ - SD_MBR_COMMAND_COMPARE, /**< This command works like memcmp. @see ::sd_mbr_command_compare_t*/ - SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET, /**< Change the address the MBR starts after a reset. @see - ::sd_mbr_command_vector_table_base_set_t*/ - SD_MBR_COMMAND_RESERVED, - SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET, /**< Start forwarding all interrupts to this address. @see - ::sd_mbr_command_irq_forward_address_set_t*/ -}; - -/** @} */ - -/** @addtogroup NRF_MBR_TYPES Types - * @{ */ - -/**@brief This command copies part of a new SoftDevice - * - * The destination area is erased before copying. - * If dst is in the middle of a flash page, that whole flash page will be erased. - * If (dst+len) is in the middle of a flash page, that whole flash page will be erased. - * - * The user of this function is responsible for setting the BPROT registers. - * - * @retval ::NRF_SUCCESS indicates that the contents of the memory blocks where copied correctly. - * @retval ::NRF_ERROR_INTERNAL indicates that the contents of the memory blocks where not verified correctly after copying. - */ -typedef struct { - uint32_t *src; /**< Pointer to the source of data to be copied.*/ - uint32_t *dst; /**< Pointer to the destination where the content is to be copied.*/ - uint32_t len; /**< Number of 32 bit words to copy. Must be a multiple of @ref MBR_PAGE_SIZE_IN_WORDS words.*/ -} sd_mbr_command_copy_sd_t; - -/**@brief This command works like memcmp, but takes the length in words. - * - * @retval ::NRF_SUCCESS indicates that the contents of both memory blocks are equal. - * @retval ::NRF_ERROR_NULL indicates that the contents of the memory blocks are not equal. - */ -typedef struct { - uint32_t *ptr1; /**< Pointer to block of memory. */ - uint32_t *ptr2; /**< Pointer to block of memory. */ - uint32_t len; /**< Number of 32 bit words to compare.*/ -} sd_mbr_command_compare_t; - -/**@brief This command copies a new BootLoader. - * - * The MBR assumes that either @ref MBR_BOOTLOADER_ADDR or @ref MBR_UICR_BOOTLOADER_ADDR is set to - * the address where the bootloader will be copied. If both addresses are set, the MBR will prioritize - * @ref MBR_BOOTLOADER_ADDR. - * - * The bootloader destination is erased by this function. - * If (destination+bl_len) is in the middle of a flash page, that whole flash page will be erased. - * - * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, - * see @ref sd_mbr_command. - * - * This command will use the flash protect peripheral (BPROT or ACL) to protect the flash that is - * not intended to be written. - * - * On success, this function will not return. It will start the new bootloader from reset-vector as normal. - * - * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. - * @retval ::NRF_ERROR_FORBIDDEN if the bootloader address is not set. - * @retval ::NRF_ERROR_INVALID_LENGTH if parameters attempts to read or write outside flash area. - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. - */ -typedef struct { - uint32_t *bl_src; /**< Pointer to the source of the bootloader to be be copied.*/ - uint32_t bl_len; /**< Number of 32 bit words to copy for BootLoader. */ -} sd_mbr_command_copy_bl_t; - -/**@brief Change the address the MBR starts after a reset - * - * Once this function has been called, this address is where the MBR will start to forward - * interrupts to after a reset. - * - * To restore default forwarding, this function should be called with @ref address set to 0. If a - * bootloader is present, interrupts will be forwarded to the bootloader. If not, interrupts will - * be forwarded to the SoftDevice. - * - * The location of a bootloader can be specified in @ref MBR_BOOTLOADER_ADDR or - * @ref MBR_UICR_BOOTLOADER_ADDR. If both addresses are set, the MBR will prioritize - * @ref MBR_BOOTLOADER_ADDR. - * - * This command requires that @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR is set, - * see @ref sd_mbr_command. - * - * On success, this function will not return. It will reset the device. - * - * @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen. - * @retval ::NRF_ERROR_INVALID_ADDR if parameter address is outside of the flash size. - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page is provided. See @ref sd_mbr_command. - */ -typedef struct { - uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ -} sd_mbr_command_vector_table_base_set_t; - -/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the MBR - * - * Unlike sd_mbr_command_vector_table_base_set_t, this function does not reset, and it does not - * change where the MBR starts after reset. - * - * @retval ::NRF_SUCCESS - */ -typedef struct { - uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/ -} sd_mbr_command_irq_forward_address_set_t; - -/**@brief Input structure containing data used when calling ::sd_mbr_command - * - * Depending on what command value that is set, the corresponding params value type must also be - * set. See @ref NRF_MBR_COMMANDS for command types and corresponding params value type. If command - * @ref SD_MBR_COMMAND_INIT_SD is set, it is not necessary to set any values under params. - */ -typedef struct { - uint32_t command; /**< Type of command to be issued. See @ref NRF_MBR_COMMANDS. */ - union { - sd_mbr_command_copy_sd_t copy_sd; /**< Parameters for copy SoftDevice.*/ - sd_mbr_command_compare_t compare; /**< Parameters for verify.*/ - sd_mbr_command_copy_bl_t copy_bl; /**< Parameters for copy BootLoader. Requires parameter page. */ - sd_mbr_command_vector_table_base_set_t base_set; /**< Parameters for vector table base set. Requires parameter page.*/ - sd_mbr_command_irq_forward_address_set_t irq_forward_address_set; /**< Parameters for irq forward address set*/ - } params; /**< Command parameters. */ -} sd_mbr_command_t; - -/** @} */ - -/** @addtogroup NRF_MBR_FUNCTIONS Functions - * @{ */ - -/**@brief Issue Master Boot Record commands - * - * Commands used when updating a SoftDevice and bootloader. - * - * The @ref SD_MBR_COMMAND_COPY_BL and @ref SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET requires - * parameters to be retained by the MBR when resetting the IC. This is done in a separate flash - * page. The location of the flash page should be provided by the application in either - * @ref MBR_PARAM_PAGE_ADDR or @ref MBR_UICR_PARAM_PAGE_ADDR. If both addresses are set, the MBR - * will prioritize @ref MBR_PARAM_PAGE_ADDR. This page will be cleared by the MBR and is used to - * store the command before reset. When an address is specified, the page it refers to must not be - * used by the application. If no address is provided by the application, i.e. both - * @ref MBR_PARAM_PAGE_ADDR and @ref MBR_UICR_PARAM_PAGE_ADDR is 0xFFFFFFFF, MBR commands which use - * flash will be unavailable and return @ref NRF_ERROR_NO_MEM. - * - * @param[in] param Pointer to a struct describing the command. - * - * @note For a complete set of return values, see ::sd_mbr_command_copy_sd_t, - * ::sd_mbr_command_copy_bl_t, ::sd_mbr_command_compare_t, - * ::sd_mbr_command_vector_table_base_set_t, ::sd_mbr_command_irq_forward_address_set_t - * - * @retval ::NRF_ERROR_NO_MEM No MBR parameter page provided - * @retval ::NRF_ERROR_INVALID_PARAM if an invalid command is given. - */ -SVCALL(SD_MBR_COMMAND, uint32_t, sd_mbr_command(sd_mbr_command_t *param)); - -/** @} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_MBR_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error.h b/variants/wio-sdk-wm1110/softdevice/nrf_error.h deleted file mode 100644 index fb2831e191..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_error.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @defgroup nrf_error SoftDevice Global Error Codes - @{ - - @brief Global Error definitions -*/ - -/* Header guard */ -#ifndef NRF_ERROR_H__ -#define NRF_ERROR_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** @defgroup NRF_ERRORS_BASE Error Codes Base number definitions - * @{ */ -#define NRF_ERROR_BASE_NUM (0x0) ///< Global error base -#define NRF_ERROR_SDM_BASE_NUM (0x1000) ///< SDM error base -#define NRF_ERROR_SOC_BASE_NUM (0x2000) ///< SoC error base -#define NRF_ERROR_STK_BASE_NUM (0x3000) ///< STK error base -/** @} */ - -#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command -#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing -#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled -#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error -#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation -#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found -#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported -#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter -#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state -#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length -#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags -#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data -#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Invalid Data size -#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out -#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer -#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation -#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address -#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy -#define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded. -#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_H__ - -/** - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h b/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h deleted file mode 100644 index 2fd6210576..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_error_sdm.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup nrf_sdm_api - @{ - @defgroup nrf_sdm_error SoftDevice Manager Error Codes - @{ - - @brief Error definitions for the SDM API -*/ - -/* Header guard */ -#ifndef NRF_ERROR_SDM_H__ -#define NRF_ERROR_SDM_H__ - -#include "nrf_error.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN (NRF_ERROR_SDM_BASE_NUM + 0) ///< Unknown LFCLK source. -#define NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION \ - (NRF_ERROR_SDM_BASE_NUM + 1) ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having - ///< enabled SoftDevice interrupts). -#define NRF_ERROR_SDM_INCORRECT_CLENR0 \ - (NRF_ERROR_SDM_BASE_NUM + 2) ///< Incorrect CLENR0 (can be caused by erroneous SoftDevice flashing). - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_SDM_H__ - -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h b/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h deleted file mode 100644 index cbd0ba8ac4..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_error_soc.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - @addtogroup nrf_soc_api - @{ - @defgroup nrf_soc_error SoC Library Error Codes - @{ - - @brief Error definitions for the SoC library - -*/ - -/* Header guard */ -#ifndef NRF_ERROR_SOC_H__ -#define NRF_ERROR_SOC_H__ - -#include "nrf_error.h" -#ifdef __cplusplus -extern "C" { -#endif - -/* Mutex Errors */ -#define NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN (NRF_ERROR_SOC_BASE_NUM + 0) ///< Mutex already taken - -/* NVIC errors */ -#define NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE (NRF_ERROR_SOC_BASE_NUM + 1) ///< NVIC interrupt not available -#define NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED (NRF_ERROR_SOC_BASE_NUM + 2) ///< NVIC interrupt priority not allowed -#define NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 3) ///< NVIC should not return - -/* Power errors */ -#define NRF_ERROR_SOC_POWER_MODE_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 4) ///< Power mode unknown -#define NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 5) ///< Power POF threshold unknown -#define NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 6) ///< Power off should not return - -/* Rand errors */ -#define NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES (NRF_ERROR_SOC_BASE_NUM + 7) ///< RAND not enough values - -/* PPI errors */ -#define NRF_ERROR_SOC_PPI_INVALID_CHANNEL (NRF_ERROR_SOC_BASE_NUM + 8) ///< Invalid PPI Channel -#define NRF_ERROR_SOC_PPI_INVALID_GROUP (NRF_ERROR_SOC_BASE_NUM + 9) ///< Invalid PPI Group - -#ifdef __cplusplus -} -#endif -#endif // NRF_ERROR_SOC_H__ -/** - @} - @} -*/ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h b/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h deleted file mode 100644 index d4ab204d96..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_nvic.h +++ /dev/null @@ -1,449 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @defgroup nrf_nvic_api SoftDevice NVIC API - * @{ - * - * @note In order to use this module, the following code has to be added to a .c file: - * \code - * nrf_nvic_state_t nrf_nvic_state = {0}; - * \endcode - * - * @note Definitions and declarations starting with __ (double underscore) in this header file are - * not intended for direct use by the application. - * - * @brief APIs for the accessing NVIC when using a SoftDevice. - * - */ - -#ifndef NRF_NVIC_H__ -#define NRF_NVIC_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup NRF_NVIC_DEFINES Defines - * @{ */ - -/**@defgroup NRF_NVIC_ISER_DEFINES SoftDevice NVIC internal definitions - * @{ */ - -#define __NRF_NVIC_NVMC_IRQn \ - (30) /**< The peripheral ID of the NVMC. IRQ numbers are used to identify peripherals, but the NVMC doesn't have an IRQ \ - number in the MDK. */ - -#define __NRF_NVIC_ISER_COUNT (2) /**< The number of ISER/ICER registers in the NVIC that are used. */ - -/**@brief Interrupt priority levels used by the SoftDevice. */ -#define __NRF_NVIC_SD_IRQ_PRIOS \ - ((uint8_t)((1U << 0) /**< Priority level high .*/ \ - | (1U << 1) /**< Priority level medium. */ \ - | (1U << 4) /**< Priority level low. */ \ - )) - -/**@brief Interrupt priority levels available to the application. */ -#define __NRF_NVIC_APP_IRQ_PRIOS ((uint8_t)~__NRF_NVIC_SD_IRQ_PRIOS) - -/**@brief Interrupts used by the SoftDevice, with IRQn in the range 0-31. */ -#define __NRF_NVIC_SD_IRQS_0 \ - ((uint32_t)((1U << POWER_CLOCK_IRQn) | (1U << RADIO_IRQn) | (1U << RTC0_IRQn) | (1U << TIMER0_IRQn) | (1U << RNG_IRQn) | \ - (1U << ECB_IRQn) | (1U << CCM_AAR_IRQn) | (1U << TEMP_IRQn) | (1U << __NRF_NVIC_NVMC_IRQn) | \ - (1U << (uint32_t)SWI5_IRQn))) - -/**@brief Interrupts used by the SoftDevice, with IRQn in the range 32-63. */ -#define __NRF_NVIC_SD_IRQS_1 ((uint32_t)0) - -/**@brief Interrupts available for to application, with IRQn in the range 0-31. */ -#define __NRF_NVIC_APP_IRQS_0 (~__NRF_NVIC_SD_IRQS_0) - -/**@brief Interrupts available for to application, with IRQn in the range 32-63. */ -#define __NRF_NVIC_APP_IRQS_1 (~__NRF_NVIC_SD_IRQS_1) - -/**@} */ - -/**@} */ - -/**@addtogroup NRF_NVIC_VARIABLES Variables - * @{ */ - -/**@brief Type representing the state struct for the SoftDevice NVIC module. */ -typedef struct { - uint32_t volatile __irq_masks[__NRF_NVIC_ISER_COUNT]; /**< IRQs enabled by the application in the NVIC. */ - uint32_t volatile __cr_flag; /**< Non-zero if already in a critical region */ -} nrf_nvic_state_t; - -/**@brief Variable keeping the state for the SoftDevice NVIC module. This must be declared in an - * application source file. */ -extern nrf_nvic_state_t nrf_nvic_state; - -/**@} */ - -/**@addtogroup NRF_NVIC_INTERNAL_FUNCTIONS SoftDevice NVIC internal functions - * @{ */ - -/**@brief Disables IRQ interrupts globally, including the SoftDevice's interrupts. - * - * @retval The value of PRIMASK prior to disabling the interrupts. - */ -__STATIC_INLINE int __sd_nvic_irq_disable(void); - -/**@brief Enables IRQ interrupts globally, including the SoftDevice's interrupts. - */ -__STATIC_INLINE void __sd_nvic_irq_enable(void); - -/**@brief Checks if IRQn is available to application - * @param[in] IRQn IRQ to check - * - * @retval 1 (true) if the IRQ to check is available to the application - */ -__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn); - -/**@brief Checks if priority is available to application - * @param[in] priority priority to check - * - * @retval 1 (true) if the priority to check is available to the application - */ -__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority); - -/**@} */ - -/**@addtogroup NRF_NVIC_FUNCTIONS SoftDevice NVIC public functions - * @{ */ - -/**@brief Enable External Interrupt. - * @note Corresponds to NVIC_EnableIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_EnableIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt was enabled. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt has a priority not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn); - -/**@brief Disable External Interrupt. - * @note Corresponds to NVIC_DisableIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_DisableIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt was disabled. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn); - -/**@brief Get Pending Interrupt. - * @note Corresponds to NVIC_GetPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_GetPendingIRQ documentation in CMSIS. - * @param[out] p_pending_irq Return value from NVIC_GetPendingIRQ. - * - * @retval ::NRF_SUCCESS The interrupt is available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq); - -/**@brief Set Pending Interrupt. - * @note Corresponds to NVIC_SetPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_SetPendingIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt is set pending. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn); - -/**@brief Clear Pending Interrupt. - * @note Corresponds to NVIC_ClearPendingIRQ in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_ClearPendingIRQ documentation in CMSIS. - * - * @retval ::NRF_SUCCESS The interrupt pending flag is cleared. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn); - -/**@brief Set Interrupt Priority. - * @note Corresponds to NVIC_SetPriority in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * @pre Priority is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_SetPriority documentation in CMSIS. - * @param[in] priority A valid IRQ priority for use by the application. - * - * @retval ::NRF_SUCCESS The interrupt and priority level is available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt priority is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority); - -/**@brief Get Interrupt Priority. - * @note Corresponds to NVIC_GetPriority in CMSIS. - * - * @pre IRQn is valid and not reserved by the stack. - * - * @param[in] IRQn See the NVIC_GetPriority documentation in CMSIS. - * @param[out] p_priority Return value from NVIC_GetPriority. - * - * @retval ::NRF_SUCCESS The interrupt priority is returned in p_priority. - * @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE - IRQn is not available for the application. - */ -__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority); - -/**@brief System Reset. - * @note Corresponds to NVIC_SystemReset in CMSIS. - * - * @retval ::NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN - */ -__STATIC_INLINE uint32_t sd_nvic_SystemReset(void); - -/**@brief Enter critical region. - * - * @post Application interrupts will be disabled. - * @note sd_nvic_critical_region_enter() and ::sd_nvic_critical_region_exit() must be called in matching pairs inside each - * execution context - * @sa sd_nvic_critical_region_exit - * - * @param[out] p_is_nested_critical_region If 1, the application is now in a nested critical region. - * - * @retval ::NRF_SUCCESS - */ -__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region); - -/**@brief Exit critical region. - * - * @pre Application has entered a critical region using ::sd_nvic_critical_region_enter. - * @post If not in a nested critical region, the application interrupts will restored to the state before - * ::sd_nvic_critical_region_enter was called. - * - * @param[in] is_nested_critical_region If this is set to 1, the critical region won't be exited. @sa - * sd_nvic_critical_region_enter. - * - * @retval ::NRF_SUCCESS - */ -__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region); - -/**@} */ - -#ifndef SUPPRESS_INLINE_IMPLEMENTATION - -__STATIC_INLINE int __sd_nvic_irq_disable(void) -{ - int pm = __get_PRIMASK(); - __disable_irq(); - return pm; -} - -__STATIC_INLINE void __sd_nvic_irq_enable(void) -{ - __enable_irq(); -} - -__STATIC_INLINE uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn) -{ - if (IRQn < 32) { - return ((1UL << IRQn) & __NRF_NVIC_APP_IRQS_0) != 0; - } else if (IRQn < 64) { - return ((1UL << (IRQn - 32)) & __NRF_NVIC_APP_IRQS_1) != 0; - } else { - return 1; - } -} - -__STATIC_INLINE uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority) -{ - if ((priority >= (1 << __NVIC_PRIO_BITS)) || (((1 << priority) & __NRF_NVIC_APP_IRQ_PRIOS) == 0)) { - return 0; - } - return 1; -} - -__STATIC_INLINE uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - if (!__sd_nvic_is_app_accessible_priority(NVIC_GetPriority(IRQn))) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; - } - - if (nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] |= - (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F)); - } else { - NVIC_EnableIRQ(IRQn); - } - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - - if (nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] &= ~(1UL << ((uint32_t)(IRQn)&0x1F)); - } else { - NVIC_DisableIRQ(IRQn); - } - - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t *p_pending_irq) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - *p_pending_irq = NVIC_GetPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - NVIC_SetPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - NVIC_ClearPendingIRQ(IRQn); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority) -{ - if (!__sd_nvic_app_accessible_irq(IRQn)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } - - if (!__sd_nvic_is_app_accessible_priority(priority)) { - return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED; - } - - NVIC_SetPriority(IRQn, (uint32_t)priority); - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t *p_priority) -{ - if (__sd_nvic_app_accessible_irq(IRQn)) { - *p_priority = (NVIC_GetPriority(IRQn) & 0xFF); - return NRF_SUCCESS; - } else { - return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE; - } -} - -__STATIC_INLINE uint32_t sd_nvic_SystemReset(void) -{ - NVIC_SystemReset(); - return NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN; -} - -__STATIC_INLINE uint32_t sd_nvic_critical_region_enter(uint8_t *p_is_nested_critical_region) -{ - int was_masked = __sd_nvic_irq_disable(); - if (!nrf_nvic_state.__cr_flag) { - nrf_nvic_state.__cr_flag = 1; - nrf_nvic_state.__irq_masks[0] = (NVIC->ICER[0] & __NRF_NVIC_APP_IRQS_0); - NVIC->ICER[0] = __NRF_NVIC_APP_IRQS_0; - nrf_nvic_state.__irq_masks[1] = (NVIC->ICER[1] & __NRF_NVIC_APP_IRQS_1); - NVIC->ICER[1] = __NRF_NVIC_APP_IRQS_1; - *p_is_nested_critical_region = 0; - } else { - *p_is_nested_critical_region = 1; - } - if (!was_masked) { - __sd_nvic_irq_enable(); - } - return NRF_SUCCESS; -} - -__STATIC_INLINE uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region) -{ - if (nrf_nvic_state.__cr_flag && (is_nested_critical_region == 0)) { - int was_masked = __sd_nvic_irq_disable(); - NVIC->ISER[0] = nrf_nvic_state.__irq_masks[0]; - NVIC->ISER[1] = nrf_nvic_state.__irq_masks[1]; - nrf_nvic_state.__cr_flag = 0; - if (!was_masked) { - __sd_nvic_irq_enable(); - } - } - - return NRF_SUCCESS; -} - -#endif /* SUPPRESS_INLINE_IMPLEMENTATION */ - -#ifdef __cplusplus -} -#endif - -#endif // NRF_NVIC_H__ - -/**@} */ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_soc.h b/variants/wio-sdk-wm1110/softdevice/nrf_soc.h deleted file mode 100644 index c649ca836d..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_soc.h +++ /dev/null @@ -1,1046 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @defgroup nrf_soc_api SoC Library API - * @{ - * - * @brief APIs for the SoC library. - * - */ - -#ifndef NRF_SOC_H__ -#define NRF_SOC_H__ - -#include "nrf.h" -#include "nrf_error.h" -#include "nrf_error_soc.h" -#include "nrf_svc.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/**@addtogroup NRF_SOC_DEFINES Defines - * @{ */ - -/**@brief The number of the lowest SVC number reserved for the SoC library. */ -#define SOC_SVC_BASE (0x20) /**< Base value for SVCs that are available when the SoftDevice is disabled. */ -#define SOC_SVC_BASE_NOT_AVAILABLE (0x2C) /**< Base value for SVCs that are not available when the SoftDevice is disabled. */ - -/**@brief Guaranteed time for application to process radio inactive notification. */ -#define NRF_RADIO_NOTIFICATION_INACTIVE_GUARANTEED_TIME_US (62) - -/**@brief The minimum allowed timeslot extension time. */ -#define NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US (200) - -/**@brief The maximum processing time to handle a timeslot extension. */ -#define NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US (20) - -/**@brief The latest time before the end of a timeslot the timeslot can be extended. */ -#define NRF_RADIO_MIN_EXTENSION_MARGIN_US (82) - -#define SOC_ECB_KEY_LENGTH (16) /**< ECB key length. */ -#define SOC_ECB_CLEARTEXT_LENGTH (16) /**< ECB cleartext length. */ -#define SOC_ECB_CIPHERTEXT_LENGTH (SOC_ECB_CLEARTEXT_LENGTH) /**< ECB ciphertext length. */ - -#define SD_EVT_IRQn (SWI2_IRQn) /**< SoftDevice Event IRQ number. Used for both protocol events and SoC events. */ -#define SD_EVT_IRQHandler \ - (SWI2_IRQHandler) /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. \ - The default interrupt priority for this handler is set to 6 */ -#define RADIO_NOTIFICATION_IRQn (SWI1_IRQn) /**< The radio notification IRQ number. */ -#define RADIO_NOTIFICATION_IRQHandler \ - (SWI1_IRQHandler) /**< The radio notification IRQ handler. \ - The default interrupt priority for this handler is set to 6 */ -#define NRF_RADIO_LENGTH_MIN_US (100) /**< The shortest allowed radio timeslot, in microseconds. */ -#define NRF_RADIO_LENGTH_MAX_US (100000) /**< The longest allowed radio timeslot, in microseconds. */ - -#define NRF_RADIO_DISTANCE_MAX_US \ - (128000000UL - 1UL) /**< The longest timeslot distance, in microseconds, allowed for the distance parameter (see @ref \ - nrf_radio_request_normal_t) in the request. */ - -#define NRF_RADIO_EARLIEST_TIMEOUT_MAX_US \ - (128000000UL - 1UL) /**< The longest timeout, in microseconds, allowed when requesting the earliest possible timeslot. */ - -#define NRF_RADIO_START_JITTER_US \ - (2) /**< The maximum jitter in @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START relative to the requested start time. */ - -/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is disabled. */ -#define NRF_SOC_SD_PPI_CHANNELS_SD_DISABLED_MSK ((uint32_t)(0)) - -/**@brief Mask of PPI channels reserved by the SoftDevice when the SoftDevice is enabled. */ -#define NRF_SOC_SD_PPI_CHANNELS_SD_ENABLED_MSK \ - ((uint32_t)((1U << 17) | (1U << 18) | (1U << 19) | (1U << 20) | (1U << 21) | (1U << 22) | (1U << 23) | (1U << 24) | \ - (1U << 25) | (1U << 26) | (1U << 27) | (1U << 28) | (1U << 29) | (1U << 30) | (1U << 31))) - -/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is disabled. */ -#define NRF_SOC_SD_PPI_GROUPS_SD_DISABLED_MSK ((uint32_t)(0)) - -/**@brief Mask of PPI groups reserved by the SoftDevice when the SoftDevice is enabled. */ -#define NRF_SOC_SD_PPI_GROUPS_SD_ENABLED_MSK ((uint32_t)((1U << 4) | (1U << 5))) - -/**@} */ - -/**@addtogroup NRF_SOC_ENUMS Enumerations - * @{ */ - -/**@brief The SVC numbers used by the SVC functions in the SoC library. */ -enum NRF_SOC_SVCS { - SD_PPI_CHANNEL_ENABLE_GET = SOC_SVC_BASE, - SD_PPI_CHANNEL_ENABLE_SET = SOC_SVC_BASE + 1, - SD_PPI_CHANNEL_ENABLE_CLR = SOC_SVC_BASE + 2, - SD_PPI_CHANNEL_ASSIGN = SOC_SVC_BASE + 3, - SD_PPI_GROUP_TASK_ENABLE = SOC_SVC_BASE + 4, - SD_PPI_GROUP_TASK_DISABLE = SOC_SVC_BASE + 5, - SD_PPI_GROUP_ASSIGN = SOC_SVC_BASE + 6, - SD_PPI_GROUP_GET = SOC_SVC_BASE + 7, - SD_FLASH_PAGE_ERASE = SOC_SVC_BASE + 8, - SD_FLASH_WRITE = SOC_SVC_BASE + 9, - SD_PROTECTED_REGISTER_WRITE = SOC_SVC_BASE + 11, - SD_MUTEX_NEW = SOC_SVC_BASE_NOT_AVAILABLE, - SD_MUTEX_ACQUIRE = SOC_SVC_BASE_NOT_AVAILABLE + 1, - SD_MUTEX_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 2, - SD_RAND_APPLICATION_POOL_CAPACITY_GET = SOC_SVC_BASE_NOT_AVAILABLE + 3, - SD_RAND_APPLICATION_BYTES_AVAILABLE_GET = SOC_SVC_BASE_NOT_AVAILABLE + 4, - SD_RAND_APPLICATION_VECTOR_GET = SOC_SVC_BASE_NOT_AVAILABLE + 5, - SD_POWER_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 6, - SD_POWER_SYSTEM_OFF = SOC_SVC_BASE_NOT_AVAILABLE + 7, - SD_POWER_RESET_REASON_GET = SOC_SVC_BASE_NOT_AVAILABLE + 8, - SD_POWER_RESET_REASON_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 9, - SD_POWER_POF_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 10, - SD_POWER_POF_THRESHOLD_SET = SOC_SVC_BASE_NOT_AVAILABLE + 11, - SD_POWER_POF_THRESHOLDVDDH_SET = SOC_SVC_BASE_NOT_AVAILABLE + 12, - SD_POWER_RAM_POWER_SET = SOC_SVC_BASE_NOT_AVAILABLE + 13, - SD_POWER_RAM_POWER_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 14, - SD_POWER_RAM_POWER_GET = SOC_SVC_BASE_NOT_AVAILABLE + 15, - SD_POWER_GPREGRET_SET = SOC_SVC_BASE_NOT_AVAILABLE + 16, - SD_POWER_GPREGRET_CLR = SOC_SVC_BASE_NOT_AVAILABLE + 17, - SD_POWER_GPREGRET_GET = SOC_SVC_BASE_NOT_AVAILABLE + 18, - SD_POWER_DCDC_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 19, - SD_POWER_DCDC0_MODE_SET = SOC_SVC_BASE_NOT_AVAILABLE + 20, - SD_APP_EVT_WAIT = SOC_SVC_BASE_NOT_AVAILABLE + 21, - SD_CLOCK_HFCLK_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 22, - SD_CLOCK_HFCLK_RELEASE = SOC_SVC_BASE_NOT_AVAILABLE + 23, - SD_CLOCK_HFCLK_IS_RUNNING = SOC_SVC_BASE_NOT_AVAILABLE + 24, - SD_RADIO_NOTIFICATION_CFG_SET = SOC_SVC_BASE_NOT_AVAILABLE + 25, - SD_ECB_BLOCK_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 26, - SD_ECB_BLOCKS_ENCRYPT = SOC_SVC_BASE_NOT_AVAILABLE + 27, - SD_RADIO_SESSION_OPEN = SOC_SVC_BASE_NOT_AVAILABLE + 28, - SD_RADIO_SESSION_CLOSE = SOC_SVC_BASE_NOT_AVAILABLE + 29, - SD_RADIO_REQUEST = SOC_SVC_BASE_NOT_AVAILABLE + 30, - SD_EVT_GET = SOC_SVC_BASE_NOT_AVAILABLE + 31, - SD_TEMP_GET = SOC_SVC_BASE_NOT_AVAILABLE + 32, - SD_POWER_USBPWRRDY_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 33, - SD_POWER_USBDETECTED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 34, - SD_POWER_USBREMOVED_ENABLE = SOC_SVC_BASE_NOT_AVAILABLE + 35, - SD_POWER_USBREGSTATUS_GET = SOC_SVC_BASE_NOT_AVAILABLE + 36, - SVC_SOC_LAST = SOC_SVC_BASE_NOT_AVAILABLE + 37 -}; - -/**@brief Possible values of a ::nrf_mutex_t. */ -enum NRF_MUTEX_VALUES { NRF_MUTEX_FREE, NRF_MUTEX_TAKEN }; - -/**@brief Power modes. */ -enum NRF_POWER_MODES { - NRF_POWER_MODE_CONSTLAT, /**< Constant latency mode. See power management in the reference manual. */ - NRF_POWER_MODE_LOWPWR /**< Low power mode. See power management in the reference manual. */ -}; - -/**@brief Power failure thresholds */ -enum NRF_POWER_THRESHOLDS { - NRF_POWER_THRESHOLD_V17 = 4UL, /**< 1.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V18, /**< 1.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V19, /**< 1.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V20, /**< 2.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V21, /**< 2.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V22, /**< 2.2 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V23, /**< 2.3 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V24, /**< 2.4 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V25, /**< 2.5 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V26, /**< 2.6 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V27, /**< 2.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLD_V28 /**< 2.8 Volts power failure threshold. */ -}; - -/**@brief Power failure thresholds for high voltage */ -enum NRF_POWER_THRESHOLDVDDHS { - NRF_POWER_THRESHOLDVDDH_V27, /**< 2.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V28, /**< 2.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V29, /**< 2.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V30, /**< 3.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V31, /**< 3.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V32, /**< 3.2 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V33, /**< 3.3 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V34, /**< 3.4 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V35, /**< 3.5 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V36, /**< 3.6 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V37, /**< 3.7 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V38, /**< 3.8 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V39, /**< 3.9 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V40, /**< 4.0 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V41, /**< 4.1 Volts power failure threshold. */ - NRF_POWER_THRESHOLDVDDH_V42 /**< 4.2 Volts power failure threshold. */ -}; - -/**@brief DC/DC converter modes. */ -enum NRF_POWER_DCDC_MODES { - NRF_POWER_DCDC_DISABLE, /**< The DCDC is disabled. */ - NRF_POWER_DCDC_ENABLE /**< The DCDC is enabled. */ -}; - -/**@brief Radio notification distances. */ -enum NRF_RADIO_NOTIFICATION_DISTANCES { - NRF_RADIO_NOTIFICATION_DISTANCE_NONE = 0, /**< The event does not have a notification. */ - NRF_RADIO_NOTIFICATION_DISTANCE_800US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_1740US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_2680US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_3620US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_4560US, /**< The distance from the active notification to start of radio activity. */ - NRF_RADIO_NOTIFICATION_DISTANCE_5500US /**< The distance from the active notification to start of radio activity. */ -}; - -/**@brief Radio notification types. */ -enum NRF_RADIO_NOTIFICATION_TYPES { - NRF_RADIO_NOTIFICATION_TYPE_NONE = 0, /**< The event does not have a radio notification signal. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, /**< Using interrupt for notification when the radio will be enabled. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, /**< Using interrupt for notification when the radio has been disabled. */ - NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, /**< Using interrupt for notification both when the radio will be enabled and - disabled. */ -}; - -/**@brief The Radio signal callback types. */ -enum NRF_RADIO_CALLBACK_SIGNAL_TYPE { - NRF_RADIO_CALLBACK_SIGNAL_TYPE_START, /**< This signal indicates the start of the radio timeslot. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0, /**< This signal indicates the NRF_TIMER0 interrupt. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO, /**< This signal indicates the NRF_RADIO interrupt. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED, /**< This signal indicates extend action failed. */ - NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED /**< This signal indicates extend action succeeded. */ -}; - -/**@brief The actions requested by the signal callback. - * - * This code gives the SOC instructions about what action to take when the signal callback has - * returned. - */ -enum NRF_RADIO_SIGNAL_CALLBACK_ACTION { - NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE, /**< Return without action. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND, /**< Request an extension of the current - timeslot. Maximum execution time for this action: - @ref NRF_RADIO_MAX_EXTENSION_PROCESSING_TIME_US. - This action must be started at least - @ref NRF_RADIO_MIN_EXTENSION_MARGIN_US before - the end of the timeslot. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_END, /**< End the current radio timeslot. */ - NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END /**< Request a new radio timeslot and end the current timeslot. */ -}; - -/**@brief Radio timeslot high frequency clock source configuration. */ -enum NRF_RADIO_HFCLK_CFG { - NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED, /**< The SoftDevice will guarantee that the high frequency clock source is the - external crystal for the whole duration of the timeslot. This should be the - preferred option for events that use the radio or require high timing accuracy. - @note The SoftDevice will automatically turn on and off the external crystal, - at the beginning and end of the timeslot, respectively. The crystal may also - intentionally be left running after the timeslot, in cases where it is needed - by the SoftDevice shortly after the end of the timeslot. */ - NRF_RADIO_HFCLK_CFG_NO_GUARANTEE /**< This configuration allows for earlier and tighter scheduling of timeslots. - The RC oscillator may be the clock source in part or for the whole duration of the - timeslot. The RC oscillator's accuracy must therefore be taken into consideration. - @note If the application will use the radio peripheral in timeslots with this - configuration, it must make sure that the crystal is running and stable before - starting the radio. */ -}; - -/**@brief Radio timeslot priorities. */ -enum NRF_RADIO_PRIORITY { - NRF_RADIO_PRIORITY_HIGH, /**< High (equal priority as the normal connection priority of the SoftDevice stack(s)). */ - NRF_RADIO_PRIORITY_NORMAL, /**< Normal (equal priority as the priority of secondary activities of the SoftDevice stack(s)). */ -}; - -/**@brief Radio timeslot request type. */ -enum NRF_RADIO_REQUEST_TYPE { - NRF_RADIO_REQ_TYPE_EARLIEST, /**< Request radio timeslot as early as possible. This should always be used for the first - request in a session. */ - NRF_RADIO_REQ_TYPE_NORMAL /**< Normal radio timeslot request. */ -}; - -/**@brief SoC Events. */ -enum NRF_SOC_EVTS { - NRF_EVT_HFCLKSTARTED, /**< Event indicating that the HFCLK has started. */ - NRF_EVT_POWER_FAILURE_WARNING, /**< Event indicating that a power failure warning has occurred. */ - NRF_EVT_FLASH_OPERATION_SUCCESS, /**< Event indicating that the ongoing flash operation has completed successfully. */ - NRF_EVT_FLASH_OPERATION_ERROR, /**< Event indicating that the ongoing flash operation has timed out with an error. */ - NRF_EVT_RADIO_BLOCKED, /**< Event indicating that a radio timeslot was blocked. */ - NRF_EVT_RADIO_CANCELED, /**< Event indicating that a radio timeslot was canceled by SoftDevice. */ - NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN, /**< Event indicating that a radio timeslot signal callback handler return was - invalid. */ - NRF_EVT_RADIO_SESSION_IDLE, /**< Event indicating that a radio timeslot session is idle. */ - NRF_EVT_RADIO_SESSION_CLOSED, /**< Event indicating that a radio timeslot session is closed. */ - NRF_EVT_POWER_USB_POWER_READY, /**< Event indicating that a USB 3.3 V supply is ready. */ - NRF_EVT_POWER_USB_DETECTED, /**< Event indicating that voltage supply is detected on VBUS. */ - NRF_EVT_POWER_USB_REMOVED, /**< Event indicating that voltage supply is removed from VBUS. */ - NRF_EVT_NUMBER_OF_EVTS -}; - -/**@} */ - -/**@addtogroup NRF_SOC_STRUCTURES Structures - * @{ */ - -/**@brief Represents a mutex for use with the nrf_mutex functions. - * @note Accessing the value directly is not safe, use the mutex functions! - */ -typedef volatile uint8_t nrf_mutex_t; - -/**@brief Parameters for a request for a timeslot as early as possible. */ -typedef struct { - uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ - uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ - uint32_t length_us; /**< The radio timeslot length (in the range 100 to 100,000] microseconds). */ - uint32_t timeout_us; /**< Longest acceptable delay until the start of the requested timeslot (up to @ref - NRF_RADIO_EARLIEST_TIMEOUT_MAX_US microseconds). */ -} nrf_radio_request_earliest_t; - -/**@brief Parameters for a normal radio timeslot request. */ -typedef struct { - uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */ - uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */ - uint32_t distance_us; /**< Distance from the start of the previous radio timeslot (up to @ref NRF_RADIO_DISTANCE_MAX_US - microseconds). */ - uint32_t length_us; /**< The radio timeslot length (in the range [100..100,000] microseconds). */ -} nrf_radio_request_normal_t; - -/**@brief Radio timeslot request parameters. */ -typedef struct { - uint8_t request_type; /**< Type of request, see @ref NRF_RADIO_REQUEST_TYPE. */ - union { - nrf_radio_request_earliest_t earliest; /**< Parameters for requesting a radio timeslot as early as possible. */ - nrf_radio_request_normal_t normal; /**< Parameters for requesting a normal radio timeslot. */ - } params; /**< Parameter union. */ -} nrf_radio_request_t; - -/**@brief Return parameters of the radio timeslot signal callback. */ -typedef struct { - uint8_t callback_action; /**< The action requested by the application when returning from the signal callback, see @ref - NRF_RADIO_SIGNAL_CALLBACK_ACTION. */ - union { - struct { - nrf_radio_request_t *p_next; /**< The request parameters for the next radio timeslot. */ - } request; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END. */ - struct { - uint32_t length_us; /**< Requested extension of the radio timeslot duration (microseconds) (for minimum time see @ref - NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US). */ - } extend; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND. */ - } params; /**< Parameter union. */ -} nrf_radio_signal_callback_return_param_t; - -/**@brief The radio timeslot signal callback type. - * - * @note In case of invalid return parameters, the radio timeslot will automatically end - * immediately after returning from the signal callback and the - * @ref NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN event will be sent. - * @note The returned struct pointer must remain valid after the signal callback - * function returns. For instance, this means that it must not point to a stack variable. - * - * @param[in] signal_type Type of signal, see @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE. - * - * @return Pointer to structure containing action requested by the application. - */ -typedef nrf_radio_signal_callback_return_param_t *(*nrf_radio_signal_callback_t)(uint8_t signal_type); - -/**@brief AES ECB parameter typedefs */ -typedef uint8_t soc_ecb_key_t[SOC_ECB_KEY_LENGTH]; /**< Encryption key type. */ -typedef uint8_t soc_ecb_cleartext_t[SOC_ECB_CLEARTEXT_LENGTH]; /**< Cleartext data type. */ -typedef uint8_t soc_ecb_ciphertext_t[SOC_ECB_CIPHERTEXT_LENGTH]; /**< Ciphertext data type. */ - -/**@brief AES ECB data structure */ -typedef struct { - soc_ecb_key_t key; /**< Encryption key. */ - soc_ecb_cleartext_t cleartext; /**< Cleartext data. */ - soc_ecb_ciphertext_t ciphertext; /**< Ciphertext data. */ -} nrf_ecb_hal_data_t; - -/**@brief AES ECB block. Used to provide multiple blocks in a single call - to @ref sd_ecb_blocks_encrypt.*/ -typedef struct { - soc_ecb_key_t const *p_key; /**< Pointer to the Encryption key. */ - soc_ecb_cleartext_t const *p_cleartext; /**< Pointer to the Cleartext data. */ - soc_ecb_ciphertext_t *p_ciphertext; /**< Pointer to the Ciphertext data. */ -} nrf_ecb_hal_data_block_t; - -/**@} */ - -/**@addtogroup NRF_SOC_FUNCTIONS Functions - * @{ */ - -/**@brief Initialize a mutex. - * - * @param[in] p_mutex Pointer to the mutex to initialize. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_MUTEX_NEW, uint32_t, sd_mutex_new(nrf_mutex_t *p_mutex)); - -/**@brief Attempt to acquire a mutex. - * - * @param[in] p_mutex Pointer to the mutex to acquire. - * - * @retval ::NRF_SUCCESS The mutex was successfully acquired. - * @retval ::NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN The mutex could not be acquired. - */ -SVCALL(SD_MUTEX_ACQUIRE, uint32_t, sd_mutex_acquire(nrf_mutex_t *p_mutex)); - -/**@brief Release a mutex. - * - * @param[in] p_mutex Pointer to the mutex to release. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_MUTEX_RELEASE, uint32_t, sd_mutex_release(nrf_mutex_t *p_mutex)); - -/**@brief Query the capacity of the application random pool. - * - * @param[out] p_pool_capacity The capacity of the pool. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RAND_APPLICATION_POOL_CAPACITY_GET, uint32_t, sd_rand_application_pool_capacity_get(uint8_t *p_pool_capacity)); - -/**@brief Get number of random bytes available to the application. - * - * @param[out] p_bytes_available The number of bytes currently available in the pool. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RAND_APPLICATION_BYTES_AVAILABLE_GET, uint32_t, sd_rand_application_bytes_available_get(uint8_t *p_bytes_available)); - -/**@brief Get random bytes from the application pool. - * - * @param[out] p_buff Pointer to unit8_t buffer for storing the bytes. - * @param[in] length Number of bytes to take from pool and place in p_buff. - * - * @retval ::NRF_SUCCESS The requested bytes were written to p_buff. - * @retval ::NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES No bytes were written to the buffer, because there were not enough bytes - * available. - */ -SVCALL(SD_RAND_APPLICATION_VECTOR_GET, uint32_t, sd_rand_application_vector_get(uint8_t *p_buff, uint8_t length)); - -/**@brief Gets the reset reason register. - * - * @param[out] p_reset_reason Contents of the NRF_POWER->RESETREAS register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RESET_REASON_GET, uint32_t, sd_power_reset_reason_get(uint32_t *p_reset_reason)); - -/**@brief Clears the bits of the reset reason register. - * - * @param[in] reset_reason_clr_msk Contains the bits to clear from the reset reason register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RESET_REASON_CLR, uint32_t, sd_power_reset_reason_clr(uint32_t reset_reason_clr_msk)); - -/**@brief Sets the power mode when in CPU sleep. - * - * @param[in] power_mode The power mode to use when in CPU sleep, see @ref NRF_POWER_MODES. @sa sd_app_evt_wait - * - * @retval ::NRF_SUCCESS The power mode was set. - * @retval ::NRF_ERROR_SOC_POWER_MODE_UNKNOWN The power mode was unknown. - */ -SVCALL(SD_POWER_MODE_SET, uint32_t, sd_power_mode_set(uint8_t power_mode)); - -/**@brief Puts the chip in System OFF mode. - * - * @retval ::NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN - */ -SVCALL(SD_POWER_SYSTEM_OFF, uint32_t, sd_power_system_off(void)); - -/**@brief Enables or disables the power-fail comparator. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_FAILURE_WARNING) when the power failure warning occurs. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] pof_enable True if the power-fail comparator should be enabled, false if it should be disabled. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_POF_ENABLE, uint32_t, sd_power_pof_enable(uint8_t pof_enable)); - -/**@brief Enables or disables the USB power ready event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_POWER_READY) when a USB 3.3 V supply is ready. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbpwrrdy_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBPWRRDY_ENABLE, uint32_t, sd_power_usbpwrrdy_enable(uint8_t usbpwrrdy_enable)); - -/**@brief Enables or disables the power USB-detected event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_DETECTED) when a voltage supply is detected on VBUS. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbdetected_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBDETECTED_ENABLE, uint32_t, sd_power_usbdetected_enable(uint8_t usbdetected_enable)); - -/**@brief Enables or disables the power USB-removed event. - * - * Enabling this will give a SoftDevice event (NRF_EVT_POWER_USB_REMOVED) when a voltage supply is removed from VBUS. - * The event can be retrieved with sd_evt_get(); - * - * @param[in] usbremoved_enable True if the power ready event should be enabled, false if it should be disabled. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBREMOVED_ENABLE, uint32_t, sd_power_usbremoved_enable(uint8_t usbremoved_enable)); - -/**@brief Get USB supply status register content. - * - * @param[out] usbregstatus The content of USBREGSTATUS register. - * - * @note Calling this function on a chip without USBD peripheral will result in undefined behaviour. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_USBREGSTATUS_GET, uint32_t, sd_power_usbregstatus_get(uint32_t *usbregstatus)); - -/**@brief Sets the power failure comparator threshold value. - * - * @note: Power failure comparator threshold setting. This setting applies both for normal voltage - * mode (supply connected to both VDD and VDDH) and high voltage mode (supply connected to - * VDDH only). - * - * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDS. - * - * @retval ::NRF_SUCCESS The power failure threshold was set. - * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. - */ -SVCALL(SD_POWER_POF_THRESHOLD_SET, uint32_t, sd_power_pof_threshold_set(uint8_t threshold)); - -/**@brief Sets the power failure comparator threshold value for high voltage. - * - * @note: Power failure comparator threshold setting for high voltage mode (supply connected to - * VDDH only). This setting does not apply for normal voltage mode (supply connected to both - * VDD and VDDH). - * - * @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDVDDHS. - * - * @retval ::NRF_SUCCESS The power failure threshold was set. - * @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown. - */ -SVCALL(SD_POWER_POF_THRESHOLDVDDH_SET, uint32_t, sd_power_pof_thresholdvddh_set(uint8_t threshold)); - -/**@brief Writes the NRF_POWER->RAM[index].POWERSET register. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERSET register to write to. - * @param[in] ram_powerset Contains the word to write to the NRF_POWER->RAM[index].POWERSET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_SET, uint32_t, sd_power_ram_power_set(uint8_t index, uint32_t ram_powerset)); - -/**@brief Writes the NRF_POWER->RAM[index].POWERCLR register. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWERCLR register to write to. - * @param[in] ram_powerclr Contains the word to write to the NRF_POWER->RAM[index].POWERCLR register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_CLR, uint32_t, sd_power_ram_power_clr(uint8_t index, uint32_t ram_powerclr)); - -/**@brief Get contents of NRF_POWER->RAM[index].POWER register, indicates power status of RAM[index] blocks. - * - * @param[in] index Contains the index in the NRF_POWER->RAM[index].POWER register to read from. - * @param[out] p_ram_power Content of NRF_POWER->RAM[index].POWER register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_RAM_POWER_GET, uint32_t, sd_power_ram_power_get(uint8_t index, uint32_t *p_ram_power)); - -/**@brief Set bits in the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[in] gpregret_msk Bits to be set in the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_SET, uint32_t, sd_power_gpregret_set(uint32_t gpregret_id, uint32_t gpregret_msk)); - -/**@brief Clear bits in the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[in] gpregret_msk Bits to be clear in the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_CLR, uint32_t, sd_power_gpregret_clr(uint32_t gpregret_id, uint32_t gpregret_msk)); - -/**@brief Get contents of the general purpose retention registers (NRF_POWER->GPREGRET*). - * - * @param[in] gpregret_id 0 for GPREGRET, 1 for GPREGRET2. - * @param[out] p_gpregret Contents of the GPREGRET register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_POWER_GPREGRET_GET, uint32_t, sd_power_gpregret_get(uint32_t gpregret_id, uint32_t *p_gpregret)); - -/**@brief Enable or disable the DC/DC regulator for the regulator stage 1 (REG1). - * - * @param[in] dcdc_mode The mode of the DCDC, see @ref NRF_POWER_DCDC_MODES. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_PARAM The DCDC mode is invalid. - */ -SVCALL(SD_POWER_DCDC_MODE_SET, uint32_t, sd_power_dcdc_mode_set(uint8_t dcdc_mode)); - -/**@brief Enable or disable the DC/DC regulator for the regulator stage 0 (REG0). - * - * For more details on the REG0 stage, please see product specification. - * - * @param[in] dcdc_mode The mode of the DCDC0, see @ref NRF_POWER_DCDC_MODES. - * - * @retval ::NRF_SUCCESS - * @retval ::NRF_ERROR_INVALID_PARAM The dcdc_mode is invalid. - */ -SVCALL(SD_POWER_DCDC0_MODE_SET, uint32_t, sd_power_dcdc0_mode_set(uint8_t dcdc_mode)); - -/**@brief Request the high frequency crystal oscillator. - * - * Will start the high frequency crystal oscillator, the startup time of the crystal varies - * and the ::sd_clock_hfclk_is_running function can be polled to check if it has started. - * - * @see sd_clock_hfclk_is_running - * @see sd_clock_hfclk_release - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_REQUEST, uint32_t, sd_clock_hfclk_request(void)); - -/**@brief Releases the high frequency crystal oscillator. - * - * Will stop the high frequency crystal oscillator, this happens immediately. - * - * @see sd_clock_hfclk_is_running - * @see sd_clock_hfclk_request - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_RELEASE, uint32_t, sd_clock_hfclk_release(void)); - -/**@brief Checks if the high frequency crystal oscillator is running. - * - * @see sd_clock_hfclk_request - * @see sd_clock_hfclk_release - * - * @param[out] p_is_running 1 if the external crystal oscillator is running, 0 if not. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_CLOCK_HFCLK_IS_RUNNING, uint32_t, sd_clock_hfclk_is_running(uint32_t *p_is_running)); - -/**@brief Waits for an application event. - * - * An application event is either an application interrupt or a pended interrupt when the interrupt - * is disabled. - * - * When the application waits for an application event by calling this function, an interrupt that - * is enabled will be taken immediately on pending since this function will wait in thread mode, - * then the execution will return in the application's main thread. - * - * In order to wake up from disabled interrupts, the SEVONPEND flag has to be set in the Cortex-M - * MCU's System Control Register (SCR), CMSIS_SCB. In that case, when a disabled interrupt gets - * pended, this function will return to the application's main thread. - * - * @note The application must ensure that the pended flag is cleared using ::sd_nvic_ClearPendingIRQ - * in order to sleep using this function. This is only necessary for disabled interrupts, as - * the interrupt handler will clear the pending flag automatically for enabled interrupts. - * - * @note If an application interrupt has happened since the last time sd_app_evt_wait was - * called this function will return immediately and not go to sleep. This is to avoid race - * conditions that can occur when a flag is updated in the interrupt handler and processed - * in the main loop. - * - * @post An application interrupt has happened or a interrupt pending flag is set. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_APP_EVT_WAIT, uint32_t, sd_app_evt_wait(void)); - -/**@brief Get PPI channel enable register contents. - * - * @param[out] p_channel_enable The contents of the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_GET, uint32_t, sd_ppi_channel_enable_get(uint32_t *p_channel_enable)); - -/**@brief Set PPI channel enable register. - * - * @param[in] channel_enable_set_msk Mask containing the bits to set in the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_SET, uint32_t, sd_ppi_channel_enable_set(uint32_t channel_enable_set_msk)); - -/**@brief Clear PPI channel enable register. - * - * @param[in] channel_enable_clr_msk Mask containing the bits to clear in the PPI CHEN register. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ENABLE_CLR, uint32_t, sd_ppi_channel_enable_clr(uint32_t channel_enable_clr_msk)); - -/**@brief Assign endpoints to a PPI channel. - * - * @param[in] channel_num Number of the PPI channel to assign. - * @param[in] evt_endpoint Event endpoint of the PPI channel. - * @param[in] task_endpoint Task endpoint of the PPI channel. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_CHANNEL The channel number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_CHANNEL_ASSIGN, uint32_t, - sd_ppi_channel_assign(uint8_t channel_num, const volatile void *evt_endpoint, const volatile void *task_endpoint)); - -/**@brief Task to enable a channel group. - * - * @param[in] group_num Number of the channel group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_TASK_ENABLE, uint32_t, sd_ppi_group_task_enable(uint8_t group_num)); - -/**@brief Task to disable a channel group. - * - * @param[in] group_num Number of the PPI group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_TASK_DISABLE, uint32_t, sd_ppi_group_task_disable(uint8_t group_num)); - -/**@brief Assign PPI channels to a channel group. - * - * @param[in] group_num Number of the channel group. - * @param[in] channel_msk Mask of the channels to assign to the group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_ASSIGN, uint32_t, sd_ppi_group_assign(uint8_t group_num, uint32_t channel_msk)); - -/**@brief Gets the PPI channels of a channel group. - * - * @param[in] group_num Number of the channel group. - * @param[out] p_channel_msk Mask of the channels assigned to the group. - * - * @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_PPI_GROUP_GET, uint32_t, sd_ppi_group_get(uint8_t group_num, uint32_t *p_channel_msk)); - -/**@brief Configures the Radio Notification signal. - * - * @note - * - The notification signal latency depends on the interrupt priority settings of SWI used - * for notification signal. - * - To ensure that the radio notification signal behaves in a consistent way, the radio - * notifications must be configured when there is no protocol stack or other SoftDevice - * activity in progress. It is recommended that the radio notification signal is - * configured directly after the SoftDevice has been enabled. - * - In the period between the ACTIVE signal and the start of the Radio Event, the SoftDevice - * will interrupt the application to do Radio Event preparation. - * - Using the Radio Notification feature may limit the bandwidth, as the SoftDevice may have - * to shorten the connection events to have time for the Radio Notification signals. - * - * @param[in] type Type of notification signal, see @ref NRF_RADIO_NOTIFICATION_TYPES. - * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE shall be used to turn off radio - * notification. Using @ref NRF_RADIO_NOTIFICATION_DISTANCE_NONE is - * recommended (but not required) to be used with - * @ref NRF_RADIO_NOTIFICATION_TYPE_NONE. - * - * @param[in] distance Distance between the notification signal and start of radio activity, see @ref - * NRF_RADIO_NOTIFICATION_DISTANCES. This parameter is ignored when @ref NRF_RADIO_NOTIFICATION_TYPE_NONE or - * @ref NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE is used. - * - * @retval ::NRF_ERROR_INVALID_PARAM The group number is invalid. - * @retval ::NRF_ERROR_INVALID_STATE A protocol stack or other SoftDevice is running. Stop all - * running activities and retry. - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_RADIO_NOTIFICATION_CFG_SET, uint32_t, sd_radio_notification_cfg_set(uint8_t type, uint8_t distance)); - -/**@brief Encrypts a block according to the specified parameters. - * - * 128-bit AES encryption. - * - * @note: - * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while - * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application - * main or low interrupt level. - * - * @param[in, out] p_ecb_data Pointer to the ECB parameters' struct (two input - * parameters and one output parameter). - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_ECB_BLOCK_ENCRYPT, uint32_t, sd_ecb_block_encrypt(nrf_ecb_hal_data_t *p_ecb_data)); - -/**@brief Encrypts multiple data blocks provided as an array of data block structures. - * - * @details: Performs 128-bit AES encryption on multiple data blocks - * - * @note: - * - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while - * the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application - * main or low interrupt level. - * - * @param[in] block_count Count of blocks in the p_data_blocks array. - * @param[in,out] p_data_blocks Pointer to the first entry in a contiguous array of - * @ref nrf_ecb_hal_data_block_t structures. - * - * @retval ::NRF_SUCCESS - */ -SVCALL(SD_ECB_BLOCKS_ENCRYPT, uint32_t, sd_ecb_blocks_encrypt(uint8_t block_count, nrf_ecb_hal_data_block_t *p_data_blocks)); - -/**@brief Gets any pending events generated by the SoC API. - * - * The application should keep calling this function to get events, until ::NRF_ERROR_NOT_FOUND is returned. - * - * @param[out] p_evt_id Set to one of the values in @ref NRF_SOC_EVTS, if any events are pending. - * - * @retval ::NRF_SUCCESS An event was pending. The event id is written in the p_evt_id parameter. - * @retval ::NRF_ERROR_NOT_FOUND No pending events. - */ -SVCALL(SD_EVT_GET, uint32_t, sd_evt_get(uint32_t *p_evt_id)); - -/**@brief Get the temperature measured on the chip - * - * This function will block until the temperature measurement is done. - * It takes around 50 us from call to return. - * - * @param[out] p_temp Result of temperature measurement. Die temperature in 0.25 degrees Celsius. - * - * @retval ::NRF_SUCCESS A temperature measurement was done, and the temperature was written to temp - */ -SVCALL(SD_TEMP_GET, uint32_t, sd_temp_get(int32_t *p_temp)); - -/**@brief Flash Write - * - * Commands to write a buffer to flash - * - * If the SoftDevice is enabled: - * This call initiates the flash access command, and its completion will be communicated to the - * application with exactly one of the following events: - * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. - * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. - * - * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the - * write has been completed - * - * @note - * - This call takes control over the radio and the CPU during flash erase and write to make sure that - * they will not interfere with the flash access. This means that all interrupts will be blocked - * for a predictable time (depending on the NVMC specification in the device's Product Specification - * and the command parameters). - * - The data in the p_src buffer should not be modified before the @ref NRF_EVT_FLASH_OPERATION_SUCCESS - * or the @ref NRF_EVT_FLASH_OPERATION_ERROR have been received if the SoftDevice is enabled. - * - This call will make the SoftDevice trigger a hardfault when the page is written, if it is - * protected. - * - * - * @param[in] p_dst Pointer to start of flash location to be written. - * @param[in] p_src Pointer to buffer with data to be written. - * @param[in] size Number of 32-bit words to write. Maximum size is the number of words in one - * flash page. See the device's Product Specification for details. - * - * @retval ::NRF_ERROR_INVALID_ADDR Tried to write to a non existing flash address, or p_dst or p_src was unaligned. - * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. - * @retval ::NRF_ERROR_INVALID_LENGTH Size was 0, or higher than the maximum allowed size. - * @retval ::NRF_ERROR_FORBIDDEN Tried to write to an address outside the application flash area. - * @retval ::NRF_SUCCESS The command was accepted. - */ -SVCALL(SD_FLASH_WRITE, uint32_t, sd_flash_write(uint32_t *p_dst, uint32_t const *p_src, uint32_t size)); - -/**@brief Flash Erase page - * - * Commands to erase a flash page - * If the SoftDevice is enabled: - * This call initiates the flash access command, and its completion will be communicated to the - * application with exactly one of the following events: - * - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed. - * - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started. - * - * If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the - * erase has been completed - * - * @note - * - This call takes control over the radio and the CPU during flash erase and write to make sure that - * they will not interfere with the flash access. This means that all interrupts will be blocked - * for a predictable time (depending on the NVMC specification in the device's Product Specification - * and the command parameters). - * - This call will make the SoftDevice trigger a hardfault when the page is erased, if it is - * protected. - * - * - * @param[in] page_number Page number of the page to erase - * - * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. - * @retval ::NRF_ERROR_INVALID_ADDR Tried to erase to a non existing flash page. - * @retval ::NRF_ERROR_BUSY The previous command has not yet completed. - * @retval ::NRF_ERROR_FORBIDDEN Tried to erase a page outside the application flash area. - * @retval ::NRF_SUCCESS The command was accepted. - */ -SVCALL(SD_FLASH_PAGE_ERASE, uint32_t, sd_flash_page_erase(uint32_t page_number)); - -/**@brief Opens a session for radio timeslot requests. - * - * @note Only one session can be open at a time. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) will be called when the radio timeslot - * starts. From this point the NRF_RADIO and NRF_TIMER0 peripherals can be freely accessed - * by the application. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0) is called whenever the NRF_TIMER0 - * interrupt occurs. - * @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO) is called whenever the NRF_RADIO - * interrupt occurs. - * @note p_radio_signal_callback() will be called at ARM interrupt priority level 0. This - * implies that none of the sd_* API calls can be used from p_radio_signal_callback(). - * - * @param[in] p_radio_signal_callback The signal callback. - * - * @retval ::NRF_ERROR_INVALID_ADDR p_radio_signal_callback is an invalid function pointer. - * @retval ::NRF_ERROR_BUSY If session cannot be opened. - * @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_SESSION_OPEN, uint32_t, sd_radio_session_open(nrf_radio_signal_callback_t p_radio_signal_callback)); - -/**@brief Closes a session for radio timeslot requests. - * - * @note Any current radio timeslot will be finished before the session is closed. - * @note If a radio timeslot is scheduled when the session is closed, it will be canceled. - * @note The application cannot consider the session closed until the @ref NRF_EVT_RADIO_SESSION_CLOSED - * event is received. - * - * @retval ::NRF_ERROR_FORBIDDEN If session not opened. - * @retval ::NRF_ERROR_BUSY If session is currently being closed. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_SESSION_CLOSE, uint32_t, sd_radio_session_close(void)); - -/**@brief Requests a radio timeslot. - * - * @note The request type is determined by p_request->request_type, and can be one of @ref NRF_RADIO_REQ_TYPE_EARLIEST - * and @ref NRF_RADIO_REQ_TYPE_NORMAL. The first request in a session must always be of type @ref - * NRF_RADIO_REQ_TYPE_EARLIEST. - * @note For a normal request (@ref NRF_RADIO_REQ_TYPE_NORMAL), the start time of a radio timeslot is specified by - * p_request->distance_us and is given relative to the start of the previous timeslot. - * @note A too small p_request->distance_us will lead to a @ref NRF_EVT_RADIO_BLOCKED event. - * @note Timeslots scheduled too close will lead to a @ref NRF_EVT_RADIO_BLOCKED event. - * @note See the SoftDevice Specification for more on radio timeslot scheduling, distances and lengths. - * @note If an opportunity for the first radio timeslot is not found before 100 ms after the call to this - * function, it is not scheduled, and instead a @ref NRF_EVT_RADIO_BLOCKED event is sent. - * The application may then try to schedule the first radio timeslot again. - * @note Successful requests will result in nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START). - * Unsuccessful requests will result in a @ref NRF_EVT_RADIO_BLOCKED event, see @ref NRF_SOC_EVTS. - * @note The jitter in the start time of the radio timeslots is +/- @ref NRF_RADIO_START_JITTER_US us. - * @note The nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) call has a latency relative to the - * specified radio timeslot start, but this does not affect the actual start time of the timeslot. - * @note NRF_TIMER0 is reset at the start of the radio timeslot, and is clocked at 1MHz from the high frequency - * (16 MHz) clock source. If p_request->hfclk_force_xtal is true, the high frequency clock is - * guaranteed to be clocked from the external crystal. - * @note The SoftDevice will neither access the NRF_RADIO peripheral nor the NRF_TIMER0 peripheral - * during the radio timeslot. - * - * @param[in] p_request Pointer to the request parameters. - * - * @retval ::NRF_ERROR_FORBIDDEN Either: - * - The session is not open. - * - The session is not IDLE. - * - This is the first request and its type is not @ref NRF_RADIO_REQ_TYPE_EARLIEST. - * - The request type was set to @ref NRF_RADIO_REQ_TYPE_NORMAL after a - * @ref NRF_RADIO_REQ_TYPE_EARLIEST request was blocked. - * @retval ::NRF_ERROR_INVALID_ADDR If the p_request pointer is invalid. - * @retval ::NRF_ERROR_INVALID_PARAM If the parameters of p_request are not valid. - * @retval ::NRF_SUCCESS Otherwise. - */ -SVCALL(SD_RADIO_REQUEST, uint32_t, sd_radio_request(nrf_radio_request_t const *p_request)); - -/**@brief Write register protected by the SoftDevice - * - * This function writes to a register that is write-protected by the SoftDevice. Please refer to your - * SoftDevice Specification for more details about which registers that are protected by SoftDevice. - * This function can write to the following protected peripheral: - * - ACL - * - * @note Protected registers may be read directly. - * @note Register that are write-once will return @ref NRF_SUCCESS on second set, even the value in - * the register has not changed. See the Product Specification for more details about register - * properties. - * - * @param[in] p_register Pointer to register to be written. - * @param[in] value Value to be written to the register. - * - * @retval ::NRF_ERROR_INVALID_ADDR This function can not write to the reguested register. - * @retval ::NRF_SUCCESS Value successfully written to register. - * - */ -SVCALL(SD_PROTECTED_REGISTER_WRITE, uint32_t, sd_protected_register_write(volatile uint32_t *p_register, uint32_t value)); - -/**@} */ - -#ifdef __cplusplus -} -#endif -#endif // NRF_SOC_H__ - -/**@} */ diff --git a/variants/wio-sdk-wm1110/softdevice/nrf_svc.h b/variants/wio-sdk-wm1110/softdevice/nrf_svc.h deleted file mode 100644 index 1de44656f3..0000000000 --- a/variants/wio-sdk-wm1110/softdevice/nrf_svc.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) Nordic Semiconductor ASA - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form, except as embedded into a Nordic - * Semiconductor ASA integrated circuit in a product or a software update for - * such product, must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of Nordic Semiconductor ASA nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * 4. This software, with or without modification, must only be used with a - * Nordic Semiconductor ASA integrated circuit. - * - * 5. Any software provided in binary form under this license must not be reverse - * engineered, decompiled, modified and/or disassembled. - * - * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef NRF_SVC__ -#define NRF_SVC__ - -#include "stdint.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** @brief Supervisor call declaration. - * - * A call to a function marked with @ref SVCALL, will trigger a Supervisor Call (SVC) Exception. - * The SVCs with SVC numbers 0x00-0x0F are forwared to the application. All other SVCs are handled by the SoftDevice. - * - * @param[in] number The SVC number to be used. - * @param[in] return_type The return type of the SVC function. - * @param[in] signature Function signature. The function can have at most four arguments. - */ - -#ifdef SVCALL_AS_NORMAL_FUNCTION -#define SVCALL(number, return_type, signature) return_type signature -#else - -#ifndef SVCALL -#if defined(__CC_ARM) -#define SVCALL(number, return_type, signature) return_type __svc(number) signature -#elif defined(__GNUC__) -#ifdef __cplusplus -#define GCC_CAST_CPP (uint16_t) -#else -#define GCC_CAST_CPP -#endif -#define SVCALL(number, return_type, signature) \ - _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wreturn-type\"") __attribute__((naked)) \ - __attribute__((unused)) static return_type signature \ - { \ - __asm("svc %0\n" \ - "bx r14" \ - : \ - : "I"(GCC_CAST_CPP number) \ - : "r0"); \ - } \ - _Pragma("GCC diagnostic pop") - -#elif defined(__ICCARM__) -#define PRAGMA(x) _Pragma(#x) -#define SVCALL(number, return_type, signature) \ - PRAGMA(swi_number = (number)) \ - __swi return_type signature; -#else -#define SVCALL(number, return_type, signature) return_type signature -#endif -#endif // SVCALL - -#endif // SVCALL_AS_NORMAL_FUNCTION - -#ifdef __cplusplus -} -#endif -#endif // NRF_SVC__ diff --git a/variants/wio-sdk-wm1110/variant.h b/variants/wio-sdk-wm1110/variant.h index 8f66b1f8c8..8ad8c769af 100644 --- a/variants/wio-sdk-wm1110/variant.h +++ b/variants/wio-sdk-wm1110/variant.h @@ -107,8 +107,6 @@ extern "C" { #define LR1110_GNSS_ANT_PIN (32 + 5) // P1.05 37 -#define NRF_USE_SERIAL_DFU - #ifdef __cplusplus } #endif diff --git a/variants/wio-tracker-wm1110/platformio.ini b/variants/wio-tracker-wm1110/platformio.ini index 5ecc414adc..03d7d047a7 100644 --- a/variants/wio-tracker-wm1110/platformio.ini +++ b/variants/wio-tracker-wm1110/platformio.ini @@ -2,7 +2,6 @@ [env:wio-tracker-wm1110] extends = nrf52840_base board = wio-tracker-wm1110 -; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e build_flags = ${nrf52840_base.build_flags} -Ivariants/wio-tracker-wm1110 -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DWIO_WM1110 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. @@ -12,4 +11,4 @@ lib_deps = ${nrf52840_base.lib_deps} debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink +;upload_protocol = jlink \ No newline at end of file diff --git a/variants/xiao_ble/platformio.ini b/variants/xiao_ble/platformio.ini index 6c47780d5f..613fd3599e 100644 --- a/variants/xiao_ble/platformio.ini +++ b/variants/xiao_ble/platformio.ini @@ -11,4 +11,4 @@ lib_deps = ${nrf52840_base.lib_deps} debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) -;upload_protocol = jlink +;upload_protocol = jlink \ No newline at end of file diff --git a/version.properties b/version.properties index c9336d539a..268987418b 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 3 -build = 16 +build = 14 From 8bd74588cef19f1641d69fd7960e4be757938a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 22 Jul 2024 15:42:46 +0200 Subject: [PATCH 174/211] bring back changes from #4248 --- boards/wio-tracker-wm1110.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/wio-tracker-wm1110.json b/boards/wio-tracker-wm1110.json index b4ab8db118..37a9186abb 100644 --- a/boards/wio-tracker-wm1110.json +++ b/boards/wio-tracker-wm1110.json @@ -23,7 +23,7 @@ "sd_flags": "-DS140", "sd_name": "s140", "sd_version": "7.3.0", - "sd_fwid": "0x00B6" + "sd_fwid": "0x0123" }, "bootloader": { "settings_addr": "0xFF000" From 5781149f8803f5dce2a67d5af9b4178c3ceb1c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 22 Jul 2024 15:46:15 +0200 Subject: [PATCH 175/211] *sigh* --- src/platform/nrf52/softdevice/nrf_sdm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/nrf52/softdevice/nrf_sdm.h b/src/platform/nrf52/softdevice/nrf_sdm.h index 2786a86a45..02bf135b43 100644 --- a/src/platform/nrf52/softdevice/nrf_sdm.h +++ b/src/platform/nrf52/softdevice/nrf_sdm.h @@ -141,7 +141,7 @@ the start of the SoftDevice (without MBR)*/ * Add @ref MBR_SIZE to find the first available flash address when the SoftDevice is installed * just above the MBR (the usual case). */ -#define SD_FLASH_SIZE 0x26000 +#define SD_FLASH_SIZE 0x27000 /** @brief Defines a macro for retrieving the actual FWID value from a given base address. Use * @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the usual @@ -377,4 +377,4 @@ SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table /** @} -*/ +*/ \ No newline at end of file From 646f5ad26230e7913472ac7effa8db7681066367 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:34:19 -0500 Subject: [PATCH 176/211] [create-pull-request] automated change (#4316) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 10494bf328..7f90178f18 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 10494bf328ac051fc4add9ddeb677eebf337b531 +Subproject commit 7f90178f183820e288aec41133144f30723228fe diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index dbe9281ec0..841ca7aa4b 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -176,6 +176,8 @@ typedef enum _meshtastic_HardwareModel { /* Heltec Mesh Node T114 board with nRF52840 CPU, and a 1.14 inch TFT display, Ultimate low-power design, specifically adapted for the Meshtatic project */ meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 = 69, + /* Sensecap Indicator from Seeed Studio. ESP32-S3 device with TFT and RP2040 coprocessor */ + meshtastic_HardwareModel_SENSECAP_INDICATOR = 70, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ From 7568a3537243efa8b16f315a003388795a2d313f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 22 Jul 2024 17:09:46 +0200 Subject: [PATCH 177/211] fix build and probably break GPS --- src/gps/GPS.cpp | 28 ------------------- .../Telemetry/EnvironmentTelemetry.cpp | 4 +-- src/platform/nrf52/NRF52Bluetooth.cpp | 4 ++- 3 files changed, 5 insertions(+), 31 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 3fac7a56ba..9628784d6c 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1489,20 +1489,6 @@ bool GPS::lookForTime() #ifdef GNSS_Airoha // add by WayenWeng uint8_t fix = reader.fixQuality(); uint32_t now = millis(); - if (fix > 0) { - if (lastFixStartMsec > 0) { - if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) { - return false; - } else { - clearBuffer(); - } - } else { - lastFixStartMsec = now; - return false; - } - } else { - return false; - } #endif auto ti = reader.time; @@ -1543,20 +1529,6 @@ bool GPS::lookForLocation() if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) { uint8_t fix = reader.fixQuality(); uint32_t now = millis(); - if (fix > 0) { - if (lastFixStartMsec > 0) { - if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) { - return false; - } else { - clearBuffer(); - } - } else { - lastFixStartMsec = now; - return false; - } - } else { - return false; - } } #endif diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index ca3bb665e4..92f90cfdd8 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -293,7 +293,7 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m m->which_variant = meshtastic_Telemetry_environment_metrics_tag; #ifdef T1000X_SENSOR_EN // add by WayenWeng - valid = valid && t1000xSensor.getMetrics(&m); + valid = valid && t1000xSensor.getMetrics(m); hasSensor = true; #else if (dfRobotLarkSensor.hasSensor()) { @@ -566,4 +566,4 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule return result; } -#endif +#endif \ No newline at end of file diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 890886b4dc..665e1402f7 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -16,10 +16,12 @@ static BLECharacteristic logRadio = BLECharacteristic(BLEUuid(LOGRADIO_UUID_16)) static BLEDis bledis; // DIS (Device Information Service) helper class instance static BLEBas blebas; // BAS (Battery Service) helper class instance +#ifndef BLE_DFU_SECURE static BLEDfu bledfu; // DFU software update helper service +#else static BLEDfuSecure bledfusecure; // DFU software update helper service +#endif -static BLEDfu bledfu; // DFU software update helper service // This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in // process at once // static uint8_t trBytes[_max(_max(_max(_max(ToRadio_size, RadioConfig_size), User_size), MyNodeInfo_size), FromRadio_size)]; From d8fd3f615de886a127c0b51b4eee9ba642168758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Mon, 22 Jul 2024 22:35:39 +0200 Subject: [PATCH 178/211] meesa jinxed it --- src/platform/nrf52/NRF52Bluetooth.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 665e1402f7..81a165f2df 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -14,12 +14,12 @@ static BLECharacteristic fromRadio = BLECharacteristic(BLEUuid(FROMRADIO_UUID_16 static BLECharacteristic toRadio = BLECharacteristic(BLEUuid(TORADIO_UUID_16)); static BLECharacteristic logRadio = BLECharacteristic(BLEUuid(LOGRADIO_UUID_16)); -static BLEDis bledis; // DIS (Device Information Service) helper class instance -static BLEBas blebas; // BAS (Battery Service) helper class instance +static BLEDis bledis; // DIS (Device Information Service) helper class instance +static BLEBas blebas; // BAS (Battery Service) helper class instance #ifndef BLE_DFU_SECURE -static BLEDfu bledfu; // DFU software update helper service +static BLEDfu bledfu; // DFU software update helper service #else -static BLEDfuSecure bledfusecure; // DFU software update helper service +static BLEDfuSecure bledfusecure; // DFU software update helper service #endif // This scratch buffer is used for various bluetooth reads/writes - but it is safe because only one bt operation can be in From 0d2a9b6282c9f2ddd792696a6575be3fe12935dd Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 23 Jul 2024 06:16:53 -0500 Subject: [PATCH 179/211] Fix de/compression buffer overflows in TAK packets (#4317) * Fix de/compression buffer overflows in TAK packets * Log message --- .semgrepignore | 2 +- .../compression/{unishox2.c => unishox2.cpp} | 19 +++- src/mesh/compression/unishox2.h | 76 ++++---------- src/modules/AtakPluginModule.cpp | 99 +++++++++++++------ src/modules/PositionModule.cpp | 8 +- 5 files changed, 108 insertions(+), 96 deletions(-) rename src/mesh/compression/{unishox2.c => unishox2.cpp} (98%) diff --git a/.semgrepignore b/.semgrepignore index 10fcb5f754..b4267ad236 100644 --- a/.semgrepignore +++ b/.semgrepignore @@ -1,2 +1,2 @@ .github/workflows/main_matrix.yml -src/mesh/compression/unishox2.c +src/mesh/compression/unishox2.cpp diff --git a/src/mesh/compression/unishox2.c b/src/mesh/compression/unishox2.cpp similarity index 98% rename from src/mesh/compression/unishox2.c rename to src/mesh/compression/unishox2.cpp index 99c62f6590..fcb12a2229 100644 --- a/src/mesh/compression/unishox2.c +++ b/src/mesh/compression/unishox2.cpp @@ -15,6 +15,7 @@ * * @author Arundale Ramanathan * + * Port for Particle (particle.io) / Aruino - Jonathan Greenblatt */ /** * @file unishox2.c @@ -36,6 +37,14 @@ /// uint8_t is unsigned char typedef unsigned char uint8_t; +const char *USX_FREQ_SEQ_DFLT[] = {"\": \"", "\": ", ""}; +const char *USX_FREQ_SEQ_XML[] = {"", "" \ - } -/// Frequently occurring sequences in XML content -#define USX_FREQ_SEQ_XML \ - (const char *[]) \ - { \ - "", "has_contact) { - auto length = unishox2_compress_simple(t->contact.callsign, strlen(t->contact.callsign), compressed.contact.callsign); + auto length = unishox2_compress_lines(t->contact.callsign, strlen(t->contact.callsign), compressed.contact.callsign, + sizeof(compressed.contact.callsign) - 1, USX_PSET_DFLT, NULL); + if (length < 0) { + LOG_WARN("Compression overflowed contact.callsign. Reverting to uncompressed packet\n"); + return; + } LOG_DEBUG("Compressed callsign: %d bytes\n", length); - - length = unishox2_compress_simple(t->contact.device_callsign, strlen(t->contact.device_callsign), - compressed.contact.device_callsign); + length = unishox2_compress_lines(t->contact.device_callsign, strlen(t->contact.device_callsign), + compressed.contact.device_callsign, sizeof(compressed.contact.device_callsign) - 1, + USX_PSET_DFLT, NULL); + if (length < 0) { + LOG_WARN("Compression overflowed contact.device_callsign. Reverting to uncompressed packet\n"); + return; + } LOG_DEBUG("Compressed device_callsign: %d bytes\n", length); } if (t->which_payload_variant == meshtastic_TAKPacket_chat_tag) { - auto length = unishox2_compress_simple(t->payload_variant.chat.message, strlen(t->payload_variant.chat.message), - compressed.payload_variant.chat.message); + auto length = unishox2_compress_lines(t->payload_variant.chat.message, strlen(t->payload_variant.chat.message), + compressed.payload_variant.chat.message, + sizeof(compressed.payload_variant.chat.message) - 1, USX_PSET_DFLT, NULL); + if (length < 0) { + LOG_WARN("Compression overflowed chat.message. Reverting to uncompressed packet\n"); + return; + } LOG_DEBUG("Compressed chat message: %d bytes\n", length); if (t->payload_variant.chat.has_to) { compressed.payload_variant.chat.has_to = true; - length = unishox2_compress_simple(t->payload_variant.chat.to, strlen(t->payload_variant.chat.to), - compressed.payload_variant.chat.to); + length = unishox2_compress_lines(t->payload_variant.chat.to, strlen(t->payload_variant.chat.to), + compressed.payload_variant.chat.to, + sizeof(compressed.payload_variant.chat.to) - 1, USX_PSET_DFLT, NULL); + if (length < 0) { + LOG_WARN("Compression overflowed chat.to. Reverting to uncompressed packet\n"); + return; + } LOG_DEBUG("Compressed chat to: %d bytes\n", length); } if (t->payload_variant.chat.has_to_callsign) { compressed.payload_variant.chat.has_to_callsign = true; - length = - unishox2_compress_simple(t->payload_variant.chat.to_callsign, strlen(t->payload_variant.chat.to_callsign), - compressed.payload_variant.chat.to_callsign); + length = unishox2_compress_lines(t->payload_variant.chat.to_callsign, strlen(t->payload_variant.chat.to_callsign), + compressed.payload_variant.chat.to_callsign, + sizeof(compressed.payload_variant.chat.to_callsign) - 1, USX_PSET_DFLT, NULL); + if (length < 0) { + LOG_WARN("Compression overflowed chat.to_callsign. Reverting to uncompressed packet\n"); + return; + } LOG_DEBUG("Compressed chat to_callsign: %d bytes\n", length); } } @@ -102,7 +122,7 @@ void AtakPluginModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtast } else { if (!t->is_compressed) { // Not compressed. Something is wrong - LOG_ERROR("Received uncompressed TAKPacket over radio!\n"); + LOG_WARN("Received uncompressed TAKPacket over radio! Skipping\n"); return; } @@ -112,32 +132,55 @@ void AtakPluginModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtast uncompressed.is_compressed = false; if (t->has_contact) { auto length = - unishox2_decompress_simple(t->contact.callsign, strlen(t->contact.callsign), uncompressed.contact.callsign); - + unishox2_decompress_lines(t->contact.callsign, strlen(t->contact.callsign), uncompressed.contact.callsign, + sizeof(uncompressed.contact.callsign) - 1, USX_PSET_DFLT, NULL); + if (length < 0) { + LOG_WARN("Decompression overflowed contact.callsign. Bailing out\n"); + return; + } LOG_DEBUG("Decompressed callsign: %d bytes\n", length); - length = unishox2_decompress_simple(t->contact.device_callsign, strlen(t->contact.device_callsign), - uncompressed.contact.device_callsign); - + length = unishox2_decompress_lines(t->contact.device_callsign, strlen(t->contact.device_callsign), + uncompressed.contact.device_callsign, + sizeof(uncompressed.contact.device_callsign) - 1, USX_PSET_DFLT, NULL); + if (length < 0) { + LOG_WARN("Decompression overflowed contact.device_callsign. Bailing out\n"); + return; + } LOG_DEBUG("Decompressed device_callsign: %d bytes\n", length); } if (uncompressed.which_payload_variant == meshtastic_TAKPacket_chat_tag) { - auto length = unishox2_decompress_simple(t->payload_variant.chat.message, strlen(t->payload_variant.chat.message), - uncompressed.payload_variant.chat.message); + auto length = unishox2_decompress_lines(t->payload_variant.chat.message, strlen(t->payload_variant.chat.message), + uncompressed.payload_variant.chat.message, + sizeof(uncompressed.payload_variant.chat.message) - 1, USX_PSET_DFLT, NULL); + if (length < 0) { + LOG_WARN("Decompression overflowed chat.message. Bailing out\n"); + return; + } LOG_DEBUG("Decompressed chat message: %d bytes\n", length); if (t->payload_variant.chat.has_to) { uncompressed.payload_variant.chat.has_to = true; - length = unishox2_decompress_simple(t->payload_variant.chat.to, strlen(t->payload_variant.chat.to), - uncompressed.payload_variant.chat.to); + length = unishox2_decompress_lines(t->payload_variant.chat.to, strlen(t->payload_variant.chat.to), + uncompressed.payload_variant.chat.to, + sizeof(uncompressed.payload_variant.chat.to) - 1, USX_PSET_DFLT, NULL); + if (length < 0) { + LOG_WARN("Decompression overflowed chat.to. Bailing out\n"); + return; + } LOG_DEBUG("Decompressed chat to: %d bytes\n", length); } if (t->payload_variant.chat.has_to_callsign) { uncompressed.payload_variant.chat.has_to_callsign = true; length = - unishox2_decompress_simple(t->payload_variant.chat.to_callsign, strlen(t->payload_variant.chat.to_callsign), - uncompressed.payload_variant.chat.to_callsign); + unishox2_decompress_lines(t->payload_variant.chat.to_callsign, strlen(t->payload_variant.chat.to_callsign), + uncompressed.payload_variant.chat.to_callsign, + sizeof(uncompressed.payload_variant.chat.to_callsign) - 1, USX_PSET_DFLT, NULL); + if (length < 0) { + LOG_WARN("Decompression overflowed chat.to_callsign. Bailing out\n"); + return; + } LOG_DEBUG("Decompressed chat to_callsign: %d bytes\n", length); } } @@ -148,4 +191,4 @@ void AtakPluginModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtast service.sendToPhone(decompressedCopy); } return; -} \ No newline at end of file +} diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index b3294a8669..228929e963 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -11,12 +11,12 @@ #include "configuration.h" #include "gps/GeoCoord.h" #include "main.h" +#include "mesh/compression/unishox2.h" #include "meshtastic/atak.pb.h" #include "sleep.h" #include "target_specific.h" extern "C" { -#include "mesh/compression/unishox2.h" #include } @@ -255,10 +255,12 @@ meshtastic_MeshPacket *PositionModule::allocAtakPli() .course = static_cast(localPosition.ground_track), }}}; - auto length = unishox2_compress_simple(owner.long_name, strlen(owner.long_name), takPacket.contact.device_callsign); + auto length = unishox2_compress_lines(owner.long_name, strlen(owner.long_name), takPacket.contact.device_callsign, + sizeof(takPacket.contact.device_callsign) - 1, USX_PSET_DFLT, NULL); LOG_DEBUG("Uncompressed device_callsign '%s' - %d bytes\n", owner.long_name, strlen(owner.long_name)); LOG_DEBUG("Compressed device_callsign '%s' - %d bytes\n", takPacket.contact.device_callsign, length); - length = unishox2_compress_simple(owner.long_name, strlen(owner.long_name), takPacket.contact.callsign); + length = unishox2_compress_lines(owner.long_name, strlen(owner.long_name), takPacket.contact.callsign, + sizeof(takPacket.contact.callsign) - 1, USX_PSET_DFLT, NULL); mp->decoded.payload.size = pb_encode_to_bytes(mp->decoded.payload.bytes, sizeof(mp->decoded.payload.bytes), &meshtastic_TAKPacket_msg, &takPacket); return mp; From 316928deb079d41d0d5806a1cf8bbe80ec0f85cb Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Tue, 23 Jul 2024 19:18:27 +0800 Subject: [PATCH 180/211] Cleanup GPS, add UC6580 autodetect (#4319) * Cleanup GPS, add UC6580 autodetect Our GPS code autodetects devices by default. Previously UC6580 was statically assigned, and had its own baudrate configuration inside the GPS code. This change adds autodetect functionality for the UC6580 and moves any 'special' GPS baud rate requirements for a variant out into the variant configuration. Thereby cleaning up core GPS code a little, saving the whales, and curing global warming. New Functionality: * If GPS_BAUDRATE is defined in variant.h, GPS autodetection will try that baudrate first. * UC6580 GPS chips are now automatically detected * Only run speedSelect skip the first time * Cleanup GPS, add UC6580 autodetect Our GPS code autodetects devices by default. Previously UC6580 was statically assigned, and had its own baudrate configuration inside the GPS code. This change adds autodetect functionality for the UC6580 and moves any 'special' GPS baud rate requirements for a variant out into the variant configuration. Thereby cleaning up core GPS code a little, saving the whales, and curing global warming. New Functionality: * If GPS_BAUDRATE is defined in variant.h, GPS autodetection will try that baudrate first. * UC6580 GPS chips are now automatically detected * Cleanup GPS, add UC6580 autodetect Our GPS code autodetects devices by default. Previously UC6580 was statically assigned, and had its own baudrate configuration inside the GPS code. This change adds autodetect functionality for the UC6580 and moves any 'special' GPS baud rate requirements for a variant out into the variant configuration. Thereby cleaning up core GPS code a little, saving the whales, and curing global warming. New Functionality: * If GPS_BAUDRATE is defined in variant.h, GPS autodetection will try that baudrate first. * UC6580 GPS chips are now automatically detected * Remove Airoha baud rate code It's no longer needed. --- src/configuration.h | 10 +++--- src/gps/GPS.cpp | 34 +++++++++---------- variants/heltec_wireless_tracker/variant.h | 1 + .../heltec_wireless_tracker_V1_0/variant.h | 1 + variants/tracksenger/internal/variant.h | 3 +- variants/tracksenger/lcd/variant.h | 3 +- variants/tracksenger/oled/variant.h | 3 +- 7 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/configuration.h b/src/configuration.h index aad4ac4572..6351c35b18 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -171,10 +171,6 @@ along with this program. If not, see . // ----------------------------------------------------------------------------- // GPS // ----------------------------------------------------------------------------- -#ifndef GPS_BAUDRATE -#define GPS_BAUDRATE 9600 -#endif - #ifndef GPS_THREAD_INTERVAL #define GPS_THREAD_INTERVAL 200 #endif @@ -185,6 +181,10 @@ along with this program. If not, see . /* Step #1: offer chance for variant-specific defines */ #include "variant.h" +#ifndef GPS_BAUDRATE +#define GPS_BAUDRATE 9600 +#endif + /* Step #2: follow with defines common to the architecture; also enable HAS_ option not specifically disabled by variant.h */ #include "architecture.h" @@ -313,4 +313,4 @@ along with this program. If not, see . #endif #include "DebugConfiguration.h" -#include "RF95Configuration.h" \ No newline at end of file +#include "RF95Configuration.h" diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 9628784d6c..f04b456223 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -400,14 +400,14 @@ bool GPS::setup() int msglen = 0; if (!didSerialInit) { -#ifdef GNSS_Airoha // change by WayenWeng - if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) { - probe(GPS_BAUDRATE); - LOG_INFO("GPS setting to %d.\n", GPS_BAUDRATE); - } -#else -#if !defined(GPS_UC6580) + if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) { + + // if GPS_BAUDRATE is specified in variant (i.e. not 9600), skip to the specified rate. + if (speedSelect == 0 && GPS_BAUDRATE != serialSpeeds[speedSelect]) { + speedSelect = std::find(serialSpeeds, std::end(serialSpeeds), GPS_BAUDRATE) - serialSpeeds; + } + LOG_DEBUG("Probing for GPS at %d \n", serialSpeeds[speedSelect]); gnssModel = probe(serialSpeeds[speedSelect]); if (gnssModel == GNSS_MODEL_UNKNOWN) { @@ -423,9 +423,6 @@ bool GPS::setup() } else { gnssModel = GNSS_MODEL_UNKNOWN; } -#else - gnssModel = GNSS_MODEL_UC6580; -#endif if (gnssModel == GNSS_MODEL_MTK) { /* @@ -777,7 +774,6 @@ bool GPS::setup() LOG_INFO("GNSS module configuration saved!\n"); } } -#endif // !GNSS_Airoha didSerialInit = true; } @@ -1191,6 +1187,15 @@ GnssModel_t GPS::probe(int serialSpeed) _serial_gps->write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n"); delay(20); + // get version information from Unicore UFirebirdII Series + // Works for: UC6580, UM620, UM621, UM670A, UM680A, or UM681A + _serial_gps->write("$PDTINFO\r\n"); + delay(750); + if (getACK("UC6580", 500) == GNSS_RESPONSE_OK) { + LOG_INFO("UC6580 detected, using UC6580 Module\n"); + return GNSS_MODEL_UC6580; + } + // Get version information clearBuffer(); _serial_gps->write("$PCAS06,1*1A\r\n"); @@ -1398,13 +1403,6 @@ GPS *GPS::createGps() #else _serial_gps->begin(GPS_BAUDRATE); #endif - - /* - * T-Beam-S3-Core will be preset to use gps Probe here, and other boards will not be changed first - */ -#if defined(GPS_UC6580) - _serial_gps->updateBaudRate(115200); -#endif } return new_gps; } diff --git a/variants/heltec_wireless_tracker/variant.h b/variants/heltec_wireless_tracker/variant.h index f0ee0631d0..685c9f0795 100644 --- a/variants/heltec_wireless_tracker/variant.h +++ b/variants/heltec_wireless_tracker/variant.h @@ -52,6 +52,7 @@ #define GPS_RESET_MODE LOW #define GPS_UC6580 +#define GPS_BAUDRATE 115200 #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module diff --git a/variants/heltec_wireless_tracker_V1_0/variant.h b/variants/heltec_wireless_tracker_V1_0/variant.h index 1b4751a576..6b038dc28b 100644 --- a/variants/heltec_wireless_tracker_V1_0/variant.h +++ b/variants/heltec_wireless_tracker_V1_0/variant.h @@ -49,6 +49,7 @@ #define GPS_RESET_MODE LOW #define GPS_UC6580 +#define GPS_BAUDRATE 11520 #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module diff --git a/variants/tracksenger/internal/variant.h b/variants/tracksenger/internal/variant.h index e63cecd7bc..929c387930 100644 --- a/variants/tracksenger/internal/variant.h +++ b/variants/tracksenger/internal/variant.h @@ -48,6 +48,7 @@ #define GPS_RESET_MODE LOW #define GPS_UC6580 +#define GPS_BAUDRATE 115200 #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module @@ -87,4 +88,4 @@ { \ 26, 37, 17, 16, 15, 7 \ } -// #end keyboard \ No newline at end of file +// #end keyboard diff --git a/variants/tracksenger/lcd/variant.h b/variants/tracksenger/lcd/variant.h index 0f3423d52e..3f952361bb 100644 --- a/variants/tracksenger/lcd/variant.h +++ b/variants/tracksenger/lcd/variant.h @@ -72,6 +72,7 @@ #define GPS_RESET_MODE LOW #define GPS_UC6580 +#define GPS_BAUDRATE 115200 #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module @@ -111,4 +112,4 @@ { \ 26, 37, 17, 16, 15, 7 \ } -// #end keyboard \ No newline at end of file +// #end keyboard diff --git a/variants/tracksenger/oled/variant.h b/variants/tracksenger/oled/variant.h index d6bacf1393..99f12bd233 100644 --- a/variants/tracksenger/oled/variant.h +++ b/variants/tracksenger/oled/variant.h @@ -50,6 +50,7 @@ #define GPS_RESET_MODE LOW #define GPS_UC6580 +#define GPS_BAUDRATE 115200 #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module @@ -89,4 +90,4 @@ { \ 26, 37, 17, 16, 15, 7 \ } -// #end keyboard \ No newline at end of file +// #end keyboard From 1d3ac57943b59d17c07468aed139ca84ac256240 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 23 Jul 2024 08:35:01 -0500 Subject: [PATCH 181/211] Fix type (#4323) --- variants/heltec_wireless_tracker_V1_0/variant.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/heltec_wireless_tracker_V1_0/variant.h b/variants/heltec_wireless_tracker_V1_0/variant.h index 6b038dc28b..23987adf02 100644 --- a/variants/heltec_wireless_tracker_V1_0/variant.h +++ b/variants/heltec_wireless_tracker_V1_0/variant.h @@ -49,7 +49,7 @@ #define GPS_RESET_MODE LOW #define GPS_UC6580 -#define GPS_BAUDRATE 11520 +#define GPS_BAUDRATE 115200 #define USE_SX1262 #define LORA_DIO0 -1 // a No connect on the SX1262 module From e27375d331346f63da2662f3e0f92472e641dd86 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 23 Jul 2024 17:13:58 +0300 Subject: [PATCH 182/211] Set PIN_3V3_EN to HIGH (nrf52_promicro_diy variants) (#4321) * Update variant.cpp PIN 3v3 to HIGH * Update variant.cpp * Trunk fmt --- variants/diy/nrf52_promicro_diy_tcxo/variant.cpp | 9 ++++++++- variants/diy/nrf52_promicro_diy_xtal/variant.cpp | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/variants/diy/nrf52_promicro_diy_tcxo/variant.cpp b/variants/diy/nrf52_promicro_diy_tcxo/variant.cpp index 4030122e5a..5869ed1d45 100644 --- a/variants/diy/nrf52_promicro_diy_tcxo/variant.cpp +++ b/variants/diy/nrf52_promicro_diy_tcxo/variant.cpp @@ -28,4 +28,11 @@ const uint32_t g_ADigitalPinMap[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // P1 - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; \ No newline at end of file + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // 3V3 Power Rail + pinMode(PIN_3V3_EN, OUTPUT); + digitalWrite(PIN_3V3_EN, HIGH); +} diff --git a/variants/diy/nrf52_promicro_diy_xtal/variant.cpp b/variants/diy/nrf52_promicro_diy_xtal/variant.cpp index 4030122e5a..5869ed1d45 100644 --- a/variants/diy/nrf52_promicro_diy_xtal/variant.cpp +++ b/variants/diy/nrf52_promicro_diy_xtal/variant.cpp @@ -28,4 +28,11 @@ const uint32_t g_ADigitalPinMap[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // P1 - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; \ No newline at end of file + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // 3V3 Power Rail + pinMode(PIN_3V3_EN, OUTPUT); + digitalWrite(PIN_3V3_EN, HIGH); +} From 300c3d32aa7d8103f473c5b7233fbbf3409879f9 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Tue, 23 Jul 2024 11:52:14 -0500 Subject: [PATCH 183/211] Just a bit of security hygiene. (#4313) * Make sure to call randomSeed() on esp32 * Randomize the top 22 bits of the Message ID * Make it clear that we are not calling randomSeed() on purpose --------- Co-authored-by: Ben Meadors --- src/mesh/Router.cpp | 15 ++++++++------- src/platform/esp32/main-esp32.cpp | 4 ++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index c8c18ae6d5..35536e7149 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -92,22 +92,23 @@ void Router::enqueueReceivedMessage(meshtastic_MeshPacket *p) // FIXME, move this someplace better PacketId generatePacketId() { - static uint32_t i; // Note: trying to keep this in noinit didn't help for working across reboots + static uint32_t rollingPacketId; // Note: trying to keep this in noinit didn't help for working across reboots static bool didInit = false; - uint32_t numPacketId = UINT32_MAX; - if (!didInit) { didInit = true; // pick a random initial sequence number at boot (to prevent repeated reboots always starting at 0) // Note: we mask the high order bit to ensure that we never pass a 'negative' number to random - i = random(numPacketId & 0x7fffffff); - LOG_DEBUG("Initial packet id %u, numPacketId %u\n", i, numPacketId); + rollingPacketId = random(UINT32_MAX & 0x7fffffff); + LOG_DEBUG("Initial packet id %u\n", rollingPacketId); } - i++; - PacketId id = (i % numPacketId) + 1; // return number between 1 and numPacketId (ie - never zero) + rollingPacketId++; + + rollingPacketId &= UINT32_MAX >> 22; // Mask out the top 22 bits + PacketId id = rollingPacketId | random(UINT32_MAX & 0x7fffffff) << 10; // top 22 bits + LOG_DEBUG("Partially randomized packet id %u\n", id); return id; } diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp index aa51e810a8..3910f718f1 100644 --- a/src/platform/esp32/main-esp32.cpp +++ b/src/platform/esp32/main-esp32.cpp @@ -91,8 +91,12 @@ void enableSlowCLK() void esp32Setup() { + /* We explicitly don't want to do call randomSeed, + // as that triggers the esp32 core to use a less secure pseudorandom function. uint32_t seed = esp_random(); LOG_DEBUG("Setting random seed %u\n", seed); + randomSeed(seed); + */ LOG_DEBUG("Total heap: %d\n", ESP.getHeapSize()); LOG_DEBUG("Free heap: %d\n", ESP.getFreeHeap()); From 01e089fd07f766aec13705b7a1c3d2805f1f9d5e Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 24 Jul 2024 08:23:04 -0500 Subject: [PATCH 184/211] Ignore invalid service envelopes (#4326) --- src/mqtt/MQTT.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 5f7d6d9027..a7085dffe3 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -135,6 +135,10 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length) LOG_ERROR("Invalid MQTT service envelope, topic %s, len %u!\n", topic, length); return; } else { + if (e.channel_id == NULL || e.gateway_id == NULL) { + LOG_ERROR("Invalid MQTT service envelope, topic %s, len %u!\n", topic, length); + return; + } meshtastic_Channel ch = channels.getByName(e.channel_id); if (strcmp(e.gateway_id, owner.id) == 0) { // Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message. From a000a8d347d1040ecde038a0435e19c23c8c58b7 Mon Sep 17 00:00:00 2001 From: dylanli <167049793+Dylanliacc@users.noreply.github.com> Date: Thu, 25 Jul 2024 10:10:38 +0800 Subject: [PATCH 185/211] Support Seeed Tracker-T1000-E (#4303) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feature-T1000-E: add Added the board definition for T1000-E - integrate a script for rapid dependency download that is compatible with both Linux and Windows platforms. - add the pin definitions for UART, SPI, GPIO, and other peripherals have been ensured to be correct. - add the env configuration for PlatformIO. * refact-T1000-E: redefine T1000-E board * feature-T1000-E: add basic sensors * feature-T1000-E: add button init * feat: add DRADIOLIB_GODMODE defination for use function setDioAsRfSwitch to DIO LORA RF * feat : add gps(GNSS_Airoha) sleep mode * feat: add behavier when rec or send message * chore: hang IIC bus usage to avoid sensor address conflict * feat: add sensor data acquisition * feat : support Airoha GPS - add disable it in FSM - update lookForTime and lookForLocation function * fix: fix a bug * version: change version to 0.9.0 * Update tracker-t1000-e.json Remove a space * Delete variants/tracker-t1000-e/run_once.sh Delete not need as we will change platformio.ini * Update platformio.ini Update SoftDevice 7.3.0 usage in line with other lr1110 targets Do we need to keep GODMODE ? * fix: Button behavier incorrect bug * fix:remove some invaild code of TextMessageModule * fix: remove invaild comment * version: change version to 0.9.1 - update mark's patch - remove some invaild code and comments - fix button behavier * trunk format * fix: HELTEC_CAPSULE_SENSOR_V3 block got accidentally deleted * fix: EnvironmentTelemetry upstream merge went awry. * fix: Added macro definitions to ensure correct operation of LORA section * fix :GNSS_AIROHA macro defination in line with others * fix: upstream backmerge accidentally. * fix: wrap macro PIN_3V3_EN BUZZER_EN_PIN GNSS_AIROHA in the TRACKER_T1000_E macro guard --------- Co-authored-by: Mark Trevor Birss Co-authored-by: Ben Meadors Co-authored-by: Thomas Göttgens --- boards/tracker-t1000-e.json | 58 +++++++ src/ButtonThread.cpp | 5 +- src/gps/GPS.cpp | 55 ++++++- src/gps/GPS.h | 2 +- src/mesh/LR11x0Interface.cpp | 8 +- .../Telemetry/EnvironmentTelemetry.cpp | 8 +- src/modules/Telemetry/Sensor/T1000xSensor.h | 1 - src/modules/TextMessageModule.cpp | 3 +- src/sleep.cpp | 19 +++ variants/tracker-t1000-e/platformio.ini | 16 ++ variants/tracker-t1000-e/variant.cpp | 64 ++++++++ variants/tracker-t1000-e/variant.h | 150 ++++++++++++++++++ variants/wio-t1000-s/variant.h | 2 +- 13 files changed, 373 insertions(+), 18 deletions(-) create mode 100644 boards/tracker-t1000-e.json create mode 100644 variants/tracker-t1000-e/platformio.ini create mode 100644 variants/tracker-t1000-e/variant.cpp create mode 100644 variants/tracker-t1000-e/variant.h diff --git a/boards/tracker-t1000-e.json b/boards/tracker-t1000-e.json new file mode 100644 index 0000000000..2be716e22f --- /dev/null +++ b/boards/tracker-t1000-e.json @@ -0,0 +1,58 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v7.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + ["0x239A", "0x8029"], + ["0x239A", "0x0029"], + ["0x239A", "0x002A"], + ["0x239A", "0x802A"] + ], + "usb_product": "T1000-E-BOOT", + "mcu": "nrf52840", + "variant": "Seeed_T1000-E", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "7.3.0", + "sd_fwid": "0x0123" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": ["bluetooth"], + "debug": { + "jlink_device": "nRF52840_xxAA", + "svd_path": "nrf52840.svd" + }, + "frameworks": ["arduino"], + "name": "Seeed T1000-E", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "stlink", + "cmsis-dap", + "blackmagic" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://www.seeedstudio.com/SenseCAP-Card-Tracker-T1000-E-for-Meshtastic-p-5913.html", + "vendor": "Seeed Studio" +} diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index a81518f313..d479de6ed2 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -29,7 +29,6 @@ volatile ButtonThread::ButtonEventType ButtonThread::btnEvent = ButtonThread::BU #if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) OneButton ButtonThread::userButton; // Get reference to static member #endif - ButtonThread::ButtonThread() : OSThread("Button") { #if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO) @@ -43,7 +42,7 @@ ButtonThread::ButtonThread() : OSThread("Button") int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin #if defined(HELTEC_CAPSULE_SENSOR_V3) this->userButton = OneButton(pin, false, false); -#elif defined(BUTTON_ACTIVE_LOW) // change by WayenWeng +#elif defined(BUTTON_ACTIVE_LOW) this->userButton = OneButton(pin, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP); #else this->userButton = OneButton(pin, true, true); @@ -53,7 +52,7 @@ ButtonThread::ButtonThread() : OSThread("Button") #ifdef INPUT_PULLUP_SENSE // Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did -#ifdef BUTTON_SENSE_TYPE // change by WayenWeng +#ifdef BUTTON_SENSE_TYPE pinMode(pin, BUTTON_SENSE_TYPE); #else pinMode(pin, INPUT_PULLUP_SENSE); diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index f04b456223..494622dc66 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -787,7 +787,6 @@ GPS::~GPS() // we really should unregister our sleep observer notifyDeepSleepObserver.unobserve(¬ifyDeepSleep); } - // Put the GPS hardware into a specified state void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime) { @@ -824,6 +823,11 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime) setPowerPMU(false); // Power (PMU): off writePinStandby(true); // Standby (pin): asleep (not awake) setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed +#ifdef GNSS_AIROHA + if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) { + digitalWrite(PIN_GPS_EN, LOW); + } +#endif break; case GPS_OFF: @@ -833,6 +837,11 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime) setPowerPMU(false); // Power (PMU): off writePinStandby(true); // Standby (pin): asleep setPowerUBLOX(false, 0); // Standby (UBLOX): asleep, indefinitely +#ifdef GNSS_AIROHA + if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) { + digitalWrite(PIN_GPS_EN, LOW); + } +#endif break; } } @@ -1171,7 +1180,8 @@ GnssModel_t GPS::probe(int serialSpeed) _serial_gps->updateBaudRate(serialSpeed); } #endif -#ifdef GNSS_Airoha // add by WayenWeng +#ifdef GNSS_AIROHA + return GNSS_MODEL_UNKNOWN; #else #ifdef GPS_DEBUG @@ -1484,11 +1494,25 @@ bool GPS::factoryReset() */ bool GPS::lookForTime() { -#ifdef GNSS_Airoha // add by WayenWeng + +#ifdef GNSS_AIROHA uint8_t fix = reader.fixQuality(); uint32_t now = millis(); + if (fix > 0) { + if (lastFixStartMsec > 0) { + if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) { + return false; + } else { + clearBuffer(); + } + } else { + lastFixStartMsec = now; + return false; + } + } else { + return false; + } #endif - auto ti = reader.time; auto d = reader.date; if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed @@ -1523,13 +1547,26 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s */ bool GPS::lookForLocation() { -#ifdef GNSS_Airoha // add by WayenWeng +#ifdef GNSS_AIROHA if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) { uint8_t fix = reader.fixQuality(); uint32_t now = millis(); + if (fix > 0) { + if (lastFixStartMsec > 0) { + if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) { + return false; + } else { + clearBuffer(); + } + } else { + lastFixStartMsec = now; + return false; + } + } else { + return false; + } } #endif - // By default, TinyGPS++ does not parse GPGSA lines, which give us // the 2D/3D fixType (see NMEAGPS.h) // At a minimum, use the fixQuality indicator in GPGGA (FIXME?) @@ -1739,6 +1776,12 @@ void GPS::toggleGpsMode() if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED; LOG_INFO("User toggled GpsMode. Now DISABLED.\n"); +#ifdef GNSS_AIROHA + if (powerState == GPS_ACTIVE) { + LOG_DEBUG("User power Off GPS\n"); + digitalWrite(PIN_GPS_EN, LOW); + } +#endif disable(); } else if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_DISABLED) { config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED; diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 7cbf771bcc..87d03c5928 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -69,7 +69,7 @@ class GPS : private concurrency::OSThread #endif private: const int serialSpeeds[6] = {9600, 4800, 38400, 57600, 115200, 9600}; - + uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0; uint32_t rx_gpio = 0; uint32_t tx_gpio = 0; uint32_t en_gpio = 0; diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp index fc059ec16d..1965eef898 100644 --- a/src/mesh/LR11x0Interface.cpp +++ b/src/mesh/LR11x0Interface.cpp @@ -100,7 +100,13 @@ template bool LR11x0Interface::init() // FIXME: May want to set depending on a definition, currently all LR1110 variant files use the DC-DC regulator option if (res == RADIOLIB_ERR_NONE) res = lora.setRegulatorDCDC(); - +#ifdef TRACKER_T1000_E +#ifdef LR11X0_DIO_RF_SWITCH_CONFIG + res = lora.setDioAsRfSwitch(LR11X0_DIO_RF_SWITCH_CONFIG); +#else + res = lora.setDioAsRfSwitch(0x03, 0x0, 0x01, 0x03, 0x02, 0x0, 0x0, 0x0); +#endif +#endif if (res == RADIOLIB_ERR_NONE) { if (config.lora.sx126x_rx_boosted_gain) { // the name is unfortunate but historically accurate res = lora.setRxBoostedGainMode(true); diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 92f90cfdd8..fec1ee4619 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -33,9 +33,7 @@ #include "Sensor/SHT31Sensor.h" #include "Sensor/SHT4XSensor.h" #include "Sensor/SHTC3Sensor.h" -#ifdef T1000X_SENSOR_EN #include "Sensor/T1000xSensor.h" -#endif #include "Sensor/TSL2591Sensor.h" #include "Sensor/VEML7700Sensor.h" @@ -98,7 +96,7 @@ int32_t EnvironmentTelemetryModule::runOnce() LOG_INFO("Environment Telemetry: Initializing\n"); // it's possible to have this module enabled, only for displaying values on the screen. // therefore, we should only enable the sensor loop if measurement is also enabled -#ifdef T1000X_SENSOR_EN // add by WayenWeng +#ifdef T1000X_SENSOR_EN result = t1000xSensor.runOnce(); #else if (dfRobotLarkSensor.hasSensor()) @@ -420,7 +418,11 @@ meshtastic_MeshPacket *EnvironmentTelemetryModule::allocReply() bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) { meshtastic_Telemetry m = meshtastic_Telemetry_init_zero; +#ifdef T1000X_SENSOR_EN + if (t1000xSensor.getMetrics(&m)) { +#else if (getEnvironmentTelemetry(&m)) { +#endif LOG_INFO("(Sending): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f\n", m.variant.environment_metrics.barometric_pressure, m.variant.environment_metrics.current, m.variant.environment_metrics.gas_resistance, m.variant.environment_metrics.relative_humidity, diff --git a/src/modules/Telemetry/Sensor/T1000xSensor.h b/src/modules/Telemetry/Sensor/T1000xSensor.h index 127d2630c5..a1c771cfae 100644 --- a/src/modules/Telemetry/Sensor/T1000xSensor.h +++ b/src/modules/Telemetry/Sensor/T1000xSensor.h @@ -7,7 +7,6 @@ class T1000xSensor : public TelemetrySensor { - private: protected: virtual void setup() override; diff --git a/src/modules/TextMessageModule.cpp b/src/modules/TextMessageModule.cpp index 0f86a6470d..2933718af7 100644 --- a/src/modules/TextMessageModule.cpp +++ b/src/modules/TextMessageModule.cpp @@ -2,8 +2,8 @@ #include "MeshService.h" #include "NodeDB.h" #include "PowerFSM.h" +#include "buzz.h" #include "configuration.h" - TextMessageModule *textMessageModule; ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp) @@ -12,7 +12,6 @@ ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp auto &p = mp.decoded; LOG_INFO("Received text msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes); #endif - // We only store/display messages destined for us. // Keep a copy of the most recent text message. devicestate.rx_text_message = mp; diff --git a/src/sleep.cpp b/src/sleep.cpp index 3793ee0cfa..4e685563a4 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -237,6 +237,25 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false) #ifdef PIN_POWER_EN pinMode(PIN_POWER_EN, INPUT); // power off peripherals // pinMode(PIN_POWER_EN1, INPUT_PULLDOWN); +#endif + +#ifdef TRACKER_T1000_E +#ifdef GNSS_AIROHA + digitalWrite(GPS_VRTC_EN, LOW); + digitalWrite(PIN_GPS_RESET, LOW); + digitalWrite(GPS_SLEEP_INT, LOW); + digitalWrite(GPS_RTC_INT, LOW); + pinMode(GPS_RESETB_OUT, OUTPUT); + digitalWrite(GPS_RESETB_OUT, LOW); +#endif + +#ifdef BUZZER_EN_PIN + digitalWrite(BUZZER_EN_PIN, LOW); +#endif + +#ifdef PIN_3V3_EN + digitalWrite(PIN_3V3_EN, LOW); +#endif #endif setLed(false); diff --git a/variants/tracker-t1000-e/platformio.ini b/variants/tracker-t1000-e/platformio.ini new file mode 100644 index 0000000000..1db57ca298 --- /dev/null +++ b/variants/tracker-t1000-e/platformio.ini @@ -0,0 +1,16 @@ +; tracker-t1000-e v0.9.1 +[env:tracker-t1000-e] +extends = nrf52840_base +board = tracker-t1000-e +; board_level = extra +; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e +build_flags = ${nrf52840_base.build_flags} -Ivariants/tracker-t1000-e -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DTRACKER_T1000_E -DRADIOLIB_GODMODE + -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" + -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. +board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/tracker-t1000-e> +lib_deps = + ${nrf52840_base.lib_deps} +debug_tool = jlink +; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) +upload_protocol = nrfutil diff --git a/variants/tracker-t1000-e/variant.cpp b/variants/tracker-t1000-e/variant.cpp new file mode 100644 index 0000000000..85e0c44f39 --- /dev/null +++ b/variants/tracker-t1000-e/variant.cpp @@ -0,0 +1,64 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + // LED1 & LED2 + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + pinMode(PIN_3V3_EN, OUTPUT); + digitalWrite(PIN_3V3_EN, HIGH); + + pinMode(PIN_3V3_ACC_EN, OUTPUT); + digitalWrite(PIN_3V3_ACC_EN, LOW); + + pinMode(BUZZER_EN_PIN, OUTPUT); + digitalWrite(BUZZER_EN_PIN, HIGH); + + pinMode(PIN_GPS_EN, OUTPUT); + digitalWrite(PIN_GPS_EN, LOW); + + pinMode(GPS_VRTC_EN, OUTPUT); + digitalWrite(GPS_VRTC_EN, HIGH); + + pinMode(PIN_GPS_RESET, OUTPUT); + digitalWrite(PIN_GPS_RESET, LOW); + + pinMode(GPS_SLEEP_INT, OUTPUT); + digitalWrite(GPS_SLEEP_INT, HIGH); + + pinMode(GPS_RTC_INT, OUTPUT); + digitalWrite(GPS_RTC_INT, LOW); + + pinMode(GPS_RESETB_OUT, INPUT); +} \ No newline at end of file diff --git a/variants/tracker-t1000-e/variant.h b/variants/tracker-t1000-e/variant.h new file mode 100644 index 0000000000..75d8ddffc4 --- /dev/null +++ b/variants/tracker-t1000-e/variant.h @@ -0,0 +1,150 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_TRACKER_T1000_E_ +#define _VARIANT_TRACKER_T1000_E_ + +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (6) +#define NUM_ANALOG_OUTPUTS (0) + +#define PIN_3V3_EN (32 + 6) // P1.6, Power to Sensors +#define PIN_3V3_ACC_EN (32 + 7) // P1.7, Power to Acc + +#define PIN_LED1 (0 + 24) // P0.24 +#define LED_PIN PIN_LED1 +#define LED_BUILTIN -1 +#define LED_BLUE -1 // Actually green +#define LED_STATE_ON 1 // State when LED is lit + +#define BUTTON_PIN (0 + 6) // P0.6 +#define BUTTON_ACTIVE_LOW false +#define BUTTON_ACTIVE_PULLUP false +#define BUTTON_SENSE_TYPE 0x6 + +#define HAS_WIRE 1 + +#define WIRE_INTERFACES_COUNT 1 + +// unused pins +#define PIN_WIRE_SDA (0 + 9) // P0.26 +#define PIN_WIRE_SCL (0 + 10) // P0.27 + +/* + * Serial interfaces + */ +#define PIN_SERIAL1_RX (0 + 14) // P0.14 +#define PIN_SERIAL1_TX (0 + 13) // P0.13 + +#define PIN_SERIAL2_RX (0 + 17) // P0.17 +#define PIN_SERIAL2_TX (0 + 16) // P0.16 + +#define SPI_INTERFACES_COUNT 1 + +#define PIN_SPI_MISO (32 + 8) // P1.08 +#define PIN_SPI_MOSI (32 + 9) // P1.09 +#define PIN_SPI_SCK (0 + 11) // P0.11 +#define PIN_SPI_NSS (0 + 12) // P0.12 + +#define LORA_RESET (32 + 10) // P1.10 // RST +#define LORA_DIO1 (32 + 1) // P1.01 // IRQ +#define LORA_DIO2 (0 + 7) // P0.07 // BUSY +#define LORA_SCK PIN_SPI_SCK +#define LORA_MISO PIN_SPI_MISO +#define LORA_MOSI PIN_SPI_MOSI +#define LORA_CS PIN_SPI_NSS + +// supported modules list +#define USE_LR1110 + +#define LR1110_IRQ_PIN LORA_DIO1 +#define LR1110_NRESER_PIN LORA_RESET +#define LR1110_BUSY_PIN LORA_DIO2 +#define LR1110_SPI_NSS_PIN LORA_CS +#define LR1110_SPI_SCK_PIN LORA_SCK +#define LR1110_SPI_MOSI_PIN LORA_MOSI +#define LR1110_SPI_MISO_PIN LORA_MISO + +#define LR11X0_DIO3_TCXO_VOLTAGE 1.6 +#define LR11X0_DIO_AS_RF_SWITCH +#define LR11X0_DIO_RF_SWITCH_CONFIG 0x0f, 0x0, 0x09, 0x0B, 0x0A, 0x0, 0x4, 0x0 + +#define HAS_GPS 1 +#define GNSS_AIROHA +#define GPS_RX_PIN PIN_SERIAL1_RX +#define GPS_TX_PIN PIN_SERIAL1_TX + +#define GPS_BAUDRATE 115200 + +#define PIN_GPS_EN (32 + 11) // P1.11 +#define GPS_EN_ACTIVE HIGH + +#define PIN_GPS_RESET (32 + 15) // P1.15 +#define GPS_RESET_MODE HIGH + +#define GPS_VRTC_EN (0 + 8) // P0.8, awlays high +#define GPS_SLEEP_INT (32 + 12) // P1.12, awlays high +#define GPS_RTC_INT (0 + 15) // P0.15, normal is LOW, wake by HIGH +#define GPS_RESETB_OUT (32 + 14) // P1.14, awlays input pull_up + +#define GPS_FIX_HOLD_TIME 15000 // ms +#define BATTERY_PIN 2 +#define ADC_MULTIPLIER (2.0F) + +#define ADC_RESOLUTION 14 +#define BATTERY_SENSE_RESOLUTION_BITS 12 + +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 + +// Buzzer +#define BUZZER_EN_PIN (32 + 5) // P1.05, awlays high +#define PIN_BUZZER (0 + 25) // P0.25, pwm output + +#define T1000X_SENSOR_EN +#define T1000X_VCC_PIN (0 + 4) // P0.4 +#define T1000X_NTC_PIN (0 + 31) // P0.31 +#define T1000X_LUX_PIN (0 + 29) // P0.29 + +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif // _VARIANT_TRACKER_T1000_E_ diff --git a/variants/wio-t1000-s/variant.h b/variants/wio-t1000-s/variant.h index 86bd34f620..fa6ea4abcf 100644 --- a/variants/wio-t1000-s/variant.h +++ b/variants/wio-t1000-s/variant.h @@ -106,7 +106,7 @@ extern "C" { #define LR11X0_DIO_RF_SWITCH_CONFIG 0x0f, 0x0, 0x09, 0x0B, 0x0A, 0x0, 0x4, 0x0 #define HAS_GPS 1 -#define GNSS_Airoha +#define GNSS_AIROHA #define GPS_RX_PIN PIN_SERIAL1_RX #define GPS_TX_PIN PIN_SERIAL1_TX From c5f2d2736d77f80652963621b621a0c85cdab810 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 24 Jul 2024 21:14:58 -0500 Subject: [PATCH 186/211] Whitespace trunk grousing --- src/ButtonThread.cpp | 2 +- src/gps/GPS.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index d479de6ed2..914ff8e06a 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -42,7 +42,7 @@ ButtonThread::ButtonThread() : OSThread("Button") int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin #if defined(HELTEC_CAPSULE_SENSOR_V3) this->userButton = OneButton(pin, false, false); -#elif defined(BUTTON_ACTIVE_LOW) +#elif defined(BUTTON_ACTIVE_LOW) this->userButton = OneButton(pin, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP); #else this->userButton = OneButton(pin, true, true); diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 494622dc66..aec3d595d4 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1180,7 +1180,7 @@ GnssModel_t GPS::probe(int serialSpeed) _serial_gps->updateBaudRate(serialSpeed); } #endif -#ifdef GNSS_AIROHA +#ifdef GNSS_AIROHA return GNSS_MODEL_UNKNOWN; #else From 1481ce987e405c8856f0b7aa39f98ecd2c48dd1c Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Thu, 25 Jul 2024 20:05:03 +0200 Subject: [PATCH 187/211] Fix T1000-E GPS - some changes went missing from #4303? (#4328) * Update GPS.cpp * Update GPS.cpp * Update GPS.cpp * Update GPS.cpp * Update GPS.cpp * Update GPS.cpp * Update GPS.cpp * Update GPS.cpp * Update GPS.cpp --- src/gps/GPS.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index aec3d595d4..815eb9f0f6 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -400,9 +400,16 @@ bool GPS::setup() int msglen = 0; if (!didSerialInit) { - +#ifdef GNSS_AIROHA if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) { + probe(GPS_BAUDRATE); + LOG_INFO("GPS setting to %d.\n", GPS_BAUDRATE); + } +#else +#if !defined(GPS_UC6580) + if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) { + // if GPS_BAUDRATE is specified in variant (i.e. not 9600), skip to the specified rate. if (speedSelect == 0 && GPS_BAUDRATE != serialSpeeds[speedSelect]) { speedSelect = std::find(serialSpeeds, std::end(serialSpeeds), GPS_BAUDRATE) - serialSpeeds; @@ -423,6 +430,9 @@ bool GPS::setup() } else { gnssModel = GNSS_MODEL_UNKNOWN; } +#else + gnssModel = GNSS_MODEL_UC6580; +#endif if (gnssModel == GNSS_MODEL_MTK) { /* @@ -774,6 +784,7 @@ bool GPS::setup() LOG_INFO("GNSS module configuration saved!\n"); } } +#endif didSerialInit = true; } @@ -1789,4 +1800,4 @@ void GPS::toggleGpsMode() enable(); } } -#endif // Exclude GPS \ No newline at end of file +#endif // Exclude GPS From 7ac64bd7626c389f405ae1c45599f71a6fdf77df Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 25 Jul 2024 13:09:28 -0500 Subject: [PATCH 188/211] Trunk --- src/gps/GPS.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 815eb9f0f6..c50bc7b410 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -409,7 +409,7 @@ bool GPS::setup() #if !defined(GPS_UC6580) if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) { - + // if GPS_BAUDRATE is specified in variant (i.e. not 9600), skip to the specified rate. if (speedSelect == 0 && GPS_BAUDRATE != serialSpeeds[speedSelect]) { speedSelect = std::find(serialSpeeds, std::end(serialSpeeds), GPS_BAUDRATE) - serialSpeeds; From 4b0bbb8af13a67f92e6e1a353b0b8d871b279cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Fri, 26 Jul 2024 03:16:21 +0200 Subject: [PATCH 189/211] Make STM compile again and update toolchain. (#2960) * Make STM compile again and update toolchain. The binary is too big for the flash. WIP * Making progress with OSFS, still WIP * more progress, still too big. Adding RAK3172 to the equasion * Make STM compile again and update toolchain. The binary is too big for the flash. WIP * Making progress with OSFS, still WIP * more progress, still too big. Adding RAK3172 to the equasion * still too big * minimize build * trunk fmt * fix a couple of symbol clashes * trunk fmt * down to 101% with a release vs. debug build and omitting the flash strings * fix compilation * fix compilation once more * update protobufs linkage * - Toolchain updated - Fixed macro error * silence compiler warning note: do something about this assert... * new toolkit and fix Power.cpp * STM32WL make it fit (#4330) * Add option to exclude I2C parts The I2C hals and related code uses a significant amount of flash space and aren't required for a basic node. * Add option to disable Admin and NodeInfo modules Disabled by default in minimal build. This saves a significant amount of flash * Disable unused hals These use up significant flash * Add float support for printf for debugging Makes serial look nice for debugging * This breaks my build for some reason * These build flags can save a bit of flash * Don't disable NodeInfo and Admin modules in minimal build They fit in flash * Don't include printf float support by default Only useful for debugging --------- Co-authored-by: Adam Lawson --------- Co-authored-by: Ben Meadors Co-authored-by: Adam Lawson --- arch/stm32/stm32.ini | 36 ++ arch/stm32/stm32wl5e.ini | 28 -- ...generic_wl5e.json => wiscore_rak3172.json} | 3 + src/FSCommon.cpp | 60 ++- src/FSCommon.h | 11 +- src/Power.cpp | 5 +- src/configuration.h | 1 + src/detect/ScanI2CTwoWire.cpp | 4 +- src/detect/ScanI2CTwoWire.h | 6 +- src/freertosinc.h | 2 +- src/gps/GPS.cpp | 4 +- src/gps/GeoCoord.cpp | 4 +- src/gps/GeoCoord.h | 4 +- src/main.cpp | 15 +- src/mesh/NodeDB.cpp | 16 +- src/mesh/NodeDB.h | 2 +- src/mesh/PhoneAPI.cpp | 8 + src/mesh/STM32WLE5JCInterface.h | 2 +- src/mesh/mesh-pb-constants.cpp | 6 +- src/modules/AdminModule.cpp | 2 + src/modules/CannedMessageModule.cpp | 2 +- src/modules/ExternalNotificationModule.cpp | 2 +- src/modules/Modules.cpp | 10 + src/platform/stm32wl/InternalFileSystem.cpp | 141 ------- src/platform/stm32wl/InternalFileSystem.h | 54 --- src/platform/stm32wl/LittleFS.cpp | 258 ------------- src/platform/stm32wl/LittleFS.h | 85 ---- src/platform/stm32wl/LittleFS_File.cpp | 362 ------------------ src/platform/stm32wl/LittleFS_File.h | 82 ---- src/platform/stm32wl/STM32WLCryptoEngine.cpp | 47 ++- src/platform/stm32wl/main-stm32wl.cpp | 8 - src/xmodem.cpp | 5 +- src/xmodem.h | 3 + variants/rak3172/platformio.ini | 12 + variants/rak3172/variant.h | 12 + variants/wio-e5/platformio.ini | 29 +- variants/wio-e5/variant.h | 1 + 37 files changed, 271 insertions(+), 1061 deletions(-) create mode 100644 arch/stm32/stm32.ini delete mode 100644 arch/stm32/stm32wl5e.ini rename boards/{generic_wl5e.json => wiscore_rak3172.json} (91%) delete mode 100644 src/platform/stm32wl/InternalFileSystem.cpp delete mode 100644 src/platform/stm32wl/InternalFileSystem.h delete mode 100644 src/platform/stm32wl/LittleFS.cpp delete mode 100644 src/platform/stm32wl/LittleFS.h delete mode 100644 src/platform/stm32wl/LittleFS_File.cpp delete mode 100644 src/platform/stm32wl/LittleFS_File.h create mode 100644 variants/rak3172/platformio.ini create mode 100644 variants/rak3172/variant.h diff --git a/arch/stm32/stm32.ini b/arch/stm32/stm32.ini new file mode 100644 index 0000000000..2cea4bbc58 --- /dev/null +++ b/arch/stm32/stm32.ini @@ -0,0 +1,36 @@ +[stm32_base] +extends = arduino_base +platform = ststm32 +platform_packages = platformio/framework-arduinoststm32@https://github.com/stm32duino/Arduino_Core_STM32.git#361a7fdb67e2a7104e99b4f42a802469eef8b129 + +build_type = release + +;board_build.flash_offset = 0x08000000 + +build_flags = + ${arduino_base.build_flags} + -flto + -Isrc/platform/stm32wl -g + -DMESHTASTIC_MINIMIZE_BUILD + -DDEBUG_MUTE +; -DVECT_TAB_OFFSET=0x08000000 + -DconfigUSE_CMSIS_RTOS_V2=1 +; -DSPI_MODE_0=SPI_MODE0 + -fmerge-all-constants + -ffunction-sections + -fdata-sections + +build_src_filter = + ${arduino_base.build_src_filter} - - - - - - - - - - - - - - + +board_upload.offset_address = 0x08000000 +upload_protocol = stlink + +lib_deps = + ${env.lib_deps} + charlesbaynham/OSFS@^1.2.3 + https://github.com/caveman99/Crypto.git#f61ae26a53f7a2d0ba5511625b8bf8eff3a35d5e + +lib_ignore = + mathertel/OneButton + Wire \ No newline at end of file diff --git a/arch/stm32/stm32wl5e.ini b/arch/stm32/stm32wl5e.ini deleted file mode 100644 index 4d74ade8fb..0000000000 --- a/arch/stm32/stm32wl5e.ini +++ /dev/null @@ -1,28 +0,0 @@ -[stm32wl5e_base] -platform_packages = platformio/framework-arduinoststm32 @ https://github.com/stm32duino/Arduino_Core_STM32.git#6e3f9910d0122e82a6c3438507dfac3d2fd80a39 -platform = ststm32 -board = generic_wl5e -framework = arduino - -build_type = debug - -build_flags = - ${arduino_base.build_flags} - -Isrc/platform/stm32wl -g - -DconfigUSE_CMSIS_RTOS_V2=1 - -DVECT_TAB_OFFSET=0x08000000 - -build_src_filter = - ${arduino_base.build_src_filter} - - - - - - - - - - - - - - - -board_upload.offset_address = 0x08000000 -upload_protocol = stlink - -lib_deps = - ${env.lib_deps} - https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b - https://github.com/littlefs-project/littlefs.git#v2.5.1 - https://github.com/stm32duino/STM32FreeRTOS.git#10.3.1 - -lib_ignore = - mathertel/OneButton \ No newline at end of file diff --git a/boards/generic_wl5e.json b/boards/wiscore_rak3172.json similarity index 91% rename from boards/generic_wl5e.json rename to boards/wiscore_rak3172.json index 5c4bc24a75..714e09115e 100644 --- a/boards/generic_wl5e.json +++ b/boards/wiscore_rak3172.json @@ -1,5 +1,8 @@ { "build": { + "arduino": { + "variant_h": "variant_RAK3172_MODULE.h" + }, "core": "stm32", "cpu": "cortex-m4", "extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_GENERIC_WLE5CCUX", diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp index 7d3788c4d9..3017ec085c 100644 --- a/src/FSCommon.cpp +++ b/src/FSCommon.cpp @@ -24,6 +24,30 @@ SPIClass SPI1(HSPI); #endif // HAS_SDCARD +#if defined(ARCH_STM32WL) + +uint16_t OSFS::startOfEEPROM = 1; +uint16_t OSFS::endOfEEPROM = 2048; + +// 3) How do I read from the medium? +void OSFS::readNBytes(uint16_t address, unsigned int num, byte *output) +{ + for (uint16_t i = address; i < address + num; i++) { + *output = EEPROM.read(i); + output++; + } +} + +// 4) How to I write to the medium? +void OSFS::writeNBytes(uint16_t address, unsigned int num, const byte *input) +{ + for (uint16_t i = address; i < address + num; i++) { + EEPROM.update(i, *input); + input++; + } +} +#endif + /** * @brief Copies a file from one location to another. * @@ -33,7 +57,33 @@ SPIClass SPI1(HSPI); */ bool copyFile(const char *from, const char *to) { -#ifdef FSCom +#ifdef ARCH_STM32WL + unsigned char cbuffer[2048]; + + // Var to hold the result of actions + OSFS::result r; + + r = OSFS::getFile(from, cbuffer); + + if (r == notfound) { + LOG_ERROR("Failed to open source file %s\n", from); + return false; + } else if (r == noerr) { + r = OSFS::newFile(to, cbuffer, true); + if (r == noerr) { + return true; + } else { + LOG_ERROR("OSFS Error %d\n", r); + return false; + } + + } else { + LOG_ERROR("OSFS Error %d\n", r); + return false; + } + return true; + +#elif defined(FSCom) unsigned char cbuffer[16]; File f1 = FSCom.open(from, FILE_O_READ); @@ -70,7 +120,13 @@ bool copyFile(const char *from, const char *to) */ bool renameFile(const char *pathFrom, const char *pathTo) { -#ifdef FSCom +#ifdef ARCH_STM32WL + if (copyFile(pathFrom, pathTo) && (OSFS::deleteFile(pathFrom) == OSFS::result::NO_ERROR)) { + return true; + } else { + return false; + } +#elif defined(FSCom) #ifdef ARCH_ESP32 // rename was fixed for ESP32 IDF LittleFS in April return FSCom.rename(pathFrom, pathTo); diff --git a/src/FSCommon.h b/src/FSCommon.h index 8fbabd9526..3d485d1b1d 100644 --- a/src/FSCommon.h +++ b/src/FSCommon.h @@ -15,10 +15,13 @@ #endif #if defined(ARCH_STM32WL) -#include "platform/stm32wl/InternalFileSystem.h" // STM32WL version -#define FSCom InternalFS -#define FSBegin() FSCom.begin() -using namespace LittleFS_Namespace; +// STM32WL series 2 Kbytes (8 rows of 256 bytes) +#include +#include + +// Useful consts +const OSFS::result noerr = OSFS::result::NO_ERROR; +const OSFS::result notfound = OSFS::result::FILE_NOT_FOUND; #endif #if defined(ARCH_RP2040) diff --git a/src/Power.cpp b/src/Power.cpp index 19c5c99375..138b06e719 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -200,7 +200,8 @@ class AnalogBatteryLevel : public HasBatteryLevel } #endif -#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR +#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(HAS_PMU) && \ + !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR if (hasINA()) { LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address); return getINAVoltage(); @@ -420,7 +421,7 @@ class AnalogBatteryLevel : public HasBatteryLevel } #endif -#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO) +#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) uint16_t getINAVoltage() { if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) { diff --git a/src/configuration.h b/src/configuration.h index 6351c35b18..b298d54243 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -259,6 +259,7 @@ along with this program. If not, see . #define MESHTASTIC_EXCLUDE_SCREEN 1 #define MESHTASTIC_EXCLUDE_MQTT 1 #define MESHTASTIC_EXCLUDE_POWERMON 1 +#define MESHTASTIC_EXCLUDE_I2C 1 #endif // Turn off all optional modules diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 8738e2722d..b831b0e719 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -1,7 +1,8 @@ #include "ScanI2CTwoWire.h" +#if !MESHTASTIC_EXCLUDE_I2C + #include "concurrency/LockGuard.h" -#include "configuration.h" #if defined(ARCH_PORTDUINO) #include "linux/LinuxHardwareI2C.h" #endif @@ -403,3 +404,4 @@ size_t ScanI2CTwoWire::countDevices() const { return foundDevices.size(); } +#endif \ No newline at end of file diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index 82b48f6b47..c8dd96469a 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -1,5 +1,8 @@ #pragma once +#include "configuration.h" +#if !MESHTASTIC_EXCLUDE_I2C + #include #include #include @@ -55,4 +58,5 @@ class ScanI2CTwoWire : public ScanI2C uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const; DeviceType probeOLED(ScanI2C::DeviceAddress) const; -}; \ No newline at end of file +}; +#endif \ No newline at end of file diff --git a/src/freertosinc.h b/src/freertosinc.h index 166054241c..e9e6cd53a0 100644 --- a/src/freertosinc.h +++ b/src/freertosinc.h @@ -12,7 +12,7 @@ #include #endif -#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_RP2040) +#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_RP2040) #define HAS_FREE_RTOS #include diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index c50bc7b410..67f6adb98d 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -1182,7 +1182,7 @@ int GPS::prepareDeepSleep(void *unused) GnssModel_t GPS::probe(int serialSpeed) { -#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040) +#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040) || defined(ARCH_STM32WL) _serial_gps->end(); _serial_gps->begin(serialSpeed); #else @@ -1270,7 +1270,7 @@ GnssModel_t GPS::probe(int serialSpeed) _serial_gps->write(_message_prt, sizeof(_message_prt)); delay(500); serialSpeed = 9600; -#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040) +#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040) || defined(ARCH_STM32WL) _serial_gps->end(); _serial_gps->begin(serialSpeed); #else diff --git a/src/gps/GeoCoord.cpp b/src/gps/GeoCoord.cpp index 2224bd2816..5abb25a06c 100644 --- a/src/gps/GeoCoord.cpp +++ b/src/gps/GeoCoord.cpp @@ -493,7 +493,7 @@ std::shared_ptr GeoCoord::pointAtDistance(double bearing, double range * The bearing in string format * @return Bearing in degrees */ -uint GeoCoord::bearingToDegrees(const char *bearing) +unsigned int GeoCoord::bearingToDegrees(const char *bearing) { if (strcmp(bearing, "N") == 0) return 0; @@ -537,7 +537,7 @@ uint GeoCoord::bearingToDegrees(const char *bearing) * The bearing in degrees * @return Bearing in string format */ -const char *GeoCoord::degreesToBearing(uint degrees) +const char *GeoCoord::degreesToBearing(unsigned int degrees) { if (degrees >= 348 || degrees < 11) return "N"; diff --git a/src/gps/GeoCoord.h b/src/gps/GeoCoord.h index b02d12afb8..ecdaf0ec7b 100644 --- a/src/gps/GeoCoord.h +++ b/src/gps/GeoCoord.h @@ -117,8 +117,8 @@ class GeoCoord static float bearing(double lat1, double lon1, double lat2, double lon2); static float rangeRadiansToMeters(double range_radians); static float rangeMetersToRadians(double range_meters); - static uint bearingToDegrees(const char *bearing); - static const char *degreesToBearing(uint degrees); + static unsigned int bearingToDegrees(const char *bearing); + static const char *degreesToBearing(unsigned int degrees); // Point to point conversions int32_t distanceTo(const GeoCoord &pointB); diff --git a/src/main.cpp b/src/main.cpp index 1879423449..dc5863bbc2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,7 +20,11 @@ #include "concurrency/OSThread.h" #include "concurrency/Periodic.h" #include "detect/ScanI2C.h" + +#if !MESHTASTIC_EXCLUDE_I2C #include "detect/ScanI2CTwoWire.h" +#include +#endif #include "detect/axpDebug.h" #include "detect/einkScan.h" #include "graphics/RAKled.h" @@ -31,7 +35,6 @@ #include "shutdown.h" #include "sleep.h" #include "target_specific.h" -#include #include #include // #include @@ -159,8 +162,10 @@ bool pauseBluetoothLogging = false; bool pmu_found; +#if !MESHTASTIC_EXCLUDE_I2C // Array map of sensor types with i2c address and wire as we'll find in the i2c scan std::pair nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1] = {}; +#endif Router *router = NULL; // Users of router don't care what sort of subclass implements that API @@ -349,6 +354,7 @@ void setup() #endif +#if !MESHTASTIC_EXCLUDE_I2C #if defined(I2C_SDA1) && defined(ARCH_RP2040) Wire1.setSDA(I2C_SDA1); Wire1.setSCL(I2C_SCL1); @@ -373,6 +379,7 @@ void setup() #elif HAS_WIRE Wire.begin(); #endif +#endif #ifdef PIN_LCD_RESET // FIXME - move this someplace better, LCD is at address 0x3F @@ -405,6 +412,7 @@ void setup() powerStatus->observe(&power->newStatus); power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration +#if !MESHTASTIC_EXCLUDE_I2C // We need to scan here to decide if we have a screen for nodeDB.init() and because power has been applied to // accessories auto i2cScanner = std::unique_ptr(new ScanI2CTwoWire()); @@ -560,6 +568,7 @@ void setup() SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK) i2cScanner.reset(); +#endif #ifdef HAS_SDCARD setupSDCard(); @@ -620,6 +629,7 @@ void setup() screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // keep dimension of 128x64 #endif +#if !MESHTASTIC_EXCLUDE_I2C #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR if (acc_info.type != ScanI2C::DeviceType::NONE) { config.display.wake_on_tap_or_motion = true; @@ -635,6 +645,7 @@ void setup() ambientLightingThread = new AmbientLightingThread(rgb_found.type); } #endif +#endif #ifdef T_WATCH_S3 drv.begin(); @@ -721,6 +732,7 @@ void setup() RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_NO_AXP192); // Record a hardware fault for missing hardware #endif +#if !MESHTASTIC_EXCLUDE_I2C // Don't call screen setup until after nodedb is setup (because we need // the current region name) #if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || \ @@ -733,6 +745,7 @@ void setup() #else if (screen_found.port != ScanI2C::I2CPort::NO_I2C) screen->setup(); +#endif #endif screen->print("Started...\n"); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index c0bed34371..4257837b33 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -192,9 +192,11 @@ bool NodeDB::factoryReset() LOG_INFO("Performing factory reset!\n"); // first, remove the "/prefs" (this removes most prefs) rmDir("/prefs"); +#ifdef FSCom if (FSCom.exists("/static/rangetest.csv") && !FSCom.remove("/static/rangetest.csv")) { LOG_ERROR("Could not remove rangetest.csv file\n"); } +#endif // second, install default state (this will deal with the duplicate mac address issue) installDefaultDeviceState(); installDefaultConfig(); @@ -574,7 +576,7 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t state = LoadFileResult::DECODE_FAILED; } else { LOG_INFO("Loaded %s successfully\n", filename); - state = LoadFileResult::SUCCESS; + state = LoadFileResult::LOAD_SUCCESS; } f.close(); } else { @@ -582,7 +584,7 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t } #else LOG_ERROR("ERROR: Filesystem not implemented\n"); - state = LoadFileState::NO_FILESYSTEM; + state = LoadFileResult::NO_FILESYSTEM; #endif return state; } @@ -593,7 +595,7 @@ void NodeDB::loadFromDisk() auto state = loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES * sizeof(meshtastic_NodeInfo), sizeof(meshtastic_DeviceState), &meshtastic_DeviceState_msg, &devicestate); - if (state != LoadFileResult::SUCCESS) { + if (state != LoadFileResult::LOAD_SUCCESS) { installDefaultDeviceState(); // Our in RAM copy might now be corrupt } else { if (devicestate.version < DEVICESTATE_MIN_VER) { @@ -610,7 +612,7 @@ void NodeDB::loadFromDisk() state = loadProto(configFileName, meshtastic_LocalConfig_size, sizeof(meshtastic_LocalConfig), &meshtastic_LocalConfig_msg, &config); - if (state != LoadFileResult::SUCCESS) { + if (state != LoadFileResult::LOAD_SUCCESS) { installDefaultConfig(); // Our in RAM copy might now be corrupt } else { if (config.version < DEVICESTATE_MIN_VER) { @@ -623,7 +625,7 @@ void NodeDB::loadFromDisk() state = loadProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, sizeof(meshtastic_LocalModuleConfig), &meshtastic_LocalModuleConfig_msg, &moduleConfig); - if (state != LoadFileResult::SUCCESS) { + if (state != LoadFileResult::LOAD_SUCCESS) { installDefaultModuleConfig(); // Our in RAM copy might now be corrupt } else { if (moduleConfig.version < DEVICESTATE_MIN_VER) { @@ -636,7 +638,7 @@ void NodeDB::loadFromDisk() state = loadProto(channelFileName, meshtastic_ChannelFile_size, sizeof(meshtastic_ChannelFile), &meshtastic_ChannelFile_msg, &channelFile); - if (state != LoadFileResult::SUCCESS) { + if (state != LoadFileResult::LOAD_SUCCESS) { installDefaultChannels(); // Our in RAM copy might now be corrupt } else { if (channelFile.version < DEVICESTATE_MIN_VER) { @@ -648,7 +650,7 @@ void NodeDB::loadFromDisk() } state = loadProto(oemConfigFile, meshtastic_OEMStore_size, sizeof(meshtastic_OEMStore), &meshtastic_OEMStore_msg, &oemStore); - if (state == LoadFileResult::SUCCESS) { + if (state == LoadFileResult::LOAD_SUCCESS) { LOG_INFO("Loaded OEMStore\n"); } diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 5207d8629b..258b7276dd 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -40,7 +40,7 @@ uint32_t sinceReceived(const meshtastic_MeshPacket *p); enum LoadFileResult { // Successfully opened the file - SUCCESS = 1, + LOAD_SUCCESS = 1, // File does not exist NOT_FOUND = 2, // Device does not have a filesystem diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 0b63b4a581..f0775741a7 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -42,7 +42,9 @@ void PhoneAPI::handleStartConfig() if (!isConnected()) { onConnectionChanged(true); observe(&service.fromNumChanged); +#ifdef FSCom observe(&xModem.packetReady); +#endif } // even if we were already connected - restart our state machine @@ -62,7 +64,9 @@ void PhoneAPI::close() state = STATE_SEND_NOTHING; unobserve(&service.fromNumChanged); +#ifdef FSCom unobserve(&xModem.packetReady); +#endif releasePhonePacket(); // Don't leak phone packets on shutdown releaseQueueStatusPhonePacket(); releaseMqttClientProxyPhonePacket(); @@ -110,7 +114,9 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) break; case meshtastic_ToRadio_xmodemPacket_tag: LOG_INFO("Got xmodem packet\n"); +#ifdef FSCom xModem.handlePacket(toRadioScratch.xmodemPacket); +#endif break; #if !MESHTASTIC_EXCLUDE_MQTT case meshtastic_ToRadio_mqttClientProxyMessage_tag: @@ -496,12 +502,14 @@ bool PhoneAPI::available() if (hasPacket) return true; +#ifdef FSCom if (xmodemPacketForPhone.control == meshtastic_XModem_Control_NUL) xmodemPacketForPhone = xModem.getForPhone(); if (xmodemPacketForPhone.control != meshtastic_XModem_Control_NUL) { xModem.resetForPhone(); return true; } +#endif #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_STOREFORWARD diff --git a/src/mesh/STM32WLE5JCInterface.h b/src/mesh/STM32WLE5JCInterface.h index 73d53d92f9..fad7933329 100644 --- a/src/mesh/STM32WLE5JCInterface.h +++ b/src/mesh/STM32WLE5JCInterface.h @@ -23,7 +23,7 @@ static const float tcxoVoltage = 1.7; * Wio-E5 module ONLY transmits through RFO_HP * Receive: PA4=1, PA5=0 * Transmit(high output power, SMPS mode): PA4=0, PA5=1 */ -static const RADIOLIB_PIN_TYPE rfswitch_pins[3] = {PA4, PA5, RADIOLIB_NC}; +static const RADIOLIB_PIN_TYPE rfswitch_pins[5] = {PA4, PA5, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC}; static const Module::RfSwitchMode_t rfswitch_table[4] = { {STM32WLx::MODE_IDLE, {LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, LOW}}, {STM32WLx::MODE_TX_HP, {LOW, HIGH}}, END_OF_MODE_TABLE}; diff --git a/src/mesh/mesh-pb-constants.cpp b/src/mesh/mesh-pb-constants.cpp index 93dbf0178b..676208e25a 100644 --- a/src/mesh/mesh-pb-constants.cpp +++ b/src/mesh/mesh-pb-constants.cpp @@ -1,6 +1,7 @@ -#include "mesh-pb-constants.h" -#include "FSCommon.h" #include "configuration.h" + +#include "FSCommon.h" +#include "mesh-pb-constants.h" #include #include #include @@ -15,6 +16,7 @@ size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc LOG_ERROR("Panic: can't encode protobuf reason='%s'\n", PB_GET_ERROR(&stream)); assert( 0); // If this assert fails it probably means you made a field too large for the max limits specified in mesh.options + return 0; } else { return stream.bytes_written; } diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 98b789f41d..8939b972b9 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -259,11 +259,13 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta } case meshtastic_AdminMessage_delete_file_request_tag: { LOG_DEBUG("Client is requesting to delete file: %s\n", r->delete_file_request); +#ifdef FSCom if (FSCom.remove(r->delete_file_request)) { LOG_DEBUG("Successfully deleted file\n"); } else { LOG_DEBUG("Failed to delete file\n"); } +#endif break; } #ifdef ARCH_PORTDUINO diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index 84b5a3260e..524d37a3d9 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -1066,7 +1066,7 @@ void CannedMessageModule::loadProtoForModule() { if (nodeDB->loadProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, sizeof(meshtastic_CannedMessageModuleConfig), &meshtastic_CannedMessageModuleConfig_msg, - &cannedMessageModuleConfig) != LoadFileResult::SUCCESS) { + &cannedMessageModuleConfig) != LoadFileResult::LOAD_SUCCESS) { installDefaultCannedMessageModuleConfig(); } } diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index c025592401..652db04d3d 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -355,7 +355,7 @@ ExternalNotificationModule::ExternalNotificationModule() if (moduleConfig.external_notification.enabled) { if (nodeDB->loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig), - &meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::SUCCESS) { + &meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) { memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone)); strncpy(rtttlConfig.ringtone, "24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p", diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index 300afc2460..5a0e36fea2 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -7,7 +7,9 @@ #include "input/cardKbI2cImpl.h" #include "input/kbMatrixImpl.h" #endif +#if !MESHTASTIC_EXCLUDE_ADMIN #include "modules/AdminModule.h" +#endif #if !MESHTASTIC_EXCLUDE_ATAK #include "modules/AtakPluginModule.h" #endif @@ -20,7 +22,9 @@ #if !MESHTASTIC_EXCLUDE_NEIGHBORINFO #include "modules/NeighborInfoModule.h" #endif +#if !MESHTASTIC_EXCLUDE_NODEINFO #include "modules/NodeInfoModule.h" +#endif #if !MESHTASTIC_EXCLUDE_GPS #include "modules/PositionModule.h" #endif @@ -88,8 +92,12 @@ void setupModules() #if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER inputBroker = new InputBroker(); #endif +#if !MESHTASTIC_EXCLUDE_ADMIN adminModule = new AdminModule(); +#endif +#if !MESHTASTIC_EXCLUDE_NODEINFO nodeInfoModule = new NodeInfoModule(); +#endif #if !MESHTASTIC_EXCLUDE_GPS positionModule = new PositionModule(); #endif @@ -192,7 +200,9 @@ void setupModules() #endif #endif } else { +#if !MESHTASTIC_EXCLUDE_ADMIN adminModule = new AdminModule(); +#endif #if HAS_TELEMETRY new DeviceTelemetryModule(); #endif diff --git a/src/platform/stm32wl/InternalFileSystem.cpp b/src/platform/stm32wl/InternalFileSystem.cpp deleted file mode 100644 index d42a646a56..0000000000 --- a/src/platform/stm32wl/InternalFileSystem.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 hathach for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "InternalFileSystem.h" -#include - -//--------------------------------------------------------------------+ -// LFS Disk IO -//--------------------------------------------------------------------+ - -static inline uint32_t lba2addr(uint32_t block) -{ - return ((uint32_t)LFS_FLASH_ADDR) + block * LFS_BLOCK_SIZE; -} - -static int _internal_flash_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) -{ - (void)c; - - uint32_t addr = lba2addr(block) + off; - uint8_t prom; - - for (int i = 0; i < size; i++) { - prom = EEPROM.read(addr + i); - memcpy((char *)buffer + i, &prom, 1); - } - return 0; -} - -// Program a region in a block. The block must have previously -// been erased. Negative error codes are propagated to the user. -// May return LFS_ERR_CORRUPT if the block should be considered bad. -static int _internal_flash_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) -{ - (void)c; - - uint32_t addr = lba2addr(block) + off; - uint8_t prom; - - for (int i = 0; i < size; i++) { - memcpy(&prom, (char *)buffer + i, 1); - EEPROM.update(addr + i, prom); - } - return 0; -} - -// Erase a block. A block must be erased before being programmed. -// The state of an erased block is undefined. Negative error codes -// are propagated to the user. -// May return LFS_ERR_CORRUPT if the block should be considered bad. -static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block) -{ - (void)c; - - uint32_t addr = lba2addr(block); - - // implement as write 0xff to whole block address - for (int i = 0; i < LFS_BLOCK_SIZE; i++) { - EEPROM.update(addr, 0xff); - } - - return 0; -} - -// Sync the state of the underlying block device. Negative error codes -// are propagated to the user. -static int _internal_flash_sync(const struct lfs_config *c) -{ - // we don't use a ram cache, this is a noop - return 0; -} - -static struct lfs_config _InternalFSConfig = {.context = NULL, - - .read = _internal_flash_read, - .prog = _internal_flash_prog, - .erase = _internal_flash_erase, - .sync = _internal_flash_sync, - - .read_size = LFS_CACHE_SIZE, - .prog_size = LFS_CACHE_SIZE, - .block_size = LFS_BLOCK_SIZE, - .block_count = LFS_FLASH_TOTAL_SIZE / LFS_BLOCK_SIZE, - .block_cycles = - 500, // protection against wear leveling (suggested values between 100-1000) - .cache_size = LFS_CACHE_SIZE, - .lookahead_size = LFS_CACHE_SIZE, - - .read_buffer = lfs_read_buffer, - .prog_buffer = lfs_prog_buffer, - .lookahead_buffer = lfs_lookahead_buffer}; - -InternalFileSystem InternalFS; - -//--------------------------------------------------------------------+ -// -//--------------------------------------------------------------------+ - -InternalFileSystem::InternalFileSystem(void) : LittleFS(&_InternalFSConfig) {} - -bool InternalFileSystem::begin(void) -{ - // failed to mount, erase all sector then format and mount again - if (!LittleFS::begin()) { - // Erase all sectors of internal flash region for Filesystem. - // implement as write 0xff to whole block address - for (uint32_t addr = LFS_FLASH_ADDR; addr < (LFS_FLASH_ADDR + LFS_FLASH_TOTAL_SIZE); addr++) { - EEPROM.update(addr, 0xff); - } - - // lfs format - this->format(); - - // mount again if still failed, give up - if (!LittleFS::begin()) - return false; - } - - return true; -} diff --git a/src/platform/stm32wl/InternalFileSystem.h b/src/platform/stm32wl/InternalFileSystem.h deleted file mode 100644 index 66344194e1..0000000000 --- a/src/platform/stm32wl/InternalFileSystem.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2019 hathach for Adafruit Industries - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef INTERNALFILESYSTEM_H_ -#define INTERNALFILESYSTEM_H_ - -#include "LittleFS.h" - -// The EEPROM Library assumes our usable flash area starts at logical 0 -#define LFS_FLASH_ADDR 0 - -// use the built in EEPROM emulation. Total Size is 2Kbyte -#define LFS_BLOCK_SIZE 128 // min. block size is 128 to fit CTZ pointers -#define LFS_CACHE_SIZE 16 - -#define LFS_FLASH_TOTAL_SIZE FLASH_PAGE_SIZE - -static uint8_t lfs_read_buffer[LFS_CACHE_SIZE] = {0}; -static uint8_t lfs_prog_buffer[LFS_CACHE_SIZE] = {0}; -static uint8_t lfs_lookahead_buffer[LFS_CACHE_SIZE] = {0}; - -class InternalFileSystem : public LittleFS -{ - public: - InternalFileSystem(void); - - // overwrite to also perform low level format (sector erase of whole flash region) - bool begin(void); -}; - -extern InternalFileSystem InternalFS; - -#endif /* INTERNALFILESYSTEM_H_ */ diff --git a/src/platform/stm32wl/LittleFS.cpp b/src/platform/stm32wl/LittleFS.cpp deleted file mode 100644 index b1267d88a6..0000000000 --- a/src/platform/stm32wl/LittleFS.cpp +++ /dev/null @@ -1,258 +0,0 @@ -#include -#include - -#include "LittleFS.h" - -using namespace LittleFS_Namespace; - -//--------------------------------------------------------------------+ -// Implementation -//--------------------------------------------------------------------+ - -LittleFS::LittleFS(void) : LittleFS(NULL) {} - -LittleFS::LittleFS(struct lfs_config *cfg) -{ - memset(&_lfs, 0, sizeof(_lfs)); - _lfs_cfg = cfg; - _mounted = false; - _mutex = xSemaphoreCreateMutexStatic(&this->_MutexStorageSpace); -} - -LittleFS::~LittleFS() {} - -// Initialize and mount the file system -// Return true if mounted successfully else probably corrupted. -// User should format the disk and try again -bool LittleFS::begin(struct lfs_config *cfg) -{ - _lockFS(); - - bool ret; - // not a loop, just an quick way to short-circuit on error - do { - if (_mounted) { - ret = true; - break; - } - if (cfg) { - _lfs_cfg = cfg; - } - if (nullptr == _lfs_cfg) { - ret = false; - break; - } - // actually attempt to mount, and log error if one occurs - int err = lfs_mount(&_lfs, _lfs_cfg); - PRINT_LFS_ERR(err); - _mounted = (err == LFS_ERR_OK); - ret = _mounted; - } while (0); - - _unlockFS(); - return ret; -} - -// Tear down and unmount file system -void LittleFS::end(void) -{ - _lockFS(); - - if (_mounted) { - _mounted = false; - int err = lfs_unmount(&_lfs); - PRINT_LFS_ERR(err); - (void)err; - } - - _unlockFS(); -} - -bool LittleFS::format(void) -{ - _lockFS(); - - int err = LFS_ERR_OK; - bool attemptMount = _mounted; - // not a loop, just an quick way to short-circuit on error - do { - // if already mounted: umount first -> format -> remount - if (_mounted) { - _mounted = false; - err = lfs_unmount(&_lfs); - if (LFS_ERR_OK != err) { - PRINT_LFS_ERR(err); - break; - } - } - err = lfs_format(&_lfs, _lfs_cfg); - if (LFS_ERR_OK != err) { - PRINT_LFS_ERR(err); - break; - } - - if (attemptMount) { - err = lfs_mount(&_lfs, _lfs_cfg); - if (LFS_ERR_OK != err) { - PRINT_LFS_ERR(err); - break; - } - _mounted = true; - } - // success! - } while (0); - - _unlockFS(); - return LFS_ERR_OK == err; -} - -// Open a file or folder -LittleFS_Namespace::File LittleFS::open(char const *filepath, uint8_t mode) -{ - // No lock is required here ... the File() object will synchronize with the mutex provided - return LittleFS_Namespace::File(filepath, mode, *this); -} - -// Check if file or folder exists -bool LittleFS::exists(char const *filepath) -{ - struct lfs_info info; - _lockFS(); - - bool ret = (0 == lfs_stat(&_lfs, filepath, &info)); - - _unlockFS(); - return ret; -} - -// Create a directory, create intermediate parent if needed -bool LittleFS::mkdir(char const *filepath) -{ - bool ret = true; - const char *slash = filepath; - if (slash[0] == '/') - slash++; // skip root '/' - - _lockFS(); - - // make intermediate parent directory(ies) - while (NULL != (slash = strchr(slash, '/'))) { - char parent[slash - filepath + 1] = {0}; - memcpy(parent, filepath, slash - filepath); - - int rc = lfs_mkdir(&_lfs, parent); - if (rc != LFS_ERR_OK && rc != LFS_ERR_EXIST) { - PRINT_LFS_ERR(rc); - ret = false; - break; - } - slash++; - } - // make the final requested directory - if (ret) { - int rc = lfs_mkdir(&_lfs, filepath); - if (rc != LFS_ERR_OK && rc != LFS_ERR_EXIST) { - PRINT_LFS_ERR(rc); - ret = false; - } - } - - _unlockFS(); - return ret; -} - -// Remove a file -bool LittleFS::remove(char const *filepath) -{ - _lockFS(); - - int err = lfs_remove(&_lfs, filepath); - PRINT_LFS_ERR(err); - - _unlockFS(); - return LFS_ERR_OK == err; -} - -// Rename a file -bool LittleFS::rename(char const *oldfilepath, char const *newfilepath) -{ - _lockFS(); - - int err = lfs_rename(&_lfs, oldfilepath, newfilepath); - PRINT_LFS_ERR(err); - - _unlockFS(); - return LFS_ERR_OK == err; -} - -// Remove a folder -bool LittleFS::rmdir(char const *filepath) -{ - _lockFS(); - - int err = lfs_remove(&_lfs, filepath); - PRINT_LFS_ERR(err); - - _unlockFS(); - return LFS_ERR_OK == err; -} - -// Remove a folder recursively -bool LittleFS::rmdir_r(char const *filepath) -{ - /* adafruit: lfs is modified to remove non-empty folder, - According to below issue, comment these 2 line won't corrupt filesystem - at least when using LFS v1. If moving to LFS v2, see tracked issue - to see if issues (such as the orphans in threaded linked list) are resolved. - https://github.com/ARMmbed/littlefs/issues/43 - */ - _lockFS(); - - int err = lfs_remove(&_lfs, filepath); - PRINT_LFS_ERR(err); - - _unlockFS(); - return LFS_ERR_OK == err; -} - -//------------- Debug -------------// -#if CFG_DEBUG - -const char *dbg_strerr_lfs(int32_t err) -{ - switch (err) { - case LFS_ERR_OK: - return "LFS_ERR_OK"; - case LFS_ERR_IO: - return "LFS_ERR_IO"; - case LFS_ERR_CORRUPT: - return "LFS_ERR_CORRUPT"; - case LFS_ERR_NOENT: - return "LFS_ERR_NOENT"; - case LFS_ERR_EXIST: - return "LFS_ERR_EXIST"; - case LFS_ERR_NOTDIR: - return "LFS_ERR_NOTDIR"; - case LFS_ERR_ISDIR: - return "LFS_ERR_ISDIR"; - case LFS_ERR_NOTEMPTY: - return "LFS_ERR_NOTEMPTY"; - case LFS_ERR_BADF: - return "LFS_ERR_BADF"; - case LFS_ERR_INVAL: - return "LFS_ERR_INVAL"; - case LFS_ERR_NOSPC: - return "LFS_ERR_NOSPC"; - case LFS_ERR_NOMEM: - return "LFS_ERR_NOMEM"; - - default: - static char errcode[10]; - sprintf(errcode, "%ld", err); - return errcode; - } - - return NULL; -} - -#endif diff --git a/src/platform/stm32wl/LittleFS.h b/src/platform/stm32wl/LittleFS.h deleted file mode 100644 index 4a0b01af2b..0000000000 --- a/src/platform/stm32wl/LittleFS.h +++ /dev/null @@ -1,85 +0,0 @@ - -#ifndef LITTLEFS_H_ -#define LITTLEFS_H_ - -#include - -#include "lfs.h" - -#include "LittleFS_File.h" - -#include "FreeRTOS.h" // tied to FreeRTOS for serialization -#include "semphr.h" - -class LittleFS -{ - public: - LittleFS(void); - explicit LittleFS(struct lfs_config *cfg); - virtual ~LittleFS(); - - bool begin(struct lfs_config *cfg = NULL); - void end(void); - - // Open the specified file/directory with the supplied mode (e.g. read or - // write, etc). Returns a File object for interacting with the file. - // Note that currently only one file can be open at a time. - LittleFS_Namespace::File open(char const *filename, uint8_t mode = LittleFS_Namespace::FILE_O_READ); - - // Methods to determine if the requested file path exists. - bool exists(char const *filepath); - - // Create the requested directory hierarchy--if intermediate directories - // do not exist they will be created. - bool mkdir(char const *filepath); - - // Delete the file. - bool remove(char const *filepath); - - // Rename the file. - bool rename(char const *oldfilepath, char const *newfilepath); - - // Delete a folder (must be empty) - bool rmdir(char const *filepath); - - // Delete a folder (recursively) - bool rmdir_r(char const *filepath); - - // format file system - bool format(void); - - /*------------------------------------------------------------------*/ - /* INTERNAL USAGE ONLY - * Although declare as public, it is meant to be invoked by internal - * code. User should not call these directly - *------------------------------------------------------------------*/ - lfs_t *_getFS(void) { return &_lfs; } - void _lockFS(void) { xSemaphoreTake(_mutex, portMAX_DELAY); } - void _unlockFS(void) { xSemaphoreGive(_mutex); } - - protected: - bool _mounted; - struct lfs_config *_lfs_cfg; - lfs_t _lfs; - SemaphoreHandle_t _mutex; - - private: - StaticSemaphore_t _MutexStorageSpace; -}; - -#if !CFG_DEBUG -#define VERIFY_LFS(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, NULL) -#define PRINT_LFS_ERR(_err) -#else -#define VERIFY_LFS(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, dbg_strerr_lfs) -#define PRINT_LFS_ERR(_err) \ - do { \ - if (_err) { \ - VERIFY_MESS((long int)_err, dbg_strerr_lfs); \ - } \ - } while (0) // LFS_ERR are of type int, VERIFY_MESS expects long_int - -const char *dbg_strerr_lfs(int32_t err); -#endif - -#endif /* LITTLEFS_H_ */ diff --git a/src/platform/stm32wl/LittleFS_File.cpp b/src/platform/stm32wl/LittleFS_File.cpp deleted file mode 100644 index 548a3d3009..0000000000 --- a/src/platform/stm32wl/LittleFS_File.cpp +++ /dev/null @@ -1,362 +0,0 @@ -#include - -#include "LittleFS.h" - -#include - -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM DECLARATION -//--------------------------------------------------------------------+ - -using namespace LittleFS_Namespace; - -File::File(LittleFS &fs) -{ - _fs = &fs; - _is_dir = false; - _name[0] = 0; - _dir_path = NULL; - - _dir = NULL; - _file = NULL; -} - -File::File(char const *filename, uint8_t mode, LittleFS &fs) : File(fs) -{ - // public constructor calls public API open(), which will obtain the mutex - this->open(filename, mode); -} - -bool File::_open_file(char const *filepath, uint8_t mode) -{ - int flags = (mode == FILE_O_READ) ? LFS_O_RDONLY : (mode == FILE_O_WRITE) ? (LFS_O_RDWR | LFS_O_CREAT) : 0; - - if (flags) { - _file = (lfs_file_t *)malloc(sizeof(lfs_file_t)); - if (!_file) - return false; - - int rc = lfs_file_open(_fs->_getFS(), _file, filepath, flags); - - if (rc) { - // failed to open - PRINT_LFS_ERR(rc); - return false; - } - - // move to end of file - if (mode == FILE_O_WRITE) - lfs_file_seek(_fs->_getFS(), _file, 0, LFS_SEEK_END); - - _is_dir = false; - } - - return true; -} - -bool File::_open_dir(char const *filepath) -{ - _dir = (lfs_dir_t *)malloc(sizeof(lfs_dir_t)); - if (!_dir) - return false; - - int rc = lfs_dir_open(_fs->_getFS(), _dir, filepath); - - if (rc) { - // failed to open - PRINT_LFS_ERR(rc); - return false; - } - - _is_dir = true; - - _dir_path = (char *)malloc(strlen(filepath) + 1); - strcpy(_dir_path, filepath); - - return true; -} - -bool File::open(char const *filepath, uint8_t mode) -{ - bool ret = false; - _fs->_lockFS(); - - ret = this->_open(filepath, mode); - - _fs->_unlockFS(); - return ret; -} - -bool File::_open(char const *filepath, uint8_t mode) -{ - bool ret = false; - - // close if currently opened - if (this->isOpen()) - _close(); - - struct lfs_info info; - int rc = lfs_stat(_fs->_getFS(), filepath, &info); - - if (LFS_ERR_OK == rc) { - // file existed, open file or directory accordingly - ret = (info.type == LFS_TYPE_REG) ? _open_file(filepath, mode) : _open_dir(filepath); - } else if (LFS_ERR_NOENT == rc) { - // file not existed, only proceed with FILE_O_WRITE mode - if (mode == FILE_O_WRITE) - ret = _open_file(filepath, mode); - } else { - PRINT_LFS_ERR(rc); - } - - // save bare file name - if (ret) { - char const *splash = strrchr(filepath, '/'); - strncpy(_name, splash ? (splash + 1) : filepath, LFS_NAME_MAX); - } - return ret; -} - -size_t File::write(uint8_t ch) -{ - return write(&ch, 1); -} - -size_t File::write(uint8_t const *buf, size_t size) -{ - lfs_ssize_t wrcount = 0; - _fs->_lockFS(); - - if (!this->_is_dir) { - wrcount = lfs_file_write(_fs->_getFS(), _file, buf, size); - if (wrcount < 0) { - wrcount = 0; - } - } - - _fs->_unlockFS(); - return wrcount; -} - -int File::read(void) -{ - // this thin wrapper relies on called function to synchronize - int ret = -1; - uint8_t ch; - if (read(&ch, 1) > 0) { - ret = static_cast(ch); - } - return ret; -} - -int File::read(void *buf, uint16_t nbyte) -{ - int ret = 0; - _fs->_lockFS(); - - if (!this->_is_dir) { - ret = lfs_file_read(_fs->_getFS(), _file, buf, nbyte); - } - - _fs->_unlockFS(); - return ret; -} - -int File::peek(void) -{ - int ret = -1; - _fs->_lockFS(); - - if (!this->_is_dir) { - uint32_t pos = lfs_file_tell(_fs->_getFS(), _file); - uint8_t ch = 0; - if (lfs_file_read(_fs->_getFS(), _file, &ch, 1) > 0) { - ret = static_cast(ch); - } - (void)lfs_file_seek(_fs->_getFS(), _file, pos, LFS_SEEK_SET); - } - - _fs->_unlockFS(); - return ret; -} - -int File::available(void) -{ - int ret = 0; - _fs->_lockFS(); - - if (!this->_is_dir) { - uint32_t fsize = lfs_file_size(_fs->_getFS(), _file); - uint32_t pos = lfs_file_tell(_fs->_getFS(), _file); - ret = fsize - pos; - } - - _fs->_unlockFS(); - return ret; -} - -bool File::seek(uint32_t pos) -{ - bool ret = false; - _fs->_lockFS(); - - if (!this->_is_dir) { - ret = lfs_file_seek(_fs->_getFS(), _file, pos, LFS_SEEK_SET) >= 0; - } - - _fs->_unlockFS(); - return ret; -} - -uint32_t File::position(void) -{ - uint32_t ret = 0; - _fs->_lockFS(); - - if (!this->_is_dir) { - ret = lfs_file_tell(_fs->_getFS(), _file); - } - - _fs->_unlockFS(); - return ret; -} - -uint32_t File::size(void) -{ - uint32_t ret = 0; - _fs->_lockFS(); - - if (!this->_is_dir) { - ret = lfs_file_size(_fs->_getFS(), _file); - } - - _fs->_unlockFS(); - return ret; -} - -bool File::truncate(uint32_t pos) -{ - int32_t ret = LFS_ERR_ISDIR; - _fs->_lockFS(); - if (!this->_is_dir) { - ret = lfs_file_truncate(_fs->_getFS(), _file, pos); - } - _fs->_unlockFS(); - return (ret == 0); -} - -bool File::truncate(void) -{ - int32_t ret = LFS_ERR_ISDIR; - _fs->_lockFS(); - if (!this->_is_dir) { - uint32_t pos = lfs_file_tell(_fs->_getFS(), _file); - ret = lfs_file_truncate(_fs->_getFS(), _file, pos); - } - _fs->_unlockFS(); - return (ret == 0); -} - -void File::flush(void) -{ - _fs->_lockFS(); - - if (!this->_is_dir) { - lfs_file_sync(_fs->_getFS(), _file); - } - - _fs->_unlockFS(); - return; -} - -void File::close(void) -{ - _fs->_lockFS(); - this->_close(); - _fs->_unlockFS(); -} - -void File::_close(void) -{ - if (this->isOpen()) { - if (this->_is_dir) { - lfs_dir_close(_fs->_getFS(), _dir); - free(_dir); - _dir = NULL; - - if (this->_dir_path) - free(_dir_path); - _dir_path = NULL; - } else { - lfs_file_close(this->_fs->_getFS(), _file); - free(_file); - _file = NULL; - } - } -} - -File::operator bool(void) -{ - return isOpen(); -} - -bool File::isOpen(void) -{ - return (_file != NULL) || (_dir != NULL); -} - -// WARNING -- although marked as `const`, the values pointed -// to may change. For example, if the same File -// object has `open()` called with a different -// file or directory name, this same pointer will -// suddenly (unexpectedly?) have different values. -char const *File::name(void) -{ - return this->_name; -} - -bool File::isDirectory(void) -{ - return this->_is_dir; -} - -File File::openNextFile(uint8_t mode) -{ - _fs->_lockFS(); - - File ret(*_fs); - if (this->_is_dir) { - struct lfs_info info; - int rc; - - // lfs_dir_read returns 0 when reaching end of directory, 1 if found an entry - // Skip the "." and ".." entries ... - do { - rc = lfs_dir_read(_fs->_getFS(), _dir, &info); - } while (rc == 1 && (!strcmp(".", info.name) || !strcmp("..", info.name))); - - if (rc == 1) { - // string cat name with current folder - char filepath[strlen(_dir_path) + 1 + strlen(info.name) + 1]; // potential for significant stack usage - strcpy(filepath, _dir_path); - if (!(_dir_path[0] == '/' && _dir_path[1] == 0)) - strcat(filepath, "/"); // only add '/' if cwd is not root - strcat(filepath, info.name); - - (void)ret._open(filepath, mode); // return value is ignored ... caller is expected to check isOpened() - } else if (rc < 0) { - PRINT_LFS_ERR(rc); - } - } - _fs->_unlockFS(); - return ret; -} - -void File::rewindDirectory(void) -{ - _fs->_lockFS(); - if (this->_is_dir) { - lfs_dir_rewind(_fs->_getFS(), _dir); - } - _fs->_unlockFS(); -} diff --git a/src/platform/stm32wl/LittleFS_File.h b/src/platform/stm32wl/LittleFS_File.h deleted file mode 100644 index e88a2790d8..0000000000 --- a/src/platform/stm32wl/LittleFS_File.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef LITTLEFS_FILE_H_ -#define LITTLEFS_FILE_H_ - -// Forward declaration -class LittleFS; - -namespace LittleFS_Namespace -{ - -// avoid conflict with other FileSystem FILE_READ/FILE_WRITE -enum { - FILE_O_READ = 0, - FILE_O_WRITE = 1, -}; - -class File : public Stream -{ - public: - explicit File(LittleFS &fs); - File(char const *filename, uint8_t mode, LittleFS &fs); - - public: - bool open(char const *filename, uint8_t mode); - - //------------- Stream API -------------// - virtual size_t write(uint8_t ch); - virtual size_t write(uint8_t const *buf, size_t size); - size_t write(const char *str) - { - if (str == NULL) - return 0; - return write((const uint8_t *)str, strlen(str)); - } - size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); } - - virtual int read(void); - int read(void *buf, uint16_t nbyte); - - virtual int peek(void); - virtual int available(void); - virtual void flush(void); - - bool seek(uint32_t pos); - uint32_t position(void); - uint32_t size(void); - - bool truncate(uint32_t pos); - bool truncate(void); - - void close(void); - - operator bool(void); - - bool isOpen(void); - char const *name(void); - - bool isDirectory(void); - File openNextFile(uint8_t mode = FILE_O_READ); - void rewindDirectory(void); - - private: - LittleFS *_fs; - - bool _is_dir; - - union { - lfs_file_t *_file; - lfs_dir_t *_dir; - }; - - char *_dir_path; - char _name[LFS_NAME_MAX + 1]; - - bool _open(char const *filepath, uint8_t mode); - bool _open_file(char const *filepath, uint8_t mode); - bool _open_dir(char const *filepath); - void _close(void); -}; - -} // namespace LittleFS_Namespace - -#endif /* LITTLEFS_FILE_H_ */ diff --git a/src/platform/stm32wl/STM32WLCryptoEngine.cpp b/src/platform/stm32wl/STM32WLCryptoEngine.cpp index 7367a2bc03..4debdf78e1 100644 --- a/src/platform/stm32wl/STM32WLCryptoEngine.cpp +++ b/src/platform/stm32wl/STM32WLCryptoEngine.cpp @@ -1,33 +1,64 @@ +#undef RNG +#include "AES.h" +#include "CTR.h" #include "CryptoEngine.h" -#include "aes.hpp" #include "configuration.h" class STM32WLCryptoEngine : public CryptoEngine { + + CTRCommon *ctr = NULL; + public: STM32WLCryptoEngine() {} ~STM32WLCryptoEngine() {} + virtual void setKey(const CryptoKey &k) override + { + CryptoEngine::setKey(k); + LOG_DEBUG("Installing AES%d key!\n", key.length * 8); + if (ctr) { + delete ctr; + ctr = NULL; + } + if (key.length != 0) { + if (key.length == 16) + ctr = new CTR(); + else + ctr = new CTR(); + + ctr->setKey(key.bytes, key.length); + } + } /** * Encrypt a packet * * @param bytes is updated in place */ - virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override + virtual void encrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override { if (key.length > 0) { - AES_ctx ctx; - initNonce(fromNode, packetNum); - AES_init_ctx_iv(&ctx, key.bytes, nonce); - AES_CTR_xcrypt_buffer(&ctx, bytes, numBytes); + initNonce(fromNode, packetId); + if (numBytes <= MAX_BLOCKSIZE) { + static uint8_t scratch[MAX_BLOCKSIZE]; + memcpy(scratch, bytes, numBytes); + memset(scratch + numBytes, 0, + sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it) + + ctr->setIV(nonce, sizeof(nonce)); + ctr->setCounterSize(4); + ctr->encrypt(bytes, scratch, numBytes); + } else { + LOG_ERROR("Packet too large for crypto engine: %d. noop encryption!\n", numBytes); + } } } - virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override + virtual void decrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override { // For CTR, the implementation is the same - encrypt(fromNode, packetNum, numBytes, bytes); + encrypt(fromNode, packetId, numBytes, bytes); } private: diff --git a/src/platform/stm32wl/main-stm32wl.cpp b/src/platform/stm32wl/main-stm32wl.cpp index 60c3cce107..3eddbb3cfb 100644 --- a/src/platform/stm32wl/main-stm32wl.cpp +++ b/src/platform/stm32wl/main-stm32wl.cpp @@ -26,11 +26,3 @@ void getMacAddr(uint8_t *dmac) } void cpuDeepSleep(uint32_t msecToWake) {} - -/* pacify libc_nano */ -extern "C" { -int _gettimeofday(struct timeval *tv, void *tzvp) -{ - return -1; -} -} \ No newline at end of file diff --git a/src/xmodem.cpp b/src/xmodem.cpp index 852ff34531..de73e86684 100644 --- a/src/xmodem.cpp +++ b/src/xmodem.cpp @@ -50,6 +50,8 @@ #include "xmodem.h" +#ifdef FSCom + XModemAdapter xModem; XModemAdapter::XModemAdapter() {} @@ -248,4 +250,5 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket) // Unknown control character break; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/xmodem.h b/src/xmodem.h index 2ba0bb39f1..4cfcb43e18 100644 --- a/src/xmodem.h +++ b/src/xmodem.h @@ -38,6 +38,8 @@ #define MAXRETRANS 25 +#ifdef FSCom + class XModemAdapter { public: @@ -75,3 +77,4 @@ class XModemAdapter }; extern XModemAdapter xModem; +#endif // FSCom \ No newline at end of file diff --git a/variants/rak3172/platformio.ini b/variants/rak3172/platformio.ini new file mode 100644 index 0000000000..63766c988c --- /dev/null +++ b/variants/rak3172/platformio.ini @@ -0,0 +1,12 @@ +[env:rak3172] +extends = stm32_base +board_level = extra +board = wiscore_rak3172 +build_flags = + ${stm32_base.build_flags} + -Ivariants/rak3172 + -DHAL_DAC_MODULE_ONLY + -DSERIAL_UART_INSTANCE=1 + -DPIN_SERIAL_RX=PB7 + -DPIN_SERIAL_TX=PB6 +upload_port = stlink \ No newline at end of file diff --git a/variants/rak3172/variant.h b/variants/rak3172/variant.h new file mode 100644 index 0000000000..21de65b2cd --- /dev/null +++ b/variants/rak3172/variant.h @@ -0,0 +1,12 @@ +/* +This variant is a work in progress. +Do not expect a working Meshtastic device with this target. +*/ + +#ifndef _VARIANT_RAK3172_ +#define _VARIANT_RAK3172_ + +#define USE_STM32WLx +#define MAX_NUM_NODES 10 + +#endif \ No newline at end of file diff --git a/variants/wio-e5/platformio.ini b/variants/wio-e5/platformio.ini index 07f6efa6df..12cd6190d2 100644 --- a/variants/wio-e5/platformio.ini +++ b/variants/wio-e5/platformio.ini @@ -1,11 +1,34 @@ [env:wio-e5] -extends = stm32wl5e_base +extends = stm32_base board_level = extra +board = lora_e5_dev_board build_flags = - ${stm32wl5e_base.build_flags} + ${stm32_base.build_flags} -Ivariants/wio-e5 - -DHAL_DAC_MODULE_ONLY -DSERIAL_UART_INSTANCE=1 -DPIN_SERIAL_RX=PB7 -DPIN_SERIAL_TX=PB6 + -DHAL_DAC_MODULE_ONLY + -DHAL_ADC_MODULE_DISABLED + -DHAL_COMP_MODULE_DISABLED + -DHAL_CRC_MODULE_DISABLED + -DHAL_CRYP_MODULE_DISABLED + -DHAL_GTZC_MODULE_DISABLED + -DHAL_HSEM_MODULE_DISABLED + -DHAL_I2C_MODULE_DISABLED + -DHAL_I2S_MODULE_DISABLED + -DHAL_IPCC_MODULE_DISABLED + -DHAL_IRDA_MODULE_DISABLED + -DHAL_IWDG_MODULE_DISABLED + -DHAL_LPTIM_MODULE_DISABLED + -DHAL_PKA_MODULE_DISABLED + -DHAL_RNG_MODULE_DISABLED + -DHAL_RTC_MODULE_DISABLED + -DHAL_SMARTCARD_MODULE_DISABLED + -DHAL_SMBUS_MODULE_DISABLED + -DHAL_TIM_MODULE_DISABLED + -DHAL_WWDG_MODULE_DISABLED + -DHAL_EXTI_MODULE_DISABLED +; -D PIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF + upload_port = stlink \ No newline at end of file diff --git a/variants/wio-e5/variant.h b/variants/wio-e5/variant.h index 86e58bcb2e..b4345a530e 100644 --- a/variants/wio-e5/variant.h +++ b/variants/wio-e5/variant.h @@ -13,5 +13,6 @@ Do not expect a working Meshtastic device with this target. #define _VARIANT_WIOE5_ #define USE_STM32WLx +#define MAX_NUM_NODES 10 #endif \ No newline at end of file From f645ae943dd1411fefe8c48ae83d01ad6a4072c5 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 25 Jul 2024 20:50:42 -0500 Subject: [PATCH 190/211] JSON serialization refactor (#4331) --- src/mesh/http/ContentHandler.cpp | 2 +- src/mqtt/MQTT.cpp | 304 +------------------- src/mqtt/MQTT.h | 5 +- src/{mqtt => serialization}/JSON.cpp | 0 src/{mqtt => serialization}/JSON.h | 0 src/{mqtt => serialization}/JSONValue.cpp | 0 src/{mqtt => serialization}/JSONValue.h | 0 src/serialization/MeshPacketSerializer.cpp | 317 +++++++++++++++++++++ src/serialization/MeshPacketSerializer.h | 8 + 9 files changed, 331 insertions(+), 305 deletions(-) rename src/{mqtt => serialization}/JSON.cpp (100%) rename src/{mqtt => serialization}/JSON.h (100%) rename src/{mqtt => serialization}/JSONValue.cpp (100%) rename src/{mqtt => serialization}/JSONValue.h (100%) create mode 100644 src/serialization/MeshPacketSerializer.cpp create mode 100644 src/serialization/MeshPacketSerializer.h diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index b309484e23..ca2c5d4be7 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -9,8 +9,8 @@ #if HAS_WIFI #include "mesh/wifi/WiFiAPClient.h" #endif -#include "mqtt/JSON.h" #include "power.h" +#include "serialization/JSON.h" #include "sleep.h" #include #include diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index a7085dffe3..2fce526a09 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -19,6 +19,8 @@ #include #endif #include "Default.h" +#include "serialization/JSON.h" +#include "serialization/MeshPacketSerializer.h" #include const int reconnectMax = 5; @@ -459,7 +461,7 @@ void MQTT::publishQueuedMessages() #ifndef ARCH_NRF52 // JSON is not supported on nRF52, see issue #2804 if (moduleConfig.mqtt.json_enabled) { // handle json topic - auto jsonString = this->meshPacketToJson(env->packet); + auto jsonString = MeshPacketSerializer::JsonSerialize(env->packet); if (jsonString.length() != 0) { std::string topicJson = jsonTopic + env->channel_id + "/" + owner.id; LOG_INFO("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(), @@ -520,7 +522,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket & #ifndef ARCH_NRF52 // JSON is not supported on nRF52, see issue #2804 if (moduleConfig.mqtt.json_enabled) { // handle json topic - auto jsonString = this->meshPacketToJson((meshtastic_MeshPacket *)&mp_decoded); + auto jsonString = MeshPacketSerializer::JsonSerialize((meshtastic_MeshPacket *)&mp_decoded); if (jsonString.length() != 0) { std::string topicJson = jsonTopic + channelId + "/" + owner.id; LOG_INFO("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(), @@ -621,304 +623,6 @@ void MQTT::perhapsReportToMap() } } -// converts a downstream packet into a json message -std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp) -{ - // the created jsonObj is immutable after creation, so - // we need to do the heavy lifting before assembling it. - std::string msgType; - JSONObject jsonObj; - - if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { - JSONObject msgPayload; - switch (mp->decoded.portnum) { - case meshtastic_PortNum_TEXT_MESSAGE_APP: { - msgType = "text"; - // convert bytes to string - LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size); - char payloadStr[(mp->decoded.payload.size) + 1]; - memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size); - payloadStr[mp->decoded.payload.size] = 0; // null terminated string - // check if this is a JSON payload - JSONValue *json_value = JSON::Parse(payloadStr); - if (json_value != NULL) { - LOG_INFO("text message payload is of type json\n"); - // if it is, then we can just use the json object - jsonObj["payload"] = json_value; - } else { - // if it isn't, then we need to create a json object - // with the string as the value - LOG_INFO("text message payload is of type plaintext\n"); - msgPayload["text"] = new JSONValue(payloadStr); - jsonObj["payload"] = new JSONValue(msgPayload); - } - break; - } - case meshtastic_PortNum_TELEMETRY_APP: { - msgType = "telemetry"; - meshtastic_Telemetry scratch; - meshtastic_Telemetry *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) { - decoded = &scratch; - if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) { - msgPayload["battery_level"] = new JSONValue((unsigned int)decoded->variant.device_metrics.battery_level); - msgPayload["voltage"] = new JSONValue(decoded->variant.device_metrics.voltage); - msgPayload["channel_utilization"] = new JSONValue(decoded->variant.device_metrics.channel_utilization); - msgPayload["air_util_tx"] = new JSONValue(decoded->variant.device_metrics.air_util_tx); - msgPayload["uptime_seconds"] = new JSONValue((unsigned int)decoded->variant.device_metrics.uptime_seconds); - } else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) { - msgPayload["temperature"] = new JSONValue(decoded->variant.environment_metrics.temperature); - msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity); - msgPayload["barometric_pressure"] = new JSONValue(decoded->variant.environment_metrics.barometric_pressure); - msgPayload["gas_resistance"] = new JSONValue(decoded->variant.environment_metrics.gas_resistance); - msgPayload["voltage"] = new JSONValue(decoded->variant.environment_metrics.voltage); - msgPayload["current"] = new JSONValue(decoded->variant.environment_metrics.current); - msgPayload["lux"] = new JSONValue(decoded->variant.environment_metrics.lux); - msgPayload["white_lux"] = new JSONValue(decoded->variant.environment_metrics.white_lux); - msgPayload["iaq"] = new JSONValue((uint)decoded->variant.environment_metrics.iaq); - msgPayload["wind_speed"] = new JSONValue(decoded->variant.environment_metrics.wind_speed); - msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction); - msgPayload["wind_gust"] = new JSONValue(decoded->variant.environment_metrics.wind_gust); - msgPayload["wind_lull"] = new JSONValue(decoded->variant.environment_metrics.wind_lull); - } else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) { - msgPayload["voltage_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_voltage); - msgPayload["current_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_current); - msgPayload["voltage_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_voltage); - msgPayload["current_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_current); - msgPayload["voltage_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_voltage); - msgPayload["current_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_current); - } - jsonObj["payload"] = new JSONValue(msgPayload); - } else { - LOG_ERROR("Error decoding protobuf for telemetry message!\n"); - } - break; - } - case meshtastic_PortNum_NODEINFO_APP: { - msgType = "nodeinfo"; - meshtastic_User scratch; - meshtastic_User *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) { - decoded = &scratch; - msgPayload["id"] = new JSONValue(decoded->id); - msgPayload["longname"] = new JSONValue(decoded->long_name); - msgPayload["shortname"] = new JSONValue(decoded->short_name); - msgPayload["hardware"] = new JSONValue(decoded->hw_model); - jsonObj["payload"] = new JSONValue(msgPayload); - } else { - LOG_ERROR("Error decoding protobuf for nodeinfo message!\n"); - } - break; - } - case meshtastic_PortNum_POSITION_APP: { - msgType = "position"; - meshtastic_Position scratch; - meshtastic_Position *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) { - decoded = &scratch; - if ((int)decoded->time) { - msgPayload["time"] = new JSONValue((unsigned int)decoded->time); - } - if ((int)decoded->timestamp) { - msgPayload["timestamp"] = new JSONValue((unsigned int)decoded->timestamp); - } - msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i); - msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i); - if ((int)decoded->altitude) { - msgPayload["altitude"] = new JSONValue((int)decoded->altitude); - } - if ((int)decoded->ground_speed) { - msgPayload["ground_speed"] = new JSONValue((unsigned int)decoded->ground_speed); - } - if (int(decoded->ground_track)) { - msgPayload["ground_track"] = new JSONValue((unsigned int)decoded->ground_track); - } - if (int(decoded->sats_in_view)) { - msgPayload["sats_in_view"] = new JSONValue((unsigned int)decoded->sats_in_view); - } - if ((int)decoded->PDOP) { - msgPayload["PDOP"] = new JSONValue((int)decoded->PDOP); - } - if ((int)decoded->HDOP) { - msgPayload["HDOP"] = new JSONValue((int)decoded->HDOP); - } - if ((int)decoded->VDOP) { - msgPayload["VDOP"] = new JSONValue((int)decoded->VDOP); - } - if ((int)decoded->precision_bits) { - msgPayload["precision_bits"] = new JSONValue((int)decoded->precision_bits); - } - jsonObj["payload"] = new JSONValue(msgPayload); - } else { - LOG_ERROR("Error decoding protobuf for position message!\n"); - } - break; - } - case meshtastic_PortNum_WAYPOINT_APP: { - msgType = "position"; - meshtastic_Waypoint scratch; - meshtastic_Waypoint *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) { - decoded = &scratch; - msgPayload["id"] = new JSONValue((unsigned int)decoded->id); - msgPayload["name"] = new JSONValue(decoded->name); - msgPayload["description"] = new JSONValue(decoded->description); - msgPayload["expire"] = new JSONValue((unsigned int)decoded->expire); - msgPayload["locked_to"] = new JSONValue((unsigned int)decoded->locked_to); - msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i); - msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i); - jsonObj["payload"] = new JSONValue(msgPayload); - } else { - LOG_ERROR("Error decoding protobuf for position message!\n"); - } - break; - } - case meshtastic_PortNum_NEIGHBORINFO_APP: { - msgType = "neighborinfo"; - meshtastic_NeighborInfo scratch; - meshtastic_NeighborInfo *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg, - &scratch)) { - decoded = &scratch; - msgPayload["node_id"] = new JSONValue((unsigned int)decoded->node_id); - msgPayload["node_broadcast_interval_secs"] = new JSONValue((unsigned int)decoded->node_broadcast_interval_secs); - msgPayload["last_sent_by_id"] = new JSONValue((unsigned int)decoded->last_sent_by_id); - msgPayload["neighbors_count"] = new JSONValue(decoded->neighbors_count); - JSONArray neighbors; - for (uint8_t i = 0; i < decoded->neighbors_count; i++) { - JSONObject neighborObj; - neighborObj["node_id"] = new JSONValue((unsigned int)decoded->neighbors[i].node_id); - neighborObj["snr"] = new JSONValue((int)decoded->neighbors[i].snr); - neighbors.push_back(new JSONValue(neighborObj)); - } - msgPayload["neighbors"] = new JSONValue(neighbors); - jsonObj["payload"] = new JSONValue(msgPayload); - } else { - LOG_ERROR("Error decoding protobuf for neighborinfo message!\n"); - } - break; - } - case meshtastic_PortNum_TRACEROUTE_APP: { - if (mp->decoded.request_id) { // Only report the traceroute response - msgType = "traceroute"; - meshtastic_RouteDiscovery scratch; - meshtastic_RouteDiscovery *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_RouteDiscovery_msg, - &scratch)) { - decoded = &scratch; - JSONArray route; // Route this message took - // Lambda function for adding a long name to the route - auto addToRoute = [](JSONArray *route, NodeNum num) { - char long_name[40] = "Unknown"; - meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(num); - bool name_known = node ? node->has_user : false; - if (name_known) - memcpy(long_name, node->user.long_name, sizeof(long_name)); - route->push_back(new JSONValue(long_name)); - }; - addToRoute(&route, mp->to); // Started at the original transmitter (destination of response) - for (uint8_t i = 0; i < decoded->route_count; i++) { - addToRoute(&route, decoded->route[i]); - } - addToRoute(&route, mp->from); // Ended at the original destination (source of response) - - msgPayload["route"] = new JSONValue(route); - jsonObj["payload"] = new JSONValue(msgPayload); - } else { - LOG_ERROR("Error decoding protobuf for traceroute message!\n"); - } - } - break; - } - case meshtastic_PortNum_DETECTION_SENSOR_APP: { - msgType = "detection"; - char payloadStr[(mp->decoded.payload.size) + 1]; - memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size); - payloadStr[mp->decoded.payload.size] = 0; // null terminated string - msgPayload["text"] = new JSONValue(payloadStr); - jsonObj["payload"] = new JSONValue(msgPayload); - break; - } -#ifdef ARCH_ESP32 - case meshtastic_PortNum_PAXCOUNTER_APP: { - msgType = "paxcounter"; - meshtastic_Paxcount scratch; - meshtastic_Paxcount *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Paxcount_msg, &scratch)) { - decoded = &scratch; - msgPayload["wifi_count"] = new JSONValue((unsigned int)decoded->wifi); - msgPayload["ble_count"] = new JSONValue((unsigned int)decoded->ble); - msgPayload["uptime"] = new JSONValue((unsigned int)decoded->uptime); - jsonObj["payload"] = new JSONValue(msgPayload); - } else { - LOG_ERROR("Error decoding protobuf for Paxcount message!\n"); - } - break; - } -#endif - case meshtastic_PortNum_REMOTE_HARDWARE_APP: { - meshtastic_HardwareMessage scratch; - meshtastic_HardwareMessage *decoded = NULL; - memset(&scratch, 0, sizeof(scratch)); - if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_HardwareMessage_msg, - &scratch)) { - decoded = &scratch; - if (decoded->type == meshtastic_HardwareMessage_Type_GPIOS_CHANGED) { - msgType = "gpios_changed"; - msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value); - jsonObj["payload"] = new JSONValue(msgPayload); - } else if (decoded->type == meshtastic_HardwareMessage_Type_READ_GPIOS_REPLY) { - msgType = "gpios_read_reply"; - msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value); - msgPayload["gpio_mask"] = new JSONValue((unsigned int)decoded->gpio_mask); - jsonObj["payload"] = new JSONValue(msgPayload); - } - } else { - LOG_ERROR("Error decoding protobuf for RemoteHardware message!\n"); - } - break; - } - // add more packet types here if needed - default: - break; - } - } else { - LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON\n"); - } - - jsonObj["id"] = new JSONValue((unsigned int)mp->id); - jsonObj["timestamp"] = new JSONValue((unsigned int)mp->rx_time); - jsonObj["to"] = new JSONValue((unsigned int)mp->to); - jsonObj["from"] = new JSONValue((unsigned int)mp->from); - jsonObj["channel"] = new JSONValue((unsigned int)mp->channel); - jsonObj["type"] = new JSONValue(msgType.c_str()); - jsonObj["sender"] = new JSONValue(owner.id); - if (mp->rx_rssi != 0) - jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi); - if (mp->rx_snr != 0) - jsonObj["snr"] = new JSONValue((float)mp->rx_snr); - if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) { - jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit)); - jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); - } - - // serialize and write it to the stream - JSONValue *value = new JSONValue(jsonObj); - std::string jsonStr = value->Stringify(); - - LOG_INFO("serialized json message: %s\n", jsonStr.c_str()); - - delete value; - return jsonStr; -} - bool MQTT::isValidJsonEnvelope(JSONObject &json) { // if "sender" is provided, avoid processing packets we uplinked diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index d68f1b88d7..ba09877839 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -5,7 +5,7 @@ #include "concurrency/OSThread.h" #include "mesh/Channels.h" #include "mesh/generated/meshtastic/mqtt.pb.h" -#include "mqtt/JSON.h" +#include "serialization/JSON.h" #if HAS_WIFI #include #if !defined(ARCH_PORTDUINO) @@ -106,9 +106,6 @@ class MQTT : private concurrency::OSThread /// Called when a new publish arrives from the MQTT server void onReceive(char *topic, byte *payload, size_t length); - /// Called when a new publish arrives from the MQTT server - std::string meshPacketToJson(meshtastic_MeshPacket *mp); - void publishQueuedMessages(); void publishNodeInfo(); diff --git a/src/mqtt/JSON.cpp b/src/serialization/JSON.cpp similarity index 100% rename from src/mqtt/JSON.cpp rename to src/serialization/JSON.cpp diff --git a/src/mqtt/JSON.h b/src/serialization/JSON.h similarity index 100% rename from src/mqtt/JSON.h rename to src/serialization/JSON.h diff --git a/src/mqtt/JSONValue.cpp b/src/serialization/JSONValue.cpp similarity index 100% rename from src/mqtt/JSONValue.cpp rename to src/serialization/JSONValue.cpp diff --git a/src/mqtt/JSONValue.h b/src/serialization/JSONValue.h similarity index 100% rename from src/mqtt/JSONValue.h rename to src/serialization/JSONValue.h diff --git a/src/serialization/MeshPacketSerializer.cpp b/src/serialization/MeshPacketSerializer.cpp new file mode 100644 index 0000000000..dc2db1e6ff --- /dev/null +++ b/src/serialization/MeshPacketSerializer.cpp @@ -0,0 +1,317 @@ +#include "MeshPacketSerializer.h" +#include "JSON.h" +#include "NodeDB.h" +#include "mesh/generated/meshtastic/mqtt.pb.h" +#include "mesh/generated/meshtastic/telemetry.pb.h" +#include "modules/RoutingModule.h" +#include +#include +#if defined(ARCH_ESP32) +#include "../mesh/generated/meshtastic/paxcount.pb.h" +#endif +#include "mesh/generated/meshtastic/remote_hardware.pb.h" + +std::string MeshPacketSerializer::JsonSerialize(meshtastic_MeshPacket *mp, bool shouldLog) +{ + // the created jsonObj is immutable after creation, so + // we need to do the heavy lifting before assembling it. + std::string msgType; + JSONObject jsonObj; + + if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + JSONObject msgPayload; + switch (mp->decoded.portnum) { + case meshtastic_PortNum_TEXT_MESSAGE_APP: { + msgType = "text"; + // convert bytes to string + if (shouldLog) + LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size); + + char payloadStr[(mp->decoded.payload.size) + 1]; + memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size); + payloadStr[mp->decoded.payload.size] = 0; // null terminated string + // check if this is a JSON payload + JSONValue *json_value = JSON::Parse(payloadStr); + if (json_value != NULL) { + if (shouldLog) + LOG_INFO("text message payload is of type json\n"); + + // if it is, then we can just use the json object + jsonObj["payload"] = json_value; + } else { + // if it isn't, then we need to create a json object + // with the string as the value + if (shouldLog) + LOG_INFO("text message payload is of type plaintext\n"); + + msgPayload["text"] = new JSONValue(payloadStr); + jsonObj["payload"] = new JSONValue(msgPayload); + } + break; + } + case meshtastic_PortNum_TELEMETRY_APP: { + msgType = "telemetry"; + meshtastic_Telemetry scratch; + meshtastic_Telemetry *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) { + decoded = &scratch; + if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) { + msgPayload["battery_level"] = new JSONValue((unsigned int)decoded->variant.device_metrics.battery_level); + msgPayload["voltage"] = new JSONValue(decoded->variant.device_metrics.voltage); + msgPayload["channel_utilization"] = new JSONValue(decoded->variant.device_metrics.channel_utilization); + msgPayload["air_util_tx"] = new JSONValue(decoded->variant.device_metrics.air_util_tx); + msgPayload["uptime_seconds"] = new JSONValue((unsigned int)decoded->variant.device_metrics.uptime_seconds); + } else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) { + msgPayload["temperature"] = new JSONValue(decoded->variant.environment_metrics.temperature); + msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity); + msgPayload["barometric_pressure"] = new JSONValue(decoded->variant.environment_metrics.barometric_pressure); + msgPayload["gas_resistance"] = new JSONValue(decoded->variant.environment_metrics.gas_resistance); + msgPayload["voltage"] = new JSONValue(decoded->variant.environment_metrics.voltage); + msgPayload["current"] = new JSONValue(decoded->variant.environment_metrics.current); + msgPayload["lux"] = new JSONValue(decoded->variant.environment_metrics.lux); + msgPayload["white_lux"] = new JSONValue(decoded->variant.environment_metrics.white_lux); + msgPayload["iaq"] = new JSONValue((uint)decoded->variant.environment_metrics.iaq); + msgPayload["wind_speed"] = new JSONValue(decoded->variant.environment_metrics.wind_speed); + msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction); + msgPayload["wind_gust"] = new JSONValue(decoded->variant.environment_metrics.wind_gust); + msgPayload["wind_lull"] = new JSONValue(decoded->variant.environment_metrics.wind_lull); + } else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) { + msgPayload["voltage_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_voltage); + msgPayload["current_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_current); + msgPayload["voltage_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_voltage); + msgPayload["current_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_current); + msgPayload["voltage_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_voltage); + msgPayload["current_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_current); + } + jsonObj["payload"] = new JSONValue(msgPayload); + } else if (shouldLog) { + LOG_ERROR("Error decoding protobuf for telemetry message!\n"); + } + break; + } + case meshtastic_PortNum_NODEINFO_APP: { + msgType = "nodeinfo"; + meshtastic_User scratch; + meshtastic_User *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) { + decoded = &scratch; + msgPayload["id"] = new JSONValue(decoded->id); + msgPayload["longname"] = new JSONValue(decoded->long_name); + msgPayload["shortname"] = new JSONValue(decoded->short_name); + msgPayload["hardware"] = new JSONValue(decoded->hw_model); + msgPayload["role"] = new JSONValue((int)decoded->role); + jsonObj["payload"] = new JSONValue(msgPayload); + } else if (shouldLog) { + LOG_ERROR("Error decoding protobuf for nodeinfo message!\n"); + } + break; + } + case meshtastic_PortNum_POSITION_APP: { + msgType = "position"; + meshtastic_Position scratch; + meshtastic_Position *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) { + decoded = &scratch; + if ((int)decoded->time) { + msgPayload["time"] = new JSONValue((unsigned int)decoded->time); + } + if ((int)decoded->timestamp) { + msgPayload["timestamp"] = new JSONValue((unsigned int)decoded->timestamp); + } + msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i); + msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i); + if ((int)decoded->altitude) { + msgPayload["altitude"] = new JSONValue((int)decoded->altitude); + } + if ((int)decoded->ground_speed) { + msgPayload["ground_speed"] = new JSONValue((unsigned int)decoded->ground_speed); + } + if (int(decoded->ground_track)) { + msgPayload["ground_track"] = new JSONValue((unsigned int)decoded->ground_track); + } + if (int(decoded->sats_in_view)) { + msgPayload["sats_in_view"] = new JSONValue((unsigned int)decoded->sats_in_view); + } + if ((int)decoded->PDOP) { + msgPayload["PDOP"] = new JSONValue((int)decoded->PDOP); + } + if ((int)decoded->HDOP) { + msgPayload["HDOP"] = new JSONValue((int)decoded->HDOP); + } + if ((int)decoded->VDOP) { + msgPayload["VDOP"] = new JSONValue((int)decoded->VDOP); + } + if ((int)decoded->precision_bits) { + msgPayload["precision_bits"] = new JSONValue((int)decoded->precision_bits); + } + jsonObj["payload"] = new JSONValue(msgPayload); + } else if (shouldLog) { + LOG_ERROR("Error decoding protobuf for position message!\n"); + } + break; + } + case meshtastic_PortNum_WAYPOINT_APP: { + msgType = "position"; + meshtastic_Waypoint scratch; + meshtastic_Waypoint *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) { + decoded = &scratch; + msgPayload["id"] = new JSONValue((unsigned int)decoded->id); + msgPayload["name"] = new JSONValue(decoded->name); + msgPayload["description"] = new JSONValue(decoded->description); + msgPayload["expire"] = new JSONValue((unsigned int)decoded->expire); + msgPayload["locked_to"] = new JSONValue((unsigned int)decoded->locked_to); + msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i); + msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i); + jsonObj["payload"] = new JSONValue(msgPayload); + } else if (shouldLog) { + LOG_ERROR("Error decoding protobuf for position message!\n"); + } + break; + } + case meshtastic_PortNum_NEIGHBORINFO_APP: { + msgType = "neighborinfo"; + meshtastic_NeighborInfo scratch; + meshtastic_NeighborInfo *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg, + &scratch)) { + decoded = &scratch; + msgPayload["node_id"] = new JSONValue((unsigned int)decoded->node_id); + msgPayload["node_broadcast_interval_secs"] = new JSONValue((unsigned int)decoded->node_broadcast_interval_secs); + msgPayload["last_sent_by_id"] = new JSONValue((unsigned int)decoded->last_sent_by_id); + msgPayload["neighbors_count"] = new JSONValue(decoded->neighbors_count); + JSONArray neighbors; + for (uint8_t i = 0; i < decoded->neighbors_count; i++) { + JSONObject neighborObj; + neighborObj["node_id"] = new JSONValue((unsigned int)decoded->neighbors[i].node_id); + neighborObj["snr"] = new JSONValue((int)decoded->neighbors[i].snr); + neighbors.push_back(new JSONValue(neighborObj)); + } + msgPayload["neighbors"] = new JSONValue(neighbors); + jsonObj["payload"] = new JSONValue(msgPayload); + } else if (shouldLog) { + LOG_ERROR("Error decoding protobuf for neighborinfo message!\n"); + } + break; + } + case meshtastic_PortNum_TRACEROUTE_APP: { + if (mp->decoded.request_id) { // Only report the traceroute response + msgType = "traceroute"; + meshtastic_RouteDiscovery scratch; + meshtastic_RouteDiscovery *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_RouteDiscovery_msg, + &scratch)) { + decoded = &scratch; + JSONArray route; // Route this message took + // Lambda function for adding a long name to the route + auto addToRoute = [](JSONArray *route, NodeNum num) { + char long_name[40] = "Unknown"; + meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(num); + bool name_known = node ? node->has_user : false; + if (name_known) + memcpy(long_name, node->user.long_name, sizeof(long_name)); + route->push_back(new JSONValue(long_name)); + }; + addToRoute(&route, mp->to); // Started at the original transmitter (destination of response) + for (uint8_t i = 0; i < decoded->route_count; i++) { + addToRoute(&route, decoded->route[i]); + } + addToRoute(&route, mp->from); // Ended at the original destination (source of response) + + msgPayload["route"] = new JSONValue(route); + jsonObj["payload"] = new JSONValue(msgPayload); + } else if (shouldLog) { + LOG_ERROR("Error decoding protobuf for traceroute message!\n"); + } + } + break; + } + case meshtastic_PortNum_DETECTION_SENSOR_APP: { + msgType = "detection"; + char payloadStr[(mp->decoded.payload.size) + 1]; + memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size); + payloadStr[mp->decoded.payload.size] = 0; // null terminated string + msgPayload["text"] = new JSONValue(payloadStr); + jsonObj["payload"] = new JSONValue(msgPayload); + break; + } +#ifdef ARCH_ESP32 + case meshtastic_PortNum_PAXCOUNTER_APP: { + msgType = "paxcounter"; + meshtastic_Paxcount scratch; + meshtastic_Paxcount *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Paxcount_msg, &scratch)) { + decoded = &scratch; + msgPayload["wifi_count"] = new JSONValue((unsigned int)decoded->wifi); + msgPayload["ble_count"] = new JSONValue((unsigned int)decoded->ble); + msgPayload["uptime"] = new JSONValue((unsigned int)decoded->uptime); + jsonObj["payload"] = new JSONValue(msgPayload); + } else if (shouldLog) { + LOG_ERROR("Error decoding protobuf for Paxcount message!\n"); + } + break; + } +#endif + case meshtastic_PortNum_REMOTE_HARDWARE_APP: { + meshtastic_HardwareMessage scratch; + meshtastic_HardwareMessage *decoded = NULL; + memset(&scratch, 0, sizeof(scratch)); + if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_HardwareMessage_msg, + &scratch)) { + decoded = &scratch; + if (decoded->type == meshtastic_HardwareMessage_Type_GPIOS_CHANGED) { + msgType = "gpios_changed"; + msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value); + jsonObj["payload"] = new JSONValue(msgPayload); + } else if (decoded->type == meshtastic_HardwareMessage_Type_READ_GPIOS_REPLY) { + msgType = "gpios_read_reply"; + msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value); + msgPayload["gpio_mask"] = new JSONValue((unsigned int)decoded->gpio_mask); + jsonObj["payload"] = new JSONValue(msgPayload); + } + } else if (shouldLog) { + LOG_ERROR("Error decoding protobuf for RemoteHardware message!\n"); + } + break; + } + // add more packet types here if needed + default: + break; + } + } else if (shouldLog) { + LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON\n"); + } + + jsonObj["id"] = new JSONValue((unsigned int)mp->id); + jsonObj["timestamp"] = new JSONValue((unsigned int)mp->rx_time); + jsonObj["to"] = new JSONValue((unsigned int)mp->to); + jsonObj["from"] = new JSONValue((unsigned int)mp->from); + jsonObj["channel"] = new JSONValue((unsigned int)mp->channel); + jsonObj["type"] = new JSONValue(msgType.c_str()); + jsonObj["sender"] = new JSONValue(owner.id); + if (mp->rx_rssi != 0) + jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi); + if (mp->rx_snr != 0) + jsonObj["snr"] = new JSONValue((float)mp->rx_snr); + if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) { + jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit)); + jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); + } + + // serialize and write it to the stream + JSONValue *value = new JSONValue(jsonObj); + std::string jsonStr = value->Stringify(); + + if (shouldLog) + LOG_INFO("serialized json message: %s\n", jsonStr.c_str()); + + delete value; + return jsonStr; +} \ No newline at end of file diff --git a/src/serialization/MeshPacketSerializer.h b/src/serialization/MeshPacketSerializer.h new file mode 100644 index 0000000000..579ee2fd60 --- /dev/null +++ b/src/serialization/MeshPacketSerializer.h @@ -0,0 +1,8 @@ +#include +#include + +class MeshPacketSerializer +{ + public: + static std::string JsonSerialize(meshtastic_MeshPacket *mp, bool shouldLog = true); +}; \ No newline at end of file From 755952c261322a97c521c81fc2966f5b7fe0acfa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2024 06:29:05 -0500 Subject: [PATCH 191/211] [create-pull-request] automated change (#4333) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 7f90178f18..b1a79d5db0 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 7f90178f183820e288aec41133144f30723228fe +Subproject commit b1a79d5db00f6aeeb0bbae156e8939e146c95299 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 841ca7aa4b..ca860aed53 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -178,6 +178,8 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 = 69, /* Sensecap Indicator from Seeed Studio. ESP32-S3 device with TFT and RP2040 coprocessor */ meshtastic_HardwareModel_SENSECAP_INDICATOR = 70, + /* Seeed studio T1000-E tracker card. NRF52840 w/ LR1110 radio, GPS, button, buzzer, and sensors. */ + meshtastic_HardwareModel_TRACKER_T1000_E = 71, /* ------------------------------------------------------------------------------------------------------------------------------------------ Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. ------------------------------------------------------------------------------------------------------------------------------------------ */ From 394e0e1b3e33cbf64d6518e4b7911a402eae5284 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 26 Jul 2024 06:30:28 -0500 Subject: [PATCH 192/211] T1000_E hw model --- src/platform/nrf52/architecture.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index b66552a284..99879f0f64 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -60,6 +60,8 @@ #define HW_VENDOR meshtastic_HardwareModel_NRF52_PROMICRO_DIY #elif defined(WIO_WM1110) #define HW_VENDOR meshtastic_HardwareModel_WIO_WM1110 +#elif defined(TRACKER_T1000_E) +#define HW_VENDOR meshtastic_HardwareModel_TRACKER_T1000_E #elif defined(PRIVATE_HW) || defined(FEATHER_DIY) #define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW #else From 4ee15d81282e7f861d55fc79a141292699eae790 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 26 Jul 2024 06:38:54 -0500 Subject: [PATCH 193/211] Trunk --- src/platform/nrf52/architecture.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index 99879f0f64..a276a60810 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -60,7 +60,7 @@ #define HW_VENDOR meshtastic_HardwareModel_NRF52_PROMICRO_DIY #elif defined(WIO_WM1110) #define HW_VENDOR meshtastic_HardwareModel_WIO_WM1110 -#elif defined(TRACKER_T1000_E) +#elif defined(TRACKER_T1000_E) #define HW_VENDOR meshtastic_HardwareModel_TRACKER_T1000_E #elif defined(PRIVATE_HW) || defined(FEATHER_DIY) #define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW From 8641777bac4a81a8dbe5c31d1261bba53ca4a4f6 Mon Sep 17 00:00:00 2001 From: Nestpebble <116762865+Nestpebble@users.noreply.github.com> Date: Sat, 27 Jul 2024 02:14:31 +0100 Subject: [PATCH 194/211] Add the UF2 conversion script to the p.io task menu (#4337) * Add the UF2 conversion script to the p.io task menu Update platformio-custom.py to include the UF2 conversion script as a project task. Saves you dropping into the command line every time. Tested on Windows only... * Forgot the build target... --- bin/platformio-custom.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bin/platformio-custom.py b/bin/platformio-custom.py index 3202a1e7a9..065f1267b4 100644 --- a/bin/platformio-custom.py +++ b/bin/platformio-custom.py @@ -91,3 +91,12 @@ def esp32_create_combined_bin(source, target, env): "-DAPP_VERSION_SHORT=" + verObj["short"], ] ) + +# Add a custom p.io project task to run the UF2 conversion script. +env.AddCustomTarget( + name="Convert Hex to UF2", + dependencies=None, + actions=["PYTHON .\\bin\\uf2conv.py $BUILD_DIR\$env\\firmware.hex -c -f 0xADA52840 -o $BUILD_DIR\$env\\firmware.uf2"], + title="Convert hex to uf2", + description="Runs the python script to convert an already-built .hex file into .uf2 for copying to a device" +) From 6f235232f04523c17d091e57ccc19014e40944b1 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 27 Jul 2024 13:58:55 +0300 Subject: [PATCH 195/211] Added RF95 SX1268 support (#4338) --- variants/diy/nrf52_promicro_diy_tcxo/variant.h | 2 ++ variants/diy/nrf52_promicro_diy_xtal/variant.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/variants/diy/nrf52_promicro_diy_tcxo/variant.h b/variants/diy/nrf52_promicro_diy_tcxo/variant.h index 8b957fe128..bacc0796dc 100644 --- a/variants/diy/nrf52_promicro_diy_tcxo/variant.h +++ b/variants/diy/nrf52_promicro_diy_tcxo/variant.h @@ -115,6 +115,8 @@ NRF52 PRO MICRO PIN ASSIGNMENT // LORA MODULES #define USE_LLCC68 #define USE_SX1262 +#define USE_RF95 +#define USE_SX1268 // LORA CONFIG #define SX126X_CS (32 + 13) // P1.13 FIXME - we really should define LORA_CS instead diff --git a/variants/diy/nrf52_promicro_diy_xtal/variant.h b/variants/diy/nrf52_promicro_diy_xtal/variant.h index fd0b216813..c00c424cc9 100644 --- a/variants/diy/nrf52_promicro_diy_xtal/variant.h +++ b/variants/diy/nrf52_promicro_diy_xtal/variant.h @@ -114,6 +114,8 @@ NRF52 PRO MICRO PIN ASSIGNMENT // LORA MODULES #define USE_LLCC68 #define USE_SX1262 +#define USE_RF95 +#define USE_SX1268 // LORA CONFIG #define SX126X_CS (32 + 13) // P1.13 FIXME - we really should define LORA_CS instead From f583837b4edfc1c75baa24534e90afb4f45b3a2c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 27 Jul 2024 06:39:16 -0500 Subject: [PATCH 196/211] Enable STM32 build (#4339) * Enable stm32 builds and wio-e5 board * Chmod --- .github/workflows/build_stm32.yml | 33 +++++++++++++++++++++++++++++++ .github/workflows/main_matrix.yml | 10 ++++++++++ bin/build-stm32.sh | 29 +++++++++++++++++++++++++++ variants/wio-e5/platformio.ini | 1 - 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build_stm32.yml create mode 100755 bin/build-stm32.sh diff --git a/.github/workflows/build_stm32.yml b/.github/workflows/build_stm32.yml new file mode 100644 index 0000000000..d13c52c8a1 --- /dev/null +++ b/.github/workflows/build_stm32.yml @@ -0,0 +1,33 @@ +name: Build STM32 + +on: + workflow_call: + inputs: + board: + required: true + type: string + +jobs: + build-stm32: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build base + id: base + uses: ./.github/actions/setup-base + + - name: Build STM32 + run: bin/build-stm32.sh ${{ inputs.board }} + + - name: Get release version string + run: echo "version=$(./bin/buildinfo.py long)" >> $GITHUB_OUTPUT + id: version + + - name: Store binaries as an artifact + uses: actions/upload-artifact@v4 + with: + name: firmware-${{ inputs.board }}-${{ steps.version.outputs.version }}.zip + overwrite: true + path: | + release/*.hex + release/*.bin diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index 14c8a9d10c..b1d1d307a1 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -41,6 +41,7 @@ jobs: esp32c3: ${{ steps.jsonStep.outputs.esp32c3 }} nrf52840: ${{ steps.jsonStep.outputs.nrf52840 }} rp2040: ${{ steps.jsonStep.outputs.rp2040 }} + stm32: ${{ steps.jsonStep.outputs.stm32 }} check: ${{ steps.jsonStep.outputs.check }} check: @@ -103,6 +104,15 @@ jobs: with: board: ${{ matrix.board }} + build-stm32: + needs: setup + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.setup.outputs.stm32) }} + uses: ./.github/workflows/build_stm32.yml + with: + board: ${{ matrix.board }} + package-raspbian: uses: ./.github/workflows/package_raspbian.yml diff --git a/bin/build-stm32.sh b/bin/build-stm32.sh new file mode 100755 index 0000000000..9e813a8c09 --- /dev/null +++ b/bin/build-stm32.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +set -e + +VERSION=$(bin/buildinfo.py long) +SHORT_VERSION=$(bin/buildinfo.py short) + +OUTDIR=release/ + +rm -f $OUTDIR/firmware* +rm -r $OUTDIR/* || true + +# Important to pull latest version of libs into all device flavors, otherwise some devices might be stale +platformio pkg update -e $1 + +echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS" +rm -f .pio/build/$1/firmware.* + +# The shell vars the build tool expects to find +export APP_VERSION=$VERSION + +basename=firmware-$1-$VERSION + +pio run --environment $1 # -v +SRCELF=.pio/build/$1/firmware.elf +cp $SRCELF $OUTDIR/$basename.elf + +SRCELF=.pio/build/$1/firmware.bin +cp $SRCHEX $OUTDIR/$basename.bin diff --git a/variants/wio-e5/platformio.ini b/variants/wio-e5/platformio.ini index 12cd6190d2..51591d5696 100644 --- a/variants/wio-e5/platformio.ini +++ b/variants/wio-e5/platformio.ini @@ -1,6 +1,5 @@ [env:wio-e5] extends = stm32_base -board_level = extra board = lora_e5_dev_board build_flags = ${stm32_base.build_flags} From e70435ebd7b2635fbc67aa0371b7c2697d15a0a0 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 27 Jul 2024 06:49:11 -0500 Subject: [PATCH 197/211] All builds need to only pkg update for their target environment --- .github/workflows/main_matrix.yml | 2 +- bin/build-esp32.sh | 2 +- bin/build-nrf52.sh | 2 +- bin/build-rpi2040.sh | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index b1d1d307a1..ae50b94ecb 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -24,7 +24,7 @@ jobs: strategy: fail-fast: false matrix: - arch: [esp32, esp32s3, esp32c3, nrf52840, rp2040, check] + arch: [esp32, esp32s3, esp32c3, nrf52840, rp2040, stm32, check] runs-on: ubuntu-latest steps: - id: checkout diff --git a/bin/build-esp32.sh b/bin/build-esp32.sh index f60331ed52..adb6ab12ad 100755 --- a/bin/build-esp32.sh +++ b/bin/build-esp32.sh @@ -11,7 +11,7 @@ rm -f $OUTDIR/firmware* rm -r $OUTDIR/* || true # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale -platformio pkg update +platformio pkg update -e $1 echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS" rm -f .pio/build/$1/firmware.* diff --git a/bin/build-nrf52.sh b/bin/build-nrf52.sh index c0658dad95..060d06cfda 100755 --- a/bin/build-nrf52.sh +++ b/bin/build-nrf52.sh @@ -11,7 +11,7 @@ rm -f $OUTDIR/firmware* rm -r $OUTDIR/* || true # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale -platformio pkg update +platformio pkg update -e $1 echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS" rm -f .pio/build/$1/firmware.* diff --git a/bin/build-rpi2040.sh b/bin/build-rpi2040.sh index fe0725085a..dad6a7e67e 100755 --- a/bin/build-rpi2040.sh +++ b/bin/build-rpi2040.sh @@ -11,7 +11,7 @@ rm -f $OUTDIR/firmware* rm -r $OUTDIR/* || true # Important to pull latest version of libs into all device flavors, otherwise some devices might be stale -platformio pkg update +platformio pkg update -e $1 echo "Building for $1 with $PLATFORMIO_BUILD_FLAGS" rm -f .pio/build/$1/firmware.* From bca9fbe7e4f91daf809eb8131b8a25385df7d35f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 27 Jul 2024 06:49:50 -0500 Subject: [PATCH 198/211] Missed a needs --- .github/workflows/main_matrix.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index ae50b94ecb..36125f72f1 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -144,6 +144,7 @@ jobs: build-esp32-c3, build-nrf52, build-rpi2040, + build-stm32, package-raspbian, package-raspbian-armv7l, package-native, From 1b249c32bfb10d249f069b17cbe74ddb95db5bd1 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 27 Jul 2024 07:28:11 -0500 Subject: [PATCH 199/211] Copy the actual bin --- bin/build-stm32.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/build-stm32.sh b/bin/build-stm32.sh index 9e813a8c09..76c5a75fb2 100755 --- a/bin/build-stm32.sh +++ b/bin/build-stm32.sh @@ -25,5 +25,5 @@ pio run --environment $1 # -v SRCELF=.pio/build/$1/firmware.elf cp $SRCELF $OUTDIR/$basename.elf -SRCELF=.pio/build/$1/firmware.bin -cp $SRCHEX $OUTDIR/$basename.bin +SRCBIN=.pio/build/$1/firmware.bin +cp $SRCBIN $OUTDIR/$basename.bin From 32bc2f1137ab04440569fae9394a6acba1495110 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 27 Jul 2024 09:38:28 -0500 Subject: [PATCH 200/211] Add RAK3172 to the STM32WL canon --- variants/rak3172/platformio.ini | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/variants/rak3172/platformio.ini b/variants/rak3172/platformio.ini index 63766c988c..d1bd55e832 100644 --- a/variants/rak3172/platformio.ini +++ b/variants/rak3172/platformio.ini @@ -1,12 +1,31 @@ [env:rak3172] extends = stm32_base -board_level = extra board = wiscore_rak3172 build_flags = ${stm32_base.build_flags} -Ivariants/rak3172 - -DHAL_DAC_MODULE_ONLY -DSERIAL_UART_INSTANCE=1 -DPIN_SERIAL_RX=PB7 -DPIN_SERIAL_TX=PB6 + -DHAL_DAC_MODULE_ONLY + -DHAL_ADC_MODULE_DISABLED + -DHAL_COMP_MODULE_DISABLED + -DHAL_CRC_MODULE_DISABLED + -DHAL_CRYP_MODULE_DISABLED + -DHAL_GTZC_MODULE_DISABLED + -DHAL_HSEM_MODULE_DISABLED + -DHAL_I2C_MODULE_DISABLED + -DHAL_I2S_MODULE_DISABLED + -DHAL_IPCC_MODULE_DISABLED + -DHAL_IRDA_MODULE_DISABLED + -DHAL_IWDG_MODULE_DISABLED + -DHAL_LPTIM_MODULE_DISABLED + -DHAL_PKA_MODULE_DISABLED + -DHAL_RNG_MODULE_DISABLED + -DHAL_RTC_MODULE_DISABLED + -DHAL_SMARTCARD_MODULE_DISABLED + -DHAL_SMBUS_MODULE_DISABLED + -DHAL_TIM_MODULE_DISABLED + -DHAL_WWDG_MODULE_DISABLED + -DHAL_EXTI_MODULE_DISABLED upload_port = stlink \ No newline at end of file From 1a1d545c38bfb3daa298d4aee03ec97f51d1b3ee Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sun, 28 Jul 2024 14:12:30 -0500 Subject: [PATCH 201/211] Adds a userPrefs.h file, default blank, used for default settings for custom builds (#4325) * add a userPrefs.h file, default blank, which can be used to easily set defaults on custom builds. * Add Splash Screen to userPrefs * Add channel 0 defaults to userPrefs.h * CONFIG_LORA_IGNORE_MQTT_DEFAULT * Unify naming for USERPREFS defines --------- Co-authored-by: Ben Meadors --- src/graphics/Screen.cpp | 5 +++++ src/graphics/img/icon.xbm | 4 +++- src/mesh/Channels.cpp | 27 ++++++++++++++++++++++++++- src/mesh/NodeDB.cpp | 13 +++++++++++++ userPrefs.h | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 userPrefs.h diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index b2059b71c6..54fd1ea4d5 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -20,6 +20,7 @@ along with this program. If not, see . */ #include "Screen.h" +#include "../userPrefs.h" #include "configuration.h" #if HAS_SCREEN #include @@ -156,7 +157,11 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl display->setFont(FONT_MEDIUM); display->setTextAlignment(TEXT_ALIGN_LEFT); +#ifdef SPLASH_TITLE_USERPREFS + const char *title = SPLASH_TITLE_USERPREFS; +#else const char *title = "meshtastic.org"; +#endif display->drawString(x + getStringCenteredX(title), y + SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM, title); display->setFont(FONT_SMALL); diff --git a/src/graphics/img/icon.xbm b/src/graphics/img/icon.xbm index 297f31ed6f..f90cf4946f 100644 --- a/src/graphics/img/icon.xbm +++ b/src/graphics/img/icon.xbm @@ -1,3 +1,4 @@ +#ifndef HAS_USERPREFS_SPLASH #define icon_width 50 #define icon_height 28 static uint8_t icon_bits[] = { @@ -17,4 +18,5 @@ static uint8_t icon_bits[] = { 0xFE, 0x00, 0x00, 0xFC, 0x01, 0x7E, 0x00, 0x7F, 0x00, 0x00, 0xF8, 0x01, 0x7E, 0x00, 0x3E, 0x00, 0x00, 0xF8, 0x01, 0x38, 0x00, 0x3C, 0x00, 0x00, 0x70, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, }; \ No newline at end of file + 0x00, 0x00, 0x00, 0x00, }; +#endif \ No newline at end of file diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index bb4d629e7b..1a23c78613 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -1,4 +1,5 @@ #include "Channels.h" +#include "../userPrefs.h" #include "CryptoEngine.h" #include "DisplayFormatters.h" #include "NodeDB.h" @@ -90,6 +91,7 @@ void Channels::initDefaultChannel(ChannelIndex chIndex) loraConfig.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST; // Default to Long Range & Fast loraConfig.use_preset = true; loraConfig.tx_power = 0; // default + loraConfig.channel_num = 0; uint8_t defaultpskIndex = 1; channelSettings.psk.bytes[0] = defaultpskIndex; channelSettings.psk.size = 1; @@ -99,6 +101,29 @@ void Channels::initDefaultChannel(ChannelIndex chIndex) ch.has_settings = true; ch.role = meshtastic_Channel_Role_PRIMARY; + +#ifdef LORACONFIG_MODEM_PRESET_USERPREFS + loraConfig.modem_preset = LORACONFIG_MODEM_PRESET_USERPREFS; +#endif +#ifdef LORACONFIG_CHANNEL_NUM_USERPREFS + loraConfig.channel_num = LORACONFIG_CHANNEL_NUM_USERPREFS; +#endif + + // Install custom defaults. Will eventually support setting multiple default channels + if (chIndex == 0) { +#ifdef CHANNEL_0_PSK_USERPREFS + static const uint8_t defaultpsk[] = CHANNEL_0_PSK_USERPREFS; + memcpy(channelSettings.psk.bytes, defaultpsk, sizeof(defaultpsk)); + channelSettings.psk.size = sizeof(defaultpsk); + +#endif +#ifdef CHANNEL_0_NAME_USERPREFS + strcpy(channelSettings.name, CHANNEL_0_NAME_USERPREFS); +#endif +#ifdef CHANNEL_0_PRECISION_USERPREFS + channelSettings.module_settings.position_precision = CHANNEL_0_PRECISION_USERPREFS; +#endif + } } CryptoKey Channels::getKey(ChannelIndex chIndex) @@ -330,4 +355,4 @@ bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash) int16_t Channels::setActiveByIndex(ChannelIndex channelIndex) { return setCrypto(channelIndex); -} +} \ No newline at end of file diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 4257837b33..b4b5ec2868 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1,3 +1,4 @@ +#include "../userPrefs.h" #include "configuration.h" #if !MESHTASTIC_EXCLUDE_GPS #include "GPS.h" @@ -237,10 +238,22 @@ void NodeDB::installDefaultConfig() config.lora.tx_enabled = true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off) config.lora.override_duty_cycle = false; +#ifdef CONFIG_LORA_REGION_USERPREFS + config.lora.region = CONFIG_LORA_REGION_USERPREFS; +#else config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_UNSET; +#endif +#ifdef LORACONFIG_MODEM_PRESET_USERPREFS + config.lora.modem_preset = LORACONFIG_MODEM_PRESET_USERPREFS; +#else config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST; +#endif config.lora.hop_limit = HOP_RELIABLE; +#ifdef CONFIG_LORA_IGNORE_MQTT_USERPREFS + config.lora.ignore_mqtt = CONFIG_LORA_IGNORE_MQTT_USERPREFS; +#else config.lora.ignore_mqtt = false; +#endif #ifdef PIN_GPS_EN config.position.gps_en_gpio = PIN_GPS_EN; #endif diff --git a/userPrefs.h b/userPrefs.h new file mode 100644 index 0000000000..e03b70023e --- /dev/null +++ b/userPrefs.h @@ -0,0 +1,33 @@ +#ifndef _USERPREFS_ +#define _USERPREFS_ +// Uncomment and modify to set device defaults + +// #define CONFIG_LORA_REGION_USERPREFS meshtastic_Config_LoRaConfig_RegionCode_US +// #define LORACONFIG_MODEM_PRESET_USERPREFS meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST +// #define LORACONFIG_CHANNEL_NUM_USERPREFS 31 +// #define CONFIG_LORA_IGNORE_MQTT_USERPREFS true +/* +#define CHANNEL_0_PSK_USERPREFS \ + { \ + 0x38, 0x4b, 0xbc, 0xc0, 0x1d, 0xc0, 0x22, 0xd1, 0x81, 0xbf, 0x36, 0xb8, 0x61, 0x21, 0xe1, 0xfb, 0x96, 0xb7, 0x2e, 0x55, \ + 0xbf, 0x74, 0x22, 0x7e, 0x9d, 0x6a, 0xfb, 0x48, 0xd6, 0x4c, 0xb1, 0xa1 \ + } +*/ +// #define CHANNEL_0_NAME_USERPREFS "DEFCONnect" +// #define CHANNEL_0_PRECISION_USERPREFS 13 + +// #define SPLASH_TITLE_USERPREFS "DEFCONtastic" +// #define icon_width 34 +// #define icon_height 29 +// #define HAS_USERPREFS_SPLASH +/* +static unsigned char icon_bits[] = { + 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, + 0x9E, 0xE7, 0x00, 0x00, 0x00, 0x0E, 0xC7, 0x01, 0x00, 0x1C, 0x0F, 0xC7, 0x01, 0x00, 0x1C, 0xDF, 0xE7, 0x63, 0x00, 0x1C, 0xFF, + 0xBF, 0xE1, 0x00, 0x3C, 0xF3, 0xBF, 0xE3, 0x00, 0x7F, 0xF7, 0xBF, 0xF1, 0x00, 0xFF, 0xF7, 0xBF, 0xF9, 0x03, 0xFF, 0xE7, 0x9F, + 0xFF, 0x03, 0xC0, 0xCF, 0xEF, 0xDF, 0x03, 0x00, 0xDF, 0xE3, 0x8F, 0x00, 0x00, 0x7C, 0xFB, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0x00, + 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x78, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x00, + 0x98, 0x3F, 0xF0, 0x23, 0x00, 0xFC, 0x0F, 0xE0, 0x7F, 0x00, 0xFC, 0x03, 0x80, 0xFF, 0x01, 0xFC, 0x00, 0x00, 0x3E, 0x00, 0x70, + 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00}; +*/ +#endif \ No newline at end of file From 8b0208d1c6ec750ad343ec71fc0ccf742646df77 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 28 Jul 2024 14:53:25 -0500 Subject: [PATCH 202/211] [create-pull-request] automated change (#4335) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 4c87608d0a..b8bb5e67d6 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 4 -build = 1 +build = 2 From 811a9ae2615e8586d18bf31725370e103be87d5d Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 28 Jul 2024 19:49:10 -0500 Subject: [PATCH 203/211] Macro to trace log all MeshPackets as JSON (#4336) * Macro to trace log all MeshPackets as JSON * Comment * Add trace logging to file for native target * bytes to hex * Add time_ms --------- Co-authored-by: Jonathan Bennett --- bin/config-dist.yaml | 3 +- src/RedirectablePrint.cpp | 22 +++++++++++++- src/mesh/Router.cpp | 24 +++++++++++++++ src/platform/portduino/PortduinoGlue.cpp | 14 ++++++++- src/platform/portduino/PortduinoGlue.h | 5 +++- src/serialization/MeshPacketSerializer.cpp | 34 +++++++++++++++++++++- src/serialization/MeshPacketSerializer.h | 17 ++++++++++- 7 files changed, 113 insertions(+), 6 deletions(-) diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml index 333d6eadca..0ec5a440b1 100644 --- a/bin/config-dist.yaml +++ b/bin/config-dist.yaml @@ -135,10 +135,11 @@ Input: Logging: LogLevel: info # debug, info, warn, error +# TraceFile: /var/log/meshtasticd.json Webserver: # Port: 443 # Port for Webserver & Webservices # RootPath: /usr/share/doc/meshtasticd/web # Root Dir of WebServer General: - MaxNodes: 200 + MaxNodes: 200 \ No newline at end of file diff --git a/src/RedirectablePrint.cpp b/src/RedirectablePrint.cpp index 9c3dcdc987..05d349de92 100644 --- a/src/RedirectablePrint.cpp +++ b/src/RedirectablePrint.cpp @@ -49,7 +49,11 @@ size_t RedirectablePrint::write(uint8_t c) size_t RedirectablePrint::vprintf(const char *logLevel, const char *format, va_list arg) { va_list copy; +#if ENABLE_JSON_LOGGING || ARCH_PORTDUINO + static char printBuf[512]; +#else static char printBuf[160]; +#endif va_copy(copy, arg); size_t len = vsnprintf(printBuf, sizeof(printBuf), format, copy); @@ -98,6 +102,8 @@ void RedirectablePrint::log_to_serial(const char *logLevel, const char *format, Print::write("\u001b[33m", 6); if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_ERROR) == 0) Print::write("\u001b[31m", 6); + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) + Print::write("\u001b[35m", 6); uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // display local time on logfile if (rtc_sec > 0) { long hms = rtc_sec % SEC_PER_DAY; @@ -244,7 +250,21 @@ meshtastic_LogRecord_Level RedirectablePrint::getLogLevel(const char *logLevel) void RedirectablePrint::log(const char *logLevel, const char *format, ...) { -#ifdef ARCH_PORTDUINO +#if ARCH_PORTDUINO + // level trace is special, two possible ways to handle it. + if (strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) { + if (settingsStrings[traceFilename] != "") { + va_list arg; + va_start(arg, format); + try { + traceFile << va_arg(arg, char *) << std::endl; + } catch (const std::ios_base::failure &e) { + } + va_end(arg); + } + if (settingsMap[logoutputlevel] < level_trace && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_TRACE) == 0) + return; + } if (settingsMap[logoutputlevel] < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) return; else if (settingsMap[logoutputlevel] < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 35536e7149..c1801d4199 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -11,6 +11,12 @@ #if !MESHTASTIC_EXCLUDE_MQTT #include "mqtt/MQTT.h" #endif +#if ARCH_PORTDUINO +#include "platform/portduino/PortduinoGlue.h" +#endif +#if ENABLE_JSON_LOGGING || ARCH_PORTDUINO +#include "serialization/MeshPacketSerializer.h" +#endif /** * Router todo * @@ -356,6 +362,13 @@ bool perhapsDecode(meshtastic_MeshPacket *p) } */ printPacket("decoded message", p); +#if ENABLE_JSON_LOGGING + LOG_TRACE("%s\n", MeshPacketSerializer::JsonSerialize(p, false).c_str()); +#elif ARCH_PORTDUINO + if (settingsStrings[traceFilename] != "" || settingsMap[logoutputlevel] == level_trace) { + LOG_TRACE("%s\n", MeshPacketSerializer::JsonSerialize(p, false).c_str()); + } +#endif return true; } } @@ -491,6 +504,17 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src) void Router::perhapsHandleReceived(meshtastic_MeshPacket *p) { +#if ENABLE_JSON_LOGGING + // Even ignored packets get logged in the trace + p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone + LOG_TRACE("%s\n", MeshPacketSerializer::JsonSerializeEncrypted(p).c_str()); +#elif ARCH_PORTDUINO + // Even ignored packets get logged in the trace + if (settingsStrings[traceFilename] != "" || settingsMap[logoutputlevel] == level_trace) { + p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone + LOG_TRACE("%s\n", MeshPacketSerializer::JsonSerializeEncrypted(p).c_str()); + } +#endif // assert(radioConfig.has_preferences); bool ignore = is_in_repeated(config.lora.ignore_incoming, p->from) || (config.lora.ignore_mqtt && p->via_mqtt); diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index 89ac806dd0..b910206ec2 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -17,6 +17,7 @@ std::map settingsMap; std::map settingsStrings; +std::ofstream traceFile; char *configPath = nullptr; // FIXME - move setBluetoothEnable into a HALPlatform class @@ -134,7 +135,9 @@ void portduinoSetup() try { if (yamlConfig["Logging"]) { - if (yamlConfig["Logging"]["LogLevel"].as("info") == "debug") { + if (yamlConfig["Logging"]["LogLevel"].as("info") == "trace") { + settingsMap[logoutputlevel] = level_trace; + } else if (yamlConfig["Logging"]["LogLevel"].as("info") == "debug") { settingsMap[logoutputlevel] = level_debug; } else if (yamlConfig["Logging"]["LogLevel"].as("info") == "info") { settingsMap[logoutputlevel] = level_info; @@ -143,6 +146,7 @@ void portduinoSetup() } else if (yamlConfig["Logging"]["LogLevel"].as("info") == "error") { settingsMap[logoutputlevel] = level_error; } + settingsStrings[traceFilename] = yamlConfig["Logging"]["TraceFile"].as(""); } if (yamlConfig["Lora"]) { settingsMap[use_sx1262] = false; @@ -346,6 +350,14 @@ void portduinoSetup() if (settingsStrings[spidev] != "") { SPI.begin(settingsStrings[spidev].c_str()); } + if (settingsStrings[traceFilename] != "") { + try { + traceFile.open(settingsStrings[traceFilename], std::ios::out | std::ios::app); + } catch (std::ofstream::failure &e) { + std::cout << "*** traceFile Exception " << e.what() << std::endl; + exit(EXIT_FAILURE); + } + } return; } diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index ca935ea3bf..6b9a8eb8e9 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -1,4 +1,5 @@ #pragma once +#include #include enum configNames { @@ -46,6 +47,7 @@ enum configNames { displayInvert, keyboardDevice, logoutputlevel, + traceFilename, webserver, webserverport, webserverrootpath, @@ -53,8 +55,9 @@ enum configNames { }; enum { no_screen, x11, st7789, st7735, st7735s, st7796, ili9341, ili9488, hx8357d }; enum { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 }; -enum { level_error, level_warn, level_info, level_debug }; +enum { level_error, level_warn, level_info, level_debug, level_trace }; extern std::map settingsMap; extern std::map settingsStrings; +extern std::ofstream traceFile; int initGPIOPin(int pinNum, std::string gpioChipname); \ No newline at end of file diff --git a/src/serialization/MeshPacketSerializer.cpp b/src/serialization/MeshPacketSerializer.cpp index dc2db1e6ff..a42bb867ae 100644 --- a/src/serialization/MeshPacketSerializer.cpp +++ b/src/serialization/MeshPacketSerializer.cpp @@ -11,7 +11,7 @@ #endif #include "mesh/generated/meshtastic/remote_hardware.pb.h" -std::string MeshPacketSerializer::JsonSerialize(meshtastic_MeshPacket *mp, bool shouldLog) +std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, bool shouldLog) { // the created jsonObj is immutable after creation, so // we need to do the heavy lifting before assembling it. @@ -312,6 +312,38 @@ std::string MeshPacketSerializer::JsonSerialize(meshtastic_MeshPacket *mp, bool if (shouldLog) LOG_INFO("serialized json message: %s\n", jsonStr.c_str()); + delete value; + return jsonStr; +} + +std::string MeshPacketSerializer::JsonSerializeEncrypted(const meshtastic_MeshPacket *mp) +{ + JSONObject jsonObj; + + jsonObj["id"] = new JSONValue((unsigned int)mp->id); + jsonObj["time_ms"] = new JSONValue((double)millis()); + jsonObj["timestamp"] = new JSONValue((unsigned int)mp->rx_time); + jsonObj["to"] = new JSONValue((unsigned int)mp->to); + jsonObj["from"] = new JSONValue((unsigned int)mp->from); + jsonObj["channel"] = new JSONValue((unsigned int)mp->channel); + jsonObj["want_ack"] = new JSONValue(mp->want_ack); + + if (mp->rx_rssi != 0) + jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi); + if (mp->rx_snr != 0) + jsonObj["snr"] = new JSONValue((float)mp->rx_snr); + if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) { + jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit)); + jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start)); + } + jsonObj["size"] = new JSONValue((unsigned int)mp->encrypted.size); + auto encryptedStr = bytesToHex(mp->encrypted.bytes, mp->encrypted.size); + jsonObj["bytes"] = new JSONValue(encryptedStr.c_str()); + + // serialize and write it to the stream + JSONValue *value = new JSONValue(jsonObj); + std::string jsonStr = value->Stringify(); + delete value; return jsonStr; } \ No newline at end of file diff --git a/src/serialization/MeshPacketSerializer.h b/src/serialization/MeshPacketSerializer.h index 579ee2fd60..03860ab354 100644 --- a/src/serialization/MeshPacketSerializer.h +++ b/src/serialization/MeshPacketSerializer.h @@ -1,8 +1,23 @@ #include #include +static const char hexChars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + class MeshPacketSerializer { public: - static std::string JsonSerialize(meshtastic_MeshPacket *mp, bool shouldLog = true); + static std::string JsonSerialize(const meshtastic_MeshPacket *mp, bool shouldLog = true); + static std::string JsonSerializeEncrypted(const meshtastic_MeshPacket *mp); + + private: + static std::string bytesToHex(const uint8_t *bytes, int len) + { + std::string result = ""; + for (int i = 0; i < len; ++i) { + char const byte = bytes[i]; + result += hexChars[(byte & 0xF0) >> 4]; + result += hexChars[(byte & 0x0F) >> 0]; + } + return result; + } }; \ No newline at end of file From cf22b7ff04e9f51114762a4c7443d544bd7e0e8d Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 29 Jul 2024 06:11:08 -0500 Subject: [PATCH 204/211] Latest pip version of setuptools is broken. Install specific version --- .github/actions/setup-base/action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml index 7f8659523b..cbb1e12f76 100644 --- a/.github/actions/setup-base/action.yml +++ b/.github/actions/setup-base/action.yml @@ -33,6 +33,7 @@ runs: shell: bash run: | python -m pip install --upgrade pip + pip install -U setuptools<72.0.0 pip install -U platformio adafruit-nrfutil pip install -U meshtastic --pre From 8c0ff89972f017b9f478a53ed8777a6c37d8314c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 29 Jul 2024 06:14:32 -0500 Subject: [PATCH 205/211] Trunk --- .github/actions/setup-base/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml index cbb1e12f76..f74f702a7e 100644 --- a/.github/actions/setup-base/action.yml +++ b/.github/actions/setup-base/action.yml @@ -11,7 +11,7 @@ runs: ref: ${{github.event.pull_request.head.ref}} repository: ${{github.event.pull_request.head.repo.full_name}} - - name: Install dependencies + - name: Install dependencies shell: bash run: | sudo apt-get -y update --fix-missing From c501cc501dc646607cbf7e5799daeaeadd599671 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 29 Jul 2024 06:37:19 -0500 Subject: [PATCH 206/211] Pip pip cheerios plz --- .github/actions/setup-base/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml index f74f702a7e..80fa8db9d7 100644 --- a/.github/actions/setup-base/action.yml +++ b/.github/actions/setup-base/action.yml @@ -32,8 +32,8 @@ runs: - name: Upgrade python tools shell: bash run: | + pip install --no-build-isolation --no-cache-dir "setuptools<72" python -m pip install --upgrade pip - pip install -U setuptools<72.0.0 pip install -U platformio adafruit-nrfutil pip install -U meshtastic --pre From 2ffc93324db330d17b68f5ed6d6db5bc83bb22e6 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 29 Jul 2024 06:38:34 -0500 Subject: [PATCH 207/211] After --- .github/actions/setup-base/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml index 80fa8db9d7..1fb3d6c96f 100644 --- a/.github/actions/setup-base/action.yml +++ b/.github/actions/setup-base/action.yml @@ -32,8 +32,8 @@ runs: - name: Upgrade python tools shell: bash run: | - pip install --no-build-isolation --no-cache-dir "setuptools<72" python -m pip install --upgrade pip + pip install --no-build-isolation --no-cache-dir "setuptools<72" pip install -U platformio adafruit-nrfutil pip install -U meshtastic --pre From 4aa6f60e95a6d3fb88f08110e65ff925f56d32c6 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 29 Jul 2024 06:41:26 -0500 Subject: [PATCH 208/211] Maybe remove pip cache --- .github/actions/setup-base/action.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml index 1fb3d6c96f..e19eff7863 100644 --- a/.github/actions/setup-base/action.yml +++ b/.github/actions/setup-base/action.yml @@ -22,12 +22,12 @@ runs: with: python-version: 3.x - - name: Cache python libs - uses: actions/cache@v4 - id: cache-pip # needed in if test - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip + # - name: Cache python libs + # uses: actions/cache@v4 + # id: cache-pip # needed in if test + # with: + # path: ~/.cache/pip + # key: ${{ runner.os }}-pip - name: Upgrade python tools shell: bash From 6813b8e4e9bf5e4f424070a9b92392f7daa6c366 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 29 Jul 2024 06:52:14 -0500 Subject: [PATCH 209/211] Just literally trying stuff at this point --- .github/actions/setup-base/action.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/actions/setup-base/action.yml b/.github/actions/setup-base/action.yml index e19eff7863..61466655d1 100644 --- a/.github/actions/setup-base/action.yml +++ b/.github/actions/setup-base/action.yml @@ -33,9 +33,9 @@ runs: shell: bash run: | python -m pip install --upgrade pip - pip install --no-build-isolation --no-cache-dir "setuptools<72" - pip install -U platformio adafruit-nrfutil - pip install -U meshtastic --pre + pip install -U --no-build-isolation --no-cache-dir "setuptools<72" + pip install -U platformio adafruit-nrfutil --no-build-isolation + pip install -U meshtastic --pre --no-build-isolation - name: Upgrade platformio shell: bash From 59cc57fc29b7f7f1e0285c5ab10bed549d284d4f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 29 Jul 2024 20:16:47 -0500 Subject: [PATCH 210/211] Event mode: Enforce reliable hop limit and disallow default public MQTT (#4343) * Event mode: Enforce reliable hop limit * Event mode: Short circuit wantsLink on MQTT for default broker address * Just enforce at channels level since everything uses this * For events never forward packets with excessive hop_limit * In EVENT_MODE, don't respond with hop_limit set more then the configured max. * Correct hop_start when correcting hop_limit in event mode. * Make EVENT_MODE work from userPrefs.h * Event mode: Disallow Router or Repeater roles --------- Co-authored-by: Jonathan Bennett --- src/mesh/Channels.cpp | 7 +++++++ src/mesh/Default.cpp | 10 ++++++++++ src/mesh/Default.h | 1 + src/mesh/FloodingRouter.cpp | 8 ++++++++ src/mesh/ReliableRouter.cpp | 3 ++- src/mesh/Router.cpp | 3 ++- src/modules/AdminModule.cpp | 7 +++++++ src/modules/RoutingModule.cpp | 6 +++++- userPrefs.h | 3 +++ 9 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 1a23c78613..8d5b4353b5 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -1,6 +1,7 @@ #include "Channels.h" #include "../userPrefs.h" #include "CryptoEngine.h" +#include "Default.h" #include "DisplayFormatters.h" #include "NodeDB.h" #include "RadioInterface.h" @@ -276,6 +277,12 @@ void Channels::setChannel(const meshtastic_Channel &c) bool Channels::anyMqttEnabled() { +#if EVENT_MODE + // Don't publish messages on the public MQTT broker if we are in event mode + if (strcmp(moduleConfig.mqtt.address, default_mqtt_address) == 0) { + return false; + } +#endif for (int i = 0; i < getNumChannels(); i++) if (channelFile.channels[i].role != meshtastic_Channel_Role_DISABLED && channelFile.channels[i].has_settings && (channelFile.channels[i].settings.downlink_enabled || channelFile.channels[i].settings.uplink_enabled)) diff --git a/src/mesh/Default.cpp b/src/mesh/Default.cpp index d4e9b3d790..ac74413949 100644 --- a/src/mesh/Default.cpp +++ b/src/mesh/Default.cpp @@ -1,4 +1,5 @@ #include "Default.h" +#include "../userPrefs.h" uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval) { @@ -40,4 +41,13 @@ uint32_t Default::getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t d return getConfiguredOrDefaultMs(configured, defaultValue); return getConfiguredOrDefaultMs(configured, defaultValue) * congestionScalingCoefficient(numOnlineNodes); +} + +uint8_t Default::getConfiguredOrDefaultHopLimit(uint8_t configured) +{ +#if EVENT_MODE + return (configured > HOP_RELIABLE) ? HOP_RELIABLE : config.lora.hop_limit; +#else + return (configured >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit; +#endif } \ No newline at end of file diff --git a/src/mesh/Default.h b/src/mesh/Default.h index 7d79d696e5..3c95544dac 100644 --- a/src/mesh/Default.h +++ b/src/mesh/Default.h @@ -30,6 +30,7 @@ class Default static uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval); static uint32_t getConfiguredOrDefault(uint32_t configured, uint32_t defaultValue); static uint32_t getConfiguredOrDefaultMsScaled(uint32_t configured, uint32_t defaultValue, uint32_t numOnlineNodes); + static uint8_t getConfiguredOrDefaultHopLimit(uint8_t configured); private: static float congestionScalingCoefficient(int numOnlineNodes) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 0fdde52772..fbe56159c0 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -1,4 +1,5 @@ #include "FloodingRouter.h" +#include "../userPrefs.h" #include "configuration.h" #include "mesh-pb-constants.h" @@ -46,6 +47,13 @@ void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it tosend->hop_limit--; // bump down the hop count +#if EVENT_MODE + if (tosend->hop_limit > 2) { + // if we are "correcting" the hop_limit, "correct" the hop_start by the same amount to preserve hops away. + tosend->hop_start -= (tosend->hop_limit - 2); + tosend->hop_limit = 2; + } +#endif LOG_INFO("Rebroadcasting received floodmsg to neighbors\n"); // Note: we are careful to resend using the original senders node id diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index d3246b48d0..c91ce50c5b 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -1,4 +1,5 @@ #include "ReliableRouter.h" +#include "Default.h" #include "MeshModule.h" #include "MeshTypes.h" #include "configuration.h" @@ -17,7 +18,7 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p) // message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop // counts and we want this message to get through the whole mesh, so use the default. if (p->hop_limit == 0) { - p->hop_limit = (config.lora.hop_limit >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit; + p->hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit); } auto copy = packetPool.allocCopy(*p); diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index c1801d4199..9bffd7a5db 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -11,6 +11,7 @@ #if !MESHTASTIC_EXCLUDE_MQTT #include "mqtt/MQTT.h" #endif +#include "Default.h" #if ARCH_PORTDUINO #include "platform/portduino/PortduinoGlue.h" #endif @@ -125,7 +126,7 @@ meshtastic_MeshPacket *Router::allocForSending() p->which_payload_variant = meshtastic_MeshPacket_decoded_tag; // Assume payload is decoded at start. p->from = nodeDB->getNodeNum(); p->to = NODENUM_BROADCAST; - p->hop_limit = (config.lora.hop_limit >= HOP_MAX) ? HOP_MAX : config.lora.hop_limit; + p->hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit); p->id = generatePacketId(); p->rx_time = getValidTime(RTCQualityFromNet); // Just in case we process the packet locally - make sure it has a valid timestamp diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 8939b972b9..c1e9b388b5 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -400,6 +400,13 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c) requiresReboot = true; } } +#if EVENT_MODE + // If we're in event mode, nobody is a Router or Repeater + if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER || + config.device.role == meshtastic_Config_DeviceConfig_Role_REPEATER) { + config.device.role = meshtastic_Config_DeviceConfig_Role_CLIENT; + } +#endif break; case meshtastic_Config_position_tag: LOG_INFO("Setting config: Position\n"); diff --git a/src/modules/RoutingModule.cpp b/src/modules/RoutingModule.cpp index fe1abab05d..80ac92fff1 100644 --- a/src/modules/RoutingModule.cpp +++ b/src/modules/RoutingModule.cpp @@ -1,4 +1,5 @@ #include "RoutingModule.h" +#include "Default.h" #include "MeshService.h" #include "NodeDB.h" #include "Router.h" @@ -50,12 +51,15 @@ uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit // Hops used by the request. If somebody in between running modified firmware modified it, ignore it uint8_t hopsUsed = hopStart < hopLimit ? config.lora.hop_limit : hopStart - hopLimit; if (hopsUsed > config.lora.hop_limit) { +// In event mode, we never want to send packets with more than our default 3 hops. +#if !(EVENTMODE) // This falls through to the default. return hopsUsed; // If the request used more hops than the limit, use the same amount of hops +#endif } else if ((uint8_t)(hopsUsed + 2) < config.lora.hop_limit) { return hopsUsed + 2; // Use only the amount of hops needed with some margin as the way back may be different } } - return config.lora.hop_limit; // Use the default hop limit + return Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit); // Use the default hop limit } RoutingModule::RoutingModule() : ProtobufModule("routing", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg) diff --git a/userPrefs.h b/userPrefs.h index e03b70023e..b365e8c6f8 100644 --- a/userPrefs.h +++ b/userPrefs.h @@ -1,7 +1,10 @@ #ifndef _USERPREFS_ #define _USERPREFS_ + // Uncomment and modify to set device defaults +// #define EVENT_MODE 1 + // #define CONFIG_LORA_REGION_USERPREFS meshtastic_Config_LoRaConfig_RegionCode_US // #define LORACONFIG_MODEM_PRESET_USERPREFS meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST // #define LORACONFIG_CHANNEL_NUM_USERPREFS 31 From 302caa854a9799250b6f3ac05660aae2d86b9891 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:13:25 -0500 Subject: [PATCH 211/211] [create-pull-request] automated change (#4354) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/config.pb.h | 12 ++++++++---- src/mesh/generated/meshtastic/deviceonly.pb.h | 2 +- src/mesh/generated/meshtastic/localonly.pb.h | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/protobufs b/protobufs index b1a79d5db0..abd5eaa875 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit b1a79d5db00f6aeeb0bbae156e8939e146c95299 +Subproject commit abd5eaa875233d9bcee7e4cef3d5edcbc5b66307 diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h index 44a86f4d64..27a7c13830 100644 --- a/src/mesh/generated/meshtastic/config.pb.h +++ b/src/mesh/generated/meshtastic/config.pb.h @@ -303,6 +303,8 @@ typedef struct _meshtastic_Config_DeviceConfig { char tzdef[65]; /* If true, disable the default blinking LED (LED_PIN) behavior on the device */ bool led_heartbeat_disabled; + /* Enable LogRecord messages over Serial for API connections */ + bool logrecord_serial_enabled; } meshtastic_Config_DeviceConfig; /* Position Config */ @@ -614,7 +616,7 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}} -#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} +#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0, 0} #define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} #define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""} @@ -623,7 +625,7 @@ extern "C" { #define meshtastic_Config_LoRaConfig_init_default {0, _meshtastic_Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _meshtastic_Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0} #define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0, 0} #define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}} -#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} +#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0, 0} #define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} #define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""} @@ -645,6 +647,7 @@ extern "C" { #define meshtastic_Config_DeviceConfig_disable_triple_click_tag 10 #define meshtastic_Config_DeviceConfig_tzdef_tag 11 #define meshtastic_Config_DeviceConfig_led_heartbeat_disabled_tag 12 +#define meshtastic_Config_DeviceConfig_logrecord_serial_enabled_tag 13 #define meshtastic_Config_PositionConfig_position_broadcast_secs_tag 1 #define meshtastic_Config_PositionConfig_position_broadcast_smart_enabled_tag 2 #define meshtastic_Config_PositionConfig_fixed_position_tag 3 @@ -750,7 +753,8 @@ X(a, STATIC, SINGULAR, BOOL, double_tap_as_button_press, 8) \ X(a, STATIC, SINGULAR, BOOL, is_managed, 9) \ X(a, STATIC, SINGULAR, BOOL, disable_triple_click, 10) \ X(a, STATIC, SINGULAR, STRING, tzdef, 11) \ -X(a, STATIC, SINGULAR, BOOL, led_heartbeat_disabled, 12) +X(a, STATIC, SINGULAR, BOOL, led_heartbeat_disabled, 12) \ +X(a, STATIC, SINGULAR, BOOL, logrecord_serial_enabled, 13) #define meshtastic_Config_DeviceConfig_CALLBACK NULL #define meshtastic_Config_DeviceConfig_DEFAULT NULL @@ -873,7 +877,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size #define meshtastic_Config_BluetoothConfig_size 12 -#define meshtastic_Config_DeviceConfig_size 100 +#define meshtastic_Config_DeviceConfig_size 102 #define meshtastic_Config_DisplayConfig_size 30 #define meshtastic_Config_LoRaConfig_size 82 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20 diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index eb37f4f957..fb6ab1bf28 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -307,7 +307,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg; #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size #define meshtastic_ChannelFile_size 718 #define meshtastic_NodeInfoLite_size 166 -#define meshtastic_OEMStore_size 3388 +#define meshtastic_OEMStore_size 3390 #define meshtastic_PositionLite_size 28 #ifdef __cplusplus diff --git a/src/mesh/generated/meshtastic/localonly.pb.h b/src/mesh/generated/meshtastic/localonly.pb.h index 983f48ad3f..9eff147541 100644 --- a/src/mesh/generated/meshtastic/localonly.pb.h +++ b/src/mesh/generated/meshtastic/localonly.pb.h @@ -181,7 +181,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size -#define meshtastic_LocalConfig_size 555 +#define meshtastic_LocalConfig_size 557 #define meshtastic_LocalModuleConfig_size 687 #ifdef __cplusplus